1 /*
2  * (C) Copyright 2016 Google, Inc
3  *
4  * SPDX-License-Identifier:	GPL-2.0
5  */
6 
7 #include <common.h>
8 #include <clk-uclass.h>
9 #include <dm.h>
10 #include <asm/io.h>
11 #include <asm/arch/scu_ast2500.h>
12 #include <dm/lists.h>
13 #include <dt-bindings/clock/ast2500-scu.h>
14 
15 DECLARE_GLOBAL_DATA_PTR;
16 
17 /*
18  * For H-PLL and M-PLL the formula is
19  * (Output Frequency) = CLKIN * ((M + 1) / (N + 1)) / (P + 1)
20  * M - Numerator
21  * N - Denumerator
22  * P - Post Divider
23  * They have the same layout in their control register.
24  */
25 
26 /*
27  * Get the rate of the M-PLL clock from input clock frequency and
28  * the value of the M-PLL Parameter Register.
29  */
30 static ulong ast2500_get_mpll_rate(ulong clkin, u32 mpll_reg)
31 {
32 	const ulong num = (mpll_reg >> SCU_MPLL_NUM_SHIFT) & SCU_MPLL_NUM_MASK;
33 	const ulong denum = (mpll_reg >> SCU_MPLL_DENUM_SHIFT)
34 			& SCU_MPLL_DENUM_MASK;
35 	const ulong post_div = (mpll_reg >> SCU_MPLL_POST_SHIFT)
36 			& SCU_MPLL_POST_MASK;
37 
38 	return (clkin * ((num + 1) / (denum + 1))) / (post_div + 1);
39 }
40 
41 /*
42  * Get the rate of the H-PLL clock from input clock frequency and
43  * the value of the H-PLL Parameter Register.
44  */
45 static ulong ast2500_get_hpll_rate(ulong clkin, u32 hpll_reg)
46 {
47 	const ulong num = (hpll_reg >> SCU_HPLL_NUM_SHIFT) & SCU_HPLL_NUM_MASK;
48 	const ulong denum = (hpll_reg >> SCU_HPLL_DENUM_SHIFT)
49 			& SCU_HPLL_DENUM_MASK;
50 	const ulong post_div = (hpll_reg >> SCU_HPLL_POST_SHIFT)
51 			& SCU_HPLL_POST_MASK;
52 
53 	return (clkin * ((num + 1) / (denum + 1))) / (post_div + 1);
54 }
55 
56 static ulong ast2500_get_clkin(struct ast2500_scu *scu)
57 {
58 	return readl(&scu->hwstrap) & SCU_HWSTRAP_CLKIN_25MHZ
59 			? 25 * 1000 * 1000 : 24 * 1000 * 1000;
60 }
61 
62 /**
63  * Get current rate or uart clock
64  *
65  * @scu SCU registers
66  * @uart_index UART index, 1-5
67  *
68  * @return current setting for uart clock rate
69  */
70 static ulong ast2500_get_uart_clk_rate(struct ast2500_scu *scu, int uart_index)
71 {
72 	/*
73 	 * ast2500 datasheet is very confusing when it comes to UART clocks,
74 	 * especially when CLKIN = 25 MHz. The settings are in
75 	 * different registers and it is unclear how they interact.
76 	 *
77 	 * This has only been tested with default settings and CLKIN = 24 MHz.
78 	 */
79 	ulong uart_clkin;
80 
81 	if (readl(&scu->misc_ctrl2) &
82 	    (1 << (uart_index - 1 + SCU_MISC2_UARTCLK_SHIFT)))
83 		uart_clkin = 192 * 1000 * 1000;
84 	else
85 		uart_clkin = 24 * 1000 * 1000;
86 
87 	if (readl(&scu->misc_ctrl1) & SCU_MISC_UARTCLK_DIV13)
88 		uart_clkin /= 13;
89 
90 	return uart_clkin;
91 }
92 
93 static ulong ast2500_clk_get_rate(struct clk *clk)
94 {
95 	struct ast2500_clk_priv *priv = dev_get_priv(clk->dev);
96 	ulong clkin = ast2500_get_clkin(priv->scu);
97 	ulong rate;
98 
99 	switch (clk->id) {
100 	case PLL_HPLL:
101 	case ARMCLK:
102 		/*
103 		 * This ignores dynamic/static slowdown of ARMCLK and may
104 		 * be inaccurate.
105 		 */
106 		rate = ast2500_get_hpll_rate(clkin,
107 					     readl(&priv->scu->h_pll_param));
108 		break;
109 	case MCLK_DDR:
110 		rate = ast2500_get_mpll_rate(clkin,
111 					     readl(&priv->scu->m_pll_param));
112 		break;
113 	case PCLK_UART1:
114 		rate = ast2500_get_uart_clk_rate(priv->scu, 1);
115 		break;
116 	case PCLK_UART2:
117 		rate = ast2500_get_uart_clk_rate(priv->scu, 2);
118 		break;
119 	case PCLK_UART3:
120 		rate = ast2500_get_uart_clk_rate(priv->scu, 3);
121 		break;
122 	case PCLK_UART4:
123 		rate = ast2500_get_uart_clk_rate(priv->scu, 4);
124 		break;
125 	case PCLK_UART5:
126 		rate = ast2500_get_uart_clk_rate(priv->scu, 5);
127 		break;
128 	default:
129 		return -ENOENT;
130 	}
131 
132 	return rate;
133 }
134 
135 static void ast2500_scu_unlock(struct ast2500_scu *scu)
136 {
137 	writel(SCU_UNLOCK_VALUE, &scu->protection_key);
138 	while (!readl(&scu->protection_key))
139 		;
140 }
141 
142 static void ast2500_scu_lock(struct ast2500_scu *scu)
143 {
144 	writel(~SCU_UNLOCK_VALUE, &scu->protection_key);
145 	while (readl(&scu->protection_key))
146 		;
147 }
148 
149 static ulong ast2500_configure_ddr(struct ast2500_scu *scu, ulong rate)
150 {
151 	ulong clkin = ast2500_get_clkin(scu);
152 	u32 mpll_reg;
153 
154 	/*
155 	 * There are not that many combinations of numerator, denumerator
156 	 * and post divider, so just brute force the best combination.
157 	 * However, to avoid overflow when multiplying, use kHz.
158 	 */
159 	const ulong clkin_khz = clkin / 1000;
160 	const ulong rate_khz = rate / 1000;
161 	ulong best_num = 0;
162 	ulong best_denum = 0;
163 	ulong best_post = 0;
164 	ulong delta = rate;
165 	ulong num, denum, post;
166 
167 	for (denum = 0; denum <= SCU_MPLL_DENUM_MASK; ++denum) {
168 		for (post = 0; post <= SCU_MPLL_POST_MASK; ++post) {
169 			num = (rate_khz * (post + 1) / clkin_khz) * (denum + 1);
170 			ulong new_rate_khz = (clkin_khz
171 					      * ((num + 1) / (denum + 1)))
172 					     / (post + 1);
173 
174 			/* Keep the rate below requested one. */
175 			if (new_rate_khz > rate_khz)
176 				continue;
177 
178 			if (new_rate_khz - rate_khz < delta) {
179 				delta = new_rate_khz - rate_khz;
180 
181 				best_num = num;
182 				best_denum = denum;
183 				best_post = post;
184 
185 				if (delta == 0)
186 					goto rate_calc_done;
187 			}
188 		}
189 	}
190 
191  rate_calc_done:
192 	mpll_reg = readl(&scu->m_pll_param);
193 	mpll_reg &= ~((SCU_MPLL_POST_MASK << SCU_MPLL_POST_SHIFT)
194 		      | (SCU_MPLL_NUM_MASK << SCU_MPLL_NUM_SHIFT)
195 		      | (SCU_MPLL_DENUM_MASK << SCU_MPLL_DENUM_SHIFT));
196 	mpll_reg |= (best_post << SCU_MPLL_POST_SHIFT)
197 	    | (best_num << SCU_MPLL_NUM_SHIFT)
198 	    | (best_denum << SCU_MPLL_DENUM_SHIFT);
199 
200 	ast2500_scu_unlock(scu);
201 	writel(mpll_reg, &scu->m_pll_param);
202 	ast2500_scu_lock(scu);
203 
204 	return ast2500_get_mpll_rate(clkin, mpll_reg);
205 }
206 
207 static ulong ast2500_clk_set_rate(struct clk *clk, ulong rate)
208 {
209 	struct ast2500_clk_priv *priv = dev_get_priv(clk->dev);
210 
211 	ulong new_rate;
212 	switch (clk->id) {
213 	case PLL_MPLL:
214 	case MCLK_DDR:
215 		new_rate = ast2500_configure_ddr(priv->scu, rate);
216 		break;
217 	default:
218 		return -ENOENT;
219 	}
220 
221 	return new_rate;
222 }
223 
224 struct clk_ops ast2500_clk_ops = {
225 	.get_rate = ast2500_clk_get_rate,
226 	.set_rate = ast2500_clk_set_rate,
227 };
228 
229 static int ast2500_clk_probe(struct udevice *dev)
230 {
231 	struct ast2500_clk_priv *priv = dev_get_priv(dev);
232 
233 	priv->scu = dev_get_addr_ptr(dev);
234 	if (IS_ERR(priv->scu))
235 		return PTR_ERR(priv->scu);
236 
237 	return 0;
238 }
239 
240 static int ast2500_clk_bind(struct udevice *dev)
241 {
242 	int ret;
243 
244 	/* The reset driver does not have a device node, so bind it here */
245 	ret = device_bind_driver(gd->dm_root, "ast_sysreset", "reset", &dev);
246 	if (ret)
247 		debug("Warning: No reset driver: ret=%d\n", ret);
248 
249 	return 0;
250 }
251 
252 static const struct udevice_id ast2500_clk_ids[] = {
253 	{ .compatible = "aspeed,ast2500-scu" },
254 	{ }
255 };
256 
257 U_BOOT_DRIVER(aspeed_ast2500_scu) = {
258 	.name		= "aspeed_ast2500_scu",
259 	.id		= UCLASS_CLK,
260 	.of_match	= ast2500_clk_ids,
261 	.priv_auto_alloc_size = sizeof(struct ast2500_clk_priv),
262 	.ops		= &ast2500_clk_ops,
263 	.bind		= ast2500_clk_bind,
264 	.probe		= ast2500_clk_probe,
265 };
266