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