1 /*
2  * Copyright 2014 Broadcom Corporation.
3  *
4  * SPDX-License-Identifier:	GPL-2.0+
5  */
6 
7 #include <common.h>
8 #include <asm/io.h>
9 #include <asm/iproc-common/armpll.h>
10 #include <asm/iproc-common/sysmap.h>
11 
12 #define NELEMS(x)	(sizeof(x) / sizeof(x[0]))
13 
14 struct armpll_parameters {
15 	unsigned int mode;
16 	unsigned int ndiv_int;
17 	unsigned int ndiv_frac;
18 	unsigned int pdiv;
19 	unsigned int freqid;
20 };
21 
22 struct armpll_parameters armpll_clk_tab[] = {
23 	{   25, 64,      1, 1, 0},
24 	{  100, 64,      1, 1, 2},
25 	{  400, 64,      1, 1, 6},
26 	{  448, 71, 713050, 1, 6},
27 	{  500, 80,      1, 1, 6},
28 	{  560, 89, 629145, 1, 6},
29 	{  600, 96,      1, 1, 6},
30 	{  800, 64,      1, 1, 7},
31 	{  896, 71, 713050, 1, 7},
32 	{ 1000, 80,      1, 1, 7},
33 	{ 1100, 88,      1, 1, 7},
34 	{ 1120, 89, 629145, 1, 7},
35 	{ 1200, 96,      1, 1, 7},
36 };
37 
38 uint32_t armpll_config(uint32_t clkmhz)
39 {
40 	uint32_t freqid;
41 	uint32_t ndiv_frac;
42 	uint32_t pll;
43 	uint32_t status = 1;
44 	uint32_t timeout_countdown;
45 	int i;
46 
47 	for (i = 0; i < NELEMS(armpll_clk_tab); i++) {
48 		if (armpll_clk_tab[i].mode == clkmhz) {
49 			status = 0;
50 			break;
51 		}
52 	}
53 
54 	if (status) {
55 		printf("Error: Clock configuration not supported\n");
56 		goto armpll_config_done;
57 	}
58 
59 	/* Enable write access */
60 	writel(IPROC_REG_WRITE_ACCESS, IHOST_PROC_CLK_WR_ACCESS);
61 
62 	if (clkmhz == 25)
63 		freqid = 0;
64 	else
65 		freqid = 2;
66 
67 	/* Bypass ARM clock and run on sysclk */
68 	writel(1 << IHOST_PROC_CLK_POLICY_FREQ__PRIV_ACCESS_MODE |
69 	       freqid << IHOST_PROC_CLK_POLICY_FREQ__POLICY3_FREQ_R |
70 	       freqid << IHOST_PROC_CLK_POLICY_FREQ__POLICY2_FREQ_R |
71 	       freqid << IHOST_PROC_CLK_POLICY_FREQ__POLICY1_FREQ_R |
72 	       freqid << IHOST_PROC_CLK_POLICY_FREQ__POLICY0_FREQ_R,
73 	       IHOST_PROC_CLK_POLICY_FREQ);
74 
75 	writel(1 << IHOST_PROC_CLK_POLICY_CTL__GO |
76 	       1 << IHOST_PROC_CLK_POLICY_CTL__GO_AC,
77 	       IHOST_PROC_CLK_POLICY_CTL);
78 
79 	/* Poll CCU until operation complete */
80 	timeout_countdown = 0x100000;
81 	while (readl(IHOST_PROC_CLK_POLICY_CTL) &
82 	       (1 << IHOST_PROC_CLK_POLICY_CTL__GO)) {
83 		timeout_countdown--;
84 		if (timeout_countdown == 0) {
85 			printf("CCU polling timedout\n");
86 			status = 1;
87 			goto armpll_config_done;
88 		}
89 	}
90 
91 	if (clkmhz == 25 || clkmhz == 100) {
92 		status = 0;
93 		goto armpll_config_done;
94 	}
95 
96 	/* Now it is safe to program the PLL */
97 	pll = readl(IHOST_PROC_CLK_PLLARMB);
98 	pll &= ~((1 << IHOST_PROC_CLK_PLLARMB__PLLARM_NDIV_FRAC_WIDTH) - 1);
99 	ndiv_frac =
100 		((1 << IHOST_PROC_CLK_PLLARMB__PLLARM_NDIV_FRAC_WIDTH) - 1) &
101 		 (armpll_clk_tab[i].ndiv_frac <<
102 		 IHOST_PROC_CLK_PLLARMB__PLLARM_NDIV_FRAC_R);
103 	pll |= ndiv_frac;
104 	writel(pll, IHOST_PROC_CLK_PLLARMB);
105 
106 	writel(1 << IHOST_PROC_CLK_PLLARMA__PLLARM_LOCK |
107 	       armpll_clk_tab[i].ndiv_int <<
108 			IHOST_PROC_CLK_PLLARMA__PLLARM_NDIV_INT_R |
109 	       armpll_clk_tab[i].pdiv <<
110 			IHOST_PROC_CLK_PLLARMA__PLLARM_PDIV_R |
111 	       1 << IHOST_PROC_CLK_PLLARMA__PLLARM_SOFT_RESETB,
112 	       IHOST_PROC_CLK_PLLARMA);
113 
114 	/* Poll ARM PLL Lock until operation complete */
115 	timeout_countdown = 0x100000;
116 	while (readl(IHOST_PROC_CLK_PLLARMA) &
117 	       (1 << IHOST_PROC_CLK_PLLARMA__PLLARM_LOCK)) {
118 		timeout_countdown--;
119 		if (timeout_countdown == 0) {
120 			printf("ARM PLL lock failed\n");
121 			status = 1;
122 			goto armpll_config_done;
123 		}
124 	}
125 
126 	pll = readl(IHOST_PROC_CLK_PLLARMA);
127 	pll |= (1 << IHOST_PROC_CLK_PLLARMA__PLLARM_SOFT_POST_RESETB);
128 	writel(pll, IHOST_PROC_CLK_PLLARMA);
129 
130 	/* Set the policy */
131 	writel(1 << IHOST_PROC_CLK_POLICY_FREQ__PRIV_ACCESS_MODE |
132 	       armpll_clk_tab[i].freqid <<
133 			IHOST_PROC_CLK_POLICY_FREQ__POLICY3_FREQ_R |
134 	       armpll_clk_tab[i].freqid <<
135 			IHOST_PROC_CLK_POLICY_FREQ__POLICY2_FREQ_R |
136 	       armpll_clk_tab[i].freqid <<
137 			IHOST_PROC_CLK_POLICY_FREQ__POLICY1_FREQ_R |
138 	       armpll_clk_tab[i+4].freqid <<
139 			IHOST_PROC_CLK_POLICY_FREQ__POLICY0_FREQ_R,
140 	       IHOST_PROC_CLK_POLICY_FREQ);
141 
142 	writel(IPROC_CLKCT_HDELAY_SW_EN, IHOST_PROC_CLK_CORE0_CLKGATE);
143 	writel(IPROC_CLKCT_HDELAY_SW_EN, IHOST_PROC_CLK_CORE1_CLKGATE);
144 	writel(IPROC_CLKCT_HDELAY_SW_EN, IHOST_PROC_CLK_ARM_SWITCH_CLKGATE);
145 	writel(IPROC_CLKCT_HDELAY_SW_EN, IHOST_PROC_CLK_ARM_PERIPH_CLKGATE);
146 	writel(IPROC_CLKCT_HDELAY_SW_EN, IHOST_PROC_CLK_APB0_CLKGATE);
147 
148 	writel(1 << IHOST_PROC_CLK_POLICY_CTL__GO |
149 	       1 << IHOST_PROC_CLK_POLICY_CTL__GO_AC,
150 	       IHOST_PROC_CLK_POLICY_CTL);
151 
152 	/* Poll CCU until operation complete */
153 	timeout_countdown = 0x100000;
154 	while (readl(IHOST_PROC_CLK_POLICY_CTL) &
155 	       (1 << IHOST_PROC_CLK_POLICY_CTL__GO)) {
156 		timeout_countdown--;
157 		if (timeout_countdown == 0) {
158 			printf("CCU polling failed\n");
159 			status = 1;
160 			goto armpll_config_done;
161 		}
162 	}
163 
164 	status = 0;
165 armpll_config_done:
166 	/* Disable access to PLL registers */
167 	writel(0, IHOST_PROC_CLK_WR_ACCESS);
168 
169 	return status;
170 }
171