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