1e7300d04SMaxime Bizon /* 2e7300d04SMaxime Bizon * This file is subject to the terms and conditions of the GNU General Public 3e7300d04SMaxime Bizon * License. See the file "COPYING" in the main directory of this archive 4e7300d04SMaxime Bizon * for more details. 5e7300d04SMaxime Bizon * 6e7300d04SMaxime Bizon * Copyright (C) 2008 Maxime Bizon <mbizon@freebox.fr> 7e7300d04SMaxime Bizon */ 8e7300d04SMaxime Bizon 9e7300d04SMaxime Bizon #include <linux/module.h> 10e7300d04SMaxime Bizon #include <linux/mutex.h> 11e7300d04SMaxime Bizon #include <linux/err.h> 12e7300d04SMaxime Bizon #include <linux/clk.h> 1304712f3fSMaxime Bizon #include <linux/delay.h> 14e7300d04SMaxime Bizon #include <bcm63xx_cpu.h> 15e7300d04SMaxime Bizon #include <bcm63xx_io.h> 16e7300d04SMaxime Bizon #include <bcm63xx_regs.h> 17e7300d04SMaxime Bizon #include <bcm63xx_clk.h> 18e7300d04SMaxime Bizon 19e7300d04SMaxime Bizon static DEFINE_MUTEX(clocks_mutex); 20e7300d04SMaxime Bizon 21e7300d04SMaxime Bizon 22e7300d04SMaxime Bizon static void clk_enable_unlocked(struct clk *clk) 23e7300d04SMaxime Bizon { 24e7300d04SMaxime Bizon if (clk->set && (clk->usage++) == 0) 25e7300d04SMaxime Bizon clk->set(clk, 1); 26e7300d04SMaxime Bizon } 27e7300d04SMaxime Bizon 28e7300d04SMaxime Bizon static void clk_disable_unlocked(struct clk *clk) 29e7300d04SMaxime Bizon { 30e7300d04SMaxime Bizon if (clk->set && (--clk->usage) == 0) 31e7300d04SMaxime Bizon clk->set(clk, 0); 32e7300d04SMaxime Bizon } 33e7300d04SMaxime Bizon 34e7300d04SMaxime Bizon static void bcm_hwclock_set(u32 mask, int enable) 35e7300d04SMaxime Bizon { 36e7300d04SMaxime Bizon u32 reg; 37e7300d04SMaxime Bizon 38e7300d04SMaxime Bizon reg = bcm_perf_readl(PERF_CKCTL_REG); 39e7300d04SMaxime Bizon if (enable) 40e7300d04SMaxime Bizon reg |= mask; 41e7300d04SMaxime Bizon else 42e7300d04SMaxime Bizon reg &= ~mask; 43e7300d04SMaxime Bizon bcm_perf_writel(reg, PERF_CKCTL_REG); 44e7300d04SMaxime Bizon } 45e7300d04SMaxime Bizon 46e7300d04SMaxime Bizon /* 47e7300d04SMaxime Bizon * Ethernet MAC "misc" clock: dma clocks and main clock on 6348 48e7300d04SMaxime Bizon */ 49e7300d04SMaxime Bizon static void enet_misc_set(struct clk *clk, int enable) 50e7300d04SMaxime Bizon { 51e7300d04SMaxime Bizon u32 mask; 52e7300d04SMaxime Bizon 53e7300d04SMaxime Bizon if (BCMCPU_IS_6338()) 54e7300d04SMaxime Bizon mask = CKCTL_6338_ENET_EN; 55e7300d04SMaxime Bizon else if (BCMCPU_IS_6345()) 56e7300d04SMaxime Bizon mask = CKCTL_6345_ENET_EN; 57e7300d04SMaxime Bizon else if (BCMCPU_IS_6348()) 58e7300d04SMaxime Bizon mask = CKCTL_6348_ENET_EN; 59e7300d04SMaxime Bizon else 60e7300d04SMaxime Bizon /* BCMCPU_IS_6358 */ 61e7300d04SMaxime Bizon mask = CKCTL_6358_EMUSB_EN; 62e7300d04SMaxime Bizon bcm_hwclock_set(mask, enable); 63e7300d04SMaxime Bizon } 64e7300d04SMaxime Bizon 65e7300d04SMaxime Bizon static struct clk clk_enet_misc = { 66e7300d04SMaxime Bizon .set = enet_misc_set, 67e7300d04SMaxime Bizon }; 68e7300d04SMaxime Bizon 69e7300d04SMaxime Bizon /* 70e7300d04SMaxime Bizon * Ethernet MAC clocks: only revelant on 6358, silently enable misc 71e7300d04SMaxime Bizon * clocks 72e7300d04SMaxime Bizon */ 73e7300d04SMaxime Bizon static void enetx_set(struct clk *clk, int enable) 74e7300d04SMaxime Bizon { 75e7300d04SMaxime Bizon if (enable) 76e7300d04SMaxime Bizon clk_enable_unlocked(&clk_enet_misc); 77e7300d04SMaxime Bizon else 78e7300d04SMaxime Bizon clk_disable_unlocked(&clk_enet_misc); 79e7300d04SMaxime Bizon 80e7300d04SMaxime Bizon if (BCMCPU_IS_6358()) { 81e7300d04SMaxime Bizon u32 mask; 82e7300d04SMaxime Bizon 83e7300d04SMaxime Bizon if (clk->id == 0) 84e7300d04SMaxime Bizon mask = CKCTL_6358_ENET0_EN; 85e7300d04SMaxime Bizon else 86e7300d04SMaxime Bizon mask = CKCTL_6358_ENET1_EN; 87e7300d04SMaxime Bizon bcm_hwclock_set(mask, enable); 88e7300d04SMaxime Bizon } 89e7300d04SMaxime Bizon } 90e7300d04SMaxime Bizon 91e7300d04SMaxime Bizon static struct clk clk_enet0 = { 92e7300d04SMaxime Bizon .id = 0, 93e7300d04SMaxime Bizon .set = enetx_set, 94e7300d04SMaxime Bizon }; 95e7300d04SMaxime Bizon 96e7300d04SMaxime Bizon static struct clk clk_enet1 = { 97e7300d04SMaxime Bizon .id = 1, 98e7300d04SMaxime Bizon .set = enetx_set, 99e7300d04SMaxime Bizon }; 100e7300d04SMaxime Bizon 101e7300d04SMaxime Bizon /* 102e7300d04SMaxime Bizon * Ethernet PHY clock 103e7300d04SMaxime Bizon */ 104e7300d04SMaxime Bizon static void ephy_set(struct clk *clk, int enable) 105e7300d04SMaxime Bizon { 106e7300d04SMaxime Bizon if (!BCMCPU_IS_6358()) 107e7300d04SMaxime Bizon return; 108e7300d04SMaxime Bizon bcm_hwclock_set(CKCTL_6358_EPHY_EN, enable); 109e7300d04SMaxime Bizon } 110e7300d04SMaxime Bizon 111e7300d04SMaxime Bizon 112e7300d04SMaxime Bizon static struct clk clk_ephy = { 113e7300d04SMaxime Bizon .set = ephy_set, 114e7300d04SMaxime Bizon }; 115e7300d04SMaxime Bizon 116e7300d04SMaxime Bizon /* 11704712f3fSMaxime Bizon * Ethernet switch clock 11804712f3fSMaxime Bizon */ 11904712f3fSMaxime Bizon static void enetsw_set(struct clk *clk, int enable) 12004712f3fSMaxime Bizon { 12104712f3fSMaxime Bizon if (!BCMCPU_IS_6368()) 12204712f3fSMaxime Bizon return; 123d9831a41SFlorian Fainelli bcm_hwclock_set(CKCTL_6368_ROBOSW_EN | 12404712f3fSMaxime Bizon CKCTL_6368_SWPKT_USB_EN | 12504712f3fSMaxime Bizon CKCTL_6368_SWPKT_SAR_EN, enable); 12604712f3fSMaxime Bizon if (enable) { 12704712f3fSMaxime Bizon u32 val; 12804712f3fSMaxime Bizon 12904712f3fSMaxime Bizon /* reset switch core afer clock change */ 13004712f3fSMaxime Bizon val = bcm_perf_readl(PERF_SOFTRESET_6368_REG); 13104712f3fSMaxime Bizon val &= ~SOFTRESET_6368_ENETSW_MASK; 13204712f3fSMaxime Bizon bcm_perf_writel(val, PERF_SOFTRESET_6368_REG); 13304712f3fSMaxime Bizon msleep(10); 13404712f3fSMaxime Bizon val |= SOFTRESET_6368_ENETSW_MASK; 13504712f3fSMaxime Bizon bcm_perf_writel(val, PERF_SOFTRESET_6368_REG); 13604712f3fSMaxime Bizon msleep(10); 13704712f3fSMaxime Bizon } 13804712f3fSMaxime Bizon } 13904712f3fSMaxime Bizon 14004712f3fSMaxime Bizon static struct clk clk_enetsw = { 14104712f3fSMaxime Bizon .set = enetsw_set, 14204712f3fSMaxime Bizon }; 14304712f3fSMaxime Bizon 14404712f3fSMaxime Bizon /* 145e7300d04SMaxime Bizon * PCM clock 146e7300d04SMaxime Bizon */ 147e7300d04SMaxime Bizon static void pcm_set(struct clk *clk, int enable) 148e7300d04SMaxime Bizon { 149e7300d04SMaxime Bizon if (!BCMCPU_IS_6358()) 150e7300d04SMaxime Bizon return; 151e7300d04SMaxime Bizon bcm_hwclock_set(CKCTL_6358_PCM_EN, enable); 152e7300d04SMaxime Bizon } 153e7300d04SMaxime Bizon 154e7300d04SMaxime Bizon static struct clk clk_pcm = { 155e7300d04SMaxime Bizon .set = pcm_set, 156e7300d04SMaxime Bizon }; 157e7300d04SMaxime Bizon 158e7300d04SMaxime Bizon /* 159e7300d04SMaxime Bizon * USB host clock 160e7300d04SMaxime Bizon */ 161e7300d04SMaxime Bizon static void usbh_set(struct clk *clk, int enable) 162e7300d04SMaxime Bizon { 16304712f3fSMaxime Bizon if (BCMCPU_IS_6348()) 164e7300d04SMaxime Bizon bcm_hwclock_set(CKCTL_6348_USBH_EN, enable); 16504712f3fSMaxime Bizon else if (BCMCPU_IS_6368()) 166d9831a41SFlorian Fainelli bcm_hwclock_set(CKCTL_6368_USBH_EN, enable); 167e7300d04SMaxime Bizon } 168e7300d04SMaxime Bizon 169e7300d04SMaxime Bizon static struct clk clk_usbh = { 170e7300d04SMaxime Bizon .set = usbh_set, 171e7300d04SMaxime Bizon }; 172e7300d04SMaxime Bizon 173e7300d04SMaxime Bizon /* 174e7300d04SMaxime Bizon * SPI clock 175e7300d04SMaxime Bizon */ 176e7300d04SMaxime Bizon static void spi_set(struct clk *clk, int enable) 177e7300d04SMaxime Bizon { 178e7300d04SMaxime Bizon u32 mask; 179e7300d04SMaxime Bizon 180e7300d04SMaxime Bizon if (BCMCPU_IS_6338()) 181e7300d04SMaxime Bizon mask = CKCTL_6338_SPI_EN; 182e7300d04SMaxime Bizon else if (BCMCPU_IS_6348()) 183e7300d04SMaxime Bizon mask = CKCTL_6348_SPI_EN; 18419372b24SFlorian Fainelli else if (BCMCPU_IS_6358()) 185e7300d04SMaxime Bizon mask = CKCTL_6358_SPI_EN; 18619372b24SFlorian Fainelli else 18719372b24SFlorian Fainelli /* BCMCPU_IS_6368 */ 18819372b24SFlorian Fainelli mask = CKCTL_6368_SPI_EN; 189e7300d04SMaxime Bizon bcm_hwclock_set(mask, enable); 190e7300d04SMaxime Bizon } 191e7300d04SMaxime Bizon 192e7300d04SMaxime Bizon static struct clk clk_spi = { 193e7300d04SMaxime Bizon .set = spi_set, 194e7300d04SMaxime Bizon }; 195e7300d04SMaxime Bizon 196e7300d04SMaxime Bizon /* 19704712f3fSMaxime Bizon * XTM clock 19804712f3fSMaxime Bizon */ 19904712f3fSMaxime Bizon static void xtm_set(struct clk *clk, int enable) 20004712f3fSMaxime Bizon { 20104712f3fSMaxime Bizon if (!BCMCPU_IS_6368()) 20204712f3fSMaxime Bizon return; 20304712f3fSMaxime Bizon 204d9831a41SFlorian Fainelli bcm_hwclock_set(CKCTL_6368_SAR_EN | 20504712f3fSMaxime Bizon CKCTL_6368_SWPKT_SAR_EN, enable); 20604712f3fSMaxime Bizon 20704712f3fSMaxime Bizon if (enable) { 20804712f3fSMaxime Bizon u32 val; 20904712f3fSMaxime Bizon 21004712f3fSMaxime Bizon /* reset sar core afer clock change */ 21104712f3fSMaxime Bizon val = bcm_perf_readl(PERF_SOFTRESET_6368_REG); 21204712f3fSMaxime Bizon val &= ~SOFTRESET_6368_SAR_MASK; 21304712f3fSMaxime Bizon bcm_perf_writel(val, PERF_SOFTRESET_6368_REG); 21404712f3fSMaxime Bizon mdelay(1); 21504712f3fSMaxime Bizon val |= SOFTRESET_6368_SAR_MASK; 21604712f3fSMaxime Bizon bcm_perf_writel(val, PERF_SOFTRESET_6368_REG); 21704712f3fSMaxime Bizon mdelay(1); 21804712f3fSMaxime Bizon } 21904712f3fSMaxime Bizon } 22004712f3fSMaxime Bizon 22104712f3fSMaxime Bizon 22204712f3fSMaxime Bizon static struct clk clk_xtm = { 22304712f3fSMaxime Bizon .set = xtm_set, 22404712f3fSMaxime Bizon }; 22504712f3fSMaxime Bizon 22604712f3fSMaxime Bizon /* 227*0b55561bSFlorian Fainelli * IPsec clock 228*0b55561bSFlorian Fainelli */ 229*0b55561bSFlorian Fainelli static void ipsec_set(struct clk *clk, int enable) 230*0b55561bSFlorian Fainelli { 231*0b55561bSFlorian Fainelli bcm_hwclock_set(CKCTL_6368_IPSEC_EN, enable); 232*0b55561bSFlorian Fainelli } 233*0b55561bSFlorian Fainelli 234*0b55561bSFlorian Fainelli static struct clk clk_ipsec = { 235*0b55561bSFlorian Fainelli .set = ipsec_set, 236*0b55561bSFlorian Fainelli }; 237*0b55561bSFlorian Fainelli 238*0b55561bSFlorian Fainelli /* 239e7300d04SMaxime Bizon * Internal peripheral clock 240e7300d04SMaxime Bizon */ 241e7300d04SMaxime Bizon static struct clk clk_periph = { 242e7300d04SMaxime Bizon .rate = (50 * 1000 * 1000), 243e7300d04SMaxime Bizon }; 244e7300d04SMaxime Bizon 245e7300d04SMaxime Bizon 246e7300d04SMaxime Bizon /* 247e7300d04SMaxime Bizon * Linux clock API implementation 248e7300d04SMaxime Bizon */ 249e7300d04SMaxime Bizon int clk_enable(struct clk *clk) 250e7300d04SMaxime Bizon { 251e7300d04SMaxime Bizon mutex_lock(&clocks_mutex); 252e7300d04SMaxime Bizon clk_enable_unlocked(clk); 253e7300d04SMaxime Bizon mutex_unlock(&clocks_mutex); 254e7300d04SMaxime Bizon return 0; 255e7300d04SMaxime Bizon } 256e7300d04SMaxime Bizon 257e7300d04SMaxime Bizon EXPORT_SYMBOL(clk_enable); 258e7300d04SMaxime Bizon 259e7300d04SMaxime Bizon void clk_disable(struct clk *clk) 260e7300d04SMaxime Bizon { 261e7300d04SMaxime Bizon mutex_lock(&clocks_mutex); 262e7300d04SMaxime Bizon clk_disable_unlocked(clk); 263e7300d04SMaxime Bizon mutex_unlock(&clocks_mutex); 264e7300d04SMaxime Bizon } 265e7300d04SMaxime Bizon 266e7300d04SMaxime Bizon EXPORT_SYMBOL(clk_disable); 267e7300d04SMaxime Bizon 268e7300d04SMaxime Bizon unsigned long clk_get_rate(struct clk *clk) 269e7300d04SMaxime Bizon { 270e7300d04SMaxime Bizon return clk->rate; 271e7300d04SMaxime Bizon } 272e7300d04SMaxime Bizon 273e7300d04SMaxime Bizon EXPORT_SYMBOL(clk_get_rate); 274e7300d04SMaxime Bizon 275e7300d04SMaxime Bizon struct clk *clk_get(struct device *dev, const char *id) 276e7300d04SMaxime Bizon { 277e7300d04SMaxime Bizon if (!strcmp(id, "enet0")) 278e7300d04SMaxime Bizon return &clk_enet0; 279e7300d04SMaxime Bizon if (!strcmp(id, "enet1")) 280e7300d04SMaxime Bizon return &clk_enet1; 28104712f3fSMaxime Bizon if (!strcmp(id, "enetsw")) 28204712f3fSMaxime Bizon return &clk_enetsw; 283e7300d04SMaxime Bizon if (!strcmp(id, "ephy")) 284e7300d04SMaxime Bizon return &clk_ephy; 285e7300d04SMaxime Bizon if (!strcmp(id, "usbh")) 286e7300d04SMaxime Bizon return &clk_usbh; 287e7300d04SMaxime Bizon if (!strcmp(id, "spi")) 288e7300d04SMaxime Bizon return &clk_spi; 28904712f3fSMaxime Bizon if (!strcmp(id, "xtm")) 29004712f3fSMaxime Bizon return &clk_xtm; 291e7300d04SMaxime Bizon if (!strcmp(id, "periph")) 292e7300d04SMaxime Bizon return &clk_periph; 293e7300d04SMaxime Bizon if (BCMCPU_IS_6358() && !strcmp(id, "pcm")) 294e7300d04SMaxime Bizon return &clk_pcm; 295*0b55561bSFlorian Fainelli if (BCMCPU_IS_6368() && !strcmp(id, "ipsec")) 296*0b55561bSFlorian Fainelli return &clk_ipsec; 297e7300d04SMaxime Bizon return ERR_PTR(-ENOENT); 298e7300d04SMaxime Bizon } 299e7300d04SMaxime Bizon 300e7300d04SMaxime Bizon EXPORT_SYMBOL(clk_get); 301e7300d04SMaxime Bizon 302e7300d04SMaxime Bizon void clk_put(struct clk *clk) 303e7300d04SMaxime Bizon { 304e7300d04SMaxime Bizon } 305e7300d04SMaxime Bizon 306e7300d04SMaxime Bizon EXPORT_SYMBOL(clk_put); 307