1550e691bSryan_chen // SPDX-License-Identifier: GPL-2.0
2550e691bSryan_chen /*
37c51833cSryan_chen * (C) Copyright 2016 Google, Inc
4d1e64dd1Sryan_chen *
5d1e64dd1Sryan_chen * Copyright (C) ASPEED Technology Inc.
6d1e64dd1Sryan_chen *
7550e691bSryan_chen */
8550e691bSryan_chen
9550e691bSryan_chen #include <common.h>
10550e691bSryan_chen #include <clk-uclass.h>
11550e691bSryan_chen #include <dm.h>
12550e691bSryan_chen #include <asm/io.h>
13550e691bSryan_chen #include <dm/lists.h>
1439283ea7Sryan_chen #include <asm/arch/scu_ast2500.h>
153f781edcSryan_chen #include <dt-bindings/clock/ast2500-clock.h>
1639283ea7Sryan_chen #include <dt-bindings/reset/ast2500-reset.h>
17550e691bSryan_chen
18550e691bSryan_chen /*
19550e691bSryan_chen * MAC Clock Delay settings, taken from Aspeed SDK
20550e691bSryan_chen */
21550e691bSryan_chen #define RGMII_TXCLK_ODLY 8
22550e691bSryan_chen #define RMII_RXCLK_IDLY 2
23550e691bSryan_chen
24550e691bSryan_chen /*
25550e691bSryan_chen * TGMII Clock Duty constants, taken from Aspeed SDK
26550e691bSryan_chen */
27550e691bSryan_chen #define RGMII2_TXCK_DUTY 0x66
28550e691bSryan_chen #define RGMII1_TXCK_DUTY 0x64
29550e691bSryan_chen
30550e691bSryan_chen #define D2PLL_DEFAULT_RATE (250 * 1000 * 1000)
31550e691bSryan_chen
32550e691bSryan_chen DECLARE_GLOBAL_DATA_PTR;
33550e691bSryan_chen
34550e691bSryan_chen /*
35550e691bSryan_chen * Clock divider/multiplier configuration struct.
36550e691bSryan_chen * For H-PLL and M-PLL the formula is
37550e691bSryan_chen * (Output Frequency) = CLKIN * ((M + 1) / (N + 1)) / (P + 1)
38550e691bSryan_chen * M - Numerator
39550e691bSryan_chen * N - Denumerator
40550e691bSryan_chen * P - Post Divider
41550e691bSryan_chen * They have the same layout in their control register.
42550e691bSryan_chen *
43550e691bSryan_chen * D-PLL and D2-PLL have extra divider (OD + 1), which is not
44550e691bSryan_chen * yet needed and ignored by clock configurations.
45550e691bSryan_chen */
467c51833cSryan_chen struct ast2500_div_config {
47550e691bSryan_chen unsigned int num;
48550e691bSryan_chen unsigned int denum;
49550e691bSryan_chen unsigned int post_div;
50550e691bSryan_chen };
51550e691bSryan_chen
ast2500_get_clkin(struct ast2500_scu * scu)524f22e838Sryan_chen extern u32 ast2500_get_clkin(struct ast2500_scu *scu)
5339283ea7Sryan_chen {
5439283ea7Sryan_chen return readl(&scu->hwstrap) & SCU_HWSTRAP_CLKIN_25MHZ
5539283ea7Sryan_chen ? 25 * 1000 * 1000 : 24 * 1000 * 1000;
5639283ea7Sryan_chen }
5739283ea7Sryan_chen
58550e691bSryan_chen /*
59550e691bSryan_chen * Get the rate of the M-PLL clock from input clock frequency and
60550e691bSryan_chen * the value of the M-PLL Parameter Register.
61550e691bSryan_chen */
ast2500_get_mpll_rate(struct ast2500_scu * scu)624f22e838Sryan_chen extern u32 ast2500_get_mpll_rate(struct ast2500_scu *scu)
63550e691bSryan_chen {
6439283ea7Sryan_chen u32 clkin = ast2500_get_clkin(scu);
6539283ea7Sryan_chen u32 mpll_reg = readl(&scu->m_pll_param);
6639283ea7Sryan_chen
67550e691bSryan_chen const ulong num = (mpll_reg & SCU_MPLL_NUM_MASK) >> SCU_MPLL_NUM_SHIFT;
68550e691bSryan_chen const ulong denum = (mpll_reg & SCU_MPLL_DENUM_MASK)
69550e691bSryan_chen >> SCU_MPLL_DENUM_SHIFT;
70550e691bSryan_chen const ulong post_div = (mpll_reg & SCU_MPLL_POST_MASK)
71550e691bSryan_chen >> SCU_MPLL_POST_SHIFT;
72550e691bSryan_chen
73550e691bSryan_chen return (clkin * ((num + 1) / (denum + 1))) / (post_div + 1);
74550e691bSryan_chen }
75550e691bSryan_chen
76550e691bSryan_chen /*
77550e691bSryan_chen * Get the rate of the H-PLL clock from input clock frequency and
78550e691bSryan_chen * the value of the H-PLL Parameter Register.
79550e691bSryan_chen */
ast2500_get_hpll_rate(struct ast2500_scu * scu)804f22e838Sryan_chen extern u32 ast2500_get_hpll_rate(struct ast2500_scu *scu)
81550e691bSryan_chen {
8239283ea7Sryan_chen u32 clkin = ast2500_get_clkin(scu);
8339283ea7Sryan_chen u32 hpll_reg = readl(&scu->h_pll_param);
8439283ea7Sryan_chen
85d1e64dd1Sryan_chen /* F = clkin * [(M+1) / (N+1)] / (P + 1) */
86550e691bSryan_chen const ulong num = (hpll_reg & SCU_HPLL_NUM_MASK) >> SCU_HPLL_NUM_SHIFT;
87550e691bSryan_chen const ulong denum = (hpll_reg & SCU_HPLL_DENUM_MASK)
88550e691bSryan_chen >> SCU_HPLL_DENUM_SHIFT;
89550e691bSryan_chen const ulong post_div = (hpll_reg & SCU_HPLL_POST_MASK)
90550e691bSryan_chen >> SCU_HPLL_POST_SHIFT;
91550e691bSryan_chen
92550e691bSryan_chen return (clkin * ((num + 1) / (denum + 1))) / (post_div + 1);
93550e691bSryan_chen }
94550e691bSryan_chen
9539283ea7Sryan_chen /*
9639283ea7Sryan_chen * Get the rate of the D-PLL clock from input clock frequency and
9739283ea7Sryan_chen * the value of the D-PLL Parameter Register.
9839283ea7Sryan_chen */
ast2500_get_dpll_rate(struct ast2500_scu * scu)994f22e838Sryan_chen extern u32 ast2500_get_dpll_rate(struct ast2500_scu *scu)
1007c51833cSryan_chen {
10139283ea7Sryan_chen u32 clkin = ast2500_get_clkin(scu);
10239283ea7Sryan_chen u32 dpll_reg = readl(&scu->d_pll_param);
10339283ea7Sryan_chen
10439283ea7Sryan_chen /* F = clkin * [(M+1) / (N+1)] / (P + 1)/ (od + 1) */
10539283ea7Sryan_chen const ulong num = (dpll_reg & 0xff);
10639283ea7Sryan_chen const ulong denum = (dpll_reg >> 8) & 0x1f;
10739283ea7Sryan_chen const ulong post_div = (dpll_reg >> 13) & 0x3f;
10839283ea7Sryan_chen const ulong od_div = (dpll_reg >> 19) & 0x7;
10939283ea7Sryan_chen return (((clkin * ((num + 1) / (denum + 1))) / (post_div + 1))/ (od_div + 1));
11039283ea7Sryan_chen }
11139283ea7Sryan_chen
11239283ea7Sryan_chen /*
11339283ea7Sryan_chen * Get the rate of the D2-PLL clock from input clock frequency and
11439283ea7Sryan_chen * the value of the D2-PLL Parameter Register.
11539283ea7Sryan_chen */
ast2500_get_d2pll_rate(struct ast2500_scu * scu)1164f22e838Sryan_chen extern u32 ast2500_get_d2pll_rate(struct ast2500_scu *scu)
11739283ea7Sryan_chen {
11839283ea7Sryan_chen u32 clkin = ast2500_get_clkin(scu);
11939283ea7Sryan_chen u32 d2pll_reg = readl(&scu->d2_pll_param);
12039283ea7Sryan_chen
12139283ea7Sryan_chen /* F = clkin * [(M+1) / (N+1)] / (P + 1)/ (od + 1) */
12239283ea7Sryan_chen const ulong num = (d2pll_reg & 0xff);
12339283ea7Sryan_chen const ulong denum = (d2pll_reg >> 8) & 0x1f;
12439283ea7Sryan_chen const ulong post_div = (d2pll_reg >> 13) & 0x3f;
12539283ea7Sryan_chen const ulong od_div = (d2pll_reg >> 19) & 0x7 ;
12639283ea7Sryan_chen
12739283ea7Sryan_chen return (((clkin * ((num + 1) / (denum + 1))) / (post_div + 1))/ (od_div + 1));
1287c51833cSryan_chen }
129550e691bSryan_chen
130d812df15Sryan_chen #define SCU_HWSTRAP_AXIAHB_DIV_SHIFT 9
131d812df15Sryan_chen #define SCU_HWSTRAP_AXIAHB_DIV_MASK (0x7 << SCU_HWSTRAP_AXIAHB_DIV_SHIFT)
132d812df15Sryan_chen
ast2500_get_hclk(struct ast2500_scu * scu)133d812df15Sryan_chen static u32 ast2500_get_hclk(struct ast2500_scu *scu)
134d812df15Sryan_chen {
135d812df15Sryan_chen ulong ahb_div = 1 + ((readl(&scu->hwstrap)
136d812df15Sryan_chen & SCU_HWSTRAP_AXIAHB_DIV_MASK)
137d812df15Sryan_chen >> SCU_HWSTRAP_AXIAHB_DIV_SHIFT);
138d812df15Sryan_chen
139d812df15Sryan_chen ulong axi_div = 2;
140d812df15Sryan_chen u32 rate = 0;
141d812df15Sryan_chen
142d812df15Sryan_chen rate = ast2500_get_hpll_rate(scu);
143d812df15Sryan_chen return (rate / axi_div / ahb_div);
144d812df15Sryan_chen }
145d812df15Sryan_chen
ast2500_get_pclk(struct ast2500_scu * scu)1462717883aSryan_chen static u32 ast2500_get_pclk(struct ast2500_scu *scu)
1472717883aSryan_chen {
1482717883aSryan_chen u32 rate = 0;
1492717883aSryan_chen ulong apb_div = 4 + 4 * ((readl(&scu->clk_sel1)
1502717883aSryan_chen & SCU_PCLK_DIV_MASK)
1512717883aSryan_chen >> SCU_PCLK_DIV_SHIFT);
1522717883aSryan_chen rate = ast2500_get_hpll_rate(scu);
1532717883aSryan_chen
1542717883aSryan_chen return (rate / apb_div);
1552717883aSryan_chen }
156d812df15Sryan_chen
ast2500_get_sdio_clk_rate(struct ast2500_scu * scu)157d812df15Sryan_chen static u32 ast2500_get_sdio_clk_rate(struct ast2500_scu *scu)
158d812df15Sryan_chen {
159d812df15Sryan_chen u32 clkin = ast2500_get_hpll_rate(scu);
160d812df15Sryan_chen u32 clk_sel = readl(&scu->clk_sel1);
161d812df15Sryan_chen u32 div = (clk_sel >> 12) & 0x7;
162d812df15Sryan_chen
163d812df15Sryan_chen div = (div + 1) << 2;
164d812df15Sryan_chen
165d812df15Sryan_chen return (clkin / div);
166d812df15Sryan_chen }
167d812df15Sryan_chen
ast2500_get_uart_clk_rate(struct ast2500_scu * scu,int uart_idx)16881ffab47Sryan_chen static u32 ast2500_get_uart_clk_rate(struct ast2500_scu *scu, int uart_idx)
169550e691bSryan_chen {
170550e691bSryan_chen /*
1717c51833cSryan_chen * ast2500 datasheet is very confusing when it comes to UART clocks,
172550e691bSryan_chen * especially when CLKIN = 25 MHz. The settings are in
173550e691bSryan_chen * different registers and it is unclear how they interact.
174550e691bSryan_chen *
175550e691bSryan_chen * This has only been tested with default settings and CLKIN = 24 MHz.
176550e691bSryan_chen */
17739283ea7Sryan_chen u32 uart_clkin;
178550e691bSryan_chen
1797c51833cSryan_chen if (readl(&scu->misc_ctrl2) &
1804ff289bdSryan_chen (1 << (uart_idx - 1 + SCU_MISC2_UARTCLK_SHIFT)))
181550e691bSryan_chen uart_clkin = 192 * 1000 * 1000;
182550e691bSryan_chen else
183550e691bSryan_chen uart_clkin = 24 * 1000 * 1000;
184550e691bSryan_chen
1857c51833cSryan_chen if (readl(&scu->misc_ctrl1) & SCU_MISC_UARTCLK_DIV13)
186550e691bSryan_chen uart_clkin /= 13;
187550e691bSryan_chen
188550e691bSryan_chen return uart_clkin;
189550e691bSryan_chen }
190550e691bSryan_chen
ast2500_clk_get_rate(struct clk * clk)191d812df15Sryan_chen static ulong ast2500_clk_get_rate(struct clk *clk)
192550e691bSryan_chen {
1937c51833cSryan_chen struct ast2500_clk_priv *priv = dev_get_priv(clk->dev);
194550e691bSryan_chen ulong rate;
195550e691bSryan_chen
196550e691bSryan_chen switch (clk->id) {
197d1e64dd1Sryan_chen case ASPEED_CLK_HPLL:
19839283ea7Sryan_chen rate = ast2500_get_hpll_rate(priv->scu);
199d1e64dd1Sryan_chen break;
200f0d895afSryan_chen case ASPEED_CLK_MPLL:
20139283ea7Sryan_chen rate = ast2500_get_mpll_rate(priv->scu);
202550e691bSryan_chen break;
203d35ac78cSryan_chen case ASPEED_CLK_DPLL:
204d35ac78cSryan_chen rate = ast2500_get_dpll_rate(priv->scu);
205d35ac78cSryan_chen break;
206d35ac78cSryan_chen case ASPEED_CLK_D2PLL:
207d35ac78cSryan_chen rate = ast2500_get_d2pll_rate(priv->scu);
208d35ac78cSryan_chen break;
209d812df15Sryan_chen case ASPEED_CLK_AHB:
210d812df15Sryan_chen rate = ast2500_get_hclk(priv->scu);
211d812df15Sryan_chen break;
21239283ea7Sryan_chen case ASPEED_CLK_APB:
2132717883aSryan_chen rate = ast2500_get_pclk(priv->scu);
214550e691bSryan_chen break;
21599357bacSryan_chen case ASPEED_CLK_GATE_UART1CLK:
2167c51833cSryan_chen rate = ast2500_get_uart_clk_rate(priv->scu, 1);
217550e691bSryan_chen break;
21899357bacSryan_chen case ASPEED_CLK_GATE_UART2CLK:
2197c51833cSryan_chen rate = ast2500_get_uart_clk_rate(priv->scu, 2);
220550e691bSryan_chen break;
22199357bacSryan_chen case ASPEED_CLK_GATE_UART3CLK:
2227c51833cSryan_chen rate = ast2500_get_uart_clk_rate(priv->scu, 3);
223550e691bSryan_chen break;
22499357bacSryan_chen case ASPEED_CLK_GATE_UART4CLK:
2257c51833cSryan_chen rate = ast2500_get_uart_clk_rate(priv->scu, 4);
226550e691bSryan_chen break;
22799357bacSryan_chen case ASPEED_CLK_GATE_UART5CLK:
2287c51833cSryan_chen rate = ast2500_get_uart_clk_rate(priv->scu, 5);
229550e691bSryan_chen break;
2307a403349Sryan_chen case ASPEED_CLK_SDIO:
2317a403349Sryan_chen rate = ast2500_get_sdio_clk_rate(priv->scu);
2327a403349Sryan_chen break;
233550e691bSryan_chen default:
2347a403349Sryan_chen pr_debug("can't get clk rate \n");
235550e691bSryan_chen return -ENOENT;
236d812df15Sryan_chen break;
237550e691bSryan_chen }
238550e691bSryan_chen
239550e691bSryan_chen return rate;
240550e691bSryan_chen }
241550e691bSryan_chen
2427c51833cSryan_chen struct ast2500_clock_config {
243550e691bSryan_chen ulong input_rate;
244550e691bSryan_chen ulong rate;
2457c51833cSryan_chen struct ast2500_div_config cfg;
246550e691bSryan_chen };
247550e691bSryan_chen
2487c51833cSryan_chen static const struct ast2500_clock_config ast2500_clock_config_defaults[] = {
249550e691bSryan_chen { 24000000, 250000000, { .num = 124, .denum = 1, .post_div = 5 } },
250550e691bSryan_chen };
251550e691bSryan_chen
ast2500_get_clock_config_default(ulong input_rate,ulong requested_rate,struct ast2500_div_config * cfg)2527c51833cSryan_chen static bool ast2500_get_clock_config_default(ulong input_rate,
253550e691bSryan_chen ulong requested_rate,
2547c51833cSryan_chen struct ast2500_div_config *cfg)
255550e691bSryan_chen {
256550e691bSryan_chen int i;
257550e691bSryan_chen
2587c51833cSryan_chen for (i = 0; i < ARRAY_SIZE(ast2500_clock_config_defaults); i++) {
2597c51833cSryan_chen const struct ast2500_clock_config *default_cfg =
2607c51833cSryan_chen &ast2500_clock_config_defaults[i];
261550e691bSryan_chen if (default_cfg->input_rate == input_rate &&
262550e691bSryan_chen default_cfg->rate == requested_rate) {
263550e691bSryan_chen *cfg = default_cfg->cfg;
264550e691bSryan_chen return true;
265550e691bSryan_chen }
266550e691bSryan_chen }
267550e691bSryan_chen
268550e691bSryan_chen return false;
269550e691bSryan_chen }
270550e691bSryan_chen
271550e691bSryan_chen /*
272550e691bSryan_chen * @input_rate - the rate of input clock in Hz
273550e691bSryan_chen * @requested_rate - desired output rate in Hz
274550e691bSryan_chen * @div - this is an IN/OUT parameter, at input all fields of the config
275550e691bSryan_chen * need to be set to their maximum allowed values.
276550e691bSryan_chen * The result (the best config we could find), would also be returned
277550e691bSryan_chen * in this structure.
278550e691bSryan_chen *
279550e691bSryan_chen * @return The clock rate, when the resulting div_config is used.
280550e691bSryan_chen */
ast2500_calc_clock_config(ulong input_rate,ulong requested_rate,struct ast2500_div_config * cfg)2817c51833cSryan_chen static ulong ast2500_calc_clock_config(ulong input_rate, ulong requested_rate,
2827c51833cSryan_chen struct ast2500_div_config *cfg)
283550e691bSryan_chen {
284550e691bSryan_chen /*
285550e691bSryan_chen * The assumption is that kHz precision is good enough and
286550e691bSryan_chen * also enough to avoid overflow when multiplying.
287550e691bSryan_chen */
288550e691bSryan_chen const ulong input_rate_khz = input_rate / 1000;
289550e691bSryan_chen const ulong rate_khz = requested_rate / 1000;
2907c51833cSryan_chen const struct ast2500_div_config max_vals = *cfg;
2917c51833cSryan_chen struct ast2500_div_config it = { 0, 0, 0 };
292550e691bSryan_chen ulong delta = rate_khz;
293550e691bSryan_chen ulong new_rate_khz = 0;
294550e691bSryan_chen
295550e691bSryan_chen /*
296550e691bSryan_chen * Look for a well known frequency first.
297550e691bSryan_chen */
2987c51833cSryan_chen if (ast2500_get_clock_config_default(input_rate, requested_rate, cfg))
299550e691bSryan_chen return requested_rate;
300550e691bSryan_chen
301550e691bSryan_chen for (; it.denum <= max_vals.denum; ++it.denum) {
302550e691bSryan_chen for (it.post_div = 0; it.post_div <= max_vals.post_div;
303550e691bSryan_chen ++it.post_div) {
304550e691bSryan_chen it.num = (rate_khz * (it.post_div + 1) / input_rate_khz)
305550e691bSryan_chen * (it.denum + 1);
306550e691bSryan_chen if (it.num > max_vals.num)
307550e691bSryan_chen continue;
308550e691bSryan_chen
309550e691bSryan_chen new_rate_khz = (input_rate_khz
310550e691bSryan_chen * ((it.num + 1) / (it.denum + 1)))
311550e691bSryan_chen / (it.post_div + 1);
312550e691bSryan_chen
313550e691bSryan_chen /* Keep the rate below requested one. */
314550e691bSryan_chen if (new_rate_khz > rate_khz)
315550e691bSryan_chen continue;
316550e691bSryan_chen
317550e691bSryan_chen if (new_rate_khz - rate_khz < delta) {
318550e691bSryan_chen delta = new_rate_khz - rate_khz;
319550e691bSryan_chen *cfg = it;
320550e691bSryan_chen if (delta == 0)
321550e691bSryan_chen return new_rate_khz * 1000;
322550e691bSryan_chen }
323550e691bSryan_chen }
324550e691bSryan_chen }
325550e691bSryan_chen
326550e691bSryan_chen return new_rate_khz * 1000;
327550e691bSryan_chen }
328550e691bSryan_chen
ast2500_configure_ddr(struct ast2500_scu * scu,ulong rate)3297c51833cSryan_chen static ulong ast2500_configure_ddr(struct ast2500_scu *scu, ulong rate)
330550e691bSryan_chen {
3317c51833cSryan_chen ulong clkin = ast2500_get_clkin(scu);
332550e691bSryan_chen u32 mpll_reg;
3337c51833cSryan_chen struct ast2500_div_config div_cfg = {
334550e691bSryan_chen .num = (SCU_MPLL_NUM_MASK >> SCU_MPLL_NUM_SHIFT),
335550e691bSryan_chen .denum = (SCU_MPLL_DENUM_MASK >> SCU_MPLL_DENUM_SHIFT),
336550e691bSryan_chen .post_div = (SCU_MPLL_POST_MASK >> SCU_MPLL_POST_SHIFT),
337550e691bSryan_chen };
338550e691bSryan_chen
3397c51833cSryan_chen ast2500_calc_clock_config(clkin, rate, &div_cfg);
340550e691bSryan_chen
3417c51833cSryan_chen mpll_reg = readl(&scu->m_pll_param);
342550e691bSryan_chen mpll_reg &= ~(SCU_MPLL_POST_MASK | SCU_MPLL_NUM_MASK
343550e691bSryan_chen | SCU_MPLL_DENUM_MASK);
344550e691bSryan_chen mpll_reg |= (div_cfg.post_div << SCU_MPLL_POST_SHIFT)
345550e691bSryan_chen | (div_cfg.num << SCU_MPLL_NUM_SHIFT)
346550e691bSryan_chen | (div_cfg.denum << SCU_MPLL_DENUM_SHIFT);
347550e691bSryan_chen
3487c51833cSryan_chen writel(mpll_reg, &scu->m_pll_param);
349550e691bSryan_chen
35039283ea7Sryan_chen return ast2500_get_mpll_rate(scu);
351550e691bSryan_chen }
352550e691bSryan_chen
ast2500_configure_d2pll(struct ast2500_scu * scu,ulong rate)35300fbf296Sryan_chen static ulong ast2500_configure_d2pll(struct ast2500_scu *scu, ulong rate)
35400fbf296Sryan_chen {
35500fbf296Sryan_chen /*
35600fbf296Sryan_chen * The values and the meaning of the next three
35700fbf296Sryan_chen * parameters are undocumented. Taken from Aspeed SDK.
35800fbf296Sryan_chen *
35900fbf296Sryan_chen * TODO(clg@kaod.org): the SIP and SIC values depend on the
36000fbf296Sryan_chen * Numerator value
36100fbf296Sryan_chen */
36200fbf296Sryan_chen const u32 d2_pll_ext_param = 0x2c;
36300fbf296Sryan_chen const u32 d2_pll_sip = 0x11;
36400fbf296Sryan_chen const u32 d2_pll_sic = 0x18;
36500fbf296Sryan_chen struct ast2500_div_config div_cfg = {
36600fbf296Sryan_chen .num = SCU_D2PLL_NUM_MASK >> SCU_D2PLL_NUM_SHIFT,
36700fbf296Sryan_chen .denum = SCU_D2PLL_DENUM_MASK >> SCU_D2PLL_DENUM_SHIFT,
36800fbf296Sryan_chen .post_div = SCU_D2PLL_POST_MASK >> SCU_D2PLL_POST_SHIFT,
36900fbf296Sryan_chen };
37000fbf296Sryan_chen ulong clkin = ast2500_get_clkin(scu);
37100fbf296Sryan_chen ulong new_rate;
37200fbf296Sryan_chen
37300fbf296Sryan_chen writel((d2_pll_ext_param << SCU_D2PLL_EXT1_PARAM_SHIFT)
37400fbf296Sryan_chen | SCU_D2PLL_EXT1_OFF
37500fbf296Sryan_chen | SCU_D2PLL_EXT1_RESET, &scu->d2_pll_ext_param[0]);
37600fbf296Sryan_chen
37700fbf296Sryan_chen /*
37800fbf296Sryan_chen * Select USB2.0 port1 PHY clock as a clock source for GCRT.
37900fbf296Sryan_chen * This would disconnect it from D2-PLL.
38000fbf296Sryan_chen */
38100fbf296Sryan_chen clrsetbits_le32(&scu->misc_ctrl1, SCU_MISC_D2PLL_OFF,
38200fbf296Sryan_chen SCU_MISC_GCRT_USB20CLK);
38300fbf296Sryan_chen
38400fbf296Sryan_chen new_rate = ast2500_calc_clock_config(clkin, rate, &div_cfg);
38500fbf296Sryan_chen writel((d2_pll_sip << SCU_D2PLL_SIP_SHIFT)
38600fbf296Sryan_chen | (d2_pll_sic << SCU_D2PLL_SIC_SHIFT)
38700fbf296Sryan_chen | (div_cfg.num << SCU_D2PLL_NUM_SHIFT)
38800fbf296Sryan_chen | (div_cfg.denum << SCU_D2PLL_DENUM_SHIFT)
38900fbf296Sryan_chen | (div_cfg.post_div << SCU_D2PLL_POST_SHIFT),
39000fbf296Sryan_chen &scu->d2_pll_param);
39100fbf296Sryan_chen
39200fbf296Sryan_chen clrbits_le32(&scu->d2_pll_ext_param[0],
39300fbf296Sryan_chen SCU_D2PLL_EXT1_OFF | SCU_D2PLL_EXT1_RESET);
39400fbf296Sryan_chen
39500fbf296Sryan_chen clrsetbits_le32(&scu->misc_ctrl2,
39600fbf296Sryan_chen SCU_MISC2_RGMII_HPLL | SCU_MISC2_RMII_MPLL
39700fbf296Sryan_chen | SCU_MISC2_RGMII_CLKDIV_MASK |
39800fbf296Sryan_chen SCU_MISC2_RMII_CLKDIV_MASK,
39900fbf296Sryan_chen (4 << SCU_MISC2_RMII_CLKDIV_SHIFT));
40000fbf296Sryan_chen
40100fbf296Sryan_chen return new_rate;
40200fbf296Sryan_chen }
403f9aa0ee1Sryan_chen
ast2500_clk_set_rate(struct clk * clk,ulong rate)404f9aa0ee1Sryan_chen static unsigned long ast2500_clk_set_rate(struct clk *clk, ulong rate)
405f9aa0ee1Sryan_chen {
406f9aa0ee1Sryan_chen struct ast2500_clk_priv *priv = dev_get_priv(clk->dev);
407f9aa0ee1Sryan_chen
408f9aa0ee1Sryan_chen ulong new_rate;
409f9aa0ee1Sryan_chen switch (clk->id) {
410f9aa0ee1Sryan_chen //mpll
411f9aa0ee1Sryan_chen case ASPEED_CLK_MPLL:
412f9aa0ee1Sryan_chen new_rate = ast2500_configure_ddr(priv->scu, rate);
413f9aa0ee1Sryan_chen // printf("ast2500_clk_set_rate mpll %ld \n", new_rate);
414f9aa0ee1Sryan_chen break;
415f9aa0ee1Sryan_chen case ASPEED_CLK_D2PLL:
416f9aa0ee1Sryan_chen new_rate = ast2500_configure_d2pll(priv->scu, rate);
417f9aa0ee1Sryan_chen // printf("ast2500_clk_set_rate d2pll ==== %ld \n", new_rate);
418f9aa0ee1Sryan_chen break;
419f9aa0ee1Sryan_chen default:
420f9aa0ee1Sryan_chen return -ENOENT;
421f9aa0ee1Sryan_chen }
422f9aa0ee1Sryan_chen
423f9aa0ee1Sryan_chen return new_rate;
424f9aa0ee1Sryan_chen }
425f9aa0ee1Sryan_chen
42686f91560Sryan_chen #define SCU_CLKSTOP_MAC1 (20)
42786f91560Sryan_chen #define SCU_CLKSTOP_MAC2 (21)
428feb42054Sryan_chen
ast2500_configure_mac(struct ast2500_scu * scu,int index)4297c51833cSryan_chen static ulong ast2500_configure_mac(struct ast2500_scu *scu, int index)
430550e691bSryan_chen {
43139283ea7Sryan_chen ulong hpll_rate = ast2500_get_hpll_rate(scu);
432550e691bSryan_chen ulong required_rate;
433550e691bSryan_chen u32 hwstrap;
434550e691bSryan_chen u32 divisor;
435550e691bSryan_chen u32 reset_bit;
436550e691bSryan_chen u32 clkstop_bit;
43739283ea7Sryan_chen u32 clk_delay_settings =
43839283ea7Sryan_chen (RMII_RXCLK_IDLY << SCU_MICDS_MAC1RMII_RDLY_SHIFT)
43939283ea7Sryan_chen | (RMII_RXCLK_IDLY << SCU_MICDS_MAC2RMII_RDLY_SHIFT)
44039283ea7Sryan_chen | (RGMII_TXCLK_ODLY << SCU_MICDS_MAC1RGMII_TXDLY_SHIFT)
44139283ea7Sryan_chen | (RGMII_TXCLK_ODLY << SCU_MICDS_MAC2RGMII_TXDLY_SHIFT);
4427c51833cSryan_chen
443550e691bSryan_chen /*
444550e691bSryan_chen * According to data sheet, for 10/100 mode the MAC clock frequency
445550e691bSryan_chen * should be at least 25MHz and for 1000 mode at least 100MHz
446550e691bSryan_chen */
4477c51833cSryan_chen hwstrap = readl(&scu->hwstrap);
448550e691bSryan_chen if (hwstrap & (SCU_HWSTRAP_MAC1_RGMII | SCU_HWSTRAP_MAC2_RGMII))
449550e691bSryan_chen required_rate = 100 * 1000 * 1000;
450550e691bSryan_chen else
451550e691bSryan_chen required_rate = 25 * 1000 * 1000;
452550e691bSryan_chen
453550e691bSryan_chen divisor = hpll_rate / required_rate;
454550e691bSryan_chen
455550e691bSryan_chen if (divisor < 4) {
456550e691bSryan_chen /* Clock can't run fast enough, but let's try anyway */
457550e691bSryan_chen debug("MAC clock too slow\n");
458550e691bSryan_chen divisor = 4;
459550e691bSryan_chen } else if (divisor > 16) {
460550e691bSryan_chen /* Can't slow down the clock enough, but let's try anyway */
461550e691bSryan_chen debug("MAC clock too fast\n");
462550e691bSryan_chen divisor = 16;
463550e691bSryan_chen }
464550e691bSryan_chen
465550e691bSryan_chen switch (index) {
466550e691bSryan_chen case 1:
46739283ea7Sryan_chen reset_bit = BIT(ASPEED_RESET_MAC1);
46886f91560Sryan_chen clkstop_bit = BIT(SCU_CLKSTOP_MAC1);
469550e691bSryan_chen break;
470550e691bSryan_chen case 2:
47139283ea7Sryan_chen reset_bit = BIT(ASPEED_RESET_MAC2);
47286f91560Sryan_chen clkstop_bit = BIT(SCU_CLKSTOP_MAC2);
473550e691bSryan_chen break;
474550e691bSryan_chen default:
475550e691bSryan_chen return -EINVAL;
476550e691bSryan_chen }
477550e691bSryan_chen
4787c51833cSryan_chen clrsetbits_le32(&scu->clk_sel1, SCU_MACCLK_MASK,
479550e691bSryan_chen ((divisor - 2) / 2) << SCU_MACCLK_SHIFT);
480550e691bSryan_chen
481550e691bSryan_chen /*
482550e691bSryan_chen * Disable MAC, start its clock and re-enable it.
483550e691bSryan_chen * The procedure and the delays (100us & 10ms) are
484550e691bSryan_chen * specified in the datasheet.
485550e691bSryan_chen */
486550e691bSryan_chen setbits_le32(&scu->sysreset_ctrl1, reset_bit);
487550e691bSryan_chen udelay(100);
488550e691bSryan_chen clrbits_le32(&scu->clk_stop_ctrl1, clkstop_bit);
489550e691bSryan_chen mdelay(10);
490550e691bSryan_chen clrbits_le32(&scu->sysreset_ctrl1, reset_bit);
491550e691bSryan_chen
492550e691bSryan_chen writel((RGMII2_TXCK_DUTY << SCU_CLKDUTY_RGMII2TXCK_SHIFT)
493550e691bSryan_chen | (RGMII1_TXCK_DUTY << SCU_CLKDUTY_RGMII1TXCK_SHIFT),
494550e691bSryan_chen &scu->clk_duty_sel);
4957c51833cSryan_chen
49639283ea7Sryan_chen writel(clk_delay_settings | SCU_MICDS_RGMIIPLL, &scu->mac_clk_delay);
49739283ea7Sryan_chen writel(clk_delay_settings, &scu->mac_clk_delay_100M);
49839283ea7Sryan_chen writel(clk_delay_settings, &scu->mac_clk_delay_10M);
49939283ea7Sryan_chen
500550e691bSryan_chen return required_rate;
501550e691bSryan_chen }
502550e691bSryan_chen
5037a403349Sryan_chen #define SCU_CLKSTOP_SDIO 27
ast2500_enable_sdclk(struct ast2500_scu * scu)5047a403349Sryan_chen static ulong ast2500_enable_sdclk(struct ast2500_scu *scu)
5057a403349Sryan_chen {
5067a403349Sryan_chen u32 reset_bit;
5077a403349Sryan_chen u32 clkstop_bit;
5087a403349Sryan_chen
5097a403349Sryan_chen reset_bit = BIT(ASEPPD_RESET_SDIO);
5107a403349Sryan_chen clkstop_bit = BIT(SCU_CLKSTOP_SDIO);
5117a403349Sryan_chen
5127a403349Sryan_chen setbits_le32(&scu->sysreset_ctrl1, reset_bit);
5137a403349Sryan_chen udelay(100);
5147a403349Sryan_chen //enable clk
5157a403349Sryan_chen clrbits_le32(&scu->clk_stop_ctrl1, clkstop_bit);
5167a403349Sryan_chen mdelay(10);
5177a403349Sryan_chen clrbits_le32(&scu->sysreset_ctrl1, reset_bit);
5187a403349Sryan_chen
5197a403349Sryan_chen return 0;
520550e691bSryan_chen }
521550e691bSryan_chen
5227a403349Sryan_chen #define SCU_CLKSTOP_EXTSD 15
5237a403349Sryan_chen #define SCU_CLK_SD_MASK (0x7 << 12)
5247a403349Sryan_chen #define SCU_CLK_SD_DIV(x) (x << 12)
5257a403349Sryan_chen
ast2500_enable_extsdclk(struct ast2500_scu * scu)5267a403349Sryan_chen static ulong ast2500_enable_extsdclk(struct ast2500_scu *scu)
5277a403349Sryan_chen {
5287a403349Sryan_chen u32 clk_sel = readl(&scu->clk_sel1);
5297a403349Sryan_chen u32 enableclk_bit;
5307a403349Sryan_chen
5317a403349Sryan_chen enableclk_bit = BIT(SCU_CLKSTOP_EXTSD);
5327a403349Sryan_chen
5337a403349Sryan_chen // SDCLK = G4 H-PLL / 4, G5 = H-PLL /8
5347a403349Sryan_chen clk_sel &= ~SCU_CLK_SD_MASK;
5357a403349Sryan_chen clk_sel |= SCU_CLK_SD_DIV(1);
5367a403349Sryan_chen writel(clk_sel, &scu->clk_sel1);
5377a403349Sryan_chen
5387a403349Sryan_chen //enable clk
5397a403349Sryan_chen setbits_le32(&scu->clk_sel1, enableclk_bit);
5407a403349Sryan_chen
5417a403349Sryan_chen return 0;
542550e691bSryan_chen }
543550e691bSryan_chen
ast2500_enable_usbahclk(struct ast2500_scu * scu)544*6898fa38Sneal_liu static ulong ast2500_enable_usbahclk(struct ast2500_scu *scu)
545*6898fa38Sneal_liu {
546*6898fa38Sneal_liu u32 reset_bit;
547*6898fa38Sneal_liu u32 clkstop_bit;
548*6898fa38Sneal_liu
549*6898fa38Sneal_liu reset_bit = BIT(ASPEED_RESET_EHCI_P1);
550*6898fa38Sneal_liu clkstop_bit = BIT(14);
551*6898fa38Sneal_liu
552*6898fa38Sneal_liu setbits_le32(&scu->sysreset_ctrl1, reset_bit);
553*6898fa38Sneal_liu udelay(100);
554*6898fa38Sneal_liu setbits_le32(&scu->clk_stop_ctrl1, clkstop_bit);
555*6898fa38Sneal_liu mdelay(20);
556*6898fa38Sneal_liu
557*6898fa38Sneal_liu clrbits_le32(&scu->sysreset_ctrl1, reset_bit);
558*6898fa38Sneal_liu
559*6898fa38Sneal_liu return 0;
560*6898fa38Sneal_liu }
561*6898fa38Sneal_liu
ast2500_enable_usbbhclk(struct ast2500_scu * scu)562*6898fa38Sneal_liu static ulong ast2500_enable_usbbhclk(struct ast2500_scu *scu)
563*6898fa38Sneal_liu {
564*6898fa38Sneal_liu u32 reset_bit;
565*6898fa38Sneal_liu u32 clkstop_bit;
566*6898fa38Sneal_liu
567*6898fa38Sneal_liu reset_bit = BIT(ASPEED_RESET_EHCI_P2);
568*6898fa38Sneal_liu clkstop_bit = BIT(7);
569*6898fa38Sneal_liu
570*6898fa38Sneal_liu setbits_le32(&scu->sysreset_ctrl1, reset_bit);
571*6898fa38Sneal_liu udelay(100);
572*6898fa38Sneal_liu clrbits_le32(&scu->clk_stop_ctrl1, clkstop_bit);
573*6898fa38Sneal_liu mdelay(20);
574*6898fa38Sneal_liu
575*6898fa38Sneal_liu clrbits_le32(&scu->sysreset_ctrl1, reset_bit);
576*6898fa38Sneal_liu
577*6898fa38Sneal_liu return 0;
578*6898fa38Sneal_liu }
579*6898fa38Sneal_liu
ast2500_clk_enable(struct clk * clk)5807c51833cSryan_chen static int ast2500_clk_enable(struct clk *clk)
581550e691bSryan_chen {
5827c51833cSryan_chen struct ast2500_clk_priv *priv = dev_get_priv(clk->dev);
583550e691bSryan_chen
584550e691bSryan_chen switch (clk->id) {
585550e691bSryan_chen /*
586550e691bSryan_chen * For MAC clocks the clock rate is
587550e691bSryan_chen * configured based on whether RGMII or RMII mode has been selected
588550e691bSryan_chen * through hardware strapping.
589550e691bSryan_chen */
59086f91560Sryan_chen case ASPEED_CLK_GATE_MAC1CLK:
5917c51833cSryan_chen ast2500_configure_mac(priv->scu, 1);
592550e691bSryan_chen break;
59386f91560Sryan_chen case ASPEED_CLK_GATE_MAC2CLK:
5947c51833cSryan_chen ast2500_configure_mac(priv->scu, 2);
595550e691bSryan_chen break;
59639283ea7Sryan_chen case ASPEED_CLK_D2PLL:
5977c51833cSryan_chen ast2500_configure_d2pll(priv->scu, D2PLL_DEFAULT_RATE);
598550e691bSryan_chen break;
5997a403349Sryan_chen case ASPEED_CLK_GATE_SDCLK:
6007a403349Sryan_chen ast2500_enable_sdclk(priv->scu);
6017a403349Sryan_chen break;
6027a403349Sryan_chen case ASPEED_CLK_GATE_SDEXTCLK:
6037a403349Sryan_chen ast2500_enable_extsdclk(priv->scu);
6047a403349Sryan_chen break;
605*6898fa38Sneal_liu case ASPEED_CLK_GATE_USBPORT1CLK:
606*6898fa38Sneal_liu ast2500_enable_usbahclk(priv->scu);
607*6898fa38Sneal_liu break;
608*6898fa38Sneal_liu case ASPEED_CLK_GATE_USBPORT2CLK:
609*6898fa38Sneal_liu ast2500_enable_usbbhclk(priv->scu);
610*6898fa38Sneal_liu break;
611550e691bSryan_chen default:
6127a403349Sryan_chen pr_debug("can't enable clk \n");
613550e691bSryan_chen return -ENOENT;
614f9aa0ee1Sryan_chen break;
615550e691bSryan_chen }
616550e691bSryan_chen
617550e691bSryan_chen return 0;
618550e691bSryan_chen }
619550e691bSryan_chen
6207c51833cSryan_chen struct clk_ops ast2500_clk_ops = {
6217c51833cSryan_chen .get_rate = ast2500_clk_get_rate,
6227c51833cSryan_chen .set_rate = ast2500_clk_set_rate,
6237c51833cSryan_chen .enable = ast2500_clk_enable,
624550e691bSryan_chen };
625550e691bSryan_chen
ast2500_clk_probe(struct udevice * dev)6267c51833cSryan_chen static int ast2500_clk_probe(struct udevice *dev)
627550e691bSryan_chen {
6287c51833cSryan_chen struct ast2500_clk_priv *priv = dev_get_priv(dev);
629550e691bSryan_chen
6307c51833cSryan_chen priv->scu = devfdt_get_addr_ptr(dev);
6317c51833cSryan_chen if (IS_ERR(priv->scu))
6327c51833cSryan_chen return PTR_ERR(priv->scu);
633550e691bSryan_chen
634550e691bSryan_chen return 0;
635550e691bSryan_chen }
636550e691bSryan_chen
ast2500_clk_bind(struct udevice * dev)6377c51833cSryan_chen static int ast2500_clk_bind(struct udevice *dev)
638550e691bSryan_chen {
639550e691bSryan_chen int ret;
640550e691bSryan_chen
641550e691bSryan_chen /* The reset driver does not have a device node, so bind it here */
642550e691bSryan_chen ret = device_bind_driver(gd->dm_root, "ast_sysreset", "reset", &dev);
643550e691bSryan_chen if (ret)
644550e691bSryan_chen debug("Warning: No reset driver: ret=%d\n", ret);
645550e691bSryan_chen
646550e691bSryan_chen return 0;
647550e691bSryan_chen }
648550e691bSryan_chen
649d35ac78cSryan_chen #if CONFIG_IS_ENABLED(CMD_CLK)
650d35ac78cSryan_chen struct aspeed_clks {
651d35ac78cSryan_chen ulong id;
652d35ac78cSryan_chen const char *name;
653d35ac78cSryan_chen };
654d35ac78cSryan_chen
655d35ac78cSryan_chen static struct aspeed_clks aspeed_clk_names[] = {
656d35ac78cSryan_chen { ASPEED_CLK_HPLL, "hpll" },
657d35ac78cSryan_chen { ASPEED_CLK_MPLL, "mpll" },
658d35ac78cSryan_chen { ASPEED_CLK_DPLL, "dpll" },
659d35ac78cSryan_chen { ASPEED_CLK_D2PLL, "d2pll" },
660d35ac78cSryan_chen { ASPEED_CLK_AHB, "hclk" },
661d35ac78cSryan_chen { ASPEED_CLK_APB, "pclk" },
662d35ac78cSryan_chen };
663d35ac78cSryan_chen
soc_clk_dump(void)664d35ac78cSryan_chen int soc_clk_dump(void)
665d35ac78cSryan_chen {
666d35ac78cSryan_chen struct udevice *dev;
667d35ac78cSryan_chen struct clk clk;
668d35ac78cSryan_chen unsigned long rate;
669d35ac78cSryan_chen int i, ret;
670d35ac78cSryan_chen
671d35ac78cSryan_chen ret = uclass_get_device_by_driver(UCLASS_CLK,
672d35ac78cSryan_chen DM_GET_DRIVER(aspeed_scu), &dev);
673d35ac78cSryan_chen if (ret)
674d35ac78cSryan_chen return ret;
675d35ac78cSryan_chen
676d35ac78cSryan_chen printf("Clk\t\tHz\n");
677d35ac78cSryan_chen
678d35ac78cSryan_chen for (i = 0; i < ARRAY_SIZE(aspeed_clk_names); i++) {
679d35ac78cSryan_chen clk.id = aspeed_clk_names[i].id;
680d35ac78cSryan_chen ret = clk_request(dev, &clk);
681d35ac78cSryan_chen if (ret < 0) {
682d35ac78cSryan_chen debug("%s clk_request() failed: %d\n", __func__, ret);
683d35ac78cSryan_chen continue;
684d35ac78cSryan_chen }
685d35ac78cSryan_chen
686d35ac78cSryan_chen ret = clk_get_rate(&clk);
687d35ac78cSryan_chen rate = ret;
688d35ac78cSryan_chen
689d35ac78cSryan_chen clk_free(&clk);
690d35ac78cSryan_chen
691d35ac78cSryan_chen if (ret == -ENOTSUPP) {
692d35ac78cSryan_chen printf("clk ID %lu not supported yet\n",
693d35ac78cSryan_chen aspeed_clk_names[i].id);
694d35ac78cSryan_chen continue;
695d35ac78cSryan_chen }
696d35ac78cSryan_chen if (ret < 0) {
697d35ac78cSryan_chen printf("%s %lu: get_rate err: %d\n",
698d35ac78cSryan_chen __func__, aspeed_clk_names[i].id, ret);
699d35ac78cSryan_chen continue;
700d35ac78cSryan_chen }
701d35ac78cSryan_chen
702d35ac78cSryan_chen printf("%s(%3lu):\t%lu\n",
703d35ac78cSryan_chen aspeed_clk_names[i].name, aspeed_clk_names[i].id, rate);
704d35ac78cSryan_chen }
705d35ac78cSryan_chen
706d35ac78cSryan_chen return 0;
707d35ac78cSryan_chen }
708d35ac78cSryan_chen #endif
709d35ac78cSryan_chen
7107c51833cSryan_chen static const struct udevice_id ast2500_clk_ids[] = {
7117c51833cSryan_chen { .compatible = "aspeed,ast2500-scu" },
712550e691bSryan_chen { }
713550e691bSryan_chen };
714550e691bSryan_chen
715aa36597fSDylan Hung U_BOOT_DRIVER(aspeed_scu) = {
716aa36597fSDylan Hung .name = "aspeed_scu",
717550e691bSryan_chen .id = UCLASS_CLK,
7187c51833cSryan_chen .of_match = ast2500_clk_ids,
7197c51833cSryan_chen .priv_auto_alloc_size = sizeof(struct ast2500_clk_priv),
7207c51833cSryan_chen .ops = &ast2500_clk_ops,
7217c51833cSryan_chen .bind = ast2500_clk_bind,
7227c51833cSryan_chen .probe = ast2500_clk_probe,
723550e691bSryan_chen };
724