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