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 #include <bcm63xx_clk.h> 19 20 static DEFINE_MUTEX(clocks_mutex); 21 22 23 static void clk_enable_unlocked(struct clk *clk) 24 { 25 if (clk->set && (clk->usage++) == 0) 26 clk->set(clk, 1); 27 } 28 29 static void clk_disable_unlocked(struct clk *clk) 30 { 31 if (clk->set && (--clk->usage) == 0) 32 clk->set(clk, 0); 33 } 34 35 static void bcm_hwclock_set(u32 mask, int enable) 36 { 37 u32 reg; 38 39 reg = bcm_perf_readl(PERF_CKCTL_REG); 40 if (enable) 41 reg |= mask; 42 else 43 reg &= ~mask; 44 bcm_perf_writel(reg, PERF_CKCTL_REG); 45 } 46 47 /* 48 * Ethernet MAC "misc" clock: dma clocks and main clock on 6348 49 */ 50 static void enet_misc_set(struct clk *clk, int enable) 51 { 52 u32 mask; 53 54 if (BCMCPU_IS_6338()) 55 mask = CKCTL_6338_ENET_EN; 56 else if (BCMCPU_IS_6345()) 57 mask = CKCTL_6345_ENET_EN; 58 else if (BCMCPU_IS_6348()) 59 mask = CKCTL_6348_ENET_EN; 60 else 61 /* BCMCPU_IS_6358 */ 62 mask = CKCTL_6358_EMUSB_EN; 63 bcm_hwclock_set(mask, enable); 64 } 65 66 static struct clk clk_enet_misc = { 67 .set = enet_misc_set, 68 }; 69 70 /* 71 * Ethernet MAC clocks: only revelant on 6358, silently enable misc 72 * clocks 73 */ 74 static void enetx_set(struct clk *clk, int enable) 75 { 76 if (enable) 77 clk_enable_unlocked(&clk_enet_misc); 78 else 79 clk_disable_unlocked(&clk_enet_misc); 80 81 if (BCMCPU_IS_6358()) { 82 u32 mask; 83 84 if (clk->id == 0) 85 mask = CKCTL_6358_ENET0_EN; 86 else 87 mask = CKCTL_6358_ENET1_EN; 88 bcm_hwclock_set(mask, enable); 89 } 90 } 91 92 static struct clk clk_enet0 = { 93 .id = 0, 94 .set = enetx_set, 95 }; 96 97 static struct clk clk_enet1 = { 98 .id = 1, 99 .set = enetx_set, 100 }; 101 102 /* 103 * Ethernet PHY clock 104 */ 105 static void ephy_set(struct clk *clk, int enable) 106 { 107 if (!BCMCPU_IS_6358()) 108 return; 109 bcm_hwclock_set(CKCTL_6358_EPHY_EN, enable); 110 } 111 112 113 static struct clk clk_ephy = { 114 .set = ephy_set, 115 }; 116 117 /* 118 * Ethernet switch clock 119 */ 120 static void enetsw_set(struct clk *clk, int enable) 121 { 122 if (!BCMCPU_IS_6368()) 123 return; 124 bcm_hwclock_set(CKCTL_6368_ROBOSW_EN | 125 CKCTL_6368_SWPKT_USB_EN | 126 CKCTL_6368_SWPKT_SAR_EN, enable); 127 if (enable) { 128 /* reset switch core afer clock change */ 129 bcm63xx_core_set_reset(BCM63XX_RESET_ENETSW, 1); 130 msleep(10); 131 bcm63xx_core_set_reset(BCM63XX_RESET_ENETSW, 0); 132 msleep(10); 133 } 134 } 135 136 static struct clk clk_enetsw = { 137 .set = enetsw_set, 138 }; 139 140 /* 141 * PCM clock 142 */ 143 static void pcm_set(struct clk *clk, int enable) 144 { 145 if (!BCMCPU_IS_6358()) 146 return; 147 bcm_hwclock_set(CKCTL_6358_PCM_EN, enable); 148 } 149 150 static struct clk clk_pcm = { 151 .set = pcm_set, 152 }; 153 154 /* 155 * USB host clock 156 */ 157 static void usbh_set(struct clk *clk, int enable) 158 { 159 if (BCMCPU_IS_6328()) 160 bcm_hwclock_set(CKCTL_6328_USBH_EN, enable); 161 else if (BCMCPU_IS_6348()) 162 bcm_hwclock_set(CKCTL_6348_USBH_EN, enable); 163 else if (BCMCPU_IS_6368()) 164 bcm_hwclock_set(CKCTL_6368_USBH_EN, enable); 165 } 166 167 static struct clk clk_usbh = { 168 .set = usbh_set, 169 }; 170 171 /* 172 * USB device clock 173 */ 174 static void usbd_set(struct clk *clk, int enable) 175 { 176 if (BCMCPU_IS_6328()) 177 bcm_hwclock_set(CKCTL_6328_USBD_EN, enable); 178 else if (BCMCPU_IS_6368()) 179 bcm_hwclock_set(CKCTL_6368_USBD_EN, enable); 180 } 181 182 static struct clk clk_usbd = { 183 .set = usbd_set, 184 }; 185 186 /* 187 * SPI clock 188 */ 189 static void spi_set(struct clk *clk, int enable) 190 { 191 u32 mask; 192 193 if (BCMCPU_IS_6338()) 194 mask = CKCTL_6338_SPI_EN; 195 else if (BCMCPU_IS_6348()) 196 mask = CKCTL_6348_SPI_EN; 197 else if (BCMCPU_IS_6358()) 198 mask = CKCTL_6358_SPI_EN; 199 else if (BCMCPU_IS_6362()) 200 mask = CKCTL_6362_SPI_EN; 201 else 202 /* BCMCPU_IS_6368 */ 203 mask = CKCTL_6368_SPI_EN; 204 bcm_hwclock_set(mask, enable); 205 } 206 207 static struct clk clk_spi = { 208 .set = spi_set, 209 }; 210 211 /* 212 * XTM clock 213 */ 214 static void xtm_set(struct clk *clk, int enable) 215 { 216 if (!BCMCPU_IS_6368()) 217 return; 218 219 bcm_hwclock_set(CKCTL_6368_SAR_EN | 220 CKCTL_6368_SWPKT_SAR_EN, enable); 221 222 if (enable) { 223 /* reset sar core afer clock change */ 224 bcm63xx_core_set_reset(BCM63XX_RESET_SAR, 1); 225 mdelay(1); 226 bcm63xx_core_set_reset(BCM63XX_RESET_SAR, 0); 227 mdelay(1); 228 } 229 } 230 231 232 static struct clk clk_xtm = { 233 .set = xtm_set, 234 }; 235 236 /* 237 * IPsec clock 238 */ 239 static void ipsec_set(struct clk *clk, int enable) 240 { 241 bcm_hwclock_set(CKCTL_6368_IPSEC_EN, enable); 242 } 243 244 static struct clk clk_ipsec = { 245 .set = ipsec_set, 246 }; 247 248 /* 249 * PCIe clock 250 */ 251 252 static void pcie_set(struct clk *clk, int enable) 253 { 254 bcm_hwclock_set(CKCTL_6328_PCIE_EN, enable); 255 } 256 257 static struct clk clk_pcie = { 258 .set = pcie_set, 259 }; 260 261 /* 262 * Internal peripheral clock 263 */ 264 static struct clk clk_periph = { 265 .rate = (50 * 1000 * 1000), 266 }; 267 268 269 /* 270 * Linux clock API implementation 271 */ 272 int clk_enable(struct clk *clk) 273 { 274 mutex_lock(&clocks_mutex); 275 clk_enable_unlocked(clk); 276 mutex_unlock(&clocks_mutex); 277 return 0; 278 } 279 280 EXPORT_SYMBOL(clk_enable); 281 282 void clk_disable(struct clk *clk) 283 { 284 mutex_lock(&clocks_mutex); 285 clk_disable_unlocked(clk); 286 mutex_unlock(&clocks_mutex); 287 } 288 289 EXPORT_SYMBOL(clk_disable); 290 291 unsigned long clk_get_rate(struct clk *clk) 292 { 293 return clk->rate; 294 } 295 296 EXPORT_SYMBOL(clk_get_rate); 297 298 struct clk *clk_get(struct device *dev, const char *id) 299 { 300 if (!strcmp(id, "enet0")) 301 return &clk_enet0; 302 if (!strcmp(id, "enet1")) 303 return &clk_enet1; 304 if (!strcmp(id, "enetsw")) 305 return &clk_enetsw; 306 if (!strcmp(id, "ephy")) 307 return &clk_ephy; 308 if (!strcmp(id, "usbh")) 309 return &clk_usbh; 310 if (!strcmp(id, "usbd")) 311 return &clk_usbd; 312 if (!strcmp(id, "spi")) 313 return &clk_spi; 314 if (!strcmp(id, "xtm")) 315 return &clk_xtm; 316 if (!strcmp(id, "periph")) 317 return &clk_periph; 318 if (BCMCPU_IS_6358() && !strcmp(id, "pcm")) 319 return &clk_pcm; 320 if (BCMCPU_IS_6368() && !strcmp(id, "ipsec")) 321 return &clk_ipsec; 322 if (BCMCPU_IS_6328() && !strcmp(id, "pcie")) 323 return &clk_pcie; 324 return ERR_PTR(-ENOENT); 325 } 326 327 EXPORT_SYMBOL(clk_get); 328 329 void clk_put(struct clk *clk) 330 { 331 } 332 333 EXPORT_SYMBOL(clk_put); 334