xref: /openbmc/linux/arch/mips/bcm63xx/clk.c (revision 7aa2d05299f92ab73591988ab514f0ddc98138f3)
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>
17ba00e2e5SJonas Gorski #include <bcm63xx_reset.h>
18042df4faSJonas Gorski 
19042df4faSJonas Gorski struct clk {
20042df4faSJonas Gorski 	void		(*set)(struct clk *, int);
21042df4faSJonas Gorski 	unsigned int	rate;
22042df4faSJonas Gorski 	unsigned int	usage;
23042df4faSJonas Gorski 	int		id;
24042df4faSJonas Gorski };
25e7300d04SMaxime Bizon 
26e7300d04SMaxime Bizon static DEFINE_MUTEX(clocks_mutex);
27e7300d04SMaxime Bizon 
28e7300d04SMaxime Bizon 
29e7300d04SMaxime Bizon static void clk_enable_unlocked(struct clk *clk)
30e7300d04SMaxime Bizon {
31e7300d04SMaxime Bizon 	if (clk->set && (clk->usage++) == 0)
32e7300d04SMaxime Bizon 		clk->set(clk, 1);
33e7300d04SMaxime Bizon }
34e7300d04SMaxime Bizon 
35e7300d04SMaxime Bizon static void clk_disable_unlocked(struct clk *clk)
36e7300d04SMaxime Bizon {
37e7300d04SMaxime Bizon 	if (clk->set && (--clk->usage) == 0)
38e7300d04SMaxime Bizon 		clk->set(clk, 0);
39e7300d04SMaxime Bizon }
40e7300d04SMaxime Bizon 
41e7300d04SMaxime Bizon static void bcm_hwclock_set(u32 mask, int enable)
42e7300d04SMaxime Bizon {
43e7300d04SMaxime Bizon 	u32 reg;
44e7300d04SMaxime Bizon 
45e7300d04SMaxime Bizon 	reg = bcm_perf_readl(PERF_CKCTL_REG);
46e7300d04SMaxime Bizon 	if (enable)
47e7300d04SMaxime Bizon 		reg |= mask;
48e7300d04SMaxime Bizon 	else
49e7300d04SMaxime Bizon 		reg &= ~mask;
50e7300d04SMaxime Bizon 	bcm_perf_writel(reg, PERF_CKCTL_REG);
51e7300d04SMaxime Bizon }
52e7300d04SMaxime Bizon 
53e7300d04SMaxime Bizon /*
54e7300d04SMaxime Bizon  * Ethernet MAC "misc" clock: dma clocks and main clock on 6348
55e7300d04SMaxime Bizon  */
56e7300d04SMaxime Bizon static void enet_misc_set(struct clk *clk, int enable)
57e7300d04SMaxime Bizon {
58e7300d04SMaxime Bizon 	u32 mask;
59e7300d04SMaxime Bizon 
60e7300d04SMaxime Bizon 	if (BCMCPU_IS_6338())
61e7300d04SMaxime Bizon 		mask = CKCTL_6338_ENET_EN;
62e7300d04SMaxime Bizon 	else if (BCMCPU_IS_6345())
63e7300d04SMaxime Bizon 		mask = CKCTL_6345_ENET_EN;
64e7300d04SMaxime Bizon 	else if (BCMCPU_IS_6348())
65e7300d04SMaxime Bizon 		mask = CKCTL_6348_ENET_EN;
66e7300d04SMaxime Bizon 	else
67e7300d04SMaxime Bizon 		/* BCMCPU_IS_6358 */
68e7300d04SMaxime Bizon 		mask = CKCTL_6358_EMUSB_EN;
69e7300d04SMaxime Bizon 	bcm_hwclock_set(mask, enable);
70e7300d04SMaxime Bizon }
71e7300d04SMaxime Bizon 
72e7300d04SMaxime Bizon static struct clk clk_enet_misc = {
73e7300d04SMaxime Bizon 	.set	= enet_misc_set,
74e7300d04SMaxime Bizon };
75e7300d04SMaxime Bizon 
76e7300d04SMaxime Bizon /*
77e7300d04SMaxime Bizon  * Ethernet MAC clocks: only revelant on 6358, silently enable misc
78e7300d04SMaxime Bizon  * clocks
79e7300d04SMaxime Bizon  */
80e7300d04SMaxime Bizon static void enetx_set(struct clk *clk, int enable)
81e7300d04SMaxime Bizon {
82e7300d04SMaxime Bizon 	if (enable)
83e7300d04SMaxime Bizon 		clk_enable_unlocked(&clk_enet_misc);
84e7300d04SMaxime Bizon 	else
85e7300d04SMaxime Bizon 		clk_disable_unlocked(&clk_enet_misc);
86e7300d04SMaxime Bizon 
877b933421SFlorian Fainelli 	if (BCMCPU_IS_3368() || BCMCPU_IS_6358()) {
88e7300d04SMaxime Bizon 		u32 mask;
89e7300d04SMaxime Bizon 
90e7300d04SMaxime Bizon 		if (clk->id == 0)
91e7300d04SMaxime Bizon 			mask = CKCTL_6358_ENET0_EN;
92e7300d04SMaxime Bizon 		else
93e7300d04SMaxime Bizon 			mask = CKCTL_6358_ENET1_EN;
94e7300d04SMaxime Bizon 		bcm_hwclock_set(mask, enable);
95e7300d04SMaxime Bizon 	}
96e7300d04SMaxime Bizon }
97e7300d04SMaxime Bizon 
98e7300d04SMaxime Bizon static struct clk clk_enet0 = {
99e7300d04SMaxime Bizon 	.id	= 0,
100e7300d04SMaxime Bizon 	.set	= enetx_set,
101e7300d04SMaxime Bizon };
102e7300d04SMaxime Bizon 
103e7300d04SMaxime Bizon static struct clk clk_enet1 = {
104e7300d04SMaxime Bizon 	.id	= 1,
105e7300d04SMaxime Bizon 	.set	= enetx_set,
106e7300d04SMaxime Bizon };
107e7300d04SMaxime Bizon 
108e7300d04SMaxime Bizon /*
109e7300d04SMaxime Bizon  * Ethernet PHY clock
110e7300d04SMaxime Bizon  */
111e7300d04SMaxime Bizon static void ephy_set(struct clk *clk, int enable)
112e7300d04SMaxime Bizon {
1137b933421SFlorian Fainelli 	if (BCMCPU_IS_3368() || BCMCPU_IS_6358())
114e7300d04SMaxime Bizon 		bcm_hwclock_set(CKCTL_6358_EPHY_EN, enable);
115e7300d04SMaxime Bizon }
116e7300d04SMaxime Bizon 
117e7300d04SMaxime Bizon 
118e7300d04SMaxime Bizon static struct clk clk_ephy = {
119e7300d04SMaxime Bizon 	.set	= ephy_set,
120e7300d04SMaxime Bizon };
121e7300d04SMaxime Bizon 
122e7300d04SMaxime Bizon /*
12304712f3fSMaxime Bizon  * Ethernet switch clock
12404712f3fSMaxime Bizon  */
12504712f3fSMaxime Bizon static void enetsw_set(struct clk *clk, int enable)
12604712f3fSMaxime Bizon {
1271cd1c049SJonas Gorski 	if (BCMCPU_IS_6328())
1281cd1c049SJonas Gorski 		bcm_hwclock_set(CKCTL_6328_ROBOSW_EN, enable);
1291cd1c049SJonas Gorski 	else if (BCMCPU_IS_6362())
1301cd1c049SJonas Gorski 		bcm_hwclock_set(CKCTL_6362_ROBOSW_EN, enable);
1311cd1c049SJonas Gorski 	else if (BCMCPU_IS_6368())
132d9831a41SFlorian Fainelli 		bcm_hwclock_set(CKCTL_6368_ROBOSW_EN |
13304712f3fSMaxime Bizon 				CKCTL_6368_SWPKT_USB_EN |
1341cd1c049SJonas Gorski 				CKCTL_6368_SWPKT_SAR_EN,
1351cd1c049SJonas Gorski 				enable);
1361cd1c049SJonas Gorski 	else
1371cd1c049SJonas Gorski 		return;
1381cd1c049SJonas Gorski 
13904712f3fSMaxime Bizon 	if (enable) {
14004712f3fSMaxime Bizon 		/* reset switch core afer clock change */
141ba00e2e5SJonas Gorski 		bcm63xx_core_set_reset(BCM63XX_RESET_ENETSW, 1);
14204712f3fSMaxime Bizon 		msleep(10);
143ba00e2e5SJonas Gorski 		bcm63xx_core_set_reset(BCM63XX_RESET_ENETSW, 0);
14404712f3fSMaxime Bizon 		msleep(10);
14504712f3fSMaxime Bizon 	}
14604712f3fSMaxime Bizon }
14704712f3fSMaxime Bizon 
14804712f3fSMaxime Bizon static struct clk clk_enetsw = {
14904712f3fSMaxime Bizon 	.set	= enetsw_set,
15004712f3fSMaxime Bizon };
15104712f3fSMaxime Bizon 
15204712f3fSMaxime Bizon /*
153e7300d04SMaxime Bizon  * PCM clock
154e7300d04SMaxime Bizon  */
155e7300d04SMaxime Bizon static void pcm_set(struct clk *clk, int enable)
156e7300d04SMaxime Bizon {
1577b933421SFlorian Fainelli 	if (BCMCPU_IS_3368())
1587b933421SFlorian Fainelli 		bcm_hwclock_set(CKCTL_3368_PCM_EN, enable);
1597b933421SFlorian Fainelli 	if (BCMCPU_IS_6358())
160e7300d04SMaxime Bizon 		bcm_hwclock_set(CKCTL_6358_PCM_EN, enable);
161e7300d04SMaxime Bizon }
162e7300d04SMaxime Bizon 
163e7300d04SMaxime Bizon static struct clk clk_pcm = {
164e7300d04SMaxime Bizon 	.set	= pcm_set,
165e7300d04SMaxime Bizon };
166e7300d04SMaxime Bizon 
167e7300d04SMaxime Bizon /*
168e7300d04SMaxime Bizon  * USB host clock
169e7300d04SMaxime Bizon  */
170e7300d04SMaxime Bizon static void usbh_set(struct clk *clk, int enable)
171e7300d04SMaxime Bizon {
172dd89d60cSKevin Cernekee 	if (BCMCPU_IS_6328())
173dd89d60cSKevin Cernekee 		bcm_hwclock_set(CKCTL_6328_USBH_EN, enable);
174dd89d60cSKevin Cernekee 	else if (BCMCPU_IS_6348())
175e7300d04SMaxime Bizon 		bcm_hwclock_set(CKCTL_6348_USBH_EN, enable);
1761cd1c049SJonas Gorski 	else if (BCMCPU_IS_6362())
1771cd1c049SJonas Gorski 		bcm_hwclock_set(CKCTL_6362_USBH_EN, enable);
17804712f3fSMaxime Bizon 	else if (BCMCPU_IS_6368())
179d9831a41SFlorian Fainelli 		bcm_hwclock_set(CKCTL_6368_USBH_EN, enable);
180e7300d04SMaxime Bizon }
181e7300d04SMaxime Bizon 
182e7300d04SMaxime Bizon static struct clk clk_usbh = {
183e7300d04SMaxime Bizon 	.set	= usbh_set,
184e7300d04SMaxime Bizon };
185e7300d04SMaxime Bizon 
186e7300d04SMaxime Bizon /*
187dd89d60cSKevin Cernekee  * USB device clock
188dd89d60cSKevin Cernekee  */
189dd89d60cSKevin Cernekee static void usbd_set(struct clk *clk, int enable)
190dd89d60cSKevin Cernekee {
191dd89d60cSKevin Cernekee 	if (BCMCPU_IS_6328())
192dd89d60cSKevin Cernekee 		bcm_hwclock_set(CKCTL_6328_USBD_EN, enable);
1931cd1c049SJonas Gorski 	else if (BCMCPU_IS_6362())
1941cd1c049SJonas Gorski 		bcm_hwclock_set(CKCTL_6362_USBD_EN, enable);
195dd89d60cSKevin Cernekee 	else if (BCMCPU_IS_6368())
196dd89d60cSKevin Cernekee 		bcm_hwclock_set(CKCTL_6368_USBD_EN, enable);
197dd89d60cSKevin Cernekee }
198dd89d60cSKevin Cernekee 
199dd89d60cSKevin Cernekee static struct clk clk_usbd = {
200dd89d60cSKevin Cernekee 	.set	= usbd_set,
201dd89d60cSKevin Cernekee };
202dd89d60cSKevin Cernekee 
203dd89d60cSKevin Cernekee /*
204e7300d04SMaxime Bizon  * SPI clock
205e7300d04SMaxime Bizon  */
206e7300d04SMaxime Bizon static void spi_set(struct clk *clk, int enable)
207e7300d04SMaxime Bizon {
208e7300d04SMaxime Bizon 	u32 mask;
209e7300d04SMaxime Bizon 
210e7300d04SMaxime Bizon 	if (BCMCPU_IS_6338())
211e7300d04SMaxime Bizon 		mask = CKCTL_6338_SPI_EN;
212e7300d04SMaxime Bizon 	else if (BCMCPU_IS_6348())
213e7300d04SMaxime Bizon 		mask = CKCTL_6348_SPI_EN;
2147b933421SFlorian Fainelli 	else if (BCMCPU_IS_3368() || BCMCPU_IS_6358())
215e7300d04SMaxime Bizon 		mask = CKCTL_6358_SPI_EN;
21608a41d12SJonas Gorski 	else if (BCMCPU_IS_6362())
21708a41d12SJonas Gorski 		mask = CKCTL_6362_SPI_EN;
21819372b24SFlorian Fainelli 	else
21919372b24SFlorian Fainelli 		/* BCMCPU_IS_6368 */
22019372b24SFlorian Fainelli 		mask = CKCTL_6368_SPI_EN;
221e7300d04SMaxime Bizon 	bcm_hwclock_set(mask, enable);
222e7300d04SMaxime Bizon }
223e7300d04SMaxime Bizon 
224e7300d04SMaxime Bizon static struct clk clk_spi = {
225e7300d04SMaxime Bizon 	.set	= spi_set,
226e7300d04SMaxime Bizon };
227e7300d04SMaxime Bizon 
228e7300d04SMaxime Bizon /*
22904712f3fSMaxime Bizon  * XTM clock
23004712f3fSMaxime Bizon  */
23104712f3fSMaxime Bizon static void xtm_set(struct clk *clk, int enable)
23204712f3fSMaxime Bizon {
23304712f3fSMaxime Bizon 	if (!BCMCPU_IS_6368())
23404712f3fSMaxime Bizon 		return;
23504712f3fSMaxime Bizon 
236d9831a41SFlorian Fainelli 	bcm_hwclock_set(CKCTL_6368_SAR_EN |
23704712f3fSMaxime Bizon 			CKCTL_6368_SWPKT_SAR_EN, enable);
23804712f3fSMaxime Bizon 
23904712f3fSMaxime Bizon 	if (enable) {
24004712f3fSMaxime Bizon 		/* reset sar core afer clock change */
241ba00e2e5SJonas Gorski 		bcm63xx_core_set_reset(BCM63XX_RESET_SAR, 1);
24204712f3fSMaxime Bizon 		mdelay(1);
243ba00e2e5SJonas Gorski 		bcm63xx_core_set_reset(BCM63XX_RESET_SAR, 0);
24404712f3fSMaxime Bizon 		mdelay(1);
24504712f3fSMaxime Bizon 	}
24604712f3fSMaxime Bizon }
24704712f3fSMaxime Bizon 
24804712f3fSMaxime Bizon 
24904712f3fSMaxime Bizon static struct clk clk_xtm = {
25004712f3fSMaxime Bizon 	.set	= xtm_set,
25104712f3fSMaxime Bizon };
25204712f3fSMaxime Bizon 
25304712f3fSMaxime Bizon /*
2540b55561bSFlorian Fainelli  * IPsec clock
2550b55561bSFlorian Fainelli  */
2560b55561bSFlorian Fainelli static void ipsec_set(struct clk *clk, int enable)
2570b55561bSFlorian Fainelli {
2581cd1c049SJonas Gorski 	if (BCMCPU_IS_6362())
2591cd1c049SJonas Gorski 		bcm_hwclock_set(CKCTL_6362_IPSEC_EN, enable);
2601cd1c049SJonas Gorski 	else if (BCMCPU_IS_6368())
2610b55561bSFlorian Fainelli 		bcm_hwclock_set(CKCTL_6368_IPSEC_EN, enable);
2620b55561bSFlorian Fainelli }
2630b55561bSFlorian Fainelli 
2640b55561bSFlorian Fainelli static struct clk clk_ipsec = {
2650b55561bSFlorian Fainelli 	.set	= ipsec_set,
2660b55561bSFlorian Fainelli };
2670b55561bSFlorian Fainelli 
2680b55561bSFlorian Fainelli /*
269f2d1035eSJonas Gorski  * PCIe clock
270f2d1035eSJonas Gorski  */
271f2d1035eSJonas Gorski 
272f2d1035eSJonas Gorski static void pcie_set(struct clk *clk, int enable)
273f2d1035eSJonas Gorski {
2741cd1c049SJonas Gorski 	if (BCMCPU_IS_6328())
275f2d1035eSJonas Gorski 		bcm_hwclock_set(CKCTL_6328_PCIE_EN, enable);
2761cd1c049SJonas Gorski 	else if (BCMCPU_IS_6362())
2771cd1c049SJonas Gorski 		bcm_hwclock_set(CKCTL_6362_PCIE_EN, enable);
278f2d1035eSJonas Gorski }
279f2d1035eSJonas Gorski 
280f2d1035eSJonas Gorski static struct clk clk_pcie = {
281f2d1035eSJonas Gorski 	.set	= pcie_set,
282f2d1035eSJonas Gorski };
283f2d1035eSJonas Gorski 
284f2d1035eSJonas Gorski /*
285e7300d04SMaxime Bizon  * Internal peripheral clock
286e7300d04SMaxime Bizon  */
287e7300d04SMaxime Bizon static struct clk clk_periph = {
288e7300d04SMaxime Bizon 	.rate	= (50 * 1000 * 1000),
289e7300d04SMaxime Bizon };
290e7300d04SMaxime Bizon 
291e7300d04SMaxime Bizon 
292e7300d04SMaxime Bizon /*
293e7300d04SMaxime Bizon  * Linux clock API implementation
294e7300d04SMaxime Bizon  */
295e7300d04SMaxime Bizon int clk_enable(struct clk *clk)
296e7300d04SMaxime Bizon {
297e7300d04SMaxime Bizon 	mutex_lock(&clocks_mutex);
298e7300d04SMaxime Bizon 	clk_enable_unlocked(clk);
299e7300d04SMaxime Bizon 	mutex_unlock(&clocks_mutex);
300e7300d04SMaxime Bizon 	return 0;
301e7300d04SMaxime Bizon }
302e7300d04SMaxime Bizon 
303e7300d04SMaxime Bizon EXPORT_SYMBOL(clk_enable);
304e7300d04SMaxime Bizon 
305e7300d04SMaxime Bizon void clk_disable(struct clk *clk)
306e7300d04SMaxime Bizon {
307e7300d04SMaxime Bizon 	mutex_lock(&clocks_mutex);
308e7300d04SMaxime Bizon 	clk_disable_unlocked(clk);
309e7300d04SMaxime Bizon 	mutex_unlock(&clocks_mutex);
310e7300d04SMaxime Bizon }
311e7300d04SMaxime Bizon 
312e7300d04SMaxime Bizon EXPORT_SYMBOL(clk_disable);
313e7300d04SMaxime Bizon 
314e7300d04SMaxime Bizon unsigned long clk_get_rate(struct clk *clk)
315e7300d04SMaxime Bizon {
316e7300d04SMaxime Bizon 	return clk->rate;
317e7300d04SMaxime Bizon }
318e7300d04SMaxime Bizon 
319e7300d04SMaxime Bizon EXPORT_SYMBOL(clk_get_rate);
320e7300d04SMaxime Bizon 
321*7aa2d052SMarkos Chandras int clk_set_rate(struct clk *clk, unsigned long rate)
322*7aa2d052SMarkos Chandras {
323*7aa2d052SMarkos Chandras 	return 0;
324*7aa2d052SMarkos Chandras }
325*7aa2d052SMarkos Chandras EXPORT_SYMBOL_GPL(clk_set_rate);
326*7aa2d052SMarkos Chandras 
327*7aa2d052SMarkos Chandras long clk_round_rate(struct clk *clk, unsigned long rate)
328*7aa2d052SMarkos Chandras {
329*7aa2d052SMarkos Chandras 	return 0;
330*7aa2d052SMarkos Chandras }
331*7aa2d052SMarkos Chandras EXPORT_SYMBOL_GPL(clk_round_rate);
332*7aa2d052SMarkos Chandras 
333e7300d04SMaxime Bizon struct clk *clk_get(struct device *dev, const char *id)
334e7300d04SMaxime Bizon {
335e7300d04SMaxime Bizon 	if (!strcmp(id, "enet0"))
336e7300d04SMaxime Bizon 		return &clk_enet0;
337e7300d04SMaxime Bizon 	if (!strcmp(id, "enet1"))
338e7300d04SMaxime Bizon 		return &clk_enet1;
33904712f3fSMaxime Bizon 	if (!strcmp(id, "enetsw"))
34004712f3fSMaxime Bizon 		return &clk_enetsw;
341e7300d04SMaxime Bizon 	if (!strcmp(id, "ephy"))
342e7300d04SMaxime Bizon 		return &clk_ephy;
343e7300d04SMaxime Bizon 	if (!strcmp(id, "usbh"))
344e7300d04SMaxime Bizon 		return &clk_usbh;
345dd89d60cSKevin Cernekee 	if (!strcmp(id, "usbd"))
346dd89d60cSKevin Cernekee 		return &clk_usbd;
347e7300d04SMaxime Bizon 	if (!strcmp(id, "spi"))
348e7300d04SMaxime Bizon 		return &clk_spi;
34904712f3fSMaxime Bizon 	if (!strcmp(id, "xtm"))
35004712f3fSMaxime Bizon 		return &clk_xtm;
351e7300d04SMaxime Bizon 	if (!strcmp(id, "periph"))
352e7300d04SMaxime Bizon 		return &clk_periph;
3537b933421SFlorian Fainelli 	if ((BCMCPU_IS_3368() || BCMCPU_IS_6358()) && !strcmp(id, "pcm"))
354e7300d04SMaxime Bizon 		return &clk_pcm;
3551cd1c049SJonas Gorski 	if ((BCMCPU_IS_6362() || BCMCPU_IS_6368()) && !strcmp(id, "ipsec"))
3560b55561bSFlorian Fainelli 		return &clk_ipsec;
3571cd1c049SJonas Gorski 	if ((BCMCPU_IS_6328() || BCMCPU_IS_6362()) && !strcmp(id, "pcie"))
358f2d1035eSJonas Gorski 		return &clk_pcie;
359e7300d04SMaxime Bizon 	return ERR_PTR(-ENOENT);
360e7300d04SMaxime Bizon }
361e7300d04SMaxime Bizon 
362e7300d04SMaxime Bizon EXPORT_SYMBOL(clk_get);
363e7300d04SMaxime Bizon 
364e7300d04SMaxime Bizon void clk_put(struct clk *clk)
365e7300d04SMaxime Bizon {
366e7300d04SMaxime Bizon }
367e7300d04SMaxime Bizon 
368e7300d04SMaxime Bizon EXPORT_SYMBOL(clk_put);
369