1 /*
2 * Copyright (c) 2016-2020, Broadcom
3 *
4 * SPDX-License-Identifier: BSD-3-Clause
5 */
6
7 #include <stdint.h>
8
9 #include <common/debug.h>
10 #include <lib/mmio.h>
11
12 #include <dmu.h>
13
14 #define IHOST0_CONFIG_ROOT 0x66000000
15 #define IHOST1_CONFIG_ROOT 0x66002000
16 #define IHOST2_CONFIG_ROOT 0x66004000
17 #define IHOST3_CONFIG_ROOT 0x66006000
18 #define A72_CRM_PLL_PWR_ON 0x00000070
19 #define A72_CRM_PLL_PWR_ON__PLL0_RESETB_R 4
20 #define A72_CRM_PLL_PWR_ON__PLL0_POST_RESETB_R 5
21 #define A72_CRM_PLL_CHNL_BYPS_EN 0x000000ac
22 #define A72_CRM_PLL_CHNL_BYPS_EN__PLL_0_CHNL_0_BYPS_EN_R 0
23 #define A72_CRM_PLL_CHNL_BYPS_EN_DATAMASK 0x0000ec1f
24 #define A72_CRM_PLL_CMD 0x00000080
25 #define A72_CRM_PLL_CMD__UPDATE_PLL0_FREQUENCY_VCO_R 0
26 #define A72_CRM_PLL_CMD__UPDATE_PLL0_FREQUENCY_POST_R 1
27 #define A72_CRM_PLL_STATUS 0x00000084
28 #define A72_CRM_PLL_STATUS__PLL0_LOCK_R 9
29 #define A72_CRM_PLL0_CTRL1 0x00000100
30 #define A72_CRM_PLL0_CTRL2 0x00000104
31 #define A72_CRM_PLL0_CTRL3 0x00000108
32 #define A72_CRM_PLL0_CTRL3__PLL0_PDIV_R 12
33 #define A72_CRM_PLL0_CTRL4 0x0000010c
34 #define A72_CRM_PLL0_CTRL4__PLL0_KP_R 0
35 #define A72_CRM_PLL0_CTRL4__PLL0_KI_R 4
36 #define A72_CRM_PLL0_CTRL4__PLL0_KA_R 7
37 #define A72_CRM_PLL0_CTRL4__PLL0_FREFEFF_INFO_R 10
38
39 #define PLL_MODE_VCO 0x0
40 #define PLL_MODE_BYPASS 0x1
41 #define PLL_RESET_TYPE_PLL 0x1
42 #define PLL_RESET_TYPE_POST 0x2
43 #define PLL_VCO 0x1
44 #define PLL_POSTDIV 0x2
45 #define ARM_FREQ_3G PLL_FREQ_FULL
46 #define ARM_FREQ_1P5G PLL_FREQ_HALF
47 #define ARM_FREQ_750M PLL_FREQ_QRTR
48
ARMCOE_crm_getBaseAddress(unsigned int cluster_num)49 static unsigned int ARMCOE_crm_getBaseAddress(unsigned int cluster_num)
50 {
51 unsigned int ihostx_config_root;
52
53 switch (cluster_num) {
54 case 0:
55 default:
56 ihostx_config_root = IHOST0_CONFIG_ROOT;
57 break;
58 case 1:
59 ihostx_config_root = IHOST1_CONFIG_ROOT;
60 break;
61 case 2:
62 ihostx_config_root = IHOST2_CONFIG_ROOT;
63 break;
64 case 3:
65 ihostx_config_root = IHOST3_CONFIG_ROOT;
66 break;
67 }
68
69 return ihostx_config_root;
70 }
71
ARMCOE_crm_pllAssertReset(unsigned int cluster_num,unsigned int reset_type)72 static void ARMCOE_crm_pllAssertReset(unsigned int cluster_num,
73 unsigned int reset_type)
74 {
75 unsigned long ihostx_config_root;
76 unsigned int pll_rst_ctrl;
77
78 ihostx_config_root = ARMCOE_crm_getBaseAddress(cluster_num);
79 pll_rst_ctrl = mmio_read_32(ihostx_config_root + A72_CRM_PLL_PWR_ON);
80
81 // PLL reset
82 if (reset_type & PLL_RESET_TYPE_PLL) {
83 pll_rst_ctrl &= ~(0x1<<A72_CRM_PLL_PWR_ON__PLL0_RESETB_R);
84 }
85 // post-div channel reset
86 if (reset_type & PLL_RESET_TYPE_POST) {
87 pll_rst_ctrl &= ~(0x1<<A72_CRM_PLL_PWR_ON__PLL0_POST_RESETB_R);
88 }
89
90 mmio_write_32(ihostx_config_root + A72_CRM_PLL_PWR_ON, pll_rst_ctrl);
91 }
92
ARMCOE_crm_pllSetMode(unsigned int cluster_num,unsigned int mode)93 static void ARMCOE_crm_pllSetMode(unsigned int cluster_num, unsigned int mode)
94 {
95 unsigned long ihostx_config_root;
96 unsigned int pll_byp_ctrl;
97
98 ihostx_config_root = ARMCOE_crm_getBaseAddress(cluster_num);
99 pll_byp_ctrl = mmio_read_32(ihostx_config_root +
100 A72_CRM_PLL_CHNL_BYPS_EN);
101
102 if (mode == PLL_MODE_VCO) {
103 // use PLL DCO output
104 pll_byp_ctrl &=
105 ~BIT(A72_CRM_PLL_CHNL_BYPS_EN__PLL_0_CHNL_0_BYPS_EN_R);
106 } else {
107 // use PLL bypass sources
108 pll_byp_ctrl |=
109 BIT(A72_CRM_PLL_CHNL_BYPS_EN__PLL_0_CHNL_0_BYPS_EN_R);
110 }
111
112 mmio_write_32(ihostx_config_root + A72_CRM_PLL_CHNL_BYPS_EN,
113 pll_byp_ctrl);
114 }
115
ARMCOE_crm_pllFreqSet(unsigned int cluster_num,unsigned int ihost_pll_freq_sel,unsigned int pdiv)116 static void ARMCOE_crm_pllFreqSet(unsigned int cluster_num,
117 unsigned int ihost_pll_freq_sel,
118 unsigned int pdiv)
119 {
120 unsigned int ndiv_int;
121 unsigned int ndiv_frac_low, ndiv_frac_high;
122 unsigned long ihostx_config_root;
123
124 ndiv_frac_low = 0x0;
125 ndiv_frac_high = 0x0;
126
127 if (ihost_pll_freq_sel == ARM_FREQ_3G) {
128 ndiv_int = 0x78;
129 } else if (ihost_pll_freq_sel == ARM_FREQ_1P5G) {
130 ndiv_int = 0x3c;
131 } else if (ihost_pll_freq_sel == ARM_FREQ_750M) {
132 ndiv_int = 0x1e;
133 } else {
134 return;
135 }
136
137 ndiv_int &= 0x3FF; // low 10 bits
138 ndiv_frac_low &= 0x3FF;
139 ndiv_frac_high &= 0x3FF;
140
141 ihostx_config_root = ARMCOE_crm_getBaseAddress(cluster_num);
142
143 mmio_write_32(ihostx_config_root+A72_CRM_PLL0_CTRL1, ndiv_frac_low);
144 mmio_write_32(ihostx_config_root+A72_CRM_PLL0_CTRL2, ndiv_frac_high);
145 mmio_write_32(ihostx_config_root+A72_CRM_PLL0_CTRL3,
146 ndiv_int |
147 ((pdiv << A72_CRM_PLL0_CTRL3__PLL0_PDIV_R & 0xF000)));
148
149 mmio_write_32(ihostx_config_root + A72_CRM_PLL0_CTRL4,
150 /* From Section 10 of PLL spec */
151 (3 << A72_CRM_PLL0_CTRL4__PLL0_KP_R) |
152 /* From Section 10 of PLL spec */
153 (2 << A72_CRM_PLL0_CTRL4__PLL0_KI_R) |
154 /* Normal mode (i.e. not fast-locking) */
155 (0 << A72_CRM_PLL0_CTRL4__PLL0_KA_R) |
156 /* 50 MHz */
157 (50 << A72_CRM_PLL0_CTRL4__PLL0_FREFEFF_INFO_R));
158 }
159
ARMCOE_crm_pllDeassertReset(unsigned int cluster_num,unsigned int reset_type)160 static void ARMCOE_crm_pllDeassertReset(unsigned int cluster_num,
161 unsigned int reset_type)
162 {
163 unsigned long ihostx_config_root;
164 unsigned int pll_rst_ctrl;
165
166 ihostx_config_root = ARMCOE_crm_getBaseAddress(cluster_num);
167 pll_rst_ctrl = mmio_read_32(ihostx_config_root + A72_CRM_PLL_PWR_ON);
168
169 // PLL reset
170 if (reset_type & PLL_RESET_TYPE_PLL) {
171 pll_rst_ctrl |= (0x1 << A72_CRM_PLL_PWR_ON__PLL0_RESETB_R);
172 }
173
174 // post-div channel reset
175 if (reset_type & PLL_RESET_TYPE_POST) {
176 pll_rst_ctrl |= (0x1 << A72_CRM_PLL_PWR_ON__PLL0_POST_RESETB_R);
177 }
178
179 mmio_write_32(ihostx_config_root + A72_CRM_PLL_PWR_ON, pll_rst_ctrl);
180 }
181
ARMCOE_crm_pllUpdate(unsigned int cluster_num,unsigned int type)182 static void ARMCOE_crm_pllUpdate(unsigned int cluster_num, unsigned int type)
183 {
184 unsigned long ihostx_config_root;
185 unsigned int pll_cmd;
186
187 ihostx_config_root = ARMCOE_crm_getBaseAddress(cluster_num);
188 pll_cmd = mmio_read_32(ihostx_config_root + A72_CRM_PLL_CMD);
189
190 // VCO update
191 if (type & PLL_VCO) {
192 pll_cmd |= BIT(A72_CRM_PLL_CMD__UPDATE_PLL0_FREQUENCY_VCO_R);
193 }
194 // post-div channel update
195 if (type & PLL_POSTDIV) {
196 pll_cmd |= BIT(A72_CRM_PLL_CMD__UPDATE_PLL0_FREQUENCY_POST_R);
197 }
198
199 mmio_write_32(ihostx_config_root+A72_CRM_PLL_CMD, pll_cmd);
200 }
201
insert_delay(unsigned int delay)202 static void insert_delay(unsigned int delay)
203 {
204 volatile unsigned int index;
205
206 for (index = 0; index < delay; index++)
207 ;
208 }
209
210
211 /*
212 * Returns 1 if PLL locked within certain interval
213 */
ARMCOE_crm_pllIsLocked(unsigned int cluster_num)214 static unsigned int ARMCOE_crm_pllIsLocked(unsigned int cluster_num)
215 {
216 unsigned long ihostx_config_root;
217 unsigned int lock_status;
218 unsigned int i;
219
220 ihostx_config_root = ARMCOE_crm_getBaseAddress(cluster_num);
221
222 /* wait a while for pll to lock before returning from this function */
223 for (i = 0; i < 1500; i++) {
224 insert_delay(256);
225 lock_status = mmio_read_32(ihostx_config_root +
226 A72_CRM_PLL_STATUS);
227 if (lock_status & BIT(A72_CRM_PLL_STATUS__PLL0_LOCK_R))
228 return 1;
229 }
230
231 ERROR("PLL of Cluster #%u failed to lock\n", cluster_num);
232 return 0;
233 }
234
235 /*
236 * ihost PLL Variable Frequency Configuration
237 *
238 * Frequency Limit {VCO,ARM} (GHz):
239 * 0 - no limit,
240 * 1 - {3.0,1.5},
241 * 2 - {4.0,2.0},
242 * 3 - {5.0,2.5}
243 */
bcm_set_ihost_pll_freq(uint32_t cluster_num,int ihost_pll_freq_sel)244 uint32_t bcm_set_ihost_pll_freq(uint32_t cluster_num, int ihost_pll_freq_sel)
245 {
246 NOTICE("cluster: %u, freq_sel:0x%x\n", cluster_num, ihost_pll_freq_sel);
247
248 //bypass PLL
249 ARMCOE_crm_pllSetMode(cluster_num, PLL_MODE_BYPASS);
250 //assert reset
251 ARMCOE_crm_pllAssertReset(cluster_num,
252 PLL_RESET_TYPE_PLL | PLL_RESET_TYPE_POST);
253 //set ndiv_int for different freq
254 ARMCOE_crm_pllFreqSet(cluster_num, ihost_pll_freq_sel, 0x1);
255 //de-assert reset
256 ARMCOE_crm_pllDeassertReset(cluster_num, PLL_RESET_TYPE_PLL);
257 ARMCOE_crm_pllUpdate(cluster_num, PLL_VCO);
258 //waiting for PLL lock
259 ARMCOE_crm_pllIsLocked(cluster_num);
260 ARMCOE_crm_pllDeassertReset(cluster_num, PLL_RESET_TYPE_POST);
261 //disable bypass PLL
262 ARMCOE_crm_pllSetMode(cluster_num, PLL_MODE_VCO);
263
264 return 0;
265 }
266
bcm_get_ihost_pll_freq(uint32_t cluster_num)267 uint32_t bcm_get_ihost_pll_freq(uint32_t cluster_num)
268 {
269 unsigned long ihostx_config_root;
270 uint32_t ndiv_int;
271 uint32_t ihost_pll_freq_sel;
272
273 ihostx_config_root = ARMCOE_crm_getBaseAddress(cluster_num);
274 ndiv_int = mmio_read_32(ihostx_config_root+A72_CRM_PLL0_CTRL3) & 0x3FF;
275
276 if (ndiv_int == 0x78) {
277 ihost_pll_freq_sel = ARM_FREQ_3G;
278 } else if (ndiv_int == 0x3c) {
279 ihost_pll_freq_sel = ARM_FREQ_1P5G;
280 } else if (ndiv_int == 0x1e) {
281 ihost_pll_freq_sel = ARM_FREQ_750M;
282 } else {
283 /* return unlimit otherwise*/
284 ihost_pll_freq_sel = 0;
285 }
286 return ihost_pll_freq_sel;
287 }
288