xref: /openbmc/u-boot/drivers/clk/aspeed/clk_ast2600.c (revision 54f9cba120010f9d8ce356ea7dfce87e160dc181)
1550e691bSryan_chen // SPDX-License-Identifier: GPL-2.0
2550e691bSryan_chen /*
3550e691bSryan_chen  * Copyright (C) ASPEED Technology Inc.
4550e691bSryan_chen  */
5550e691bSryan_chen 
6550e691bSryan_chen #include <common.h>
7550e691bSryan_chen #include <clk-uclass.h>
8550e691bSryan_chen #include <dm.h>
9550e691bSryan_chen #include <asm/io.h>
10550e691bSryan_chen #include <dm/lists.h>
1162a6bcbfSryan_chen #include <asm/arch/scu_ast2600.h>
12d6e349c7Sryan_chen #include <dt-bindings/clock/ast2600-clock.h>
1339283ea7Sryan_chen #include <dt-bindings/reset/ast2600-reset.h>
14550e691bSryan_chen 
15550e691bSryan_chen /*
16550e691bSryan_chen  * MAC Clock Delay settings, taken from Aspeed SDK
17550e691bSryan_chen  */
18550e691bSryan_chen #define RGMII_TXCLK_ODLY	8
19550e691bSryan_chen #define RMII_RXCLK_IDLY		2
20550e691bSryan_chen 
21ed30249cSDylan Hung #define MAC_DEF_DELAY_1G	0x00410410
22*54f9cba1SDylan Hung #define MAC_DEF_DELAY_100M	0x00410410
23*54f9cba1SDylan Hung #define MAC_DEF_DELAY_10M	0x00410410
24*54f9cba1SDylan Hung 
25*54f9cba1SDylan Hung #define MAC34_DEF_DELAY_1G	0x00104208
26*54f9cba1SDylan Hung #define MAC34_DEF_DELAY_100M	0x00104208
27*54f9cba1SDylan Hung #define MAC34_DEF_DELAY_10M	0x00104208
284760b3f8SDylan Hung 
29550e691bSryan_chen /*
30550e691bSryan_chen  * TGMII Clock Duty constants, taken from Aspeed SDK
31550e691bSryan_chen  */
32550e691bSryan_chen #define RGMII2_TXCK_DUTY	0x66
33550e691bSryan_chen #define RGMII1_TXCK_DUTY	0x64
34550e691bSryan_chen 
35550e691bSryan_chen #define D2PLL_DEFAULT_RATE	(250 * 1000 * 1000)
36550e691bSryan_chen 
37550e691bSryan_chen DECLARE_GLOBAL_DATA_PTR;
38550e691bSryan_chen 
39550e691bSryan_chen /*
40550e691bSryan_chen  * Clock divider/multiplier configuration struct.
41550e691bSryan_chen  * For H-PLL and M-PLL the formula is
42550e691bSryan_chen  * (Output Frequency) = CLKIN * ((M + 1) / (N + 1)) / (P + 1)
43550e691bSryan_chen  * M - Numerator
44550e691bSryan_chen  * N - Denumerator
45550e691bSryan_chen  * P - Post Divider
46550e691bSryan_chen  * They have the same layout in their control register.
47550e691bSryan_chen  *
48550e691bSryan_chen  * D-PLL and D2-PLL have extra divider (OD + 1), which is not
49550e691bSryan_chen  * yet needed and ignored by clock configurations.
50550e691bSryan_chen  */
5139283ea7Sryan_chen struct ast2600_div_config {
52550e691bSryan_chen 	unsigned int num;
53550e691bSryan_chen 	unsigned int denum;
54550e691bSryan_chen 	unsigned int post_div;
55550e691bSryan_chen };
56550e691bSryan_chen 
57bbbfb0c5Sryan_chen extern u32 ast2600_get_pll_rate(struct ast2600_scu *scu, int pll_idx)
58550e691bSryan_chen {
59d6e349c7Sryan_chen 	u32 clkin = AST2600_CLK_IN;
60bbbfb0c5Sryan_chen 	u32 pll_reg = 0;
619639db61Sryan_chen 	unsigned int mult, div = 1;
62550e691bSryan_chen 
63bbbfb0c5Sryan_chen 	switch(pll_idx) {
64bbbfb0c5Sryan_chen 		case ASPEED_CLK_HPLL:
65bbbfb0c5Sryan_chen 			pll_reg = readl(&scu->h_pll_param);
66bbbfb0c5Sryan_chen 			break;
67bbbfb0c5Sryan_chen 		case ASPEED_CLK_MPLL:
68bbbfb0c5Sryan_chen 			pll_reg = readl(&scu->m_pll_param);
69bbbfb0c5Sryan_chen 			break;
70bbbfb0c5Sryan_chen 		case ASPEED_CLK_DPLL:
71bbbfb0c5Sryan_chen 			pll_reg = readl(&scu->d_pll_param);
72bbbfb0c5Sryan_chen 			break;
73bbbfb0c5Sryan_chen 		case ASPEED_CLK_EPLL:
74bbbfb0c5Sryan_chen 			pll_reg = readl(&scu->e_pll_param);
75bbbfb0c5Sryan_chen 			break;
76bbbfb0c5Sryan_chen 
77bbbfb0c5Sryan_chen 	}
78bbbfb0c5Sryan_chen 	if (pll_reg & BIT(24)) {
799639db61Sryan_chen 		/* Pass through mode */
809639db61Sryan_chen 		mult = div = 1;
819639db61Sryan_chen 	} else {
829639db61Sryan_chen 		/* F = 25Mhz * [(M + 2) / (n + 1)] / (p + 1) */
83bbbfb0c5Sryan_chen 		u32 m = pll_reg  & 0x1fff;
84bbbfb0c5Sryan_chen 		u32 n = (pll_reg >> 13) & 0x3f;
85bbbfb0c5Sryan_chen 		u32 p = (pll_reg >> 19) & 0xf;
869639db61Sryan_chen 		mult = (m + 1) / (n + 1);
879639db61Sryan_chen 		div = (p + 1);
889639db61Sryan_chen 	}
899639db61Sryan_chen 	return ((clkin * mult)/div);
90550e691bSryan_chen 
91550e691bSryan_chen }
92550e691bSryan_chen 
934f22e838Sryan_chen extern u32 ast2600_get_apll_rate(struct ast2600_scu *scu)
94550e691bSryan_chen {
95bbbfb0c5Sryan_chen 	u32 clkin = AST2600_CLK_IN;
9639283ea7Sryan_chen 	u32 apll_reg = readl(&scu->a_pll_param);
9739283ea7Sryan_chen 	unsigned int mult, div = 1;
98d6e349c7Sryan_chen 
9939283ea7Sryan_chen 	if (apll_reg & BIT(20)) {
100d6e349c7Sryan_chen 		/* Pass through mode */
101d6e349c7Sryan_chen 		mult = div = 1;
102d6e349c7Sryan_chen 	} else {
103bbbfb0c5Sryan_chen 		/* F = 25Mhz * (2-od) * [(m + 2) / (n + 1)] */
10439283ea7Sryan_chen 		u32 m = (apll_reg >> 5) & 0x3f;
10539283ea7Sryan_chen 		u32 od = (apll_reg >> 4) & 0x1;
10639283ea7Sryan_chen 		u32 n = apll_reg & 0xf;
107d6e349c7Sryan_chen 
108bbbfb0c5Sryan_chen 		mult = (2 - od) * (m + 2);
109bbbfb0c5Sryan_chen 		div = n + 1;
110d6e349c7Sryan_chen 	}
111bbbfb0c5Sryan_chen 	return ((clkin * mult)/div);
11239283ea7Sryan_chen }
11339283ea7Sryan_chen 
114d812df15Sryan_chen static u32 ast2600_a0_axi_ahb_div_table[] = {
115d812df15Sryan_chen 	2, 2, 3, 5,
116d812df15Sryan_chen };
117d812df15Sryan_chen 
118d812df15Sryan_chen static u32 ast2600_a1_axi_ahb_div_table[] = {
119d812df15Sryan_chen 	4, 6, 2, 4,
120d812df15Sryan_chen };
121d812df15Sryan_chen 
122d812df15Sryan_chen static u32 ast2600_get_hclk(struct ast2600_scu *scu)
123d812df15Sryan_chen {
124d812df15Sryan_chen 	u32 hw_rev = readl(&scu->chip_id0);
125d812df15Sryan_chen 	u32 hwstrap1 = readl(&scu->hwstrap1);
126d812df15Sryan_chen 	u32 axi_div = 1;
127d812df15Sryan_chen 	u32 ahb_div = 0;
128d812df15Sryan_chen 	u32 rate = 0;
129d812df15Sryan_chen 
130c29e1cc8Sryan_chen 	if(hwstrap1 & BIT(16))
131d812df15Sryan_chen 		axi_div = 1;
132d812df15Sryan_chen 	else
133d812df15Sryan_chen 		axi_div = 2;
134d812df15Sryan_chen 
135d812df15Sryan_chen 	if (hw_rev & BIT(16))
136d812df15Sryan_chen 		ahb_div = ast2600_a1_axi_ahb_div_table[(hwstrap1 >> 11) & 0x3];
137d812df15Sryan_chen 	else
138d812df15Sryan_chen 		ahb_div = ast2600_a0_axi_ahb_div_table[(hwstrap1 >> 11) & 0x3];
139d812df15Sryan_chen 
140bbbfb0c5Sryan_chen 	rate = ast2600_get_pll_rate(scu, ASPEED_CLK_HPLL);
141d812df15Sryan_chen 
1422717883aSryan_chen 	return (rate / axi_div / ahb_div);
1432717883aSryan_chen }
1442717883aSryan_chen 
1452717883aSryan_chen static u32 ast2600_hpll_pclk_div_table[] = {
1462717883aSryan_chen 	4, 8, 12, 16, 20, 24, 28, 32,
1472717883aSryan_chen };
1482717883aSryan_chen 
1492717883aSryan_chen static u32 ast2600_get_pclk(struct ast2600_scu *scu)
1502717883aSryan_chen {
1512717883aSryan_chen 	u32 clk_sel1 = readl(&scu->clk_sel1);
1522717883aSryan_chen 	u32 apb_div = ast2600_hpll_pclk_div_table[((clk_sel1 >> 23) & 0x7)];
153bbbfb0c5Sryan_chen 	u32 rate = ast2600_get_pll_rate(scu, ASPEED_CLK_HPLL);
1542717883aSryan_chen 
1552717883aSryan_chen 	return (rate / apb_div);
156d812df15Sryan_chen }
157d812df15Sryan_chen 
15827881d20Sryan_chen static u32 ast2600_get_uxclk_rate(struct ast2600_scu *scu)
159d6e349c7Sryan_chen {
16027881d20Sryan_chen 	u32 clk_in = 0;
16127881d20Sryan_chen 	u32 uxclk_sel = readl(&scu->clk_sel4);
162550e691bSryan_chen 
16327881d20Sryan_chen 	uxclk_sel &= 0x3;
16427881d20Sryan_chen 	switch(uxclk_sel) {
16527881d20Sryan_chen 		case 0:
16627881d20Sryan_chen 			clk_in = ast2600_get_apll_rate(scu) / 4;
16727881d20Sryan_chen 			break;
16827881d20Sryan_chen 		case 1:
16927881d20Sryan_chen 			clk_in = ast2600_get_apll_rate(scu) / 2;
17027881d20Sryan_chen 			break;
17127881d20Sryan_chen 		case 2:
17227881d20Sryan_chen 			clk_in = ast2600_get_apll_rate(scu);
17327881d20Sryan_chen 			break;
17427881d20Sryan_chen 		case 3:
17527881d20Sryan_chen 			clk_in = ast2600_get_hclk(scu);
17627881d20Sryan_chen 			break;
17727881d20Sryan_chen 	}
178d6e349c7Sryan_chen 
17927881d20Sryan_chen 	return clk_in;
18027881d20Sryan_chen }
18127881d20Sryan_chen 
18227881d20Sryan_chen static u32 ast2600_get_huxclk_rate(struct ast2600_scu *scu)
18327881d20Sryan_chen {
18427881d20Sryan_chen 	u32 clk_in = 0;
18527881d20Sryan_chen 	u32 huclk_sel = readl(&scu->clk_sel4);
18627881d20Sryan_chen 
18727881d20Sryan_chen 	huclk_sel = ((huclk_sel >> 3) & 0x3);
18827881d20Sryan_chen 	switch(huclk_sel) {
18927881d20Sryan_chen 		case 0:
19027881d20Sryan_chen 			clk_in = ast2600_get_apll_rate(scu) / 4;
19127881d20Sryan_chen 			break;
19227881d20Sryan_chen 		case 1:
19327881d20Sryan_chen 			clk_in = ast2600_get_apll_rate(scu) / 2;
19427881d20Sryan_chen 			break;
19527881d20Sryan_chen 		case 2:
19627881d20Sryan_chen 			clk_in = ast2600_get_apll_rate(scu);
19727881d20Sryan_chen 			break;
19827881d20Sryan_chen 		case 3:
19927881d20Sryan_chen 			clk_in = ast2600_get_hclk(scu);
20027881d20Sryan_chen 			break;
20127881d20Sryan_chen 	}
20227881d20Sryan_chen 
20327881d20Sryan_chen 	return clk_in;
20427881d20Sryan_chen }
20527881d20Sryan_chen 
20627881d20Sryan_chen static u32 ast2600_get_uart_from_uxclk_rate(struct ast2600_scu *scu)
20727881d20Sryan_chen {
20827881d20Sryan_chen 	u32 clk_in = ast2600_get_uxclk_rate(scu);
20927881d20Sryan_chen 	u32 div_reg = readl(&scu->uart_24m_ref_uxclk);
21027881d20Sryan_chen 	unsigned int mult, div;
21127881d20Sryan_chen 
21227881d20Sryan_chen 	u32 n = (div_reg >> 8) & 0x3ff;
21327881d20Sryan_chen 	u32 r = div_reg & 0xff;
21427881d20Sryan_chen 
21527881d20Sryan_chen 	mult = r;
21627881d20Sryan_chen 	div = (n * 4);
21727881d20Sryan_chen 	return (clk_in * mult)/div;
21827881d20Sryan_chen }
21927881d20Sryan_chen 
22027881d20Sryan_chen static u32 ast2600_get_uart_from_huxclk_rate(struct ast2600_scu *scu)
22127881d20Sryan_chen {
22227881d20Sryan_chen 	u32 clk_in = ast2600_get_huxclk_rate(scu);
22327881d20Sryan_chen 	u32 div_reg = readl(&scu->uart_24m_ref_huxclk);
22427881d20Sryan_chen 
22527881d20Sryan_chen 	unsigned int mult, div;
22627881d20Sryan_chen 
22727881d20Sryan_chen 	u32 n = (div_reg >> 8) & 0x3ff;
22827881d20Sryan_chen 	u32 r = div_reg & 0xff;
22927881d20Sryan_chen 
23027881d20Sryan_chen 	mult = r;
23127881d20Sryan_chen 	div = (n * 4);
23227881d20Sryan_chen 	return (clk_in * mult)/div;
23327881d20Sryan_chen }
23427881d20Sryan_chen 
235f51926eeSryan_chen static u32 ast2600_get_sdio_clk_rate(struct ast2600_scu *scu)
236f51926eeSryan_chen {
237f51926eeSryan_chen 	u32 clkin = 0;
238f51926eeSryan_chen 	u32 clk_sel = readl(&scu->clk_sel4);
239f51926eeSryan_chen 	u32 div = (clk_sel >> 28) & 0x7;
240f51926eeSryan_chen 
241f51926eeSryan_chen 	if(clk_sel & BIT(8)) {
242f51926eeSryan_chen 		clkin = ast2600_get_apll_rate(scu);
243f51926eeSryan_chen 	} else {
244f51926eeSryan_chen 		clkin = 200 * 1000 * 1000;
245f51926eeSryan_chen 	}
246f51926eeSryan_chen 	div = (div + 1) << 1;
247f51926eeSryan_chen 
248f51926eeSryan_chen 	return (clkin / div);
249f51926eeSryan_chen }
250f51926eeSryan_chen 
251f51926eeSryan_chen static u32 ast2600_get_emmc_clk_rate(struct ast2600_scu *scu)
252f51926eeSryan_chen {
253bbbfb0c5Sryan_chen 	u32 clkin = ast2600_get_pll_rate(scu, ASPEED_CLK_HPLL);
254f51926eeSryan_chen 	u32 clk_sel = readl(&scu->clk_sel1);
255f51926eeSryan_chen 	u32 div = (clk_sel >> 12) & 0x7;
256f51926eeSryan_chen 
257f51926eeSryan_chen 	div = (div + 1) << 2;
258f51926eeSryan_chen 
259f51926eeSryan_chen 	return (clkin / div);
260f51926eeSryan_chen }
261f51926eeSryan_chen 
262f51926eeSryan_chen static u32 ast2600_get_uart_clk_rate(struct ast2600_scu *scu, int uart_idx)
26327881d20Sryan_chen {
26427881d20Sryan_chen 	u32 uart_sel = readl(&scu->clk_sel4);
26527881d20Sryan_chen 	u32 uart_sel5 = readl(&scu->clk_sel5);
26627881d20Sryan_chen 	ulong uart_clk = 0;
26727881d20Sryan_chen 
26827881d20Sryan_chen 	switch(uart_idx) {
26927881d20Sryan_chen 		case 1:
27027881d20Sryan_chen 		case 2:
27127881d20Sryan_chen 		case 3:
27227881d20Sryan_chen 		case 4:
27327881d20Sryan_chen 		case 6:
27427881d20Sryan_chen 			if(uart_sel & BIT(uart_idx - 1))
27527881d20Sryan_chen 				uart_clk = ast2600_get_uart_from_uxclk_rate(scu)/13 ;
276550e691bSryan_chen 			else
27727881d20Sryan_chen 				uart_clk = ast2600_get_uart_from_huxclk_rate(scu)/13 ;
27827881d20Sryan_chen 			break;
27927881d20Sryan_chen 		case 5: //24mhz is come form usb phy 48Mhz
28027881d20Sryan_chen 			{
28127881d20Sryan_chen 			u8 uart5_clk_sel = 0;
28227881d20Sryan_chen 			//high bit
28327881d20Sryan_chen 			if (readl(&scu->misc_ctrl1) & BIT(12))
28427881d20Sryan_chen 				uart5_clk_sel = 0x2;
28527881d20Sryan_chen 			else
28627881d20Sryan_chen 				uart5_clk_sel = 0x0;
287550e691bSryan_chen 
28827881d20Sryan_chen 			if (readl(&scu->clk_sel2) & BIT(14))
28927881d20Sryan_chen 				uart5_clk_sel |= 0x1;
290550e691bSryan_chen 
29127881d20Sryan_chen 			switch(uart5_clk_sel) {
29227881d20Sryan_chen 				case 0:
29327881d20Sryan_chen 					uart_clk = 24000000;
29427881d20Sryan_chen 					break;
29527881d20Sryan_chen 				case 1:
29627881d20Sryan_chen 					uart_clk = 0;
29727881d20Sryan_chen 					break;
29827881d20Sryan_chen 				case 2:
29927881d20Sryan_chen 					uart_clk = 24000000/13;
30027881d20Sryan_chen 					break;
30127881d20Sryan_chen 				case 3:
30227881d20Sryan_chen 					uart_clk = 192000000/13;
30327881d20Sryan_chen 					break;
30427881d20Sryan_chen 			}
30527881d20Sryan_chen 			}
30627881d20Sryan_chen 			break;
30727881d20Sryan_chen 		case 7:
30827881d20Sryan_chen 		case 8:
30927881d20Sryan_chen 		case 9:
31027881d20Sryan_chen 		case 10:
31127881d20Sryan_chen 		case 11:
31227881d20Sryan_chen 		case 12:
31327881d20Sryan_chen 		case 13:
31427881d20Sryan_chen 			if(uart_sel5 & BIT(uart_idx - 1))
31527881d20Sryan_chen 				uart_clk = ast2600_get_uart_from_uxclk_rate(scu)/13 ;
31627881d20Sryan_chen 			else
31727881d20Sryan_chen 				uart_clk = ast2600_get_uart_from_huxclk_rate(scu)/13 ;
31827881d20Sryan_chen 			break;
31927881d20Sryan_chen 	}
32027881d20Sryan_chen 
32127881d20Sryan_chen 	return uart_clk;
322550e691bSryan_chen }
323550e691bSryan_chen 
324feb42054Sryan_chen static ulong ast2600_clk_get_rate(struct clk *clk)
325feb42054Sryan_chen {
326feb42054Sryan_chen 	struct ast2600_clk_priv *priv = dev_get_priv(clk->dev);
327feb42054Sryan_chen 	ulong rate = 0;
328feb42054Sryan_chen 
329feb42054Sryan_chen 	switch (clk->id) {
330feb42054Sryan_chen 	case ASPEED_CLK_HPLL:
331bbbfb0c5Sryan_chen 	case ASPEED_CLK_EPLL:
332bbbfb0c5Sryan_chen 	case ASPEED_CLK_DPLL:
333d812df15Sryan_chen 	case ASPEED_CLK_MPLL:
334bbbfb0c5Sryan_chen 		rate = ast2600_get_pll_rate(priv->scu, clk->id);
335d812df15Sryan_chen 		break;
336feb42054Sryan_chen 	case ASPEED_CLK_AHB:
337feb42054Sryan_chen 		rate = ast2600_get_hclk(priv->scu);
338feb42054Sryan_chen 		break;
339feb42054Sryan_chen 	case ASPEED_CLK_APB:
3402717883aSryan_chen 		rate = ast2600_get_pclk(priv->scu);
341feb42054Sryan_chen 		break;
342bbbfb0c5Sryan_chen 	case ASPEED_CLK_APLL:
343bbbfb0c5Sryan_chen 		rate = ast2600_get_apll_rate(priv->scu);
344bbbfb0c5Sryan_chen 		break;
345feb42054Sryan_chen 	case ASPEED_CLK_GATE_UART1CLK:
346feb42054Sryan_chen 		rate = ast2600_get_uart_clk_rate(priv->scu, 1);
347feb42054Sryan_chen 		break;
348feb42054Sryan_chen 	case ASPEED_CLK_GATE_UART2CLK:
349feb42054Sryan_chen 		rate = ast2600_get_uart_clk_rate(priv->scu, 2);
350feb42054Sryan_chen 		break;
351feb42054Sryan_chen 	case ASPEED_CLK_GATE_UART3CLK:
352feb42054Sryan_chen 		rate = ast2600_get_uart_clk_rate(priv->scu, 3);
353feb42054Sryan_chen 		break;
354feb42054Sryan_chen 	case ASPEED_CLK_GATE_UART4CLK:
355feb42054Sryan_chen 		rate = ast2600_get_uart_clk_rate(priv->scu, 4);
356feb42054Sryan_chen 		break;
357feb42054Sryan_chen 	case ASPEED_CLK_GATE_UART5CLK:
358feb42054Sryan_chen 		rate = ast2600_get_uart_clk_rate(priv->scu, 5);
359feb42054Sryan_chen 		break;
360f51926eeSryan_chen 	case ASPEED_CLK_SDIO:
361f51926eeSryan_chen 		rate = ast2600_get_sdio_clk_rate(priv->scu);
362f51926eeSryan_chen 		break;
363f51926eeSryan_chen 	case ASPEED_CLK_EMMC:
364f51926eeSryan_chen 		rate = ast2600_get_emmc_clk_rate(priv->scu);
365f51926eeSryan_chen 		break;
366feb42054Sryan_chen 	default:
367d812df15Sryan_chen 		pr_debug("can't get clk rate \n");
368feb42054Sryan_chen 		return -ENOENT;
369d812df15Sryan_chen 		break;
370feb42054Sryan_chen 	}
371feb42054Sryan_chen 
372feb42054Sryan_chen 	return rate;
373feb42054Sryan_chen }
374feb42054Sryan_chen 
375550e691bSryan_chen struct aspeed_clock_config {
376550e691bSryan_chen 	ulong input_rate;
377550e691bSryan_chen 	ulong rate;
37839283ea7Sryan_chen 	struct ast2600_div_config cfg;
379550e691bSryan_chen };
380550e691bSryan_chen 
381550e691bSryan_chen static const struct aspeed_clock_config aspeed_clock_config_defaults[] = {
3821cd71a14SDylan Hung 	{ 25000000, 400000000, { .num = 95, .denum = 2, .post_div = 1   } },
38331a90994SDylan Hung 	{ 25000000, 200000000, { .num = 127, .denum = 0, .post_div = 15 } },
38431a90994SDylan Hung 	{ 25000000, 334000000, { .num = 667, .denum = 4, .post_div = 9  } },
385cc476ffcSDylan Hung 	{ 25000000, 1000000000, { .num = 119, .denum = 2, .post_div = 0 } },
386550e691bSryan_chen };
387550e691bSryan_chen 
388550e691bSryan_chen static bool aspeed_get_clock_config_default(ulong input_rate,
389550e691bSryan_chen 					     ulong requested_rate,
39039283ea7Sryan_chen 					     struct ast2600_div_config *cfg)
391550e691bSryan_chen {
392550e691bSryan_chen 	int i;
393550e691bSryan_chen 
394550e691bSryan_chen 	for (i = 0; i < ARRAY_SIZE(aspeed_clock_config_defaults); i++) {
395550e691bSryan_chen 		const struct aspeed_clock_config *default_cfg =
396550e691bSryan_chen 			&aspeed_clock_config_defaults[i];
397550e691bSryan_chen 		if (default_cfg->input_rate == input_rate &&
398550e691bSryan_chen 		    default_cfg->rate == requested_rate) {
399550e691bSryan_chen 			*cfg = default_cfg->cfg;
400550e691bSryan_chen 			return true;
401550e691bSryan_chen 		}
402550e691bSryan_chen 	}
403550e691bSryan_chen 
404550e691bSryan_chen 	return false;
405550e691bSryan_chen }
406550e691bSryan_chen 
407550e691bSryan_chen /*
408550e691bSryan_chen  * @input_rate - the rate of input clock in Hz
409550e691bSryan_chen  * @requested_rate - desired output rate in Hz
410550e691bSryan_chen  * @div - this is an IN/OUT parameter, at input all fields of the config
411550e691bSryan_chen  * need to be set to their maximum allowed values.
412550e691bSryan_chen  * The result (the best config we could find), would also be returned
413550e691bSryan_chen  * in this structure.
414550e691bSryan_chen  *
415550e691bSryan_chen  * @return The clock rate, when the resulting div_config is used.
416550e691bSryan_chen  */
417550e691bSryan_chen static ulong aspeed_calc_clock_config(ulong input_rate, ulong requested_rate,
41839283ea7Sryan_chen 				       struct ast2600_div_config *cfg)
419550e691bSryan_chen {
420550e691bSryan_chen 	/*
421550e691bSryan_chen 	 * The assumption is that kHz precision is good enough and
422550e691bSryan_chen 	 * also enough to avoid overflow when multiplying.
423550e691bSryan_chen 	 */
424550e691bSryan_chen 	const ulong input_rate_khz = input_rate / 1000;
425550e691bSryan_chen 	const ulong rate_khz = requested_rate / 1000;
42639283ea7Sryan_chen 	const struct ast2600_div_config max_vals = *cfg;
42739283ea7Sryan_chen 	struct ast2600_div_config it = { 0, 0, 0 };
428550e691bSryan_chen 	ulong delta = rate_khz;
429550e691bSryan_chen 	ulong new_rate_khz = 0;
430550e691bSryan_chen 
431550e691bSryan_chen 	/*
432550e691bSryan_chen 	 * Look for a well known frequency first.
433550e691bSryan_chen 	 */
434550e691bSryan_chen 	if (aspeed_get_clock_config_default(input_rate, requested_rate, cfg))
435550e691bSryan_chen 		return requested_rate;
436550e691bSryan_chen 
437550e691bSryan_chen 	for (; it.denum <= max_vals.denum; ++it.denum) {
438550e691bSryan_chen 		for (it.post_div = 0; it.post_div <= max_vals.post_div;
439550e691bSryan_chen 		     ++it.post_div) {
440550e691bSryan_chen 			it.num = (rate_khz * (it.post_div + 1) / input_rate_khz)
441550e691bSryan_chen 			    * (it.denum + 1);
442550e691bSryan_chen 			if (it.num > max_vals.num)
443550e691bSryan_chen 				continue;
444550e691bSryan_chen 
445550e691bSryan_chen 			new_rate_khz = (input_rate_khz
446550e691bSryan_chen 					* ((it.num + 1) / (it.denum + 1)))
447550e691bSryan_chen 			    / (it.post_div + 1);
448550e691bSryan_chen 
449550e691bSryan_chen 			/* Keep the rate below requested one. */
450550e691bSryan_chen 			if (new_rate_khz > rate_khz)
451550e691bSryan_chen 				continue;
452550e691bSryan_chen 
453550e691bSryan_chen 			if (new_rate_khz - rate_khz < delta) {
454550e691bSryan_chen 				delta = new_rate_khz - rate_khz;
455550e691bSryan_chen 				*cfg = it;
456550e691bSryan_chen 				if (delta == 0)
457550e691bSryan_chen 					return new_rate_khz * 1000;
458550e691bSryan_chen 			}
459550e691bSryan_chen 		}
460550e691bSryan_chen 	}
461550e691bSryan_chen 
462550e691bSryan_chen 	return new_rate_khz * 1000;
463550e691bSryan_chen }
464550e691bSryan_chen 
465feb42054Sryan_chen static u32 ast2600_configure_ddr(struct ast2600_scu *scu, ulong rate)
466550e691bSryan_chen {
467d6e349c7Sryan_chen 	u32 clkin = AST2600_CLK_IN;
468550e691bSryan_chen 	u32 mpll_reg;
46939283ea7Sryan_chen 	struct ast2600_div_config div_cfg = {
470e9526877SDylan Hung 		.num = 0x1fff,			/* SCU220 bit[12:0] */
471e9526877SDylan Hung 		.denum = 0x3f,			/* SCU220 bit[18:13] */
472e9526877SDylan Hung 		.post_div = 0xf,		/* SCU220 bit[22:19] */
473550e691bSryan_chen 	};
474550e691bSryan_chen 
475550e691bSryan_chen 	aspeed_calc_clock_config(clkin, rate, &div_cfg);
476550e691bSryan_chen 
477feb42054Sryan_chen 	mpll_reg = readl(&scu->m_pll_param);
478e9526877SDylan Hung 	mpll_reg &= ~0x7fffff;
479e9526877SDylan Hung 	mpll_reg |= (div_cfg.post_div << 19)
480e9526877SDylan Hung 	    | (div_cfg.denum << 13)
481e9526877SDylan Hung 	    | (div_cfg.num << 0);
482550e691bSryan_chen 
483feb42054Sryan_chen 	writel(mpll_reg, &scu->m_pll_param);
484550e691bSryan_chen 
485cc476ffcSDylan Hung 	return ast2600_get_pll_rate(scu, ASPEED_CLK_MPLL);
486d6e349c7Sryan_chen }
487d6e349c7Sryan_chen 
488d6e349c7Sryan_chen static ulong ast2600_clk_set_rate(struct clk *clk, ulong rate)
489550e691bSryan_chen {
490f0d895afSryan_chen 	struct ast2600_clk_priv *priv = dev_get_priv(clk->dev);
491550e691bSryan_chen 
492550e691bSryan_chen 	ulong new_rate;
493550e691bSryan_chen 	switch (clk->id) {
494f0d895afSryan_chen 	case ASPEED_CLK_MPLL:
495feb42054Sryan_chen 		new_rate = ast2600_configure_ddr(priv->scu, rate);
496550e691bSryan_chen 		break;
497550e691bSryan_chen 	default:
498550e691bSryan_chen 		return -ENOENT;
499550e691bSryan_chen 	}
500550e691bSryan_chen 
501550e691bSryan_chen 	return new_rate;
502550e691bSryan_chen }
503feb42054Sryan_chen 
504f9aa0ee1Sryan_chen #define SCU_CLKSTOP_MAC1		(20)
505f9aa0ee1Sryan_chen #define SCU_CLKSTOP_MAC2		(21)
506f9aa0ee1Sryan_chen #define SCU_CLKSTOP_MAC3		(20)
507f9aa0ee1Sryan_chen #define SCU_CLKSTOP_MAC4		(21)
508f9aa0ee1Sryan_chen 
509cc476ffcSDylan Hung static u32 ast2600_configure_mac12_clk(struct ast2600_scu *scu)
510cc476ffcSDylan Hung {
511cc476ffcSDylan Hung 	u32 epll_reg;
512cc476ffcSDylan Hung 	u32 clksel;
5134760b3f8SDylan Hung 	u32 clkdelay;
514cc476ffcSDylan Hung 
515cc476ffcSDylan Hung 	struct ast2600_div_config div_cfg = {
516cc476ffcSDylan Hung 		.num = 0x1fff,			/* SCU240 bit[12:0] */
517cc476ffcSDylan Hung 		.denum = 0x3f,			/* SCU240 bit[18:13] */
518cc476ffcSDylan Hung 		.post_div = 0xf,		/* SCU240 bit[22:19] */
519cc476ffcSDylan Hung 	};
520cc476ffcSDylan Hung 
521cc476ffcSDylan Hung 	/* configure E-PLL 1000M */
522cc476ffcSDylan Hung 	aspeed_calc_clock_config(AST2600_CLK_IN, 1000000000, &div_cfg);
523cc476ffcSDylan Hung 	epll_reg = readl(&scu->e_pll_param);
524cc476ffcSDylan Hung 	epll_reg &= ~GENMASK(22, 0);
525cc476ffcSDylan Hung 	epll_reg |= (div_cfg.post_div << 19)
526cc476ffcSDylan Hung 	    | (div_cfg.denum << 13)
527cc476ffcSDylan Hung 	    | (div_cfg.num << 0);
528cc476ffcSDylan Hung 
529cc476ffcSDylan Hung 	writel(epll_reg, &scu->e_pll_param);
530cc476ffcSDylan Hung 
531cc476ffcSDylan Hung 	/* select MAC#1 and MAC#2 clock source = EPLL / 8 */
532cc476ffcSDylan Hung 	clksel = readl(&scu->clk_sel2);
533cc476ffcSDylan Hung 	clksel &= ~BIT(23);
534cc476ffcSDylan Hung 	clksel |= 0x7 << 20;
535cc476ffcSDylan Hung 	writel(clksel, &scu->clk_sel2);
536cc476ffcSDylan Hung 
5374760b3f8SDylan Hung 	/*
5384760b3f8SDylan Hung 	BIT(31): select RGMII 125M from internal source
5394760b3f8SDylan Hung 	BIT(28): RGMII 125M output enable
5404760b3f8SDylan Hung 	BIT(25:0): 1G default delay
5414760b3f8SDylan Hung 	*/
5424760b3f8SDylan Hung 	clkdelay = MAC_DEF_DELAY_1G | BIT(31) | BIT(28);
5434760b3f8SDylan Hung 	writel(clkdelay, &scu->mac12_clk_delay);
5444760b3f8SDylan Hung 
5454760b3f8SDylan Hung 	/* set 100M/10M default delay */
5464760b3f8SDylan Hung 	writel(MAC_DEF_DELAY_100M, &scu->mac12_clk_delay_100M);
5474760b3f8SDylan Hung 	writel(MAC_DEF_DELAY_10M, &scu->mac12_clk_delay_10M);
548cc476ffcSDylan Hung 
549ed30249cSDylan Hung 	/* MAC AHB = HPLL / 6 */
550894c19cfSDylan Hung 	clksel = readl(&scu->clk_sel1);
551894c19cfSDylan Hung 	clksel &= ~GENMASK(18, 16);
552ed30249cSDylan Hung 	clksel |= 0x2 << 16;
553894c19cfSDylan Hung 	writel(clksel, &scu->clk_sel1);
554894c19cfSDylan Hung 
555cc476ffcSDylan Hung 	return 0;
556cc476ffcSDylan Hung }
557cc476ffcSDylan Hung 
558*54f9cba1SDylan Hung static u32 ast2600_configure_mac34_clk(struct ast2600_scu *scu)
559*54f9cba1SDylan Hung {
560*54f9cba1SDylan Hung 	u32 reg;
561*54f9cba1SDylan Hung 
562*54f9cba1SDylan Hung 	ast2600_configure_mac12_clk(scu);
563*54f9cba1SDylan Hung 
564*54f9cba1SDylan Hung 	/*
565*54f9cba1SDylan Hung 	BIT[31]   RGMII 125M source: 0 = from IO pin
566*54f9cba1SDylan Hung 	BIT[25:0] MAC 1G delay
567*54f9cba1SDylan Hung 	*/
568*54f9cba1SDylan Hung 	reg = readl(&scu->mac34_clk_delay);
569*54f9cba1SDylan Hung 	reg &= ~(BIT(31) | GENMASK(25, 0));
570*54f9cba1SDylan Hung 	reg |= MAC34_DEF_DELAY_1G;
571*54f9cba1SDylan Hung 	writel(reg, &scu->mac34_clk_delay);
572*54f9cba1SDylan Hung 	writel(MAC34_DEF_DELAY_100M, &scu->mac34_clk_delay_100M);
573*54f9cba1SDylan Hung 	writel(MAC34_DEF_DELAY_10M, &scu->mac34_clk_delay_10M);
574*54f9cba1SDylan Hung 
575*54f9cba1SDylan Hung 	/* clock source seletion and divider */
576*54f9cba1SDylan Hung 	reg = readl(&scu->clk_sel4);
577*54f9cba1SDylan Hung 	reg &= ~GENMASK(26, 24);	/* MAC AHB = HCLK / 2 */
578*54f9cba1SDylan Hung 	reg &= ~GENMASK(18, 16);
579*54f9cba1SDylan Hung 	reg |= 0x3 << 16;		/* RMII 50M = SLICLK_200M / 4 */
580*54f9cba1SDylan Hung 	writel(reg, &scu->clk_sel4);
581*54f9cba1SDylan Hung 
582*54f9cba1SDylan Hung 	/* set driving strength */
583*54f9cba1SDylan Hung 	reg = readl(&scu->pinmux_ctrl16);
584*54f9cba1SDylan Hung 	reg &= GENMASK(3, 0);
585*54f9cba1SDylan Hung 	reg |= (0x2 << 0) | (0x2 << 2);
586*54f9cba1SDylan Hung 	writel(reg, &scu->pinmux_ctrl16);
587*54f9cba1SDylan Hung 
588*54f9cba1SDylan Hung 	return 0;
589*54f9cba1SDylan Hung }
590*54f9cba1SDylan Hung #if 0
591*54f9cba1SDylan Hung /**
592*54f9cba1SDylan Hung  * WIP: ast2600 RGMII clock source tree
593*54f9cba1SDylan Hung  *
594*54f9cba1SDylan Hung  *    125M from external PAD -------->|\
595*54f9cba1SDylan Hung  *    HPLL -->|\                      | |---->RGMII 125M for MAC#1 & MAC#2
596*54f9cba1SDylan Hung  *            | |---->| divider |---->|/                             +
597*54f9cba1SDylan Hung  *    EPLL -->|/                                                     |
598*54f9cba1SDylan Hung  *                                                                   |
599*54f9cba1SDylan Hung  *    +---------<-----------|PAD output enable|<---------------------+
600*54f9cba1SDylan Hung  *    |
601*54f9cba1SDylan Hung  *    +--->|PAD input enable|----->|\
602*54f9cba1SDylan Hung  *                                 | |----> RGMII 125M for MAC#3 & MAC#4
603*54f9cba1SDylan Hung  *    SLICLK 200M -->|divider|---->|/
604*54f9cba1SDylan Hung */
605*54f9cba1SDylan Hung struct ast2600_rgmii_clk_config {
606*54f9cba1SDylan Hung 	u32 mac_1_2_src;	/* 0=external PAD, 1=internal PLL */
607*54f9cba1SDylan Hung 	u32 int_clk_src;	/* 0=EPLL, 1=HPLL */
608*54f9cba1SDylan Hung 	u32 int_clk_div;
609*54f9cba1SDylan Hung 
610*54f9cba1SDylan Hung 	u32 mac_3_4_src;	/* 0=external PAD, 1=SLICLK */
611*54f9cba1SDylan Hung 	u32 sli_clk_div;	/* reserved */
612*54f9cba1SDylan Hung };
613*54f9cba1SDylan Hung 
614*54f9cba1SDylan Hung static void ast2600_init_rgmii_clk(struct ast2600_scu *scu, int index)
615*54f9cba1SDylan Hung {
616*54f9cba1SDylan Hung 	debug("%s not ready\n", __func__);
617*54f9cba1SDylan Hung }
618*54f9cba1SDylan Hung 
619*54f9cba1SDylan Hung static void ast2600_init_rmii_clk(struct ast2600_scu *scu, int index)
620*54f9cba1SDylan Hung {
621*54f9cba1SDylan Hung 	debug("%s not ready\n", __func__);
622*54f9cba1SDylan Hung }
623*54f9cba1SDylan Hung #endif
624f9aa0ee1Sryan_chen static u32 ast2600_configure_mac(struct ast2600_scu *scu, int index)
625f9aa0ee1Sryan_chen {
626f9aa0ee1Sryan_chen 	u32 reset_bit;
627f9aa0ee1Sryan_chen 	u32 clkstop_bit;
628f9aa0ee1Sryan_chen 
629cc476ffcSDylan Hung 	if (index < 3)
630cc476ffcSDylan Hung 		ast2600_configure_mac12_clk(scu);
631cc476ffcSDylan Hung 	else
632cc476ffcSDylan Hung 		ast2600_configure_mac34_clk(scu);
633f9aa0ee1Sryan_chen 
634f9aa0ee1Sryan_chen 	switch (index) {
635f9aa0ee1Sryan_chen 	case 1:
636f9aa0ee1Sryan_chen 		reset_bit = BIT(ASPEED_RESET_MAC1);
637f9aa0ee1Sryan_chen 		clkstop_bit = BIT(SCU_CLKSTOP_MAC1);
638f9aa0ee1Sryan_chen 		writel(reset_bit, &scu->sysreset_ctrl1);
639f9aa0ee1Sryan_chen 		udelay(100);
640f9aa0ee1Sryan_chen 		writel(clkstop_bit, &scu->clk_stop_clr_ctrl1);
641f9aa0ee1Sryan_chen 		mdelay(10);
642f9aa0ee1Sryan_chen 		writel(reset_bit, &scu->sysreset_clr_ctrl1);
643f9aa0ee1Sryan_chen 
644f9aa0ee1Sryan_chen 		break;
645f9aa0ee1Sryan_chen 	case 2:
646f9aa0ee1Sryan_chen 		reset_bit = BIT(ASPEED_RESET_MAC2);
647f9aa0ee1Sryan_chen 		clkstop_bit = BIT(SCU_CLKSTOP_MAC2);
648f9aa0ee1Sryan_chen 		writel(reset_bit, &scu->sysreset_ctrl1);
649f9aa0ee1Sryan_chen 		udelay(100);
650f9aa0ee1Sryan_chen 		writel(clkstop_bit, &scu->clk_stop_clr_ctrl1);
651f9aa0ee1Sryan_chen 		mdelay(10);
652f9aa0ee1Sryan_chen 		writel(reset_bit, &scu->sysreset_clr_ctrl1);
653f9aa0ee1Sryan_chen 		break;
654f9aa0ee1Sryan_chen 	case 3:
655f9aa0ee1Sryan_chen 		reset_bit = BIT(ASPEED_RESET_MAC3 - 32);
656f9aa0ee1Sryan_chen 		clkstop_bit = BIT(SCU_CLKSTOP_MAC3);
657f9aa0ee1Sryan_chen 		writel(reset_bit, &scu->sysreset_ctrl2);
658f9aa0ee1Sryan_chen 		udelay(100);
659f9aa0ee1Sryan_chen 		writel(clkstop_bit, &scu->clk_stop_clr_ctrl2);
660f9aa0ee1Sryan_chen 		mdelay(10);
661f9aa0ee1Sryan_chen 		writel(reset_bit, &scu->sysreset_clr_ctrl2);
662f9aa0ee1Sryan_chen 		break;
663f9aa0ee1Sryan_chen 	case 4:
664f9aa0ee1Sryan_chen 		reset_bit = BIT(ASPEED_RESET_MAC4 - 32);
665f9aa0ee1Sryan_chen 		clkstop_bit = BIT(SCU_CLKSTOP_MAC4);
666f9aa0ee1Sryan_chen 		writel(reset_bit, &scu->sysreset_ctrl2);
667f9aa0ee1Sryan_chen 		udelay(100);
668f9aa0ee1Sryan_chen 		writel(clkstop_bit, &scu->clk_stop_clr_ctrl2);
669f9aa0ee1Sryan_chen 		mdelay(10);
670f9aa0ee1Sryan_chen 		writel(reset_bit, &scu->sysreset_clr_ctrl2);
671f9aa0ee1Sryan_chen 		break;
672f9aa0ee1Sryan_chen 	default:
673f9aa0ee1Sryan_chen 		return -EINVAL;
674f9aa0ee1Sryan_chen 	}
675f9aa0ee1Sryan_chen 
676f9aa0ee1Sryan_chen 	return 0;
677f9aa0ee1Sryan_chen }
678550e691bSryan_chen 
679f51926eeSryan_chen #define SCU_CLKSTOP_SDIO 4
680f51926eeSryan_chen static ulong ast2600_enable_sdclk(struct ast2600_scu *scu)
681f51926eeSryan_chen {
682f51926eeSryan_chen 	u32 reset_bit;
683f51926eeSryan_chen 	u32 clkstop_bit;
684f51926eeSryan_chen 
685f51926eeSryan_chen 	reset_bit = BIT(ASPEED_RESET_SD - 32);
686f51926eeSryan_chen 	clkstop_bit = BIT(SCU_CLKSTOP_SDIO);
687f51926eeSryan_chen 
688f51926eeSryan_chen 	writel(reset_bit, &scu->sysreset_clr_ctrl2);
689f51926eeSryan_chen 	udelay(100);
690f51926eeSryan_chen 	//enable clk
691f51926eeSryan_chen 	writel(clkstop_bit, &scu->clk_stop_clr_ctrl2);
692f51926eeSryan_chen 	mdelay(10);
693f51926eeSryan_chen 	writel(reset_bit, &scu->sysreset_ctrl2);
694f51926eeSryan_chen 
695f51926eeSryan_chen 	return 0;
696f51926eeSryan_chen }
697f51926eeSryan_chen 
698f51926eeSryan_chen #define SCU_CLKSTOP_EXTSD 31
699f51926eeSryan_chen #define SCU_CLK_SD_MASK				(0x7 << 28)
700f51926eeSryan_chen #define SCU_CLK_SD_DIV(x)			(x << 28)
701f51926eeSryan_chen 
702f51926eeSryan_chen static ulong ast2600_enable_extsdclk(struct ast2600_scu *scu)
703f51926eeSryan_chen {
704f51926eeSryan_chen 	u32 clk_sel = readl(&scu->clk_sel4);
705f51926eeSryan_chen 	u32 enableclk_bit;
706f51926eeSryan_chen 
707f51926eeSryan_chen 	enableclk_bit = BIT(SCU_CLKSTOP_EXTSD);
708f51926eeSryan_chen 
709f51926eeSryan_chen 	clk_sel &= ~SCU_CLK_SD_MASK;
710f51926eeSryan_chen 	clk_sel |= SCU_CLK_SD_DIV(0);
711f51926eeSryan_chen 	writel(clk_sel, &scu->clk_sel4);
712f51926eeSryan_chen 
713f51926eeSryan_chen 	//enable clk
714f51926eeSryan_chen 	setbits_le32(&scu->clk_sel4, enableclk_bit);
715f51926eeSryan_chen 
716f51926eeSryan_chen 	return 0;
717f51926eeSryan_chen }
718f51926eeSryan_chen 
719f51926eeSryan_chen #define SCU_CLKSTOP_EMMC 27
720f51926eeSryan_chen static ulong ast2600_enable_emmcclk(struct ast2600_scu *scu)
721f51926eeSryan_chen {
722f51926eeSryan_chen 	u32 reset_bit;
723f51926eeSryan_chen 	u32 clkstop_bit;
724f51926eeSryan_chen 
725f51926eeSryan_chen 	reset_bit = BIT(ASPEED_RESET_EMMC);
726f51926eeSryan_chen 	clkstop_bit = BIT(SCU_CLKSTOP_EMMC);
727f51926eeSryan_chen 
728f51926eeSryan_chen 	writel(reset_bit, &scu->sysreset_clr_ctrl1);
729f51926eeSryan_chen 	udelay(100);
730f51926eeSryan_chen 	//enable clk
731f51926eeSryan_chen 	writel(clkstop_bit, &scu->clk_stop_clr_ctrl1);
732f51926eeSryan_chen 	mdelay(10);
733f51926eeSryan_chen 	writel(reset_bit, &scu->sysreset_ctrl2);
734f51926eeSryan_chen 
735f51926eeSryan_chen 	return 0;
736f51926eeSryan_chen }
737f51926eeSryan_chen 
738f51926eeSryan_chen #define SCU_CLKSTOP_EXTEMMC 15
739f51926eeSryan_chen #define SCU_CLK_EMMC_MASK			(0x7 << 12)
740f51926eeSryan_chen #define SCU_CLK_EMMC_DIV(x)			(x << 12)
741f51926eeSryan_chen 
742f51926eeSryan_chen static ulong ast2600_enable_extemmcclk(struct ast2600_scu *scu)
743f51926eeSryan_chen {
744f51926eeSryan_chen 	u32 clk_sel = readl(&scu->clk_sel1);
745f51926eeSryan_chen 	u32 enableclk_bit;
746f51926eeSryan_chen 
747f51926eeSryan_chen 	enableclk_bit = BIT(SCU_CLKSTOP_EXTSD);
748f51926eeSryan_chen 
749f51926eeSryan_chen 	clk_sel &= ~SCU_CLK_SD_MASK;
750f51926eeSryan_chen 	clk_sel |= SCU_CLK_SD_DIV(1);
751f51926eeSryan_chen 	writel(clk_sel, &scu->clk_sel1);
752f51926eeSryan_chen 
753f51926eeSryan_chen 	//enable clk
754f51926eeSryan_chen 	setbits_le32(&scu->clk_sel1, enableclk_bit);
755f51926eeSryan_chen 
756f51926eeSryan_chen 	return 0;
757f51926eeSryan_chen }
758f51926eeSryan_chen 
759d6e349c7Sryan_chen static int ast2600_clk_enable(struct clk *clk)
760550e691bSryan_chen {
761f0d895afSryan_chen 	struct ast2600_clk_priv *priv = dev_get_priv(clk->dev);
762550e691bSryan_chen 
763550e691bSryan_chen 	switch (clk->id) {
76486f91560Sryan_chen 		case ASPEED_CLK_GATE_MAC1CLK:
76586f91560Sryan_chen 			ast2600_configure_mac(priv->scu, 1);
766550e691bSryan_chen 			break;
76786f91560Sryan_chen 		case ASPEED_CLK_GATE_MAC2CLK:
76886f91560Sryan_chen 			ast2600_configure_mac(priv->scu, 2);
769550e691bSryan_chen 			break;
77077843939Sryan_chen 		case ASPEED_CLK_GATE_MAC3CLK:
77177843939Sryan_chen 			ast2600_configure_mac(priv->scu, 3);
77277843939Sryan_chen 			break;
77377843939Sryan_chen 		case ASPEED_CLK_GATE_MAC4CLK:
77477843939Sryan_chen 			ast2600_configure_mac(priv->scu, 4);
77577843939Sryan_chen 			break;
776f51926eeSryan_chen 		case ASPEED_CLK_GATE_SDCLK:
777f51926eeSryan_chen 			ast2600_enable_sdclk(priv->scu);
778f51926eeSryan_chen 			break;
779f51926eeSryan_chen 		case ASPEED_CLK_GATE_SDEXTCLK:
780f51926eeSryan_chen 			ast2600_enable_extsdclk(priv->scu);
781f51926eeSryan_chen 			break;
782f51926eeSryan_chen 		case ASPEED_CLK_GATE_EMMCCLK:
783f51926eeSryan_chen 			ast2600_enable_emmcclk(priv->scu);
784f51926eeSryan_chen 			break;
785f51926eeSryan_chen 		case ASPEED_CLK_GATE_EMMCEXTCLK:
786f51926eeSryan_chen 			ast2600_enable_extemmcclk(priv->scu);
787f51926eeSryan_chen 			break;
788550e691bSryan_chen 		default:
789f9aa0ee1Sryan_chen 			pr_debug("can't enable clk \n");
790550e691bSryan_chen 			return -ENOENT;
79177843939Sryan_chen 			break;
792550e691bSryan_chen 	}
793550e691bSryan_chen 
794550e691bSryan_chen 	return 0;
795550e691bSryan_chen }
796550e691bSryan_chen 
797f9aa0ee1Sryan_chen struct clk_ops ast2600_clk_ops = {
798d6e349c7Sryan_chen 	.get_rate = ast2600_clk_get_rate,
799d6e349c7Sryan_chen 	.set_rate = ast2600_clk_set_rate,
800d6e349c7Sryan_chen 	.enable = ast2600_clk_enable,
801550e691bSryan_chen };
802550e691bSryan_chen 
803d6e349c7Sryan_chen static int ast2600_clk_probe(struct udevice *dev)
804550e691bSryan_chen {
805f0d895afSryan_chen 	struct ast2600_clk_priv *priv = dev_get_priv(dev);
806550e691bSryan_chen 
807f0d895afSryan_chen 	priv->scu = devfdt_get_addr_ptr(dev);
808f0d895afSryan_chen 	if (IS_ERR(priv->scu))
809f0d895afSryan_chen 		return PTR_ERR(priv->scu);
810550e691bSryan_chen 
811550e691bSryan_chen 	return 0;
812550e691bSryan_chen }
813550e691bSryan_chen 
814d6e349c7Sryan_chen static int ast2600_clk_bind(struct udevice *dev)
815550e691bSryan_chen {
816550e691bSryan_chen 	int ret;
817550e691bSryan_chen 
818550e691bSryan_chen 	/* The reset driver does not have a device node, so bind it here */
819550e691bSryan_chen 	ret = device_bind_driver(gd->dm_root, "ast_sysreset", "reset", &dev);
820550e691bSryan_chen 	if (ret)
821550e691bSryan_chen 		debug("Warning: No reset driver: ret=%d\n", ret);
822550e691bSryan_chen 
823550e691bSryan_chen 	return 0;
824550e691bSryan_chen }
825550e691bSryan_chen 
826d35ac78cSryan_chen #if CONFIG_IS_ENABLED(CMD_CLK)
827d35ac78cSryan_chen struct aspeed_clks {
828d35ac78cSryan_chen 	ulong id;
829d35ac78cSryan_chen 	const char *name;
830d35ac78cSryan_chen };
831d35ac78cSryan_chen 
832d35ac78cSryan_chen static struct aspeed_clks aspeed_clk_names[] = {
833d35ac78cSryan_chen 	{ ASPEED_CLK_HPLL, "hpll" },
834d35ac78cSryan_chen 	{ ASPEED_CLK_MPLL, "mpll" },
835d35ac78cSryan_chen 	{ ASPEED_CLK_APLL, "apll" },
836d35ac78cSryan_chen 	{ ASPEED_CLK_EPLL, "epll" },
837d35ac78cSryan_chen 	{ ASPEED_CLK_DPLL, "dpll" },
838d35ac78cSryan_chen 	{ ASPEED_CLK_AHB, "hclk" },
839d35ac78cSryan_chen 	{ ASPEED_CLK_APB, "pclk" },
840d35ac78cSryan_chen };
841d35ac78cSryan_chen 
842d35ac78cSryan_chen int soc_clk_dump(void)
843d35ac78cSryan_chen {
844d35ac78cSryan_chen 	struct udevice *dev;
845d35ac78cSryan_chen 	struct clk clk;
846d35ac78cSryan_chen 	unsigned long rate;
847d35ac78cSryan_chen 	int i, ret;
848d35ac78cSryan_chen 
849d35ac78cSryan_chen 	ret = uclass_get_device_by_driver(UCLASS_CLK,
850d35ac78cSryan_chen 					  DM_GET_DRIVER(aspeed_scu), &dev);
851d35ac78cSryan_chen 	if (ret)
852d35ac78cSryan_chen 		return ret;
853d35ac78cSryan_chen 
854d35ac78cSryan_chen 	printf("Clk\t\tHz\n");
855d35ac78cSryan_chen 
856d35ac78cSryan_chen 	for (i = 0; i < ARRAY_SIZE(aspeed_clk_names); i++) {
857d35ac78cSryan_chen 		clk.id = aspeed_clk_names[i].id;
858d35ac78cSryan_chen 		ret = clk_request(dev, &clk);
859d35ac78cSryan_chen 		if (ret < 0) {
860d35ac78cSryan_chen 			debug("%s clk_request() failed: %d\n", __func__, ret);
861d35ac78cSryan_chen 			continue;
862d35ac78cSryan_chen 		}
863d35ac78cSryan_chen 
864d35ac78cSryan_chen 		ret = clk_get_rate(&clk);
865d35ac78cSryan_chen 		rate = ret;
866d35ac78cSryan_chen 
867d35ac78cSryan_chen 		clk_free(&clk);
868d35ac78cSryan_chen 
869d35ac78cSryan_chen 		if (ret == -ENOTSUPP) {
870d35ac78cSryan_chen 			printf("clk ID %lu not supported yet\n",
871d35ac78cSryan_chen 			       aspeed_clk_names[i].id);
872d35ac78cSryan_chen 			continue;
873d35ac78cSryan_chen 		}
874d35ac78cSryan_chen 		if (ret < 0) {
875d35ac78cSryan_chen 			printf("%s %lu: get_rate err: %d\n",
876d35ac78cSryan_chen 			       __func__, aspeed_clk_names[i].id, ret);
877d35ac78cSryan_chen 			continue;
878d35ac78cSryan_chen 		}
879d35ac78cSryan_chen 
880d35ac78cSryan_chen 		printf("%s(%3lu):\t%lu\n",
881d35ac78cSryan_chen 		       aspeed_clk_names[i].name, aspeed_clk_names[i].id, rate);
882d35ac78cSryan_chen 	}
883d35ac78cSryan_chen 
884d35ac78cSryan_chen 	return 0;
885d35ac78cSryan_chen }
886d35ac78cSryan_chen #endif
887d35ac78cSryan_chen 
888d6e349c7Sryan_chen static const struct udevice_id ast2600_clk_ids[] = {
889d6e349c7Sryan_chen 	{ .compatible = "aspeed,ast2600-scu", },
890550e691bSryan_chen 	{ }
891550e691bSryan_chen };
892550e691bSryan_chen 
893aa36597fSDylan Hung U_BOOT_DRIVER(aspeed_scu) = {
894aa36597fSDylan Hung 	.name		= "aspeed_scu",
895550e691bSryan_chen 	.id		= UCLASS_CLK,
896d6e349c7Sryan_chen 	.of_match	= ast2600_clk_ids,
897f0d895afSryan_chen 	.priv_auto_alloc_size = sizeof(struct ast2600_clk_priv),
898f9aa0ee1Sryan_chen 	.ops		= &ast2600_clk_ops,
899d6e349c7Sryan_chen 	.bind		= ast2600_clk_bind,
900d6e349c7Sryan_chen 	.probe		= ast2600_clk_probe,
901550e691bSryan_chen };
902