1/* 2 * This file is subject to the terms and conditions of the GNU General Public 3 * License. See the file "COPYING" in the main directory of this archive 4 * for more details. 5 * 6 * Copyright (C) 2008 Maxime Bizon <mbizon@freebox.fr> 7 */ 8 9#include <linux/module.h> 10#include <linux/mutex.h> 11#include <linux/err.h> 12#include <linux/clk.h> 13#include <linux/delay.h> 14#include <bcm63xx_cpu.h> 15#include <bcm63xx_io.h> 16#include <bcm63xx_regs.h> 17#include <bcm63xx_reset.h> 18 19struct clk { 20 void (*set)(struct clk *, int); 21 unsigned int rate; 22 unsigned int usage; 23 int id; 24}; 25 26static DEFINE_MUTEX(clocks_mutex); 27 28 29static void clk_enable_unlocked(struct clk *clk) 30{ 31 if (clk->set && (clk->usage++) == 0) 32 clk->set(clk, 1); 33} 34 35static void clk_disable_unlocked(struct clk *clk) 36{ 37 if (clk->set && (--clk->usage) == 0) 38 clk->set(clk, 0); 39} 40 41static void bcm_hwclock_set(u32 mask, int enable) 42{ 43 u32 reg; 44 45 reg = bcm_perf_readl(PERF_CKCTL_REG); 46 if (enable) 47 reg |= mask; 48 else 49 reg &= ~mask; 50 bcm_perf_writel(reg, PERF_CKCTL_REG); 51} 52 53/* 54 * Ethernet MAC "misc" clock: dma clocks and main clock on 6348 55 */ 56static void enet_misc_set(struct clk *clk, int enable) 57{ 58 u32 mask; 59 60 if (BCMCPU_IS_6338()) 61 mask = CKCTL_6338_ENET_EN; 62 else if (BCMCPU_IS_6345()) 63 mask = CKCTL_6345_ENET_EN; 64 else if (BCMCPU_IS_6348()) 65 mask = CKCTL_6348_ENET_EN; 66 else 67 /* BCMCPU_IS_6358 */ 68 mask = CKCTL_6358_EMUSB_EN; 69 bcm_hwclock_set(mask, enable); 70} 71 72static struct clk clk_enet_misc = { 73 .set = enet_misc_set, 74}; 75 76/* 77 * Ethernet MAC clocks: only revelant on 6358, silently enable misc 78 * clocks 79 */ 80static void enetx_set(struct clk *clk, int enable) 81{ 82 if (enable) 83 clk_enable_unlocked(&clk_enet_misc); 84 else 85 clk_disable_unlocked(&clk_enet_misc); 86 87 if (BCMCPU_IS_3368() || BCMCPU_IS_6358()) { 88 u32 mask; 89 90 if (clk->id == 0) 91 mask = CKCTL_6358_ENET0_EN; 92 else 93 mask = CKCTL_6358_ENET1_EN; 94 bcm_hwclock_set(mask, enable); 95 } 96} 97 98static struct clk clk_enet0 = { 99 .id = 0, 100 .set = enetx_set, 101}; 102 103static struct clk clk_enet1 = { 104 .id = 1, 105 .set = enetx_set, 106}; 107 108/* 109 * Ethernet PHY clock 110 */ 111static void ephy_set(struct clk *clk, int enable) 112{ 113 if (BCMCPU_IS_3368() || BCMCPU_IS_6358()) 114 bcm_hwclock_set(CKCTL_6358_EPHY_EN, enable); 115} 116 117 118static struct clk clk_ephy = { 119 .set = ephy_set, 120}; 121 122/* 123 * Ethernet switch clock 124 */ 125static void enetsw_set(struct clk *clk, int enable) 126{ 127 if (BCMCPU_IS_6328()) 128 bcm_hwclock_set(CKCTL_6328_ROBOSW_EN, enable); 129 else if (BCMCPU_IS_6362()) 130 bcm_hwclock_set(CKCTL_6362_ROBOSW_EN, enable); 131 else if (BCMCPU_IS_6368()) 132 bcm_hwclock_set(CKCTL_6368_ROBOSW_EN | 133 CKCTL_6368_SWPKT_USB_EN | 134 CKCTL_6368_SWPKT_SAR_EN, 135 enable); 136 else 137 return; 138 139 if (enable) { 140 /* reset switch core afer clock change */ 141 bcm63xx_core_set_reset(BCM63XX_RESET_ENETSW, 1); 142 msleep(10); 143 bcm63xx_core_set_reset(BCM63XX_RESET_ENETSW, 0); 144 msleep(10); 145 } 146} 147 148static struct clk clk_enetsw = { 149 .set = enetsw_set, 150}; 151 152/* 153 * PCM clock 154 */ 155static void pcm_set(struct clk *clk, int enable) 156{ 157 if (BCMCPU_IS_3368()) 158 bcm_hwclock_set(CKCTL_3368_PCM_EN, enable); 159 if (BCMCPU_IS_6358()) 160 bcm_hwclock_set(CKCTL_6358_PCM_EN, enable); 161} 162 163static struct clk clk_pcm = { 164 .set = pcm_set, 165}; 166 167/* 168 * USB host clock 169 */ 170static void usbh_set(struct clk *clk, int enable) 171{ 172 if (BCMCPU_IS_6328()) 173 bcm_hwclock_set(CKCTL_6328_USBH_EN, enable); 174 else if (BCMCPU_IS_6348()) 175 bcm_hwclock_set(CKCTL_6348_USBH_EN, enable); 176 else if (BCMCPU_IS_6362()) 177 bcm_hwclock_set(CKCTL_6362_USBH_EN, enable); 178 else if (BCMCPU_IS_6368()) 179 bcm_hwclock_set(CKCTL_6368_USBH_EN, enable); 180} 181 182static struct clk clk_usbh = { 183 .set = usbh_set, 184}; 185 186/* 187 * USB device clock 188 */ 189static void usbd_set(struct clk *clk, int enable) 190{ 191 if (BCMCPU_IS_6328()) 192 bcm_hwclock_set(CKCTL_6328_USBD_EN, enable); 193 else if (BCMCPU_IS_6362()) 194 bcm_hwclock_set(CKCTL_6362_USBD_EN, enable); 195 else if (BCMCPU_IS_6368()) 196 bcm_hwclock_set(CKCTL_6368_USBD_EN, enable); 197} 198 199static struct clk clk_usbd = { 200 .set = usbd_set, 201}; 202 203/* 204 * SPI clock 205 */ 206static void spi_set(struct clk *clk, int enable) 207{ 208 u32 mask; 209 210 if (BCMCPU_IS_6338()) 211 mask = CKCTL_6338_SPI_EN; 212 else if (BCMCPU_IS_6348()) 213 mask = CKCTL_6348_SPI_EN; 214 else if (BCMCPU_IS_3368() || BCMCPU_IS_6358()) 215 mask = CKCTL_6358_SPI_EN; 216 else if (BCMCPU_IS_6362()) 217 mask = CKCTL_6362_SPI_EN; 218 else 219 /* BCMCPU_IS_6368 */ 220 mask = CKCTL_6368_SPI_EN; 221 bcm_hwclock_set(mask, enable); 222} 223 224static struct clk clk_spi = { 225 .set = spi_set, 226}; 227 228/* 229 * HSSPI clock 230 */ 231static void hsspi_set(struct clk *clk, int enable) 232{ 233 u32 mask; 234 235 if (BCMCPU_IS_6328()) 236 mask = CKCTL_6328_HSSPI_EN; 237 else if (BCMCPU_IS_6362()) 238 mask = CKCTL_6362_HSSPI_EN; 239 else 240 return; 241 242 bcm_hwclock_set(mask, enable); 243} 244 245static struct clk clk_hsspi = { 246 .set = hsspi_set, 247}; 248 249 250/* 251 * XTM clock 252 */ 253static void xtm_set(struct clk *clk, int enable) 254{ 255 if (!BCMCPU_IS_6368()) 256 return; 257 258 bcm_hwclock_set(CKCTL_6368_SAR_EN | 259 CKCTL_6368_SWPKT_SAR_EN, enable); 260 261 if (enable) { 262 /* reset sar core afer clock change */ 263 bcm63xx_core_set_reset(BCM63XX_RESET_SAR, 1); 264 mdelay(1); 265 bcm63xx_core_set_reset(BCM63XX_RESET_SAR, 0); 266 mdelay(1); 267 } 268} 269 270 271static struct clk clk_xtm = { 272 .set = xtm_set, 273}; 274 275/* 276 * IPsec clock 277 */ 278static void ipsec_set(struct clk *clk, int enable) 279{ 280 if (BCMCPU_IS_6362()) 281 bcm_hwclock_set(CKCTL_6362_IPSEC_EN, enable); 282 else if (BCMCPU_IS_6368()) 283 bcm_hwclock_set(CKCTL_6368_IPSEC_EN, enable); 284} 285 286static struct clk clk_ipsec = { 287 .set = ipsec_set, 288}; 289 290/* 291 * PCIe clock 292 */ 293 294static void pcie_set(struct clk *clk, int enable) 295{ 296 if (BCMCPU_IS_6328()) 297 bcm_hwclock_set(CKCTL_6328_PCIE_EN, enable); 298 else if (BCMCPU_IS_6362()) 299 bcm_hwclock_set(CKCTL_6362_PCIE_EN, enable); 300} 301 302static struct clk clk_pcie = { 303 .set = pcie_set, 304}; 305 306/* 307 * Internal peripheral clock 308 */ 309static struct clk clk_periph = { 310 .rate = (50 * 1000 * 1000), 311}; 312 313 314/* 315 * Linux clock API implementation 316 */ 317int clk_enable(struct clk *clk) 318{ 319 mutex_lock(&clocks_mutex); 320 clk_enable_unlocked(clk); 321 mutex_unlock(&clocks_mutex); 322 return 0; 323} 324 325EXPORT_SYMBOL(clk_enable); 326 327void clk_disable(struct clk *clk) 328{ 329 mutex_lock(&clocks_mutex); 330 clk_disable_unlocked(clk); 331 mutex_unlock(&clocks_mutex); 332} 333 334EXPORT_SYMBOL(clk_disable); 335 336unsigned long clk_get_rate(struct clk *clk) 337{ 338 return clk->rate; 339} 340 341EXPORT_SYMBOL(clk_get_rate); 342 343int clk_set_rate(struct clk *clk, unsigned long rate) 344{ 345 return 0; 346} 347EXPORT_SYMBOL_GPL(clk_set_rate); 348 349long clk_round_rate(struct clk *clk, unsigned long rate) 350{ 351 return 0; 352} 353EXPORT_SYMBOL_GPL(clk_round_rate); 354 355struct clk *clk_get(struct device *dev, const char *id) 356{ 357 if (!strcmp(id, "enet0")) 358 return &clk_enet0; 359 if (!strcmp(id, "enet1")) 360 return &clk_enet1; 361 if (!strcmp(id, "enetsw")) 362 return &clk_enetsw; 363 if (!strcmp(id, "ephy")) 364 return &clk_ephy; 365 if (!strcmp(id, "usbh")) 366 return &clk_usbh; 367 if (!strcmp(id, "usbd")) 368 return &clk_usbd; 369 if (!strcmp(id, "spi")) 370 return &clk_spi; 371 if (!strcmp(id, "hsspi")) 372 return &clk_hsspi; 373 if (!strcmp(id, "xtm")) 374 return &clk_xtm; 375 if (!strcmp(id, "periph")) 376 return &clk_periph; 377 if ((BCMCPU_IS_3368() || BCMCPU_IS_6358()) && !strcmp(id, "pcm")) 378 return &clk_pcm; 379 if ((BCMCPU_IS_6362() || BCMCPU_IS_6368()) && !strcmp(id, "ipsec")) 380 return &clk_ipsec; 381 if ((BCMCPU_IS_6328() || BCMCPU_IS_6362()) && !strcmp(id, "pcie")) 382 return &clk_pcie; 383 return ERR_PTR(-ENOENT); 384} 385 386EXPORT_SYMBOL(clk_get); 387 388void clk_put(struct clk *clk) 389{ 390} 391 392EXPORT_SYMBOL(clk_put); 393 394#define HSSPI_PLL_HZ_6328 133333333 395#define HSSPI_PLL_HZ_6362 400000000 396 397static int __init bcm63xx_clk_init(void) 398{ 399 switch (bcm63xx_get_cpu_id()) { 400 case BCM6328_CPU_ID: 401 clk_hsspi.rate = HSSPI_PLL_HZ_6328; 402 break; 403 case BCM6362_CPU_ID: 404 clk_hsspi.rate = HSSPI_PLL_HZ_6362; 405 break; 406 } 407 408 return 0; 409} 410arch_initcall(bcm63xx_clk_init); 411