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 200 /* BCMCPU_IS_6368 */ 201 mask = CKCTL_6368_SPI_EN; 202 bcm_hwclock_set(mask, enable); 203 } 204 205 static struct clk clk_spi = { 206 .set = spi_set, 207 }; 208 209 /* 210 * XTM clock 211 */ 212 static void xtm_set(struct clk *clk, int enable) 213 { 214 if (!BCMCPU_IS_6368()) 215 return; 216 217 bcm_hwclock_set(CKCTL_6368_SAR_EN | 218 CKCTL_6368_SWPKT_SAR_EN, enable); 219 220 if (enable) { 221 /* reset sar core afer clock change */ 222 bcm63xx_core_set_reset(BCM63XX_RESET_SAR, 1); 223 mdelay(1); 224 bcm63xx_core_set_reset(BCM63XX_RESET_SAR, 0); 225 mdelay(1); 226 } 227 } 228 229 230 static struct clk clk_xtm = { 231 .set = xtm_set, 232 }; 233 234 /* 235 * IPsec clock 236 */ 237 static void ipsec_set(struct clk *clk, int enable) 238 { 239 bcm_hwclock_set(CKCTL_6368_IPSEC_EN, enable); 240 } 241 242 static struct clk clk_ipsec = { 243 .set = ipsec_set, 244 }; 245 246 /* 247 * PCIe clock 248 */ 249 250 static void pcie_set(struct clk *clk, int enable) 251 { 252 bcm_hwclock_set(CKCTL_6328_PCIE_EN, enable); 253 } 254 255 static struct clk clk_pcie = { 256 .set = pcie_set, 257 }; 258 259 /* 260 * Internal peripheral clock 261 */ 262 static struct clk clk_periph = { 263 .rate = (50 * 1000 * 1000), 264 }; 265 266 267 /* 268 * Linux clock API implementation 269 */ 270 int clk_enable(struct clk *clk) 271 { 272 mutex_lock(&clocks_mutex); 273 clk_enable_unlocked(clk); 274 mutex_unlock(&clocks_mutex); 275 return 0; 276 } 277 278 EXPORT_SYMBOL(clk_enable); 279 280 void clk_disable(struct clk *clk) 281 { 282 mutex_lock(&clocks_mutex); 283 clk_disable_unlocked(clk); 284 mutex_unlock(&clocks_mutex); 285 } 286 287 EXPORT_SYMBOL(clk_disable); 288 289 unsigned long clk_get_rate(struct clk *clk) 290 { 291 return clk->rate; 292 } 293 294 EXPORT_SYMBOL(clk_get_rate); 295 296 struct clk *clk_get(struct device *dev, const char *id) 297 { 298 if (!strcmp(id, "enet0")) 299 return &clk_enet0; 300 if (!strcmp(id, "enet1")) 301 return &clk_enet1; 302 if (!strcmp(id, "enetsw")) 303 return &clk_enetsw; 304 if (!strcmp(id, "ephy")) 305 return &clk_ephy; 306 if (!strcmp(id, "usbh")) 307 return &clk_usbh; 308 if (!strcmp(id, "usbd")) 309 return &clk_usbd; 310 if (!strcmp(id, "spi")) 311 return &clk_spi; 312 if (!strcmp(id, "xtm")) 313 return &clk_xtm; 314 if (!strcmp(id, "periph")) 315 return &clk_periph; 316 if (BCMCPU_IS_6358() && !strcmp(id, "pcm")) 317 return &clk_pcm; 318 if (BCMCPU_IS_6368() && !strcmp(id, "ipsec")) 319 return &clk_ipsec; 320 if (BCMCPU_IS_6328() && !strcmp(id, "pcie")) 321 return &clk_pcie; 322 return ERR_PTR(-ENOENT); 323 } 324 325 EXPORT_SYMBOL(clk_get); 326 327 void clk_put(struct clk *clk) 328 { 329 } 330 331 EXPORT_SYMBOL(clk_put); 332