Back to home page

OSCL-LXR

 
 

    


0001 /*
0002  * This file is subject to the terms and conditions of the GNU General Public
0003  * License.  See the file "COPYING" in the main directory of this archive
0004  * for more details.
0005  *
0006  * Copyright (C) 2008 Maxime Bizon <mbizon@freebox.fr>
0007  */
0008 
0009 #include <linux/init.h>
0010 #include <linux/export.h>
0011 #include <linux/mutex.h>
0012 #include <linux/err.h>
0013 #include <linux/clk.h>
0014 #include <linux/clkdev.h>
0015 #include <linux/delay.h>
0016 #include <bcm63xx_cpu.h>
0017 #include <bcm63xx_io.h>
0018 #include <bcm63xx_regs.h>
0019 #include <bcm63xx_reset.h>
0020 
0021 struct clk {
0022     void        (*set)(struct clk *, int);
0023     unsigned int    rate;
0024     unsigned int    usage;
0025     int     id;
0026 };
0027 
0028 static DEFINE_MUTEX(clocks_mutex);
0029 
0030 
0031 static void clk_enable_unlocked(struct clk *clk)
0032 {
0033     if (clk->set && (clk->usage++) == 0)
0034         clk->set(clk, 1);
0035 }
0036 
0037 static void clk_disable_unlocked(struct clk *clk)
0038 {
0039     if (clk->set && (--clk->usage) == 0)
0040         clk->set(clk, 0);
0041 }
0042 
0043 static void bcm_hwclock_set(u32 mask, int enable)
0044 {
0045     u32 reg;
0046 
0047     reg = bcm_perf_readl(PERF_CKCTL_REG);
0048     if (enable)
0049         reg |= mask;
0050     else
0051         reg &= ~mask;
0052     bcm_perf_writel(reg, PERF_CKCTL_REG);
0053 }
0054 
0055 /*
0056  * Ethernet MAC "misc" clock: dma clocks and main clock on 6348
0057  */
0058 static void enet_misc_set(struct clk *clk, int enable)
0059 {
0060     u32 mask;
0061 
0062     if (BCMCPU_IS_6338())
0063         mask = CKCTL_6338_ENET_EN;
0064     else if (BCMCPU_IS_6345())
0065         mask = CKCTL_6345_ENET_EN;
0066     else if (BCMCPU_IS_6348())
0067         mask = CKCTL_6348_ENET_EN;
0068     else
0069         /* BCMCPU_IS_6358 */
0070         mask = CKCTL_6358_EMUSB_EN;
0071     bcm_hwclock_set(mask, enable);
0072 }
0073 
0074 static struct clk clk_enet_misc = {
0075     .set    = enet_misc_set,
0076 };
0077 
0078 /*
0079  * Ethernet MAC clocks: only relevant on 6358, silently enable misc
0080  * clocks
0081  */
0082 static void enetx_set(struct clk *clk, int enable)
0083 {
0084     if (enable)
0085         clk_enable_unlocked(&clk_enet_misc);
0086     else
0087         clk_disable_unlocked(&clk_enet_misc);
0088 
0089     if (BCMCPU_IS_3368() || BCMCPU_IS_6358()) {
0090         u32 mask;
0091 
0092         if (clk->id == 0)
0093             mask = CKCTL_6358_ENET0_EN;
0094         else
0095             mask = CKCTL_6358_ENET1_EN;
0096         bcm_hwclock_set(mask, enable);
0097     }
0098 }
0099 
0100 static struct clk clk_enet0 = {
0101     .id = 0,
0102     .set    = enetx_set,
0103 };
0104 
0105 static struct clk clk_enet1 = {
0106     .id = 1,
0107     .set    = enetx_set,
0108 };
0109 
0110 /*
0111  * Ethernet PHY clock
0112  */
0113 static void ephy_set(struct clk *clk, int enable)
0114 {
0115     if (BCMCPU_IS_3368() || BCMCPU_IS_6358())
0116         bcm_hwclock_set(CKCTL_6358_EPHY_EN, enable);
0117 }
0118 
0119 
0120 static struct clk clk_ephy = {
0121     .set    = ephy_set,
0122 };
0123 
0124 /*
0125  * Ethernet switch SAR clock
0126  */
0127 static void swpkt_sar_set(struct clk *clk, int enable)
0128 {
0129     if (BCMCPU_IS_6368())
0130         bcm_hwclock_set(CKCTL_6368_SWPKT_SAR_EN, enable);
0131     else
0132         return;
0133 }
0134 
0135 static struct clk clk_swpkt_sar = {
0136     .set    = swpkt_sar_set,
0137 };
0138 
0139 /*
0140  * Ethernet switch USB clock
0141  */
0142 static void swpkt_usb_set(struct clk *clk, int enable)
0143 {
0144     if (BCMCPU_IS_6368())
0145         bcm_hwclock_set(CKCTL_6368_SWPKT_USB_EN, enable);
0146     else
0147         return;
0148 }
0149 
0150 static struct clk clk_swpkt_usb = {
0151     .set    = swpkt_usb_set,
0152 };
0153 
0154 /*
0155  * Ethernet switch clock
0156  */
0157 static void enetsw_set(struct clk *clk, int enable)
0158 {
0159     if (BCMCPU_IS_6328()) {
0160         bcm_hwclock_set(CKCTL_6328_ROBOSW_EN, enable);
0161     } else if (BCMCPU_IS_6362()) {
0162         bcm_hwclock_set(CKCTL_6362_ROBOSW_EN, enable);
0163     } else if (BCMCPU_IS_6368()) {
0164         if (enable) {
0165             clk_enable_unlocked(&clk_swpkt_sar);
0166             clk_enable_unlocked(&clk_swpkt_usb);
0167         } else {
0168             clk_disable_unlocked(&clk_swpkt_usb);
0169             clk_disable_unlocked(&clk_swpkt_sar);
0170         }
0171         bcm_hwclock_set(CKCTL_6368_ROBOSW_EN, enable);
0172     } else {
0173         return;
0174     }
0175 
0176     if (enable) {
0177         /* reset switch core afer clock change */
0178         bcm63xx_core_set_reset(BCM63XX_RESET_ENETSW, 1);
0179         msleep(10);
0180         bcm63xx_core_set_reset(BCM63XX_RESET_ENETSW, 0);
0181         msleep(10);
0182     }
0183 }
0184 
0185 static struct clk clk_enetsw = {
0186     .set    = enetsw_set,
0187 };
0188 
0189 /*
0190  * PCM clock
0191  */
0192 static void pcm_set(struct clk *clk, int enable)
0193 {
0194     if (BCMCPU_IS_3368())
0195         bcm_hwclock_set(CKCTL_3368_PCM_EN, enable);
0196     if (BCMCPU_IS_6358())
0197         bcm_hwclock_set(CKCTL_6358_PCM_EN, enable);
0198 }
0199 
0200 static struct clk clk_pcm = {
0201     .set    = pcm_set,
0202 };
0203 
0204 /*
0205  * USB host clock
0206  */
0207 static void usbh_set(struct clk *clk, int enable)
0208 {
0209     if (BCMCPU_IS_6328())
0210         bcm_hwclock_set(CKCTL_6328_USBH_EN, enable);
0211     else if (BCMCPU_IS_6348())
0212         bcm_hwclock_set(CKCTL_6348_USBH_EN, enable);
0213     else if (BCMCPU_IS_6362())
0214         bcm_hwclock_set(CKCTL_6362_USBH_EN, enable);
0215     else if (BCMCPU_IS_6368())
0216         bcm_hwclock_set(CKCTL_6368_USBH_EN, enable);
0217 }
0218 
0219 static struct clk clk_usbh = {
0220     .set    = usbh_set,
0221 };
0222 
0223 /*
0224  * USB device clock
0225  */
0226 static void usbd_set(struct clk *clk, int enable)
0227 {
0228     if (BCMCPU_IS_6328())
0229         bcm_hwclock_set(CKCTL_6328_USBD_EN, enable);
0230     else if (BCMCPU_IS_6362())
0231         bcm_hwclock_set(CKCTL_6362_USBD_EN, enable);
0232     else if (BCMCPU_IS_6368())
0233         bcm_hwclock_set(CKCTL_6368_USBD_EN, enable);
0234 }
0235 
0236 static struct clk clk_usbd = {
0237     .set    = usbd_set,
0238 };
0239 
0240 /*
0241  * SPI clock
0242  */
0243 static void spi_set(struct clk *clk, int enable)
0244 {
0245     u32 mask;
0246 
0247     if (BCMCPU_IS_6338())
0248         mask = CKCTL_6338_SPI_EN;
0249     else if (BCMCPU_IS_6348())
0250         mask = CKCTL_6348_SPI_EN;
0251     else if (BCMCPU_IS_3368() || BCMCPU_IS_6358())
0252         mask = CKCTL_6358_SPI_EN;
0253     else if (BCMCPU_IS_6362())
0254         mask = CKCTL_6362_SPI_EN;
0255     else
0256         /* BCMCPU_IS_6368 */
0257         mask = CKCTL_6368_SPI_EN;
0258     bcm_hwclock_set(mask, enable);
0259 }
0260 
0261 static struct clk clk_spi = {
0262     .set    = spi_set,
0263 };
0264 
0265 /*
0266  * HSSPI clock
0267  */
0268 static void hsspi_set(struct clk *clk, int enable)
0269 {
0270     u32 mask;
0271 
0272     if (BCMCPU_IS_6328())
0273         mask = CKCTL_6328_HSSPI_EN;
0274     else if (BCMCPU_IS_6362())
0275         mask = CKCTL_6362_HSSPI_EN;
0276     else
0277         return;
0278 
0279     bcm_hwclock_set(mask, enable);
0280 }
0281 
0282 static struct clk clk_hsspi = {
0283     .set    = hsspi_set,
0284 };
0285 
0286 /*
0287  * HSSPI PLL
0288  */
0289 static struct clk clk_hsspi_pll;
0290 
0291 /*
0292  * XTM clock
0293  */
0294 static void xtm_set(struct clk *clk, int enable)
0295 {
0296     if (!BCMCPU_IS_6368())
0297         return;
0298 
0299     if (enable)
0300         clk_enable_unlocked(&clk_swpkt_sar);
0301     else
0302         clk_disable_unlocked(&clk_swpkt_sar);
0303 
0304     bcm_hwclock_set(CKCTL_6368_SAR_EN, enable);
0305 
0306     if (enable) {
0307         /* reset sar core afer clock change */
0308         bcm63xx_core_set_reset(BCM63XX_RESET_SAR, 1);
0309         mdelay(1);
0310         bcm63xx_core_set_reset(BCM63XX_RESET_SAR, 0);
0311         mdelay(1);
0312     }
0313 }
0314 
0315 
0316 static struct clk clk_xtm = {
0317     .set    = xtm_set,
0318 };
0319 
0320 /*
0321  * IPsec clock
0322  */
0323 static void ipsec_set(struct clk *clk, int enable)
0324 {
0325     if (BCMCPU_IS_6362())
0326         bcm_hwclock_set(CKCTL_6362_IPSEC_EN, enable);
0327     else if (BCMCPU_IS_6368())
0328         bcm_hwclock_set(CKCTL_6368_IPSEC_EN, enable);
0329 }
0330 
0331 static struct clk clk_ipsec = {
0332     .set    = ipsec_set,
0333 };
0334 
0335 /*
0336  * PCIe clock
0337  */
0338 
0339 static void pcie_set(struct clk *clk, int enable)
0340 {
0341     if (BCMCPU_IS_6328())
0342         bcm_hwclock_set(CKCTL_6328_PCIE_EN, enable);
0343     else if (BCMCPU_IS_6362())
0344         bcm_hwclock_set(CKCTL_6362_PCIE_EN, enable);
0345 }
0346 
0347 static struct clk clk_pcie = {
0348     .set    = pcie_set,
0349 };
0350 
0351 /*
0352  * Internal peripheral clock
0353  */
0354 static struct clk clk_periph = {
0355     .rate   = (50 * 1000 * 1000),
0356 };
0357 
0358 
0359 /*
0360  * Linux clock API implementation
0361  */
0362 int clk_enable(struct clk *clk)
0363 {
0364     mutex_lock(&clocks_mutex);
0365     clk_enable_unlocked(clk);
0366     mutex_unlock(&clocks_mutex);
0367     return 0;
0368 }
0369 
0370 EXPORT_SYMBOL(clk_enable);
0371 
0372 void clk_disable(struct clk *clk)
0373 {
0374     if (!clk)
0375         return;
0376 
0377     mutex_lock(&clocks_mutex);
0378     clk_disable_unlocked(clk);
0379     mutex_unlock(&clocks_mutex);
0380 }
0381 
0382 EXPORT_SYMBOL(clk_disable);
0383 
0384 struct clk *clk_get_parent(struct clk *clk)
0385 {
0386     return NULL;
0387 }
0388 EXPORT_SYMBOL(clk_get_parent);
0389 
0390 int clk_set_parent(struct clk *clk, struct clk *parent)
0391 {
0392     return 0;
0393 }
0394 EXPORT_SYMBOL(clk_set_parent);
0395 
0396 unsigned long clk_get_rate(struct clk *clk)
0397 {
0398     if (!clk)
0399         return 0;
0400 
0401     return clk->rate;
0402 }
0403 
0404 EXPORT_SYMBOL(clk_get_rate);
0405 
0406 int clk_set_rate(struct clk *clk, unsigned long rate)
0407 {
0408     return 0;
0409 }
0410 EXPORT_SYMBOL_GPL(clk_set_rate);
0411 
0412 long clk_round_rate(struct clk *clk, unsigned long rate)
0413 {
0414     return 0;
0415 }
0416 EXPORT_SYMBOL_GPL(clk_round_rate);
0417 
0418 static struct clk_lookup bcm3368_clks[] = {
0419     /* fixed rate clocks */
0420     CLKDEV_INIT(NULL, "periph", &clk_periph),
0421     CLKDEV_INIT("bcm63xx_uart.0", "refclk", &clk_periph),
0422     CLKDEV_INIT("bcm63xx_uart.1", "refclk", &clk_periph),
0423     /* gated clocks */
0424     CLKDEV_INIT(NULL, "enet0", &clk_enet0),
0425     CLKDEV_INIT(NULL, "enet1", &clk_enet1),
0426     CLKDEV_INIT(NULL, "ephy", &clk_ephy),
0427     CLKDEV_INIT(NULL, "usbh", &clk_usbh),
0428     CLKDEV_INIT(NULL, "usbd", &clk_usbd),
0429     CLKDEV_INIT(NULL, "spi", &clk_spi),
0430     CLKDEV_INIT(NULL, "pcm", &clk_pcm),
0431     CLKDEV_INIT("bcm63xx_enet.0", "enet", &clk_enet0),
0432     CLKDEV_INIT("bcm63xx_enet.1", "enet", &clk_enet1),
0433 };
0434 
0435 static struct clk_lookup bcm6328_clks[] = {
0436     /* fixed rate clocks */
0437     CLKDEV_INIT(NULL, "periph", &clk_periph),
0438     CLKDEV_INIT("bcm63xx_uart.0", "refclk", &clk_periph),
0439     CLKDEV_INIT("bcm63xx_uart.1", "refclk", &clk_periph),
0440     CLKDEV_INIT("bcm63xx-hsspi.0", "pll", &clk_hsspi_pll),
0441     /* gated clocks */
0442     CLKDEV_INIT(NULL, "enetsw", &clk_enetsw),
0443     CLKDEV_INIT(NULL, "usbh", &clk_usbh),
0444     CLKDEV_INIT(NULL, "usbd", &clk_usbd),
0445     CLKDEV_INIT(NULL, "hsspi", &clk_hsspi),
0446     CLKDEV_INIT(NULL, "pcie", &clk_pcie),
0447 };
0448 
0449 static struct clk_lookup bcm6338_clks[] = {
0450     /* fixed rate clocks */
0451     CLKDEV_INIT(NULL, "periph", &clk_periph),
0452     CLKDEV_INIT("bcm63xx_uart.0", "refclk", &clk_periph),
0453     /* gated clocks */
0454     CLKDEV_INIT(NULL, "enet0", &clk_enet0),
0455     CLKDEV_INIT(NULL, "enet1", &clk_enet1),
0456     CLKDEV_INIT(NULL, "ephy", &clk_ephy),
0457     CLKDEV_INIT(NULL, "usbh", &clk_usbh),
0458     CLKDEV_INIT(NULL, "usbd", &clk_usbd),
0459     CLKDEV_INIT(NULL, "spi", &clk_spi),
0460     CLKDEV_INIT("bcm63xx_enet.0", "enet", &clk_enet_misc),
0461 };
0462 
0463 static struct clk_lookup bcm6345_clks[] = {
0464     /* fixed rate clocks */
0465     CLKDEV_INIT(NULL, "periph", &clk_periph),
0466     CLKDEV_INIT("bcm63xx_uart.0", "refclk", &clk_periph),
0467     /* gated clocks */
0468     CLKDEV_INIT(NULL, "enet0", &clk_enet0),
0469     CLKDEV_INIT(NULL, "enet1", &clk_enet1),
0470     CLKDEV_INIT(NULL, "ephy", &clk_ephy),
0471     CLKDEV_INIT(NULL, "usbh", &clk_usbh),
0472     CLKDEV_INIT(NULL, "usbd", &clk_usbd),
0473     CLKDEV_INIT(NULL, "spi", &clk_spi),
0474     CLKDEV_INIT("bcm63xx_enet.0", "enet", &clk_enet_misc),
0475 };
0476 
0477 static struct clk_lookup bcm6348_clks[] = {
0478     /* fixed rate clocks */
0479     CLKDEV_INIT(NULL, "periph", &clk_periph),
0480     CLKDEV_INIT("bcm63xx_uart.0", "refclk", &clk_periph),
0481     /* gated clocks */
0482     CLKDEV_INIT(NULL, "enet0", &clk_enet0),
0483     CLKDEV_INIT(NULL, "enet1", &clk_enet1),
0484     CLKDEV_INIT(NULL, "ephy", &clk_ephy),
0485     CLKDEV_INIT(NULL, "usbh", &clk_usbh),
0486     CLKDEV_INIT(NULL, "usbd", &clk_usbd),
0487     CLKDEV_INIT(NULL, "spi", &clk_spi),
0488     CLKDEV_INIT("bcm63xx_enet.0", "enet", &clk_enet_misc),
0489     CLKDEV_INIT("bcm63xx_enet.1", "enet", &clk_enet_misc),
0490 };
0491 
0492 static struct clk_lookup bcm6358_clks[] = {
0493     /* fixed rate clocks */
0494     CLKDEV_INIT(NULL, "periph", &clk_periph),
0495     CLKDEV_INIT("bcm63xx_uart.0", "refclk", &clk_periph),
0496     CLKDEV_INIT("bcm63xx_uart.1", "refclk", &clk_periph),
0497     /* gated clocks */
0498     CLKDEV_INIT(NULL, "enet0", &clk_enet0),
0499     CLKDEV_INIT(NULL, "enet1", &clk_enet1),
0500     CLKDEV_INIT(NULL, "ephy", &clk_ephy),
0501     CLKDEV_INIT(NULL, "usbh", &clk_usbh),
0502     CLKDEV_INIT(NULL, "usbd", &clk_usbd),
0503     CLKDEV_INIT(NULL, "spi", &clk_spi),
0504     CLKDEV_INIT(NULL, "pcm", &clk_pcm),
0505     CLKDEV_INIT(NULL, "swpkt_sar", &clk_swpkt_sar),
0506     CLKDEV_INIT(NULL, "swpkt_usb", &clk_swpkt_usb),
0507     CLKDEV_INIT("bcm63xx_enet.0", "enet", &clk_enet0),
0508     CLKDEV_INIT("bcm63xx_enet.1", "enet", &clk_enet1),
0509 };
0510 
0511 static struct clk_lookup bcm6362_clks[] = {
0512     /* fixed rate clocks */
0513     CLKDEV_INIT(NULL, "periph", &clk_periph),
0514     CLKDEV_INIT("bcm63xx_uart.0", "refclk", &clk_periph),
0515     CLKDEV_INIT("bcm63xx_uart.1", "refclk", &clk_periph),
0516     CLKDEV_INIT("bcm63xx-hsspi.0", "pll", &clk_hsspi_pll),
0517     /* gated clocks */
0518     CLKDEV_INIT(NULL, "enetsw", &clk_enetsw),
0519     CLKDEV_INIT(NULL, "usbh", &clk_usbh),
0520     CLKDEV_INIT(NULL, "usbd", &clk_usbd),
0521     CLKDEV_INIT(NULL, "spi", &clk_spi),
0522     CLKDEV_INIT(NULL, "hsspi", &clk_hsspi),
0523     CLKDEV_INIT(NULL, "pcie", &clk_pcie),
0524     CLKDEV_INIT(NULL, "ipsec", &clk_ipsec),
0525 };
0526 
0527 static struct clk_lookup bcm6368_clks[] = {
0528     /* fixed rate clocks */
0529     CLKDEV_INIT(NULL, "periph", &clk_periph),
0530     CLKDEV_INIT("bcm63xx_uart.0", "refclk", &clk_periph),
0531     CLKDEV_INIT("bcm63xx_uart.1", "refclk", &clk_periph),
0532     /* gated clocks */
0533     CLKDEV_INIT(NULL, "enetsw", &clk_enetsw),
0534     CLKDEV_INIT(NULL, "usbh", &clk_usbh),
0535     CLKDEV_INIT(NULL, "usbd", &clk_usbd),
0536     CLKDEV_INIT(NULL, "spi", &clk_spi),
0537     CLKDEV_INIT(NULL, "xtm", &clk_xtm),
0538     CLKDEV_INIT(NULL, "ipsec", &clk_ipsec),
0539 };
0540 
0541 #define HSSPI_PLL_HZ_6328   133333333
0542 #define HSSPI_PLL_HZ_6362   400000000
0543 
0544 static int __init bcm63xx_clk_init(void)
0545 {
0546     switch (bcm63xx_get_cpu_id()) {
0547     case BCM3368_CPU_ID:
0548         clkdev_add_table(bcm3368_clks, ARRAY_SIZE(bcm3368_clks));
0549         break;
0550     case BCM6328_CPU_ID:
0551         clk_hsspi_pll.rate = HSSPI_PLL_HZ_6328;
0552         clkdev_add_table(bcm6328_clks, ARRAY_SIZE(bcm6328_clks));
0553         break;
0554     case BCM6338_CPU_ID:
0555         clkdev_add_table(bcm6338_clks, ARRAY_SIZE(bcm6338_clks));
0556         break;
0557     case BCM6345_CPU_ID:
0558         clkdev_add_table(bcm6345_clks, ARRAY_SIZE(bcm6345_clks));
0559         break;
0560     case BCM6348_CPU_ID:
0561         clkdev_add_table(bcm6348_clks, ARRAY_SIZE(bcm6348_clks));
0562         break;
0563     case BCM6358_CPU_ID:
0564         clkdev_add_table(bcm6358_clks, ARRAY_SIZE(bcm6358_clks));
0565         break;
0566     case BCM6362_CPU_ID:
0567         clk_hsspi_pll.rate = HSSPI_PLL_HZ_6362;
0568         clkdev_add_table(bcm6362_clks, ARRAY_SIZE(bcm6362_clks));
0569         break;
0570     case BCM6368_CPU_ID:
0571         clkdev_add_table(bcm6368_clks, ARRAY_SIZE(bcm6368_clks));
0572         break;
0573     }
0574 
0575     return 0;
0576 }
0577 arch_initcall(bcm63xx_clk_init);