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 * XTM clock 230 */ 231 static void xtm_set(struct clk *clk, int enable) 232 { 233 if (!BCMCPU_IS_6368()) 234 return; 235 236 bcm_hwclock_set(CKCTL_6368_SAR_EN | 237 CKCTL_6368_SWPKT_SAR_EN, enable); 238 239 if (enable) { 240 /* reset sar core afer clock change */ 241 bcm63xx_core_set_reset(BCM63XX_RESET_SAR, 1); 242 mdelay(1); 243 bcm63xx_core_set_reset(BCM63XX_RESET_SAR, 0); 244 mdelay(1); 245 } 246 } 247 248 249 static struct clk clk_xtm = { 250 .set = xtm_set, 251 }; 252 253 /* 254 * IPsec clock 255 */ 256 static void ipsec_set(struct clk *clk, int enable) 257 { 258 if (BCMCPU_IS_6362()) 259 bcm_hwclock_set(CKCTL_6362_IPSEC_EN, enable); 260 else if (BCMCPU_IS_6368()) 261 bcm_hwclock_set(CKCTL_6368_IPSEC_EN, enable); 262 } 263 264 static struct clk clk_ipsec = { 265 .set = ipsec_set, 266 }; 267 268 /* 269 * PCIe clock 270 */ 271 272 static void pcie_set(struct clk *clk, int enable) 273 { 274 if (BCMCPU_IS_6328()) 275 bcm_hwclock_set(CKCTL_6328_PCIE_EN, enable); 276 else if (BCMCPU_IS_6362()) 277 bcm_hwclock_set(CKCTL_6362_PCIE_EN, enable); 278 } 279 280 static struct clk clk_pcie = { 281 .set = pcie_set, 282 }; 283 284 /* 285 * Internal peripheral clock 286 */ 287 static struct clk clk_periph = { 288 .rate = (50 * 1000 * 1000), 289 }; 290 291 292 /* 293 * Linux clock API implementation 294 */ 295 int clk_enable(struct clk *clk) 296 { 297 mutex_lock(&clocks_mutex); 298 clk_enable_unlocked(clk); 299 mutex_unlock(&clocks_mutex); 300 return 0; 301 } 302 303 EXPORT_SYMBOL(clk_enable); 304 305 void clk_disable(struct clk *clk) 306 { 307 mutex_lock(&clocks_mutex); 308 clk_disable_unlocked(clk); 309 mutex_unlock(&clocks_mutex); 310 } 311 312 EXPORT_SYMBOL(clk_disable); 313 314 unsigned long clk_get_rate(struct clk *clk) 315 { 316 return clk->rate; 317 } 318 319 EXPORT_SYMBOL(clk_get_rate); 320 321 int clk_set_rate(struct clk *clk, unsigned long rate) 322 { 323 return 0; 324 } 325 EXPORT_SYMBOL_GPL(clk_set_rate); 326 327 long clk_round_rate(struct clk *clk, unsigned long rate) 328 { 329 return 0; 330 } 331 EXPORT_SYMBOL_GPL(clk_round_rate); 332 333 struct clk *clk_get(struct device *dev, const char *id) 334 { 335 if (!strcmp(id, "enet0")) 336 return &clk_enet0; 337 if (!strcmp(id, "enet1")) 338 return &clk_enet1; 339 if (!strcmp(id, "enetsw")) 340 return &clk_enetsw; 341 if (!strcmp(id, "ephy")) 342 return &clk_ephy; 343 if (!strcmp(id, "usbh")) 344 return &clk_usbh; 345 if (!strcmp(id, "usbd")) 346 return &clk_usbd; 347 if (!strcmp(id, "spi")) 348 return &clk_spi; 349 if (!strcmp(id, "xtm")) 350 return &clk_xtm; 351 if (!strcmp(id, "periph")) 352 return &clk_periph; 353 if ((BCMCPU_IS_3368() || BCMCPU_IS_6358()) && !strcmp(id, "pcm")) 354 return &clk_pcm; 355 if ((BCMCPU_IS_6362() || BCMCPU_IS_6368()) && !strcmp(id, "ipsec")) 356 return &clk_ipsec; 357 if ((BCMCPU_IS_6328() || BCMCPU_IS_6362()) && !strcmp(id, "pcie")) 358 return &clk_pcie; 359 return ERR_PTR(-ENOENT); 360 } 361 362 EXPORT_SYMBOL(clk_get); 363 364 void clk_put(struct clk *clk) 365 { 366 } 367 368 EXPORT_SYMBOL(clk_put); 369