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