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