xref: /openbmc/linux/arch/mips/bcm63xx/clk.c (revision 0b55561bc608abbbd1b5c98e0a4e9158334086c1)
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