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 19 struct clk { 20 void (*set)(struct clk *, int); 21 unsigned int rate; 22 unsigned int usage; 23 int id; 24 }; 25 26 static DEFINE_MUTEX(clocks_mutex); 27 28 29 static void clk_enable_unlocked(struct clk *clk) 30 { 31 if (clk->set && (clk->usage++) == 0) 32 clk->set(clk, 1); 33 } 34 35 static void clk_disable_unlocked(struct clk *clk) 36 { 37 if (clk->set && (--clk->usage) == 0) 38 clk->set(clk, 0); 39 } 40 41 static 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 */ 56 static 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 72 static 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 */ 80 static 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 98 static struct clk clk_enet0 = { 99 .id = 0, 100 .set = enetx_set, 101 }; 102 103 static struct clk clk_enet1 = { 104 .id = 1, 105 .set = enetx_set, 106 }; 107 108 /* 109 * Ethernet PHY clock 110 */ 111 static 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 118 static struct clk clk_ephy = { 119 .set = ephy_set, 120 }; 121 122 /* 123 * Ethernet switch clock 124 */ 125 static 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 148 static struct clk clk_enetsw = { 149 .set = enetsw_set, 150 }; 151 152 /* 153 * PCM clock 154 */ 155 static 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 163 static struct clk clk_pcm = { 164 .set = pcm_set, 165 }; 166 167 /* 168 * USB host clock 169 */ 170 static 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 182 static struct clk clk_usbh = { 183 .set = usbh_set, 184 }; 185 186 /* 187 * USB device clock 188 */ 189 static 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 199 static struct clk clk_usbd = { 200 .set = usbd_set, 201 }; 202 203 /* 204 * SPI clock 205 */ 206 static 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 224 static struct clk clk_spi = { 225 .set = spi_set, 226 }; 227 228 /* 229 * HSSPI clock 230 */ 231 static 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 245 static struct clk clk_hsspi = { 246 .set = hsspi_set, 247 }; 248 249 250 /* 251 * XTM clock 252 */ 253 static 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 271 static struct clk clk_xtm = { 272 .set = xtm_set, 273 }; 274 275 /* 276 * IPsec clock 277 */ 278 static 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 286 static struct clk clk_ipsec = { 287 .set = ipsec_set, 288 }; 289 290 /* 291 * PCIe clock 292 */ 293 294 static 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 302 static struct clk clk_pcie = { 303 .set = pcie_set, 304 }; 305 306 /* 307 * Internal peripheral clock 308 */ 309 static struct clk clk_periph = { 310 .rate = (50 * 1000 * 1000), 311 }; 312 313 314 /* 315 * Linux clock API implementation 316 */ 317 int 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 325 EXPORT_SYMBOL(clk_enable); 326 327 void clk_disable(struct clk *clk) 328 { 329 mutex_lock(&clocks_mutex); 330 clk_disable_unlocked(clk); 331 mutex_unlock(&clocks_mutex); 332 } 333 334 EXPORT_SYMBOL(clk_disable); 335 336 unsigned long clk_get_rate(struct clk *clk) 337 { 338 return clk->rate; 339 } 340 341 EXPORT_SYMBOL(clk_get_rate); 342 343 int clk_set_rate(struct clk *clk, unsigned long rate) 344 { 345 return 0; 346 } 347 EXPORT_SYMBOL_GPL(clk_set_rate); 348 349 long clk_round_rate(struct clk *clk, unsigned long rate) 350 { 351 return 0; 352 } 353 EXPORT_SYMBOL_GPL(clk_round_rate); 354 355 struct 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 386 EXPORT_SYMBOL(clk_get); 387 388 void clk_put(struct clk *clk) 389 { 390 } 391 392 EXPORT_SYMBOL(clk_put); 393 394 #define HSSPI_PLL_HZ_6328 133333333 395 #define HSSPI_PLL_HZ_6362 400000000 396 397 static 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 } 410 arch_initcall(bcm63xx_clk_init); 411