xref: /openbmc/u-boot/drivers/clk/aspeed/clk_ast2600.c (revision 550e691b49d8bc629d140be2137afac9313cdf07)
1*550e691bSryan_chen // SPDX-License-Identifier: GPL-2.0
2*550e691bSryan_chen /*
3*550e691bSryan_chen  * Copyright (C) ASPEED Technology Inc.
4*550e691bSryan_chen  * Ryan Chen <ryan_chen@aspeedtech.com>
5*550e691bSryan_chen  */
6*550e691bSryan_chen 
7*550e691bSryan_chen #include <common.h>
8*550e691bSryan_chen #include <clk-uclass.h>
9*550e691bSryan_chen #include <dm.h>
10*550e691bSryan_chen #include <asm/io.h>
11*550e691bSryan_chen #include <asm/arch/scu_aspeed.h>
12*550e691bSryan_chen #include <dm/lists.h>
13*550e691bSryan_chen #include <dt-bindings/clock/ast2500-scu.h>
14*550e691bSryan_chen 
15*550e691bSryan_chen /* register */
16*550e691bSryan_chen #define ASPEED_STRAP		0x70
17*550e691bSryan_chen #define SCU_HWSTRAP_VGAMEM_SHIFT	2
18*550e691bSryan_chen #define SCU_HWSTRAP_VGAMEM_MASK		(3 << SCU_HWSTRAP_VGAMEM_SHIFT)
19*550e691bSryan_chen #define SCU_HWSTRAP_MAC1_RGMII		(1 << 6)
20*550e691bSryan_chen #define SCU_HWSTRAP_MAC2_RGMII		(1 << 7)
21*550e691bSryan_chen #define SCU_HWSTRAP_DDR4		(1 << 24)
22*550e691bSryan_chen #define SCU_HWSTRAP_CLKIN_25MHZ		(1 << 23)
23*550e691bSryan_chen 
24*550e691bSryan_chen #define ASPEED_CLK_SELECT	0x08
25*550e691bSryan_chen #define SCU_PCLK_DIV_SHIFT		23
26*550e691bSryan_chen #define SCU_PCLK_DIV_MASK		(7 << SCU_PCLK_DIV_SHIFT)
27*550e691bSryan_chen 
28*550e691bSryan_chen #define ASPEED_MSIC2		0x4C
29*550e691bSryan_chen #define SCU_MISC2_RGMII_HPLL		(1 << 23)
30*550e691bSryan_chen #define SCU_MISC2_RGMII_CLKDIV_SHIFT	20
31*550e691bSryan_chen #define SCU_MISC2_RGMII_CLKDIV_MASK	(3 << SCU_MISC2_RGMII_CLKDIV_SHIFT)
32*550e691bSryan_chen #define SCU_MISC2_RMII_MPLL		(1 << 19)
33*550e691bSryan_chen #define SCU_MISC2_RMII_CLKDIV_SHIFT	16
34*550e691bSryan_chen #define SCU_MISC2_RMII_CLKDIV_MASK	(3 << SCU_MISC2_RMII_CLKDIV_SHIFT)
35*550e691bSryan_chen #define SCU_MISC2_UARTCLK_SHIFT		24
36*550e691bSryan_chen 
37*550e691bSryan_chen #define ASPEED_MPLL_PARAMETER	0x20
38*550e691bSryan_chen #define SCU_MPLL_DENUM_SHIFT		0
39*550e691bSryan_chen #define SCU_MPLL_DENUM_MASK		0x1f
40*550e691bSryan_chen #define SCU_MPLL_NUM_SHIFT		5
41*550e691bSryan_chen #define SCU_MPLL_NUM_MASK		(0xff << SCU_MPLL_NUM_SHIFT)
42*550e691bSryan_chen #define SCU_MPLL_POST_SHIFT		13
43*550e691bSryan_chen #define SCU_MPLL_POST_MASK		(0x3f << SCU_MPLL_POST_SHIFT)
44*550e691bSryan_chen 
45*550e691bSryan_chen #define ASPEED_HPLL_PARAMETER	0x24
46*550e691bSryan_chen #define SCU_HPLL_DENUM_SHIFT		0
47*550e691bSryan_chen #define SCU_HPLL_DENUM_MASK		0x1f
48*550e691bSryan_chen #define SCU_HPLL_NUM_SHIFT		5
49*550e691bSryan_chen #define SCU_HPLL_NUM_MASK		(0xff << SCU_HPLL_NUM_SHIFT)
50*550e691bSryan_chen #define SCU_HPLL_POST_SHIFT		13
51*550e691bSryan_chen #define SCU_HPLL_POST_MASK		(0x3f << SCU_HPLL_POST_SHIFT)
52*550e691bSryan_chen 
53*550e691bSryan_chen 
54*550e691bSryan_chen /*
55*550e691bSryan_chen  * MAC Clock Delay settings, taken from Aspeed SDK
56*550e691bSryan_chen  */
57*550e691bSryan_chen #define RGMII_TXCLK_ODLY		8
58*550e691bSryan_chen #define RMII_RXCLK_IDLY		2
59*550e691bSryan_chen 
60*550e691bSryan_chen /*
61*550e691bSryan_chen  * TGMII Clock Duty constants, taken from Aspeed SDK
62*550e691bSryan_chen  */
63*550e691bSryan_chen #define RGMII2_TXCK_DUTY	0x66
64*550e691bSryan_chen #define RGMII1_TXCK_DUTY	0x64
65*550e691bSryan_chen 
66*550e691bSryan_chen #define D2PLL_DEFAULT_RATE	(250 * 1000 * 1000)
67*550e691bSryan_chen 
68*550e691bSryan_chen DECLARE_GLOBAL_DATA_PTR;
69*550e691bSryan_chen 
70*550e691bSryan_chen /*
71*550e691bSryan_chen  * Clock divider/multiplier configuration struct.
72*550e691bSryan_chen  * For H-PLL and M-PLL the formula is
73*550e691bSryan_chen  * (Output Frequency) = CLKIN * ((M + 1) / (N + 1)) / (P + 1)
74*550e691bSryan_chen  * M - Numerator
75*550e691bSryan_chen  * N - Denumerator
76*550e691bSryan_chen  * P - Post Divider
77*550e691bSryan_chen  * They have the same layout in their control register.
78*550e691bSryan_chen  *
79*550e691bSryan_chen  * D-PLL and D2-PLL have extra divider (OD + 1), which is not
80*550e691bSryan_chen  * yet needed and ignored by clock configurations.
81*550e691bSryan_chen  */
82*550e691bSryan_chen struct aspeed_div_config {
83*550e691bSryan_chen 	unsigned int num;
84*550e691bSryan_chen 	unsigned int denum;
85*550e691bSryan_chen 	unsigned int post_div;
86*550e691bSryan_chen };
87*550e691bSryan_chen 
88*550e691bSryan_chen static u32 aspeed_get_clkin(struct aspeed_clk_priv *priv)
89*550e691bSryan_chen {
90*550e691bSryan_chen 	switch(priv->version) {
91*550e691bSryan_chen 		case AST2400:
92*550e691bSryan_chen 		case AST2500:
93*550e691bSryan_chen 			return readl(priv->regs + ASPEED_STRAP) & SCU_HWSTRAP_CLKIN_25MHZ
94*550e691bSryan_chen 					? 25 * 1000 * 1000 : 24 * 1000 * 1000;
95*550e691bSryan_chen 			break;
96*550e691bSryan_chen 		case AST2600:
97*550e691bSryan_chen 			return 25000000;
98*550e691bSryan_chen 			break;
99*550e691bSryan_chen 	}
100*550e691bSryan_chen 	return 0;
101*550e691bSryan_chen }
102*550e691bSryan_chen 
103*550e691bSryan_chen /*
104*550e691bSryan_chen  * Get the rate of the M-PLL clock from input clock frequency and
105*550e691bSryan_chen  * the value of the M-PLL Parameter Register.
106*550e691bSryan_chen  */
107*550e691bSryan_chen static u32 aspeed_get_mpll_rate(struct aspeed_clk_priv *priv)
108*550e691bSryan_chen {
109*550e691bSryan_chen 	u32 clkin = aspeed_get_clkin(priv);
110*550e691bSryan_chen 	u32 mpll_reg = readl(priv->regs + ASPEED_MPLL_PARAMETER);
111*550e691bSryan_chen 
112*550e691bSryan_chen 	const ulong num = (mpll_reg & SCU_MPLL_NUM_MASK) >> SCU_MPLL_NUM_SHIFT;
113*550e691bSryan_chen 	const ulong denum = (mpll_reg & SCU_MPLL_DENUM_MASK)
114*550e691bSryan_chen 			>> SCU_MPLL_DENUM_SHIFT;
115*550e691bSryan_chen 	const ulong post_div = (mpll_reg & SCU_MPLL_POST_MASK)
116*550e691bSryan_chen 			>> SCU_MPLL_POST_SHIFT;
117*550e691bSryan_chen 
118*550e691bSryan_chen 	return (clkin * ((num + 1) / (denum + 1))) / (post_div + 1);
119*550e691bSryan_chen }
120*550e691bSryan_chen 
121*550e691bSryan_chen /*
122*550e691bSryan_chen  * Get the rate of the H-PLL clock from input clock frequency and
123*550e691bSryan_chen  * the value of the H-PLL Parameter Register.
124*550e691bSryan_chen  */
125*550e691bSryan_chen static ulong aspeed_get_hpll_rate(struct aspeed_clk_priv *priv)
126*550e691bSryan_chen {
127*550e691bSryan_chen 	ulong clkin = aspeed_get_clkin(priv);
128*550e691bSryan_chen 	u32 hpll_reg = readl(priv->regs + ASPEED_HPLL_PARAMETER);
129*550e691bSryan_chen 	const ulong num = (hpll_reg & SCU_HPLL_NUM_MASK) >> SCU_HPLL_NUM_SHIFT;
130*550e691bSryan_chen 	const ulong denum = (hpll_reg & SCU_HPLL_DENUM_MASK)
131*550e691bSryan_chen 			>> SCU_HPLL_DENUM_SHIFT;
132*550e691bSryan_chen 	const ulong post_div = (hpll_reg & SCU_HPLL_POST_MASK)
133*550e691bSryan_chen 			>> SCU_HPLL_POST_SHIFT;
134*550e691bSryan_chen 
135*550e691bSryan_chen 	return (clkin * ((num + 1) / (denum + 1))) / (post_div + 1);
136*550e691bSryan_chen }
137*550e691bSryan_chen 
138*550e691bSryan_chen 
139*550e691bSryan_chen /**
140*550e691bSryan_chen  * Get current rate or uart clock
141*550e691bSryan_chen  *
142*550e691bSryan_chen  * @scu SCU registers
143*550e691bSryan_chen  * @uart_index UART index, 1-5
144*550e691bSryan_chen  *
145*550e691bSryan_chen  * @return current setting for uart clock rate
146*550e691bSryan_chen  */
147*550e691bSryan_chen static ulong aspeed_get_uart_clk_rate(struct aspeed_clk_priv *priv, int uart_index)
148*550e691bSryan_chen {
149*550e691bSryan_chen 	/*
150*550e691bSryan_chen 	 * ast2600 datasheet is very confusing when it comes to UART clocks,
151*550e691bSryan_chen 	 * especially when CLKIN = 25 MHz. The settings are in
152*550e691bSryan_chen 	 * different registers and it is unclear how they interact.
153*550e691bSryan_chen 	 *
154*550e691bSryan_chen 	 * This has only been tested with default settings and CLKIN = 24 MHz.
155*550e691bSryan_chen 	 */
156*550e691bSryan_chen 	ulong uart_clkin;
157*550e691bSryan_chen 
158*550e691bSryan_chen 	if (readl(priv->regs + ASPEED_MSIC2) &
159*550e691bSryan_chen 	    (1 << (uart_index - 1 + SCU_MISC2_UARTCLK_SHIFT)))
160*550e691bSryan_chen 		uart_clkin = 192 * 1000 * 1000;
161*550e691bSryan_chen 	else
162*550e691bSryan_chen 		uart_clkin = 24 * 1000 * 1000;
163*550e691bSryan_chen 
164*550e691bSryan_chen 	if (readl(priv->regs + ASPEED_MSIC2) & SCU_MISC_UARTCLK_DIV13)
165*550e691bSryan_chen 		uart_clkin /= 13;
166*550e691bSryan_chen 
167*550e691bSryan_chen 	return uart_clkin;
168*550e691bSryan_chen }
169*550e691bSryan_chen 
170*550e691bSryan_chen static ulong aspeed_clk_get_rate(struct clk *clk)
171*550e691bSryan_chen {
172*550e691bSryan_chen 	struct aspeed_clk_priv *priv = dev_get_priv(clk->dev);
173*550e691bSryan_chen 	ulong rate;
174*550e691bSryan_chen 
175*550e691bSryan_chen 	switch (clk->id) {
176*550e691bSryan_chen 	case PLL_HPLL:
177*550e691bSryan_chen 	case ARMCLK:
178*550e691bSryan_chen 		/*
179*550e691bSryan_chen 		 * This ignores dynamic/static slowdown of ARMCLK and may
180*550e691bSryan_chen 		 * be inaccurate.
181*550e691bSryan_chen 		 */
182*550e691bSryan_chen 		rate = aspeed_get_hpll_rate(priv);
183*550e691bSryan_chen 
184*550e691bSryan_chen 		break;
185*550e691bSryan_chen 	case MCLK_DDR:
186*550e691bSryan_chen 		rate = aspeed_get_mpll_rate(priv);
187*550e691bSryan_chen 		break;
188*550e691bSryan_chen 	case BCLK_PCLK:
189*550e691bSryan_chen 		{
190*550e691bSryan_chen 			ulong apb_div = 4 + 4 * ((readl(priv->regs + ASPEED_CLK_SELECT)
191*550e691bSryan_chen 						  & SCU_PCLK_DIV_MASK)
192*550e691bSryan_chen 						 >> SCU_PCLK_DIV_SHIFT);
193*550e691bSryan_chen 			rate = aspeed_get_hpll_rate(priv);
194*550e691bSryan_chen 			rate = rate / apb_div;
195*550e691bSryan_chen 		}
196*550e691bSryan_chen 		break;
197*550e691bSryan_chen 	case PCLK_UART1:
198*550e691bSryan_chen 		rate = aspeed_get_uart_clk_rate(priv, 1);
199*550e691bSryan_chen 		break;
200*550e691bSryan_chen 	case PCLK_UART2:
201*550e691bSryan_chen 		rate = aspeed_get_uart_clk_rate(priv, 2);
202*550e691bSryan_chen 		break;
203*550e691bSryan_chen 	case PCLK_UART3:
204*550e691bSryan_chen 		rate = aspeed_get_uart_clk_rate(priv, 3);
205*550e691bSryan_chen 		break;
206*550e691bSryan_chen 	case PCLK_UART4:
207*550e691bSryan_chen 		rate = aspeed_get_uart_clk_rate(priv, 4);
208*550e691bSryan_chen 		break;
209*550e691bSryan_chen 	case PCLK_UART5:
210*550e691bSryan_chen 		rate = aspeed_get_uart_clk_rate(priv, 5);
211*550e691bSryan_chen 		break;
212*550e691bSryan_chen 	default:
213*550e691bSryan_chen 		return -ENOENT;
214*550e691bSryan_chen 	}
215*550e691bSryan_chen 
216*550e691bSryan_chen 	return rate;
217*550e691bSryan_chen }
218*550e691bSryan_chen 
219*550e691bSryan_chen struct aspeed_clock_config {
220*550e691bSryan_chen 	ulong input_rate;
221*550e691bSryan_chen 	ulong rate;
222*550e691bSryan_chen 	struct aspeed_div_config cfg;
223*550e691bSryan_chen };
224*550e691bSryan_chen 
225*550e691bSryan_chen static const struct aspeed_clock_config aspeed_clock_config_defaults[] = {
226*550e691bSryan_chen 	{ 24000000, 250000000, { .num = 124, .denum = 1, .post_div = 5 } },
227*550e691bSryan_chen };
228*550e691bSryan_chen 
229*550e691bSryan_chen static bool aspeed_get_clock_config_default(ulong input_rate,
230*550e691bSryan_chen 					     ulong requested_rate,
231*550e691bSryan_chen 					     struct aspeed_div_config *cfg)
232*550e691bSryan_chen {
233*550e691bSryan_chen 	int i;
234*550e691bSryan_chen 
235*550e691bSryan_chen 	for (i = 0; i < ARRAY_SIZE(aspeed_clock_config_defaults); i++) {
236*550e691bSryan_chen 		const struct aspeed_clock_config *default_cfg =
237*550e691bSryan_chen 			&aspeed_clock_config_defaults[i];
238*550e691bSryan_chen 		if (default_cfg->input_rate == input_rate &&
239*550e691bSryan_chen 		    default_cfg->rate == requested_rate) {
240*550e691bSryan_chen 			*cfg = default_cfg->cfg;
241*550e691bSryan_chen 			return true;
242*550e691bSryan_chen 		}
243*550e691bSryan_chen 	}
244*550e691bSryan_chen 
245*550e691bSryan_chen 	return false;
246*550e691bSryan_chen }
247*550e691bSryan_chen 
248*550e691bSryan_chen /*
249*550e691bSryan_chen  * @input_rate - the rate of input clock in Hz
250*550e691bSryan_chen  * @requested_rate - desired output rate in Hz
251*550e691bSryan_chen  * @div - this is an IN/OUT parameter, at input all fields of the config
252*550e691bSryan_chen  * need to be set to their maximum allowed values.
253*550e691bSryan_chen  * The result (the best config we could find), would also be returned
254*550e691bSryan_chen  * in this structure.
255*550e691bSryan_chen  *
256*550e691bSryan_chen  * @return The clock rate, when the resulting div_config is used.
257*550e691bSryan_chen  */
258*550e691bSryan_chen static ulong aspeed_calc_clock_config(ulong input_rate, ulong requested_rate,
259*550e691bSryan_chen 				       struct aspeed_div_config *cfg)
260*550e691bSryan_chen {
261*550e691bSryan_chen 	/*
262*550e691bSryan_chen 	 * The assumption is that kHz precision is good enough and
263*550e691bSryan_chen 	 * also enough to avoid overflow when multiplying.
264*550e691bSryan_chen 	 */
265*550e691bSryan_chen 	const ulong input_rate_khz = input_rate / 1000;
266*550e691bSryan_chen 	const ulong rate_khz = requested_rate / 1000;
267*550e691bSryan_chen 	const struct aspeed_div_config max_vals = *cfg;
268*550e691bSryan_chen 	struct aspeed_div_config it = { 0, 0, 0 };
269*550e691bSryan_chen 	ulong delta = rate_khz;
270*550e691bSryan_chen 	ulong new_rate_khz = 0;
271*550e691bSryan_chen 
272*550e691bSryan_chen 	/*
273*550e691bSryan_chen 	 * Look for a well known frequency first.
274*550e691bSryan_chen 	 */
275*550e691bSryan_chen 	if (aspeed_get_clock_config_default(input_rate, requested_rate, cfg))
276*550e691bSryan_chen 		return requested_rate;
277*550e691bSryan_chen 
278*550e691bSryan_chen 	for (; it.denum <= max_vals.denum; ++it.denum) {
279*550e691bSryan_chen 		for (it.post_div = 0; it.post_div <= max_vals.post_div;
280*550e691bSryan_chen 		     ++it.post_div) {
281*550e691bSryan_chen 			it.num = (rate_khz * (it.post_div + 1) / input_rate_khz)
282*550e691bSryan_chen 			    * (it.denum + 1);
283*550e691bSryan_chen 			if (it.num > max_vals.num)
284*550e691bSryan_chen 				continue;
285*550e691bSryan_chen 
286*550e691bSryan_chen 			new_rate_khz = (input_rate_khz
287*550e691bSryan_chen 					* ((it.num + 1) / (it.denum + 1)))
288*550e691bSryan_chen 			    / (it.post_div + 1);
289*550e691bSryan_chen 
290*550e691bSryan_chen 			/* Keep the rate below requested one. */
291*550e691bSryan_chen 			if (new_rate_khz > rate_khz)
292*550e691bSryan_chen 				continue;
293*550e691bSryan_chen 
294*550e691bSryan_chen 			if (new_rate_khz - rate_khz < delta) {
295*550e691bSryan_chen 				delta = new_rate_khz - rate_khz;
296*550e691bSryan_chen 				*cfg = it;
297*550e691bSryan_chen 				if (delta == 0)
298*550e691bSryan_chen 					return new_rate_khz * 1000;
299*550e691bSryan_chen 			}
300*550e691bSryan_chen 		}
301*550e691bSryan_chen 	}
302*550e691bSryan_chen 
303*550e691bSryan_chen 	return new_rate_khz * 1000;
304*550e691bSryan_chen }
305*550e691bSryan_chen 
306*550e691bSryan_chen static u32 aspeed_configure_ddr(struct aspeed_clk_priv *priv, ulong rate)
307*550e691bSryan_chen {
308*550e691bSryan_chen 	u32 clkin = aspeed_get_clkin(priv);
309*550e691bSryan_chen 	u32 mpll_reg;
310*550e691bSryan_chen 	struct aspeed_div_config div_cfg = {
311*550e691bSryan_chen 		.num = (SCU_MPLL_NUM_MASK >> SCU_MPLL_NUM_SHIFT),
312*550e691bSryan_chen 		.denum = (SCU_MPLL_DENUM_MASK >> SCU_MPLL_DENUM_SHIFT),
313*550e691bSryan_chen 		.post_div = (SCU_MPLL_POST_MASK >> SCU_MPLL_POST_SHIFT),
314*550e691bSryan_chen 	};
315*550e691bSryan_chen 
316*550e691bSryan_chen 	aspeed_calc_clock_config(clkin, rate, &div_cfg);
317*550e691bSryan_chen 
318*550e691bSryan_chen 	mpll_reg = readl(priv->regs + ASPEED_MPLL_PARAMETER);
319*550e691bSryan_chen 	mpll_reg &= ~(SCU_MPLL_POST_MASK | SCU_MPLL_NUM_MASK
320*550e691bSryan_chen 		      | SCU_MPLL_DENUM_MASK);
321*550e691bSryan_chen 	mpll_reg |= (div_cfg.post_div << SCU_MPLL_POST_SHIFT)
322*550e691bSryan_chen 	    | (div_cfg.num << SCU_MPLL_NUM_SHIFT)
323*550e691bSryan_chen 	    | (div_cfg.denum << SCU_MPLL_DENUM_SHIFT);
324*550e691bSryan_chen 
325*550e691bSryan_chen 	writel(mpll_reg, priv->regs + ASPEED_MPLL_PARAMETER);
326*550e691bSryan_chen 
327*550e691bSryan_chen 	return aspeed_get_mpll_rate(priv);
328*550e691bSryan_chen }
329*550e691bSryan_chen 
330*550e691bSryan_chen static u32 aspeed_configure_mac(struct aspeed_clk_priv *priv, int index)
331*550e691bSryan_chen {
332*550e691bSryan_chen 	u32 clkin = aspeed_get_clkin(priv);
333*550e691bSryan_chen 	u32 hpll_rate = aspeed_get_hpll_rate(priv);
334*550e691bSryan_chen 	ulong required_rate;
335*550e691bSryan_chen 	u32 hwstrap;
336*550e691bSryan_chen 	u32 divisor;
337*550e691bSryan_chen 	u32 reset_bit;
338*550e691bSryan_chen 	u32 clkstop_bit;
339*550e691bSryan_chen #if 0
340*550e691bSryan_chen 	/*
341*550e691bSryan_chen 	 * According to data sheet, for 10/100 mode the MAC clock frequency
342*550e691bSryan_chen 	 * should be at least 25MHz and for 1000 mode at least 100MHz
343*550e691bSryan_chen 	 */
344*550e691bSryan_chen 	hwstrap = readl(priv->regs + ASPEED_STRAP);
345*550e691bSryan_chen 	if (hwstrap & (SCU_HWSTRAP_MAC1_RGMII | SCU_HWSTRAP_MAC2_RGMII))
346*550e691bSryan_chen 		required_rate = 100 * 1000 * 1000;
347*550e691bSryan_chen 	else
348*550e691bSryan_chen 		required_rate = 25 * 1000 * 1000;
349*550e691bSryan_chen 
350*550e691bSryan_chen 	divisor = hpll_rate / required_rate;
351*550e691bSryan_chen 
352*550e691bSryan_chen 	if (divisor < 4) {
353*550e691bSryan_chen 		/* Clock can't run fast enough, but let's try anyway */
354*550e691bSryan_chen 		debug("MAC clock too slow\n");
355*550e691bSryan_chen 		divisor = 4;
356*550e691bSryan_chen 	} else if (divisor > 16) {
357*550e691bSryan_chen 		/* Can't slow down the clock enough, but let's try anyway */
358*550e691bSryan_chen 		debug("MAC clock too fast\n");
359*550e691bSryan_chen 		divisor = 16;
360*550e691bSryan_chen 	}
361*550e691bSryan_chen 
362*550e691bSryan_chen 	switch (index) {
363*550e691bSryan_chen 	case 1:
364*550e691bSryan_chen 		reset_bit = SCU_SYSRESET_MAC1;
365*550e691bSryan_chen 		clkstop_bit = SCU_CLKSTOP_MAC1;
366*550e691bSryan_chen 		break;
367*550e691bSryan_chen 	case 2:
368*550e691bSryan_chen 		reset_bit = SCU_SYSRESET_MAC2;
369*550e691bSryan_chen 		clkstop_bit = SCU_CLKSTOP_MAC2;
370*550e691bSryan_chen 		break;
371*550e691bSryan_chen 	default:
372*550e691bSryan_chen 		return -EINVAL;
373*550e691bSryan_chen 	}
374*550e691bSryan_chen 
375*550e691bSryan_chen 	clrsetbits_le32(priv->regs + ASPEED_CLK_SELECT, SCU_MACCLK_MASK,
376*550e691bSryan_chen 			((divisor - 2) / 2) << SCU_MACCLK_SHIFT);
377*550e691bSryan_chen 
378*550e691bSryan_chen 	/*
379*550e691bSryan_chen 	 * Disable MAC, start its clock and re-enable it.
380*550e691bSryan_chen 	 * The procedure and the delays (100us & 10ms) are
381*550e691bSryan_chen 	 * specified in the datasheet.
382*550e691bSryan_chen 	 */
383*550e691bSryan_chen 	setbits_le32(&scu->sysreset_ctrl1, reset_bit);
384*550e691bSryan_chen 	udelay(100);
385*550e691bSryan_chen 	clrbits_le32(&scu->clk_stop_ctrl1, clkstop_bit);
386*550e691bSryan_chen 	mdelay(10);
387*550e691bSryan_chen 	clrbits_le32(&scu->sysreset_ctrl1, reset_bit);
388*550e691bSryan_chen 
389*550e691bSryan_chen 	writel((RGMII2_TXCK_DUTY << SCU_CLKDUTY_RGMII2TXCK_SHIFT)
390*550e691bSryan_chen 	       | (RGMII1_TXCK_DUTY << SCU_CLKDUTY_RGMII1TXCK_SHIFT),
391*550e691bSryan_chen 	       &scu->clk_duty_sel);
392*550e691bSryan_chen #endif
393*550e691bSryan_chen 	return required_rate;
394*550e691bSryan_chen }
395*550e691bSryan_chen 
396*550e691bSryan_chen static ulong aspeed_configure_d2pll(struct aspeed_clk_priv *priv, ulong rate)
397*550e691bSryan_chen {
398*550e691bSryan_chen 	/*
399*550e691bSryan_chen 	 * The values and the meaning of the next three
400*550e691bSryan_chen 	 * parameters are undocumented. Taken from Aspeed SDK.
401*550e691bSryan_chen 	 *
402*550e691bSryan_chen 	 * TODO(clg@kaod.org): the SIP and SIC values depend on the
403*550e691bSryan_chen 	 * Numerator value
404*550e691bSryan_chen 	 */
405*550e691bSryan_chen 
406*550e691bSryan_chen 	const u32 d2_pll_ext_param = 0x2c;
407*550e691bSryan_chen 	const u32 d2_pll_sip = 0x11;
408*550e691bSryan_chen 	const u32 d2_pll_sic = 0x18;
409*550e691bSryan_chen 	u32 clk_delay_settings =
410*550e691bSryan_chen 	    (RMII_RXCLK_IDLY << SCU_MICDS_MAC1RMII_RDLY_SHIFT)
411*550e691bSryan_chen 	    | (RMII_RXCLK_IDLY << SCU_MICDS_MAC2RMII_RDLY_SHIFT)
412*550e691bSryan_chen 	    | (RGMII_TXCLK_ODLY << SCU_MICDS_MAC1RGMII_TXDLY_SHIFT)
413*550e691bSryan_chen 	    | (RGMII_TXCLK_ODLY << SCU_MICDS_MAC2RGMII_TXDLY_SHIFT);
414*550e691bSryan_chen 	struct aspeed_div_config div_cfg = {
415*550e691bSryan_chen 		.num = SCU_D2PLL_NUM_MASK >> SCU_D2PLL_NUM_SHIFT,
416*550e691bSryan_chen 		.denum = SCU_D2PLL_DENUM_MASK >> SCU_D2PLL_DENUM_SHIFT,
417*550e691bSryan_chen 		.post_div = SCU_D2PLL_POST_MASK >> SCU_D2PLL_POST_SHIFT,
418*550e691bSryan_chen 	};
419*550e691bSryan_chen 	ulong clkin = aspeed_get_clkin(priv);
420*550e691bSryan_chen 	ulong new_rate;
421*550e691bSryan_chen #if 0
422*550e691bSryan_chen 	writel((d2_pll_ext_param << SCU_D2PLL_EXT1_PARAM_SHIFT)
423*550e691bSryan_chen 	       | SCU_D2PLL_EXT1_OFF
424*550e691bSryan_chen 	       | SCU_D2PLL_EXT1_RESET, &scu->d2_pll_ext_param[0]);
425*550e691bSryan_chen 
426*550e691bSryan_chen 	/*
427*550e691bSryan_chen 	 * Select USB2.0 port1 PHY clock as a clock source for GCRT.
428*550e691bSryan_chen 	 * This would disconnect it from D2-PLL.
429*550e691bSryan_chen 	 */
430*550e691bSryan_chen 	clrsetbits_le32(&scu->misc_ctrl1, SCU_MISC_D2PLL_OFF,
431*550e691bSryan_chen 			SCU_MISC_GCRT_USB20CLK);
432*550e691bSryan_chen 
433*550e691bSryan_chen 	new_rate = aspeed_calc_clock_config(clkin, rate, &div_cfg);
434*550e691bSryan_chen 	writel((d2_pll_sip << SCU_D2PLL_SIP_SHIFT)
435*550e691bSryan_chen 	       | (d2_pll_sic << SCU_D2PLL_SIC_SHIFT)
436*550e691bSryan_chen 	       | (div_cfg.num << SCU_D2PLL_NUM_SHIFT)
437*550e691bSryan_chen 	       | (div_cfg.denum << SCU_D2PLL_DENUM_SHIFT)
438*550e691bSryan_chen 	       | (div_cfg.post_div << SCU_D2PLL_POST_SHIFT),
439*550e691bSryan_chen 	       &scu->d2_pll_param);
440*550e691bSryan_chen 
441*550e691bSryan_chen 	clrbits_le32(&scu->d2_pll_ext_param[0],
442*550e691bSryan_chen 		     SCU_D2PLL_EXT1_OFF | SCU_D2PLL_EXT1_RESET);
443*550e691bSryan_chen 
444*550e691bSryan_chen 	clrsetbits_le32(&scu->misc_ctrl2,
445*550e691bSryan_chen 			SCU_MISC2_RGMII_HPLL | SCU_MISC2_RMII_MPLL
446*550e691bSryan_chen 			| SCU_MISC2_RGMII_CLKDIV_MASK |
447*550e691bSryan_chen 			SCU_MISC2_RMII_CLKDIV_MASK,
448*550e691bSryan_chen 			(4 << SCU_MISC2_RMII_CLKDIV_SHIFT));
449*550e691bSryan_chen 
450*550e691bSryan_chen 	writel(clk_delay_settings | SCU_MICDS_RGMIIPLL, &scu->mac_clk_delay);
451*550e691bSryan_chen 	writel(clk_delay_settings, &scu->mac_clk_delay_100M);
452*550e691bSryan_chen 	writel(clk_delay_settings, &scu->mac_clk_delay_10M);
453*550e691bSryan_chen #endif
454*550e691bSryan_chen 	return new_rate;
455*550e691bSryan_chen }
456*550e691bSryan_chen 
457*550e691bSryan_chen static ulong aspeed_clk_set_rate(struct clk *clk, ulong rate)
458*550e691bSryan_chen {
459*550e691bSryan_chen 	struct aspeed_clk_priv *priv = dev_get_priv(clk->dev);
460*550e691bSryan_chen 
461*550e691bSryan_chen 	ulong new_rate;
462*550e691bSryan_chen 	switch (clk->id) {
463*550e691bSryan_chen 	case PLL_MPLL:
464*550e691bSryan_chen 	case MCLK_DDR:
465*550e691bSryan_chen 		new_rate = aspeed_configure_ddr(priv, rate);
466*550e691bSryan_chen 		break;
467*550e691bSryan_chen 	case PLL_D2PLL:
468*550e691bSryan_chen 		new_rate = aspeed_configure_d2pll(priv, rate);
469*550e691bSryan_chen 		break;
470*550e691bSryan_chen 	default:
471*550e691bSryan_chen 		return -ENOENT;
472*550e691bSryan_chen 	}
473*550e691bSryan_chen 
474*550e691bSryan_chen 	return new_rate;
475*550e691bSryan_chen }
476*550e691bSryan_chen 
477*550e691bSryan_chen static int aspeed_clk_enable(struct clk *clk)
478*550e691bSryan_chen {
479*550e691bSryan_chen 	struct aspeed_clk_priv *priv = dev_get_priv(clk->dev);
480*550e691bSryan_chen 
481*550e691bSryan_chen 	switch (clk->id) {
482*550e691bSryan_chen 	/*
483*550e691bSryan_chen 	 * For MAC clocks the clock rate is
484*550e691bSryan_chen 	 * configured based on whether RGMII or RMII mode has been selected
485*550e691bSryan_chen 	 * through hardware strapping.
486*550e691bSryan_chen 	 */
487*550e691bSryan_chen 	case PCLK_MAC1:
488*550e691bSryan_chen 		aspeed_configure_mac(priv, 1);
489*550e691bSryan_chen 		break;
490*550e691bSryan_chen 	case PCLK_MAC2:
491*550e691bSryan_chen 		aspeed_configure_mac(priv, 2);
492*550e691bSryan_chen 		break;
493*550e691bSryan_chen 	case PLL_D2PLL:
494*550e691bSryan_chen 		aspeed_configure_d2pll(priv, D2PLL_DEFAULT_RATE);
495*550e691bSryan_chen 		break;
496*550e691bSryan_chen 	default:
497*550e691bSryan_chen 		return -ENOENT;
498*550e691bSryan_chen 	}
499*550e691bSryan_chen 
500*550e691bSryan_chen 	return 0;
501*550e691bSryan_chen }
502*550e691bSryan_chen 
503*550e691bSryan_chen struct clk_ops aspeed_clk_ops = {
504*550e691bSryan_chen 	.get_rate = aspeed_clk_get_rate,
505*550e691bSryan_chen 	.set_rate = aspeed_clk_set_rate,
506*550e691bSryan_chen 	.enable = aspeed_clk_enable,
507*550e691bSryan_chen };
508*550e691bSryan_chen 
509*550e691bSryan_chen static int aspeed_clk_probe(struct udevice *dev)
510*550e691bSryan_chen {
511*550e691bSryan_chen 	struct aspeed_clk_priv *priv = dev_get_priv(dev);
512*550e691bSryan_chen 
513*550e691bSryan_chen 	priv->regs = devfdt_get_addr_ptr(dev);
514*550e691bSryan_chen 
515*550e691bSryan_chen 	if (IS_ERR(priv->regs))
516*550e691bSryan_chen 		return PTR_ERR(priv->regs);
517*550e691bSryan_chen 
518*550e691bSryan_chen 	priv->version = dev_get_driver_data(dev);
519*550e691bSryan_chen 
520*550e691bSryan_chen 	return 0;
521*550e691bSryan_chen }
522*550e691bSryan_chen 
523*550e691bSryan_chen static int aspeed_clk_bind(struct udevice *dev)
524*550e691bSryan_chen {
525*550e691bSryan_chen 	int ret;
526*550e691bSryan_chen 
527*550e691bSryan_chen 	/* The reset driver does not have a device node, so bind it here */
528*550e691bSryan_chen 	ret = device_bind_driver(gd->dm_root, "ast_sysreset", "reset", &dev);
529*550e691bSryan_chen 	if (ret)
530*550e691bSryan_chen 		debug("Warning: No reset driver: ret=%d\n", ret);
531*550e691bSryan_chen 
532*550e691bSryan_chen 	return 0;
533*550e691bSryan_chen }
534*550e691bSryan_chen 
535*550e691bSryan_chen static const struct udevice_id aspeed_clk_ids[] = {
536*550e691bSryan_chen 	{ .compatible = "aspeed,ast2500-scu", .data = AST2500},
537*550e691bSryan_chen 	{ .compatible = "aspeed,ast2600-scu", .data = AST2600},
538*550e691bSryan_chen 	{ }
539*550e691bSryan_chen };
540*550e691bSryan_chen 
541*550e691bSryan_chen U_BOOT_DRIVER(aspeed_scu) = {
542*550e691bSryan_chen 	.name		= "aspeed_scu",
543*550e691bSryan_chen 	.id		= UCLASS_CLK,
544*550e691bSryan_chen 	.of_match	= aspeed_clk_ids,
545*550e691bSryan_chen 	.priv_auto_alloc_size = sizeof(struct aspeed_clk_priv),
546*550e691bSryan_chen 	.ops		= &aspeed_clk_ops,
547*550e691bSryan_chen 	.bind		= aspeed_clk_bind,
548*550e691bSryan_chen 	.probe		= aspeed_clk_probe,
549*550e691bSryan_chen };
550