xref: /openbmc/linux/arch/mips/bcm63xx/clk.c (revision ba00e2e5c24f447fb09437a99df697787103f0cd)
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>
17*ba00e2e5SJonas Gorski #include <bcm63xx_reset.h>
18e7300d04SMaxime Bizon #include <bcm63xx_clk.h>
19e7300d04SMaxime Bizon 
20e7300d04SMaxime Bizon static DEFINE_MUTEX(clocks_mutex);
21e7300d04SMaxime Bizon 
22e7300d04SMaxime Bizon 
23e7300d04SMaxime Bizon static void clk_enable_unlocked(struct clk *clk)
24e7300d04SMaxime Bizon {
25e7300d04SMaxime Bizon 	if (clk->set && (clk->usage++) == 0)
26e7300d04SMaxime Bizon 		clk->set(clk, 1);
27e7300d04SMaxime Bizon }
28e7300d04SMaxime Bizon 
29e7300d04SMaxime Bizon static void clk_disable_unlocked(struct clk *clk)
30e7300d04SMaxime Bizon {
31e7300d04SMaxime Bizon 	if (clk->set && (--clk->usage) == 0)
32e7300d04SMaxime Bizon 		clk->set(clk, 0);
33e7300d04SMaxime Bizon }
34e7300d04SMaxime Bizon 
35e7300d04SMaxime Bizon static void bcm_hwclock_set(u32 mask, int enable)
36e7300d04SMaxime Bizon {
37e7300d04SMaxime Bizon 	u32 reg;
38e7300d04SMaxime Bizon 
39e7300d04SMaxime Bizon 	reg = bcm_perf_readl(PERF_CKCTL_REG);
40e7300d04SMaxime Bizon 	if (enable)
41e7300d04SMaxime Bizon 		reg |= mask;
42e7300d04SMaxime Bizon 	else
43e7300d04SMaxime Bizon 		reg &= ~mask;
44e7300d04SMaxime Bizon 	bcm_perf_writel(reg, PERF_CKCTL_REG);
45e7300d04SMaxime Bizon }
46e7300d04SMaxime Bizon 
47e7300d04SMaxime Bizon /*
48e7300d04SMaxime Bizon  * Ethernet MAC "misc" clock: dma clocks and main clock on 6348
49e7300d04SMaxime Bizon  */
50e7300d04SMaxime Bizon static void enet_misc_set(struct clk *clk, int enable)
51e7300d04SMaxime Bizon {
52e7300d04SMaxime Bizon 	u32 mask;
53e7300d04SMaxime Bizon 
54e7300d04SMaxime Bizon 	if (BCMCPU_IS_6338())
55e7300d04SMaxime Bizon 		mask = CKCTL_6338_ENET_EN;
56e7300d04SMaxime Bizon 	else if (BCMCPU_IS_6345())
57e7300d04SMaxime Bizon 		mask = CKCTL_6345_ENET_EN;
58e7300d04SMaxime Bizon 	else if (BCMCPU_IS_6348())
59e7300d04SMaxime Bizon 		mask = CKCTL_6348_ENET_EN;
60e7300d04SMaxime Bizon 	else
61e7300d04SMaxime Bizon 		/* BCMCPU_IS_6358 */
62e7300d04SMaxime Bizon 		mask = CKCTL_6358_EMUSB_EN;
63e7300d04SMaxime Bizon 	bcm_hwclock_set(mask, enable);
64e7300d04SMaxime Bizon }
65e7300d04SMaxime Bizon 
66e7300d04SMaxime Bizon static struct clk clk_enet_misc = {
67e7300d04SMaxime Bizon 	.set	= enet_misc_set,
68e7300d04SMaxime Bizon };
69e7300d04SMaxime Bizon 
70e7300d04SMaxime Bizon /*
71e7300d04SMaxime Bizon  * Ethernet MAC clocks: only revelant on 6358, silently enable misc
72e7300d04SMaxime Bizon  * clocks
73e7300d04SMaxime Bizon  */
74e7300d04SMaxime Bizon static void enetx_set(struct clk *clk, int enable)
75e7300d04SMaxime Bizon {
76e7300d04SMaxime Bizon 	if (enable)
77e7300d04SMaxime Bizon 		clk_enable_unlocked(&clk_enet_misc);
78e7300d04SMaxime Bizon 	else
79e7300d04SMaxime Bizon 		clk_disable_unlocked(&clk_enet_misc);
80e7300d04SMaxime Bizon 
81e7300d04SMaxime Bizon 	if (BCMCPU_IS_6358()) {
82e7300d04SMaxime Bizon 		u32 mask;
83e7300d04SMaxime Bizon 
84e7300d04SMaxime Bizon 		if (clk->id == 0)
85e7300d04SMaxime Bizon 			mask = CKCTL_6358_ENET0_EN;
86e7300d04SMaxime Bizon 		else
87e7300d04SMaxime Bizon 			mask = CKCTL_6358_ENET1_EN;
88e7300d04SMaxime Bizon 		bcm_hwclock_set(mask, enable);
89e7300d04SMaxime Bizon 	}
90e7300d04SMaxime Bizon }
91e7300d04SMaxime Bizon 
92e7300d04SMaxime Bizon static struct clk clk_enet0 = {
93e7300d04SMaxime Bizon 	.id	= 0,
94e7300d04SMaxime Bizon 	.set	= enetx_set,
95e7300d04SMaxime Bizon };
96e7300d04SMaxime Bizon 
97e7300d04SMaxime Bizon static struct clk clk_enet1 = {
98e7300d04SMaxime Bizon 	.id	= 1,
99e7300d04SMaxime Bizon 	.set	= enetx_set,
100e7300d04SMaxime Bizon };
101e7300d04SMaxime Bizon 
102e7300d04SMaxime Bizon /*
103e7300d04SMaxime Bizon  * Ethernet PHY clock
104e7300d04SMaxime Bizon  */
105e7300d04SMaxime Bizon static void ephy_set(struct clk *clk, int enable)
106e7300d04SMaxime Bizon {
107e7300d04SMaxime Bizon 	if (!BCMCPU_IS_6358())
108e7300d04SMaxime Bizon 		return;
109e7300d04SMaxime Bizon 	bcm_hwclock_set(CKCTL_6358_EPHY_EN, enable);
110e7300d04SMaxime Bizon }
111e7300d04SMaxime Bizon 
112e7300d04SMaxime Bizon 
113e7300d04SMaxime Bizon static struct clk clk_ephy = {
114e7300d04SMaxime Bizon 	.set	= ephy_set,
115e7300d04SMaxime Bizon };
116e7300d04SMaxime Bizon 
117e7300d04SMaxime Bizon /*
11804712f3fSMaxime Bizon  * Ethernet switch clock
11904712f3fSMaxime Bizon  */
12004712f3fSMaxime Bizon static void enetsw_set(struct clk *clk, int enable)
12104712f3fSMaxime Bizon {
12204712f3fSMaxime Bizon 	if (!BCMCPU_IS_6368())
12304712f3fSMaxime Bizon 		return;
124d9831a41SFlorian Fainelli 	bcm_hwclock_set(CKCTL_6368_ROBOSW_EN |
12504712f3fSMaxime Bizon 			CKCTL_6368_SWPKT_USB_EN |
12604712f3fSMaxime Bizon 			CKCTL_6368_SWPKT_SAR_EN, enable);
12704712f3fSMaxime Bizon 	if (enable) {
12804712f3fSMaxime Bizon 		/* reset switch core afer clock change */
129*ba00e2e5SJonas Gorski 		bcm63xx_core_set_reset(BCM63XX_RESET_ENETSW, 1);
13004712f3fSMaxime Bizon 		msleep(10);
131*ba00e2e5SJonas Gorski 		bcm63xx_core_set_reset(BCM63XX_RESET_ENETSW, 0);
13204712f3fSMaxime Bizon 		msleep(10);
13304712f3fSMaxime Bizon 	}
13404712f3fSMaxime Bizon }
13504712f3fSMaxime Bizon 
13604712f3fSMaxime Bizon static struct clk clk_enetsw = {
13704712f3fSMaxime Bizon 	.set	= enetsw_set,
13804712f3fSMaxime Bizon };
13904712f3fSMaxime Bizon 
14004712f3fSMaxime Bizon /*
141e7300d04SMaxime Bizon  * PCM clock
142e7300d04SMaxime Bizon  */
143e7300d04SMaxime Bizon static void pcm_set(struct clk *clk, int enable)
144e7300d04SMaxime Bizon {
145e7300d04SMaxime Bizon 	if (!BCMCPU_IS_6358())
146e7300d04SMaxime Bizon 		return;
147e7300d04SMaxime Bizon 	bcm_hwclock_set(CKCTL_6358_PCM_EN, enable);
148e7300d04SMaxime Bizon }
149e7300d04SMaxime Bizon 
150e7300d04SMaxime Bizon static struct clk clk_pcm = {
151e7300d04SMaxime Bizon 	.set	= pcm_set,
152e7300d04SMaxime Bizon };
153e7300d04SMaxime Bizon 
154e7300d04SMaxime Bizon /*
155e7300d04SMaxime Bizon  * USB host clock
156e7300d04SMaxime Bizon  */
157e7300d04SMaxime Bizon static void usbh_set(struct clk *clk, int enable)
158e7300d04SMaxime Bizon {
159dd89d60cSKevin Cernekee 	if (BCMCPU_IS_6328())
160dd89d60cSKevin Cernekee 		bcm_hwclock_set(CKCTL_6328_USBH_EN, enable);
161dd89d60cSKevin Cernekee 	else if (BCMCPU_IS_6348())
162e7300d04SMaxime Bizon 		bcm_hwclock_set(CKCTL_6348_USBH_EN, enable);
16304712f3fSMaxime Bizon 	else if (BCMCPU_IS_6368())
164d9831a41SFlorian Fainelli 		bcm_hwclock_set(CKCTL_6368_USBH_EN, enable);
165e7300d04SMaxime Bizon }
166e7300d04SMaxime Bizon 
167e7300d04SMaxime Bizon static struct clk clk_usbh = {
168e7300d04SMaxime Bizon 	.set	= usbh_set,
169e7300d04SMaxime Bizon };
170e7300d04SMaxime Bizon 
171e7300d04SMaxime Bizon /*
172dd89d60cSKevin Cernekee  * USB device clock
173dd89d60cSKevin Cernekee  */
174dd89d60cSKevin Cernekee static void usbd_set(struct clk *clk, int enable)
175dd89d60cSKevin Cernekee {
176dd89d60cSKevin Cernekee 	if (BCMCPU_IS_6328())
177dd89d60cSKevin Cernekee 		bcm_hwclock_set(CKCTL_6328_USBD_EN, enable);
178dd89d60cSKevin Cernekee 	else if (BCMCPU_IS_6368())
179dd89d60cSKevin Cernekee 		bcm_hwclock_set(CKCTL_6368_USBD_EN, enable);
180dd89d60cSKevin Cernekee }
181dd89d60cSKevin Cernekee 
182dd89d60cSKevin Cernekee static struct clk clk_usbd = {
183dd89d60cSKevin Cernekee 	.set	= usbd_set,
184dd89d60cSKevin Cernekee };
185dd89d60cSKevin Cernekee 
186dd89d60cSKevin Cernekee /*
187e7300d04SMaxime Bizon  * SPI clock
188e7300d04SMaxime Bizon  */
189e7300d04SMaxime Bizon static void spi_set(struct clk *clk, int enable)
190e7300d04SMaxime Bizon {
191e7300d04SMaxime Bizon 	u32 mask;
192e7300d04SMaxime Bizon 
193e7300d04SMaxime Bizon 	if (BCMCPU_IS_6338())
194e7300d04SMaxime Bizon 		mask = CKCTL_6338_SPI_EN;
195e7300d04SMaxime Bizon 	else if (BCMCPU_IS_6348())
196e7300d04SMaxime Bizon 		mask = CKCTL_6348_SPI_EN;
19719372b24SFlorian Fainelli 	else if (BCMCPU_IS_6358())
198e7300d04SMaxime Bizon 		mask = CKCTL_6358_SPI_EN;
19919372b24SFlorian Fainelli 	else
20019372b24SFlorian Fainelli 		/* BCMCPU_IS_6368 */
20119372b24SFlorian Fainelli 		mask = CKCTL_6368_SPI_EN;
202e7300d04SMaxime Bizon 	bcm_hwclock_set(mask, enable);
203e7300d04SMaxime Bizon }
204e7300d04SMaxime Bizon 
205e7300d04SMaxime Bizon static struct clk clk_spi = {
206e7300d04SMaxime Bizon 	.set	= spi_set,
207e7300d04SMaxime Bizon };
208e7300d04SMaxime Bizon 
209e7300d04SMaxime Bizon /*
21004712f3fSMaxime Bizon  * XTM clock
21104712f3fSMaxime Bizon  */
21204712f3fSMaxime Bizon static void xtm_set(struct clk *clk, int enable)
21304712f3fSMaxime Bizon {
21404712f3fSMaxime Bizon 	if (!BCMCPU_IS_6368())
21504712f3fSMaxime Bizon 		return;
21604712f3fSMaxime Bizon 
217d9831a41SFlorian Fainelli 	bcm_hwclock_set(CKCTL_6368_SAR_EN |
21804712f3fSMaxime Bizon 			CKCTL_6368_SWPKT_SAR_EN, enable);
21904712f3fSMaxime Bizon 
22004712f3fSMaxime Bizon 	if (enable) {
22104712f3fSMaxime Bizon 		/* reset sar core afer clock change */
222*ba00e2e5SJonas Gorski 		bcm63xx_core_set_reset(BCM63XX_RESET_SAR, 1);
22304712f3fSMaxime Bizon 		mdelay(1);
224*ba00e2e5SJonas Gorski 		bcm63xx_core_set_reset(BCM63XX_RESET_SAR, 0);
22504712f3fSMaxime Bizon 		mdelay(1);
22604712f3fSMaxime Bizon 	}
22704712f3fSMaxime Bizon }
22804712f3fSMaxime Bizon 
22904712f3fSMaxime Bizon 
23004712f3fSMaxime Bizon static struct clk clk_xtm = {
23104712f3fSMaxime Bizon 	.set	= xtm_set,
23204712f3fSMaxime Bizon };
23304712f3fSMaxime Bizon 
23404712f3fSMaxime Bizon /*
2350b55561bSFlorian Fainelli  * IPsec clock
2360b55561bSFlorian Fainelli  */
2370b55561bSFlorian Fainelli static void ipsec_set(struct clk *clk, int enable)
2380b55561bSFlorian Fainelli {
2390b55561bSFlorian Fainelli 	bcm_hwclock_set(CKCTL_6368_IPSEC_EN, enable);
2400b55561bSFlorian Fainelli }
2410b55561bSFlorian Fainelli 
2420b55561bSFlorian Fainelli static struct clk clk_ipsec = {
2430b55561bSFlorian Fainelli 	.set	= ipsec_set,
2440b55561bSFlorian Fainelli };
2450b55561bSFlorian Fainelli 
2460b55561bSFlorian Fainelli /*
247f2d1035eSJonas Gorski  * PCIe clock
248f2d1035eSJonas Gorski  */
249f2d1035eSJonas Gorski 
250f2d1035eSJonas Gorski static void pcie_set(struct clk *clk, int enable)
251f2d1035eSJonas Gorski {
252f2d1035eSJonas Gorski 	bcm_hwclock_set(CKCTL_6328_PCIE_EN, enable);
253f2d1035eSJonas Gorski }
254f2d1035eSJonas Gorski 
255f2d1035eSJonas Gorski static struct clk clk_pcie = {
256f2d1035eSJonas Gorski 	.set	= pcie_set,
257f2d1035eSJonas Gorski };
258f2d1035eSJonas Gorski 
259f2d1035eSJonas Gorski /*
260e7300d04SMaxime Bizon  * Internal peripheral clock
261e7300d04SMaxime Bizon  */
262e7300d04SMaxime Bizon static struct clk clk_periph = {
263e7300d04SMaxime Bizon 	.rate	= (50 * 1000 * 1000),
264e7300d04SMaxime Bizon };
265e7300d04SMaxime Bizon 
266e7300d04SMaxime Bizon 
267e7300d04SMaxime Bizon /*
268e7300d04SMaxime Bizon  * Linux clock API implementation
269e7300d04SMaxime Bizon  */
270e7300d04SMaxime Bizon int clk_enable(struct clk *clk)
271e7300d04SMaxime Bizon {
272e7300d04SMaxime Bizon 	mutex_lock(&clocks_mutex);
273e7300d04SMaxime Bizon 	clk_enable_unlocked(clk);
274e7300d04SMaxime Bizon 	mutex_unlock(&clocks_mutex);
275e7300d04SMaxime Bizon 	return 0;
276e7300d04SMaxime Bizon }
277e7300d04SMaxime Bizon 
278e7300d04SMaxime Bizon EXPORT_SYMBOL(clk_enable);
279e7300d04SMaxime Bizon 
280e7300d04SMaxime Bizon void clk_disable(struct clk *clk)
281e7300d04SMaxime Bizon {
282e7300d04SMaxime Bizon 	mutex_lock(&clocks_mutex);
283e7300d04SMaxime Bizon 	clk_disable_unlocked(clk);
284e7300d04SMaxime Bizon 	mutex_unlock(&clocks_mutex);
285e7300d04SMaxime Bizon }
286e7300d04SMaxime Bizon 
287e7300d04SMaxime Bizon EXPORT_SYMBOL(clk_disable);
288e7300d04SMaxime Bizon 
289e7300d04SMaxime Bizon unsigned long clk_get_rate(struct clk *clk)
290e7300d04SMaxime Bizon {
291e7300d04SMaxime Bizon 	return clk->rate;
292e7300d04SMaxime Bizon }
293e7300d04SMaxime Bizon 
294e7300d04SMaxime Bizon EXPORT_SYMBOL(clk_get_rate);
295e7300d04SMaxime Bizon 
296e7300d04SMaxime Bizon struct clk *clk_get(struct device *dev, const char *id)
297e7300d04SMaxime Bizon {
298e7300d04SMaxime Bizon 	if (!strcmp(id, "enet0"))
299e7300d04SMaxime Bizon 		return &clk_enet0;
300e7300d04SMaxime Bizon 	if (!strcmp(id, "enet1"))
301e7300d04SMaxime Bizon 		return &clk_enet1;
30204712f3fSMaxime Bizon 	if (!strcmp(id, "enetsw"))
30304712f3fSMaxime Bizon 		return &clk_enetsw;
304e7300d04SMaxime Bizon 	if (!strcmp(id, "ephy"))
305e7300d04SMaxime Bizon 		return &clk_ephy;
306e7300d04SMaxime Bizon 	if (!strcmp(id, "usbh"))
307e7300d04SMaxime Bizon 		return &clk_usbh;
308dd89d60cSKevin Cernekee 	if (!strcmp(id, "usbd"))
309dd89d60cSKevin Cernekee 		return &clk_usbd;
310e7300d04SMaxime Bizon 	if (!strcmp(id, "spi"))
311e7300d04SMaxime Bizon 		return &clk_spi;
31204712f3fSMaxime Bizon 	if (!strcmp(id, "xtm"))
31304712f3fSMaxime Bizon 		return &clk_xtm;
314e7300d04SMaxime Bizon 	if (!strcmp(id, "periph"))
315e7300d04SMaxime Bizon 		return &clk_periph;
316e7300d04SMaxime Bizon 	if (BCMCPU_IS_6358() && !strcmp(id, "pcm"))
317e7300d04SMaxime Bizon 		return &clk_pcm;
3180b55561bSFlorian Fainelli 	if (BCMCPU_IS_6368() && !strcmp(id, "ipsec"))
3190b55561bSFlorian Fainelli 		return &clk_ipsec;
320f2d1035eSJonas Gorski 	if (BCMCPU_IS_6328() && !strcmp(id, "pcie"))
321f2d1035eSJonas Gorski 		return &clk_pcie;
322e7300d04SMaxime Bizon 	return ERR_PTR(-ENOENT);
323e7300d04SMaxime Bizon }
324e7300d04SMaxime Bizon 
325e7300d04SMaxime Bizon EXPORT_SYMBOL(clk_get);
326e7300d04SMaxime Bizon 
327e7300d04SMaxime Bizon void clk_put(struct clk *clk)
328e7300d04SMaxime Bizon {
329e7300d04SMaxime Bizon }
330e7300d04SMaxime Bizon 
331e7300d04SMaxime Bizon EXPORT_SYMBOL(clk_put);
332