xref: /arm-trusted-firmware/plat/marvell/armada/a8k/common/plat_ble_setup.c (revision 91f16700b400a8c0651d24a598fc48ee2997a0d7)
1*91f16700Schasinglulu /*
2*91f16700Schasinglulu  * Copyright (C) 2018 Marvell International Ltd.
3*91f16700Schasinglulu  *
4*91f16700Schasinglulu  * SPDX-License-Identifier:     BSD-3-Clause
5*91f16700Schasinglulu  * https://spdx.org/licenses
6*91f16700Schasinglulu  */
7*91f16700Schasinglulu 
8*91f16700Schasinglulu #include <common/debug.h>
9*91f16700Schasinglulu #include <drivers/marvell/ap807_clocks_init.h>
10*91f16700Schasinglulu #include <drivers/marvell/aro.h>
11*91f16700Schasinglulu #include <drivers/marvell/ccu.h>
12*91f16700Schasinglulu #include <drivers/marvell/io_win.h>
13*91f16700Schasinglulu #include <drivers/marvell/mochi/ap_setup.h>
14*91f16700Schasinglulu #include <drivers/marvell/mochi/cp110_setup.h>
15*91f16700Schasinglulu 
16*91f16700Schasinglulu #include <armada_common.h>
17*91f16700Schasinglulu #include <efuse_def.h>
18*91f16700Schasinglulu #include <mv_ddr_if.h>
19*91f16700Schasinglulu #include <mvebu_def.h>
20*91f16700Schasinglulu #include <plat_marvell.h>
21*91f16700Schasinglulu 
22*91f16700Schasinglulu /* Register for skip image use */
23*91f16700Schasinglulu #define SCRATCH_PAD_REG2		0xF06F00A8
24*91f16700Schasinglulu #define SCRATCH_PAD_SKIP_VAL		0x01
25*91f16700Schasinglulu #define NUM_OF_GPIO_PER_REG 32
26*91f16700Schasinglulu 
27*91f16700Schasinglulu #define MMAP_SAVE_AND_CONFIG		0
28*91f16700Schasinglulu #define MMAP_RESTORE_SAVED		1
29*91f16700Schasinglulu 
30*91f16700Schasinglulu /* SAR clock settings */
31*91f16700Schasinglulu #define MVEBU_AP_SAR_REG_BASE(r)	(MVEBU_AP_GEN_MGMT_BASE + 0x200 +\
32*91f16700Schasinglulu 								((r) << 2))
33*91f16700Schasinglulu 
34*91f16700Schasinglulu #define SAR_CLOCK_FREQ_MODE_OFFSET	(0)
35*91f16700Schasinglulu #define SAR_CLOCK_FREQ_MODE_MASK	(0x1f << SAR_CLOCK_FREQ_MODE_OFFSET)
36*91f16700Schasinglulu #define SAR_PIDI_LOW_SPEED_OFFSET	(20)
37*91f16700Schasinglulu #define SAR_PIDI_LOW_SPEED_MASK		(1 << SAR_PIDI_LOW_SPEED_OFFSET)
38*91f16700Schasinglulu #define SAR_PIDI_LOW_SPEED_SHIFT	(15)
39*91f16700Schasinglulu #define SAR_PIDI_LOW_SPEED_SET		(1 << SAR_PIDI_LOW_SPEED_SHIFT)
40*91f16700Schasinglulu 
41*91f16700Schasinglulu #define FREQ_MODE_AP_SAR_REG_NUM	(0)
42*91f16700Schasinglulu #define SAR_CLOCK_FREQ_MODE(v)		(((v) & SAR_CLOCK_FREQ_MODE_MASK) >> \
43*91f16700Schasinglulu 					SAR_CLOCK_FREQ_MODE_OFFSET)
44*91f16700Schasinglulu 
45*91f16700Schasinglulu #define AVS_I2C_EEPROM_ADDR		0x57	/* EEPROM */
46*91f16700Schasinglulu #define AVS_EN_CTRL_REG			(MVEBU_AP_GEN_MGMT_BASE + 0x130)
47*91f16700Schasinglulu #define AVS_ENABLE_OFFSET		(0)
48*91f16700Schasinglulu #define AVS_SOFT_RESET_OFFSET		(2)
49*91f16700Schasinglulu #define AVS_TARGET_DELTA_OFFSET		(21)
50*91f16700Schasinglulu 
51*91f16700Schasinglulu #ifndef MVEBU_SOC_AP807
52*91f16700Schasinglulu 	/* AP806 SVC bits */
53*91f16700Schasinglulu 	#define AVS_LOW_VDD_LIMIT_OFFSET	(4)
54*91f16700Schasinglulu 	#define AVS_HIGH_VDD_LIMIT_OFFSET	(12)
55*91f16700Schasinglulu 	#define AVS_VDD_LOW_LIMIT_MASK	(0xFF << AVS_LOW_VDD_LIMIT_OFFSET)
56*91f16700Schasinglulu 	#define AVS_VDD_HIGH_LIMIT_MASK	(0xFF << AVS_HIGH_VDD_LIMIT_OFFSET)
57*91f16700Schasinglulu #else
58*91f16700Schasinglulu 	/* AP807 SVC bits */
59*91f16700Schasinglulu 	#define AVS_LOW_VDD_LIMIT_OFFSET	(3)
60*91f16700Schasinglulu 	#define AVS_HIGH_VDD_LIMIT_OFFSET	(13)
61*91f16700Schasinglulu 	#define AVS_VDD_LOW_LIMIT_MASK	(0x3FF << AVS_LOW_VDD_LIMIT_OFFSET)
62*91f16700Schasinglulu 	#define AVS_VDD_HIGH_LIMIT_MASK	(0x3FF << AVS_HIGH_VDD_LIMIT_OFFSET)
63*91f16700Schasinglulu #endif
64*91f16700Schasinglulu 
65*91f16700Schasinglulu /* VDD limit is 0.9V for A70x0 @ CPU frequency < 1600MHz */
66*91f16700Schasinglulu #define AVS_A7K_LOW_CLK_VALUE		((0x80 << AVS_TARGET_DELTA_OFFSET) | \
67*91f16700Schasinglulu 					 (0x1A << AVS_HIGH_VDD_LIMIT_OFFSET) | \
68*91f16700Schasinglulu 					 (0x1A << AVS_LOW_VDD_LIMIT_OFFSET) | \
69*91f16700Schasinglulu 					 (0x1 << AVS_SOFT_RESET_OFFSET) | \
70*91f16700Schasinglulu 					 (0x1 << AVS_ENABLE_OFFSET))
71*91f16700Schasinglulu /* VDD limit is 1.0V for all A80x0 devices */
72*91f16700Schasinglulu #define AVS_A8K_CLK_VALUE		((0x80 << AVS_TARGET_DELTA_OFFSET) | \
73*91f16700Schasinglulu 					 (0x24 << AVS_HIGH_VDD_LIMIT_OFFSET) | \
74*91f16700Schasinglulu 					 (0x24 << AVS_LOW_VDD_LIMIT_OFFSET) | \
75*91f16700Schasinglulu 					 (0x1 << AVS_SOFT_RESET_OFFSET) | \
76*91f16700Schasinglulu 					 (0x1 << AVS_ENABLE_OFFSET))
77*91f16700Schasinglulu 
78*91f16700Schasinglulu /* VDD is 0.88V for 2GHz clock on CN913x devices */
79*91f16700Schasinglulu #define AVS_AP807_CLK_VALUE		((0x80UL << 24) | \
80*91f16700Schasinglulu 					 (0x2dc << 13) | \
81*91f16700Schasinglulu 					 (0x2dc << 3) | \
82*91f16700Schasinglulu 					 (0x1 << AVS_SOFT_RESET_OFFSET) | \
83*91f16700Schasinglulu 					 (0x1 << AVS_ENABLE_OFFSET))
84*91f16700Schasinglulu 
85*91f16700Schasinglulu /*
86*91f16700Schasinglulu  * - Identification information in the LD-0 eFuse:
87*91f16700Schasinglulu  *	DRO:           LD0[74:65] - Not used by the SW
88*91f16700Schasinglulu  *	Revision:      LD0[78:75] - Not used by the SW
89*91f16700Schasinglulu  *	Bin:           LD0[80:79] - Not used by the SW
90*91f16700Schasinglulu  *	SW Revision:   LD0[115:113]
91*91f16700Schasinglulu  *	Cluster 1 PWR: LD0[193] - if set to 1, power down CPU Cluster-1
92*91f16700Schasinglulu  *				  resulting in 2 CPUs active only (7020)
93*91f16700Schasinglulu  */
94*91f16700Schasinglulu /* Offsets for 2 efuse fields combined into single 64-bit value [125:63] */
95*91f16700Schasinglulu #define EFUSE_AP_LD0_DRO_OFFS		2		/* LD0[74:65] */
96*91f16700Schasinglulu #define EFUSE_AP_LD0_DRO_MASK		0x3FF
97*91f16700Schasinglulu #define EFUSE_AP_LD0_REVID_OFFS		12		/* LD0[78:75] */
98*91f16700Schasinglulu #define EFUSE_AP_LD0_REVID_MASK		0xF
99*91f16700Schasinglulu #define EFUSE_AP_LD0_BIN_OFFS		16		/* LD0[80:79] */
100*91f16700Schasinglulu #define EFUSE_AP_LD0_BIN_MASK		0x3
101*91f16700Schasinglulu #define EFUSE_AP_LD0_SWREV_MASK		0x7
102*91f16700Schasinglulu 
103*91f16700Schasinglulu #ifndef MVEBU_SOC_AP807
104*91f16700Schasinglulu 	/* AP806 AVS work points in the LD0 eFuse
105*91f16700Schasinglulu 	 * SVC1 work point:     LD0[88:81]
106*91f16700Schasinglulu 	 * SVC2 work point:     LD0[96:89]
107*91f16700Schasinglulu 	 * SVC3 work point:     LD0[104:97]
108*91f16700Schasinglulu 	 * SVC4 work point:     LD0[112:105]
109*91f16700Schasinglulu 	 */
110*91f16700Schasinglulu 	#define EFUSE_AP_LD0_SVC1_OFFS		18	/* LD0[88:81] */
111*91f16700Schasinglulu 	#define EFUSE_AP_LD0_SVC2_OFFS		26	/* LD0[96:89] */
112*91f16700Schasinglulu 	#define EFUSE_AP_LD0_SVC3_OFFS		34	/* LD0[104:97] */
113*91f16700Schasinglulu 	#define EFUSE_AP_LD0_WP_MASK		0xFF
114*91f16700Schasinglulu 	#define EFUSE_AP_LD0_SWREV_OFFS		50	/* LD0[115:113] */
115*91f16700Schasinglulu #else
116*91f16700Schasinglulu 	/* AP807 AVS work points in the LD0 eFuse
117*91f16700Schasinglulu 	 * SVC1 work point:     LD0[91:81]
118*91f16700Schasinglulu 	 * SVC2 work point:     LD0[102:92]
119*91f16700Schasinglulu 	 * SVC3 work point:     LD0[113:103]
120*91f16700Schasinglulu 	 */
121*91f16700Schasinglulu 	#define EFUSE_AP_LD0_SVC1_OFFS		18	/* LD0[91:81] */
122*91f16700Schasinglulu 	#define EFUSE_AP_LD0_SVC2_OFFS		29	/* LD0[102:92] */
123*91f16700Schasinglulu 	#define EFUSE_AP_LD0_SVC3_OFFS		40	/* LD0[113:103] */
124*91f16700Schasinglulu 	#define EFUSE_AP_LD0_WP_MASK		0x7FF	/* 10 data,1 parity */
125*91f16700Schasinglulu 	#define EFUSE_AP_LD0_SWREV_OFFS		51	/* LD0[116:114] */
126*91f16700Schasinglulu #endif
127*91f16700Schasinglulu 
128*91f16700Schasinglulu #define EFUSE_AP_LD0_SVC4_OFFS			42	/* LD0[112:105] */
129*91f16700Schasinglulu 
130*91f16700Schasinglulu #define EFUSE_AP_LD0_CLUSTER_DOWN_OFFS		4
131*91f16700Schasinglulu 
132*91f16700Schasinglulu #if MARVELL_SVC_TEST
133*91f16700Schasinglulu #define MVEBU_CP_MPP_CTRL37_OFFS	20
134*91f16700Schasinglulu #define MVEBU_CP_MPP_CTRL38_OFFS	24
135*91f16700Schasinglulu #define MVEBU_CP_MPP_I2C_FUNC		2
136*91f16700Schasinglulu #define MVEBU_MPP_CTRL_MASK		0xf
137*91f16700Schasinglulu #endif
138*91f16700Schasinglulu 
139*91f16700Schasinglulu /* Return the AP revision of the chip */
140*91f16700Schasinglulu static unsigned int ble_get_ap_type(void)
141*91f16700Schasinglulu {
142*91f16700Schasinglulu 	unsigned int chip_rev_id;
143*91f16700Schasinglulu 
144*91f16700Schasinglulu 	chip_rev_id = mmio_read_32(MVEBU_CSS_GWD_CTRL_IIDR2_REG);
145*91f16700Schasinglulu 	chip_rev_id = ((chip_rev_id & GWD_IIDR2_CHIP_ID_MASK) >>
146*91f16700Schasinglulu 			GWD_IIDR2_CHIP_ID_OFFSET);
147*91f16700Schasinglulu 
148*91f16700Schasinglulu 	return chip_rev_id;
149*91f16700Schasinglulu }
150*91f16700Schasinglulu 
151*91f16700Schasinglulu /******************************************************************************
152*91f16700Schasinglulu  * The routine allows to save the CCU and IO windows configuration during DRAM
153*91f16700Schasinglulu  * setup and restore them afterwards before exiting the BLE stage.
154*91f16700Schasinglulu  * Such window configuration is required since not all default settings coming
155*91f16700Schasinglulu  * from the HW and the BootROM allow access to peripherals connected to
156*91f16700Schasinglulu  * all available CPn components.
157*91f16700Schasinglulu  * For instance, when the boot device is located on CP0, the IO window to CP1
158*91f16700Schasinglulu  * is not opened automatically by the HW and if the DRAM SPD is located on CP1
159*91f16700Schasinglulu  * i2c channel, it cannot be read at BLE stage.
160*91f16700Schasinglulu  * Therefore the DRAM init procedure have to provide access to all available
161*91f16700Schasinglulu  * CPn peripherals during the BLE stage by setting the CCU IO window to all
162*91f16700Schasinglulu  * CPnph addresses and by enabling the IO windows accordingly.
163*91f16700Schasinglulu  * Additionally this function configures the CCU GCR to DRAM, which allows
164*91f16700Schasinglulu  * usage or more than 4GB DRAM as it configured by the default CCU DRAM window.
165*91f16700Schasinglulu  *
166*91f16700Schasinglulu  * IN:
167*91f16700Schasinglulu  *	MMAP_SAVE_AND_CONFIG	- save the existing configuration and update it
168*91f16700Schasinglulu  *	MMAP_RESTORE_SAVED	- restore saved configuration
169*91f16700Schasinglulu  * OUT:
170*91f16700Schasinglulu  *	NONE
171*91f16700Schasinglulu  ****************************************************************************
172*91f16700Schasinglulu  */
173*91f16700Schasinglulu static void ble_plat_mmap_config(int restore)
174*91f16700Schasinglulu {
175*91f16700Schasinglulu 	if (restore == MMAP_RESTORE_SAVED) {
176*91f16700Schasinglulu 		/* Restore all orig. settings that were modified by BLE stage */
177*91f16700Schasinglulu 		ccu_restore_win_all(MVEBU_AP0);
178*91f16700Schasinglulu 		/* Restore CCU */
179*91f16700Schasinglulu 		iow_restore_win_all(MVEBU_AP0);
180*91f16700Schasinglulu 		return;
181*91f16700Schasinglulu 	}
182*91f16700Schasinglulu 
183*91f16700Schasinglulu 	/* Store original values */
184*91f16700Schasinglulu 	ccu_save_win_all(MVEBU_AP0);
185*91f16700Schasinglulu 	/* Save CCU */
186*91f16700Schasinglulu 	iow_save_win_all(MVEBU_AP0);
187*91f16700Schasinglulu 
188*91f16700Schasinglulu 	init_ccu(MVEBU_AP0);
189*91f16700Schasinglulu 	/* The configuration saved, now all the changes can be done */
190*91f16700Schasinglulu 	init_io_win(MVEBU_AP0);
191*91f16700Schasinglulu }
192*91f16700Schasinglulu 
193*91f16700Schasinglulu /****************************************************************************
194*91f16700Schasinglulu  * Setup Adaptive Voltage Switching - this is required for some platforms
195*91f16700Schasinglulu  ****************************************************************************
196*91f16700Schasinglulu  */
197*91f16700Schasinglulu #if !MARVELL_SVC_TEST
198*91f16700Schasinglulu static void ble_plat_avs_config(void)
199*91f16700Schasinglulu {
200*91f16700Schasinglulu 	uint32_t freq_mode, device_id;
201*91f16700Schasinglulu 	uint32_t avs_val = 0;
202*91f16700Schasinglulu 
203*91f16700Schasinglulu 	freq_mode =
204*91f16700Schasinglulu 		SAR_CLOCK_FREQ_MODE(mmio_read_32(MVEBU_AP_SAR_REG_BASE(
205*91f16700Schasinglulu 						 FREQ_MODE_AP_SAR_REG_NUM)));
206*91f16700Schasinglulu 	/* Check which SoC is running and act accordingly */
207*91f16700Schasinglulu 	if (ble_get_ap_type() == CHIP_ID_AP807) {
208*91f16700Schasinglulu 
209*91f16700Schasinglulu 		avs_val = AVS_AP807_CLK_VALUE;
210*91f16700Schasinglulu 
211*91f16700Schasinglulu 	} else {
212*91f16700Schasinglulu 		/* Check which SoC is running and act accordingly */
213*91f16700Schasinglulu 		device_id = cp110_device_id_get(MVEBU_CP_REGS_BASE(0));
214*91f16700Schasinglulu 		switch (device_id) {
215*91f16700Schasinglulu 		case MVEBU_80X0_DEV_ID:
216*91f16700Schasinglulu 		case MVEBU_80X0_CP115_DEV_ID:
217*91f16700Schasinglulu 			/* Always fix the default AVS value on A80x0 */
218*91f16700Schasinglulu 			avs_val = AVS_A8K_CLK_VALUE;
219*91f16700Schasinglulu 			break;
220*91f16700Schasinglulu 		case MVEBU_70X0_DEV_ID:
221*91f16700Schasinglulu 		case MVEBU_70X0_CP115_DEV_ID:
222*91f16700Schasinglulu 			/* Fix AVS for CPU clocks lower than 1600MHz on A70x0 */
223*91f16700Schasinglulu 			if ((freq_mode > CPU_1600_DDR_900_RCLK_900_2) &&
224*91f16700Schasinglulu 			    (freq_mode < CPU_DDR_RCLK_INVALID))
225*91f16700Schasinglulu 				avs_val = AVS_A7K_LOW_CLK_VALUE;
226*91f16700Schasinglulu 			break;
227*91f16700Schasinglulu 		default:
228*91f16700Schasinglulu 			ERROR("Unsupported Device ID 0x%x\n", device_id);
229*91f16700Schasinglulu 			return;
230*91f16700Schasinglulu 		}
231*91f16700Schasinglulu 	}
232*91f16700Schasinglulu 
233*91f16700Schasinglulu 	if (avs_val) {
234*91f16700Schasinglulu 		VERBOSE("AVS: Setting AVS CTRL to 0x%x\n", avs_val);
235*91f16700Schasinglulu 		mmio_write_32(AVS_EN_CTRL_REG, avs_val);
236*91f16700Schasinglulu 	}
237*91f16700Schasinglulu }
238*91f16700Schasinglulu #endif
239*91f16700Schasinglulu /******************************************************************************
240*91f16700Schasinglulu  * Update or override current AVS work point value using data stored in EEPROM
241*91f16700Schasinglulu  * This is only required by QA/validation flows and activated by
242*91f16700Schasinglulu  * MARVELL_SVC_TEST flag.
243*91f16700Schasinglulu  *
244*91f16700Schasinglulu  * The function is expected to be called twice.
245*91f16700Schasinglulu  *
246*91f16700Schasinglulu  * First time with AVS value of 0 for testing if the EEPROM requests completely
247*91f16700Schasinglulu  * override the AVS value and bypass the eFuse test
248*91f16700Schasinglulu  *
249*91f16700Schasinglulu  * Second time - with non-zero AVS value obtained from eFuses as an input.
250*91f16700Schasinglulu  * In this case the EEPROM may contain AVS correction value (either positive
251*91f16700Schasinglulu  * or negative) that is added to the input AVS value and returned back for
252*91f16700Schasinglulu  * further processing.
253*91f16700Schasinglulu  ******************************************************************************
254*91f16700Schasinglulu  */
255*91f16700Schasinglulu static uint32_t avs_update_from_eeprom(uint32_t avs_workpoint)
256*91f16700Schasinglulu {
257*91f16700Schasinglulu 	uint32_t new_wp = avs_workpoint;
258*91f16700Schasinglulu #if MARVELL_SVC_TEST
259*91f16700Schasinglulu 	/* ---------------------------------------------------------------------
260*91f16700Schasinglulu 	 * EEPROM  |  Data description (avs_step)
261*91f16700Schasinglulu 	 * address |
262*91f16700Schasinglulu 	 * ---------------------------------------------------------------------
263*91f16700Schasinglulu 	 * 0x120   | AVS workpoint correction value
264*91f16700Schasinglulu 	 *         | if not 0 and not 0xff, correct the AVS taken from eFuse
265*91f16700Schasinglulu 	 *         | by the number of steps indicated by bit[6:0]
266*91f16700Schasinglulu 	 *         | bit[7] defines correction direction.
267*91f16700Schasinglulu 	 *         | If bit[7]=1, add the value from bit[6:0] to AVS workpoint,
268*91f16700Schasinglulu 	 *         | othervise substruct this value from AVS workpoint.
269*91f16700Schasinglulu 	 * ---------------------------------------------------------------------
270*91f16700Schasinglulu 	 * 0x121   | AVS workpoint override value
271*91f16700Schasinglulu 	 *         | Override the AVS workpoint with the value stored in this
272*91f16700Schasinglulu 	 *         | byte. When running on AP806, the AVS workpoint is 7 bits
273*91f16700Schasinglulu 	 *         | wide and override value is valid when bit[6:0] holds
274*91f16700Schasinglulu 	 *         | value greater than zero and smaller than 0x33.
275*91f16700Schasinglulu 	 *         | When running on AP807, the AVS workpoint is 10 bits wide.
276*91f16700Schasinglulu 	 *         | Additional 2 MSB bits are supplied by EEPROM byte 0x122.
277*91f16700Schasinglulu 	 *         | AVS override value is valid when byte @ 0x121 and bit[1:0]
278*91f16700Schasinglulu 	 *         | of byte @ 0x122 combined have non-zero value.
279*91f16700Schasinglulu 	 * ---------------------------------------------------------------------
280*91f16700Schasinglulu 	 * 0x122   | Extended AVS workpoint override value
281*91f16700Schasinglulu 	 *         | Valid only for AP807 platforms and must be less than 0x4
282*91f16700Schasinglulu 	 * ---------------------------------------------------------------------
283*91f16700Schasinglulu 	 */
284*91f16700Schasinglulu 	static uint8_t  avs_step[3] = {0};
285*91f16700Schasinglulu 	uintptr_t reg;
286*91f16700Schasinglulu 	uint32_t val;
287*91f16700Schasinglulu 	unsigned int ap_type = ble_get_ap_type();
288*91f16700Schasinglulu 
289*91f16700Schasinglulu 	/* Always happens on second call to this function */
290*91f16700Schasinglulu 	if (avs_workpoint != 0) {
291*91f16700Schasinglulu 		/* Get correction steps from the EEPROM */
292*91f16700Schasinglulu 		if ((avs_step[0] != 0) && (avs_step[0] != 0xff)) {
293*91f16700Schasinglulu 			NOTICE("AVS request to step %s by 0x%x from old 0x%x\n",
294*91f16700Schasinglulu 				avs_step[0] & 0x80 ? "DOWN" : "UP",
295*91f16700Schasinglulu 				avs_step[0] & 0x7f, new_wp);
296*91f16700Schasinglulu 			if (avs_step[0] & 0x80)
297*91f16700Schasinglulu 				new_wp -= avs_step[0] & 0x7f;
298*91f16700Schasinglulu 			else
299*91f16700Schasinglulu 				new_wp += avs_step[0] & 0x7f;
300*91f16700Schasinglulu 		}
301*91f16700Schasinglulu 
302*91f16700Schasinglulu 		return new_wp;
303*91f16700Schasinglulu 	}
304*91f16700Schasinglulu 
305*91f16700Schasinglulu 	/* AVS values are located in EEPROM
306*91f16700Schasinglulu 	 * at CP0 i2c bus #0, device 0x57 offset 0x120
307*91f16700Schasinglulu 	 * The SDA and SCK pins of CP0 i2c-0: MPP[38:37], i2c function 0x2.
308*91f16700Schasinglulu 	 */
309*91f16700Schasinglulu 	reg = MVEBU_CP_MPP_REGS(0, 4);
310*91f16700Schasinglulu 	val = mmio_read_32(reg);
311*91f16700Schasinglulu 	val &= ~((MVEBU_MPP_CTRL_MASK << MVEBU_CP_MPP_CTRL37_OFFS) |
312*91f16700Schasinglulu 		 (MVEBU_MPP_CTRL_MASK << MVEBU_CP_MPP_CTRL38_OFFS));
313*91f16700Schasinglulu 	val |= (MVEBU_CP_MPP_I2C_FUNC << MVEBU_CP_MPP_CTRL37_OFFS) |
314*91f16700Schasinglulu 		(MVEBU_CP_MPP_I2C_FUNC << MVEBU_CP_MPP_CTRL38_OFFS);
315*91f16700Schasinglulu 	mmio_write_32(reg, val);
316*91f16700Schasinglulu 
317*91f16700Schasinglulu 	/* Init CP0 i2c-0 */
318*91f16700Schasinglulu 	i2c_init((void *)(MVEBU_CP0_I2C_BASE));
319*91f16700Schasinglulu 
320*91f16700Schasinglulu 	/* Read EEPROM only once at the fist call! */
321*91f16700Schasinglulu 	i2c_read(AVS_I2C_EEPROM_ADDR, 0x120, 2, avs_step, 3);
322*91f16700Schasinglulu 	NOTICE("== SVC test build ==\n");
323*91f16700Schasinglulu 	NOTICE("EEPROM holds values 0x%x, 0x%x and 0x%x\n",
324*91f16700Schasinglulu 		avs_step[0], avs_step[1], avs_step[2]);
325*91f16700Schasinglulu 
326*91f16700Schasinglulu 	/* Override the AVS value? */
327*91f16700Schasinglulu 	if ((ap_type != CHIP_ID_AP807) && (avs_step[1] < 0x33)) {
328*91f16700Schasinglulu 		/* AP806 - AVS is 7 bits */
329*91f16700Schasinglulu 		new_wp = avs_step[1];
330*91f16700Schasinglulu 
331*91f16700Schasinglulu 	} else if (ap_type == CHIP_ID_AP807 && (avs_step[2] < 0x4)) {
332*91f16700Schasinglulu 		/* AP807 - AVS is 10 bits */
333*91f16700Schasinglulu 		new_wp = avs_step[2];
334*91f16700Schasinglulu 		new_wp <<= 8;
335*91f16700Schasinglulu 		new_wp |= avs_step[1];
336*91f16700Schasinglulu 	}
337*91f16700Schasinglulu 
338*91f16700Schasinglulu 	if (new_wp == 0)
339*91f16700Schasinglulu 		NOTICE("Ignore BAD AVS Override value in EEPROM!\n");
340*91f16700Schasinglulu 	else
341*91f16700Schasinglulu 		NOTICE("Override AVS by EEPROM value 0x%x\n", new_wp);
342*91f16700Schasinglulu #endif /* MARVELL_SVC_TEST */
343*91f16700Schasinglulu 	return new_wp;
344*91f16700Schasinglulu }
345*91f16700Schasinglulu 
346*91f16700Schasinglulu /****************************************************************************
347*91f16700Schasinglulu  * SVC flow - v0.10
348*91f16700Schasinglulu  * The feature is intended to configure AVS value according to eFuse values
349*91f16700Schasinglulu  * that are burned individually for each SoC during the test process.
350*91f16700Schasinglulu  * Primary AVS value is stored in HD efuse and processed on power on
351*91f16700Schasinglulu  * by the HW engine
352*91f16700Schasinglulu  * Secondary AVS value is located in LD efuse and contains 4 work points for
353*91f16700Schasinglulu  * various CPU frequencies.
354*91f16700Schasinglulu  * The Secondary AVS value is only taken into account if the SW Revision stored
355*91f16700Schasinglulu  * in the efuse is greater than 0 and the CPU is running in a certain speed.
356*91f16700Schasinglulu  ****************************************************************************
357*91f16700Schasinglulu  */
358*91f16700Schasinglulu static void ble_plat_svc_config(void)
359*91f16700Schasinglulu {
360*91f16700Schasinglulu 	uint32_t reg_val, avs_workpoint, freq_pidi_mode;
361*91f16700Schasinglulu 	uint64_t efuse;
362*91f16700Schasinglulu 	uint32_t device_id, single_cluster;
363*91f16700Schasinglulu 	uint16_t  svc[4], perr[4], i, sw_ver;
364*91f16700Schasinglulu 	uint8_t	 avs_data_bits, min_sw_ver, svc_fields;
365*91f16700Schasinglulu 	unsigned int ap_type;
366*91f16700Schasinglulu 
367*91f16700Schasinglulu 	/* Get test EERPOM data */
368*91f16700Schasinglulu 	avs_workpoint = avs_update_from_eeprom(0);
369*91f16700Schasinglulu 	if (avs_workpoint)
370*91f16700Schasinglulu 		goto set_aws_wp;
371*91f16700Schasinglulu 
372*91f16700Schasinglulu 	/* Set access to LD0 */
373*91f16700Schasinglulu 	reg_val = mmio_read_32(MVEBU_AP_EFUSE_SRV_CTRL_REG);
374*91f16700Schasinglulu 	reg_val &= ~EFUSE_SRV_CTRL_LD_SELECT_MASK;
375*91f16700Schasinglulu 	mmio_write_32(MVEBU_AP_EFUSE_SRV_CTRL_REG, reg_val);
376*91f16700Schasinglulu 
377*91f16700Schasinglulu 	/* Obtain the value of LD0[125:63] */
378*91f16700Schasinglulu 	efuse = mmio_read_32(MVEBU_AP_LDX_125_95_EFUSE_OFFS);
379*91f16700Schasinglulu 	efuse <<= 32;
380*91f16700Schasinglulu 	efuse |= mmio_read_32(MVEBU_AP_LDX_94_63_EFUSE_OFFS);
381*91f16700Schasinglulu 
382*91f16700Schasinglulu 	/* SW Revision:
383*91f16700Schasinglulu 	 * Starting from SW revision 1 the SVC flow is supported.
384*91f16700Schasinglulu 	 * SW version 0 (efuse not programmed) should follow the
385*91f16700Schasinglulu 	 * regular AVS update flow.
386*91f16700Schasinglulu 	 */
387*91f16700Schasinglulu 	sw_ver = (efuse >> EFUSE_AP_LD0_SWREV_OFFS) & EFUSE_AP_LD0_SWREV_MASK;
388*91f16700Schasinglulu 	if (sw_ver < 1) {
389*91f16700Schasinglulu 		NOTICE("SVC: SW Revision 0x%x. SVC is not supported\n", sw_ver);
390*91f16700Schasinglulu #if MARVELL_SVC_TEST
391*91f16700Schasinglulu 		NOTICE("SVC_TEST: AVS bypassed\n");
392*91f16700Schasinglulu 
393*91f16700Schasinglulu #else
394*91f16700Schasinglulu 		ble_plat_avs_config();
395*91f16700Schasinglulu #endif
396*91f16700Schasinglulu 		return;
397*91f16700Schasinglulu 	}
398*91f16700Schasinglulu 
399*91f16700Schasinglulu 	/* Frequency mode from SAR */
400*91f16700Schasinglulu 	freq_pidi_mode = SAR_CLOCK_FREQ_MODE(
401*91f16700Schasinglulu 				mmio_read_32(
402*91f16700Schasinglulu 					MVEBU_AP_SAR_REG_BASE(
403*91f16700Schasinglulu 						FREQ_MODE_AP_SAR_REG_NUM)));
404*91f16700Schasinglulu 
405*91f16700Schasinglulu 	/* Decode all SVC work points */
406*91f16700Schasinglulu 	svc[0] = (efuse >> EFUSE_AP_LD0_SVC1_OFFS) & EFUSE_AP_LD0_WP_MASK;
407*91f16700Schasinglulu 	svc[1] = (efuse >> EFUSE_AP_LD0_SVC2_OFFS) & EFUSE_AP_LD0_WP_MASK;
408*91f16700Schasinglulu 	svc[2] = (efuse >> EFUSE_AP_LD0_SVC3_OFFS) & EFUSE_AP_LD0_WP_MASK;
409*91f16700Schasinglulu 
410*91f16700Schasinglulu 	/* Fetch AP type to distinguish between AP806 and AP807 */
411*91f16700Schasinglulu 	ap_type = ble_get_ap_type();
412*91f16700Schasinglulu 
413*91f16700Schasinglulu 	if (ap_type != CHIP_ID_AP807) {
414*91f16700Schasinglulu 		svc[3] = (efuse >> EFUSE_AP_LD0_SVC4_OFFS)
415*91f16700Schasinglulu 			 & EFUSE_AP_LD0_WP_MASK;
416*91f16700Schasinglulu 		INFO("SVC: Efuse WP: [0]=0x%x, [1]=0x%x, [2]=0x%x, [3]=0x%x\n",
417*91f16700Schasinglulu 		     svc[0], svc[1], svc[2], svc[3]);
418*91f16700Schasinglulu 		avs_data_bits = 7;
419*91f16700Schasinglulu 		min_sw_ver = 2; /* parity check from sw revision 2 */
420*91f16700Schasinglulu 		svc_fields = 4;
421*91f16700Schasinglulu 	} else {
422*91f16700Schasinglulu 		INFO("SVC: Efuse WP: [0]=0x%x, [1]=0x%x, [2]=0x%x\n",
423*91f16700Schasinglulu 		     svc[0], svc[1], svc[2]);
424*91f16700Schasinglulu 		avs_data_bits = 10;
425*91f16700Schasinglulu 		min_sw_ver = 1; /* parity check required from sw revision 1 */
426*91f16700Schasinglulu 		svc_fields = 3;
427*91f16700Schasinglulu 	}
428*91f16700Schasinglulu 
429*91f16700Schasinglulu 	/* Validate parity of SVC workpoint values */
430*91f16700Schasinglulu 	for (i = 0; i < svc_fields; i++) {
431*91f16700Schasinglulu 		uint8_t parity, bit;
432*91f16700Schasinglulu 		perr[i] = 0;
433*91f16700Schasinglulu 
434*91f16700Schasinglulu 		for (bit = 1, parity = (svc[i] & 1); bit < avs_data_bits; bit++)
435*91f16700Schasinglulu 			parity ^= (svc[i] >> bit) & 1;
436*91f16700Schasinglulu 
437*91f16700Schasinglulu 		/* From SW version 1 or 2 (AP806/AP807), check parity */
438*91f16700Schasinglulu 		if ((sw_ver >= min_sw_ver) &&
439*91f16700Schasinglulu 		    (parity != ((svc[i] >> avs_data_bits) & 1)))
440*91f16700Schasinglulu 			perr[i] = 1; /* register the error */
441*91f16700Schasinglulu 	}
442*91f16700Schasinglulu 
443*91f16700Schasinglulu 	single_cluster = mmio_read_32(MVEBU_AP_LDX_220_189_EFUSE_OFFS);
444*91f16700Schasinglulu 	single_cluster = (single_cluster >> EFUSE_AP_LD0_CLUSTER_DOWN_OFFS) & 1;
445*91f16700Schasinglulu 
446*91f16700Schasinglulu 	device_id = cp110_device_id_get(MVEBU_CP_REGS_BASE(0));
447*91f16700Schasinglulu 	if (device_id == MVEBU_80X0_DEV_ID ||
448*91f16700Schasinglulu 	    device_id == MVEBU_80X0_CP115_DEV_ID) {
449*91f16700Schasinglulu 		/* A8040/A8020 */
450*91f16700Schasinglulu 		NOTICE("SVC: DEV ID: %s, FREQ Mode: 0x%x\n",
451*91f16700Schasinglulu 			single_cluster == 0 ? "8040" : "8020", freq_pidi_mode);
452*91f16700Schasinglulu 		switch (freq_pidi_mode) {
453*91f16700Schasinglulu 		case CPU_1800_DDR_1050_RCLK_1050:
454*91f16700Schasinglulu 			if (perr[1])
455*91f16700Schasinglulu 				goto perror;
456*91f16700Schasinglulu 			avs_workpoint = svc[1];
457*91f16700Schasinglulu 			break;
458*91f16700Schasinglulu 		case CPU_1600_DDR_1050_RCLK_1050:
459*91f16700Schasinglulu 		case CPU_1600_DDR_900_RCLK_900_2:
460*91f16700Schasinglulu 			if (perr[2])
461*91f16700Schasinglulu 				goto perror;
462*91f16700Schasinglulu 			avs_workpoint = svc[2];
463*91f16700Schasinglulu 			break;
464*91f16700Schasinglulu 		case CPU_1300_DDR_800_RCLK_800:
465*91f16700Schasinglulu 		case CPU_1300_DDR_650_RCLK_650:
466*91f16700Schasinglulu 			if (perr[3])
467*91f16700Schasinglulu 				goto perror;
468*91f16700Schasinglulu 			avs_workpoint = svc[3];
469*91f16700Schasinglulu 			break;
470*91f16700Schasinglulu 		case CPU_2000_DDR_1200_RCLK_1200:
471*91f16700Schasinglulu 		case CPU_2000_DDR_1050_RCLK_1050:
472*91f16700Schasinglulu 		default:
473*91f16700Schasinglulu 			if (perr[0])
474*91f16700Schasinglulu 				goto perror;
475*91f16700Schasinglulu 			avs_workpoint = svc[0];
476*91f16700Schasinglulu 			break;
477*91f16700Schasinglulu 		}
478*91f16700Schasinglulu 	} else if (device_id == MVEBU_70X0_DEV_ID ||
479*91f16700Schasinglulu 		   device_id == MVEBU_70X0_CP115_DEV_ID) {
480*91f16700Schasinglulu 		/* A7040/A7020/A6040 */
481*91f16700Schasinglulu 		NOTICE("SVC: DEV ID: %s, FREQ Mode: 0x%x\n",
482*91f16700Schasinglulu 			single_cluster == 0 ? "7040" : "7020", freq_pidi_mode);
483*91f16700Schasinglulu 		switch (freq_pidi_mode) {
484*91f16700Schasinglulu 		case CPU_1400_DDR_800_RCLK_800:
485*91f16700Schasinglulu 			if (single_cluster) {/* 7020 */
486*91f16700Schasinglulu 				if (perr[1])
487*91f16700Schasinglulu 					goto perror;
488*91f16700Schasinglulu 				avs_workpoint = svc[1];
489*91f16700Schasinglulu 			} else {
490*91f16700Schasinglulu 				if (perr[0])
491*91f16700Schasinglulu 					goto perror;
492*91f16700Schasinglulu 				avs_workpoint = svc[0];
493*91f16700Schasinglulu 			}
494*91f16700Schasinglulu 			break;
495*91f16700Schasinglulu 		case CPU_1200_DDR_800_RCLK_800:
496*91f16700Schasinglulu 			if (single_cluster) {/* 7020 */
497*91f16700Schasinglulu 				if (perr[2])
498*91f16700Schasinglulu 					goto perror;
499*91f16700Schasinglulu 				avs_workpoint = svc[2];
500*91f16700Schasinglulu 			} else {
501*91f16700Schasinglulu 				if (perr[1])
502*91f16700Schasinglulu 					goto perror;
503*91f16700Schasinglulu 				avs_workpoint = svc[1];
504*91f16700Schasinglulu 			}
505*91f16700Schasinglulu 			break;
506*91f16700Schasinglulu 		case CPU_800_DDR_800_RCLK_800:
507*91f16700Schasinglulu 		case CPU_1000_DDR_800_RCLK_800:
508*91f16700Schasinglulu 			if (single_cluster) {/* 7020 */
509*91f16700Schasinglulu 				if (perr[3])
510*91f16700Schasinglulu 					goto perror;
511*91f16700Schasinglulu 				avs_workpoint = svc[3];
512*91f16700Schasinglulu 			} else {
513*91f16700Schasinglulu 				if (perr[2])
514*91f16700Schasinglulu 					goto perror;
515*91f16700Schasinglulu 				avs_workpoint = svc[2];
516*91f16700Schasinglulu 			}
517*91f16700Schasinglulu 			break;
518*91f16700Schasinglulu 		case CPU_600_DDR_800_RCLK_800:
519*91f16700Schasinglulu 			if (perr[3])
520*91f16700Schasinglulu 				goto perror;
521*91f16700Schasinglulu 			avs_workpoint = svc[3]; /* Same for 6040 and 7020 */
522*91f16700Schasinglulu 			break;
523*91f16700Schasinglulu 		case CPU_1600_DDR_800_RCLK_800: /* 7020 only */
524*91f16700Schasinglulu 		default:
525*91f16700Schasinglulu 			if (single_cluster) {/* 7020 */
526*91f16700Schasinglulu 				if (perr[0])
527*91f16700Schasinglulu 					goto perror;
528*91f16700Schasinglulu 				avs_workpoint = svc[0];
529*91f16700Schasinglulu 			} else {
530*91f16700Schasinglulu #if MARVELL_SVC_TEST
531*91f16700Schasinglulu 				reg_val = mmio_read_32(AVS_EN_CTRL_REG);
532*91f16700Schasinglulu 				avs_workpoint = (reg_val &
533*91f16700Schasinglulu 					AVS_VDD_LOW_LIMIT_MASK) >>
534*91f16700Schasinglulu 					AVS_LOW_VDD_LIMIT_OFFSET;
535*91f16700Schasinglulu 				NOTICE("7040 1600Mhz, avs = 0x%x\n",
536*91f16700Schasinglulu 					avs_workpoint);
537*91f16700Schasinglulu #else
538*91f16700Schasinglulu 				NOTICE("SVC: AVS work point not changed\n");
539*91f16700Schasinglulu 				return;
540*91f16700Schasinglulu #endif
541*91f16700Schasinglulu 			}
542*91f16700Schasinglulu 			break;
543*91f16700Schasinglulu 		}
544*91f16700Schasinglulu 	} else if (device_id == MVEBU_3900_DEV_ID) {
545*91f16700Schasinglulu 		NOTICE("SVC: DEV ID: %s, FREQ Mode: 0x%x\n",
546*91f16700Schasinglulu 		       "3900", freq_pidi_mode);
547*91f16700Schasinglulu 		switch (freq_pidi_mode) {
548*91f16700Schasinglulu 		case CPU_1600_DDR_1200_RCLK_1200:
549*91f16700Schasinglulu 			if (perr[0])
550*91f16700Schasinglulu 				goto perror;
551*91f16700Schasinglulu 			avs_workpoint = svc[0];
552*91f16700Schasinglulu 			break;
553*91f16700Schasinglulu 		case CPU_1300_DDR_800_RCLK_800:
554*91f16700Schasinglulu 			if (perr[1])
555*91f16700Schasinglulu 				goto perror;
556*91f16700Schasinglulu 			avs_workpoint = svc[1];
557*91f16700Schasinglulu 			break;
558*91f16700Schasinglulu 		default:
559*91f16700Schasinglulu 			if (perr[0])
560*91f16700Schasinglulu 				goto perror;
561*91f16700Schasinglulu 			avs_workpoint = svc[0];
562*91f16700Schasinglulu 			break;
563*91f16700Schasinglulu 		}
564*91f16700Schasinglulu 	} else if (device_id == MVEBU_CN9130_DEV_ID) {
565*91f16700Schasinglulu 		NOTICE("SVC: DEV ID: %s, FREQ Mode: 0x%x\n",
566*91f16700Schasinglulu 		       "CN913x", freq_pidi_mode);
567*91f16700Schasinglulu 		switch (freq_pidi_mode) {
568*91f16700Schasinglulu 		case CPU_2200_DDR_1200_RCLK_1200:
569*91f16700Schasinglulu 			if (perr[0])
570*91f16700Schasinglulu 				goto perror;
571*91f16700Schasinglulu 			avs_workpoint = svc[0];
572*91f16700Schasinglulu 			break;
573*91f16700Schasinglulu 		case CPU_2000_DDR_1200_RCLK_1200:
574*91f16700Schasinglulu 			if (perr[1])
575*91f16700Schasinglulu 				goto perror;
576*91f16700Schasinglulu 			avs_workpoint = svc[1];
577*91f16700Schasinglulu 			break;
578*91f16700Schasinglulu 		case CPU_1600_DDR_1200_RCLK_1200:
579*91f16700Schasinglulu 			if (perr[2])
580*91f16700Schasinglulu 				goto perror;
581*91f16700Schasinglulu 			avs_workpoint = svc[2];
582*91f16700Schasinglulu 			break;
583*91f16700Schasinglulu 		default:
584*91f16700Schasinglulu 			ERROR("SVC: Unsupported Frequency 0x%x\n",
585*91f16700Schasinglulu 				freq_pidi_mode);
586*91f16700Schasinglulu 			return;
587*91f16700Schasinglulu 
588*91f16700Schasinglulu 		}
589*91f16700Schasinglulu 	} else {
590*91f16700Schasinglulu 		ERROR("SVC: Unsupported Device ID 0x%x\n", device_id);
591*91f16700Schasinglulu 		return;
592*91f16700Schasinglulu 	}
593*91f16700Schasinglulu 
594*91f16700Schasinglulu 	/* Set AVS control if needed */
595*91f16700Schasinglulu 	if (avs_workpoint == 0) {
596*91f16700Schasinglulu 		ERROR("SVC: You are using a frequency setup which is\n");
597*91f16700Schasinglulu 		ERROR("Not supported by this device\n");
598*91f16700Schasinglulu 		ERROR("This may result in malfunction of the device\n");
599*91f16700Schasinglulu 		return;
600*91f16700Schasinglulu 	}
601*91f16700Schasinglulu 
602*91f16700Schasinglulu 	/* Remove parity bit */
603*91f16700Schasinglulu 	if (ap_type != CHIP_ID_AP807)
604*91f16700Schasinglulu 		avs_workpoint &= 0x7F;
605*91f16700Schasinglulu 	else
606*91f16700Schasinglulu 		avs_workpoint &= 0x3FF;
607*91f16700Schasinglulu 
608*91f16700Schasinglulu 	/* Update WP from EEPROM if needed */
609*91f16700Schasinglulu 	avs_workpoint = avs_update_from_eeprom(avs_workpoint);
610*91f16700Schasinglulu 
611*91f16700Schasinglulu set_aws_wp:
612*91f16700Schasinglulu 	reg_val  = mmio_read_32(AVS_EN_CTRL_REG);
613*91f16700Schasinglulu 	NOTICE("SVC: AVS work point changed from 0x%x to 0x%x\n",
614*91f16700Schasinglulu 		(reg_val & AVS_VDD_LOW_LIMIT_MASK) >> AVS_LOW_VDD_LIMIT_OFFSET,
615*91f16700Schasinglulu 		avs_workpoint);
616*91f16700Schasinglulu 	reg_val &= ~(AVS_VDD_LOW_LIMIT_MASK | AVS_VDD_HIGH_LIMIT_MASK);
617*91f16700Schasinglulu 	reg_val |= 0x1 << AVS_ENABLE_OFFSET;
618*91f16700Schasinglulu 	reg_val |= avs_workpoint << AVS_HIGH_VDD_LIMIT_OFFSET;
619*91f16700Schasinglulu 	reg_val |= avs_workpoint << AVS_LOW_VDD_LIMIT_OFFSET;
620*91f16700Schasinglulu 	mmio_write_32(AVS_EN_CTRL_REG, reg_val);
621*91f16700Schasinglulu 	return;
622*91f16700Schasinglulu 
623*91f16700Schasinglulu perror:
624*91f16700Schasinglulu 	ERROR("Failed SVC WP[%d] parity check!\n", i);
625*91f16700Schasinglulu 	ERROR("Ignoring the WP values\n");
626*91f16700Schasinglulu }
627*91f16700Schasinglulu 
628*91f16700Schasinglulu #if PLAT_RECOVERY_IMAGE_ENABLE
629*91f16700Schasinglulu static int ble_skip_image_i2c(struct skip_image *skip_im)
630*91f16700Schasinglulu {
631*91f16700Schasinglulu 	ERROR("skipping image using i2c is not supported\n");
632*91f16700Schasinglulu 	/* not supported */
633*91f16700Schasinglulu 	return 0;
634*91f16700Schasinglulu }
635*91f16700Schasinglulu 
636*91f16700Schasinglulu static int ble_skip_image_other(struct skip_image *skip_im)
637*91f16700Schasinglulu {
638*91f16700Schasinglulu 	ERROR("implementation missing for skip image request\n");
639*91f16700Schasinglulu 	/* not supported, make your own implementation */
640*91f16700Schasinglulu 	return 0;
641*91f16700Schasinglulu }
642*91f16700Schasinglulu 
643*91f16700Schasinglulu static int ble_skip_image_gpio(struct skip_image *skip_im)
644*91f16700Schasinglulu {
645*91f16700Schasinglulu 	unsigned int val;
646*91f16700Schasinglulu 	unsigned int mpp_address = 0;
647*91f16700Schasinglulu 	unsigned int offset = 0;
648*91f16700Schasinglulu 
649*91f16700Schasinglulu 	switch (skip_im->info.test.cp_ap) {
650*91f16700Schasinglulu 	case(CP):
651*91f16700Schasinglulu 		mpp_address = MVEBU_CP_GPIO_DATA_IN(skip_im->info.test.cp_index,
652*91f16700Schasinglulu 						    skip_im->info.gpio.num);
653*91f16700Schasinglulu 		if (skip_im->info.gpio.num > NUM_OF_GPIO_PER_REG)
654*91f16700Schasinglulu 			offset = skip_im->info.gpio.num - NUM_OF_GPIO_PER_REG;
655*91f16700Schasinglulu 		else
656*91f16700Schasinglulu 			offset = skip_im->info.gpio.num;
657*91f16700Schasinglulu 		break;
658*91f16700Schasinglulu 	case(AP):
659*91f16700Schasinglulu 		mpp_address = MVEBU_AP_GPIO_DATA_IN;
660*91f16700Schasinglulu 		offset = skip_im->info.gpio.num;
661*91f16700Schasinglulu 		break;
662*91f16700Schasinglulu 	}
663*91f16700Schasinglulu 
664*91f16700Schasinglulu 	val = mmio_read_32(mpp_address);
665*91f16700Schasinglulu 	val &= (1 << offset);
666*91f16700Schasinglulu 	if ((!val && skip_im->info.gpio.button_state == HIGH) ||
667*91f16700Schasinglulu 	    (val && skip_im->info.gpio.button_state == LOW)) {
668*91f16700Schasinglulu 		mmio_write_32(SCRATCH_PAD_REG2, SCRATCH_PAD_SKIP_VAL);
669*91f16700Schasinglulu 		return 1;
670*91f16700Schasinglulu 	}
671*91f16700Schasinglulu 
672*91f16700Schasinglulu 	return 0;
673*91f16700Schasinglulu }
674*91f16700Schasinglulu 
675*91f16700Schasinglulu /*
676*91f16700Schasinglulu  * This function checks if there's a skip image request:
677*91f16700Schasinglulu  * return values:
678*91f16700Schasinglulu  * 1: (true) images request been made.
679*91f16700Schasinglulu  * 0: (false) no image request been made.
680*91f16700Schasinglulu  */
681*91f16700Schasinglulu static int  ble_skip_current_image(void)
682*91f16700Schasinglulu {
683*91f16700Schasinglulu 	struct skip_image *skip_im;
684*91f16700Schasinglulu 
685*91f16700Schasinglulu 	/*fetching skip image info*/
686*91f16700Schasinglulu 	skip_im = (struct skip_image *)plat_marvell_get_skip_image_data();
687*91f16700Schasinglulu 
688*91f16700Schasinglulu 	if (skip_im == NULL)
689*91f16700Schasinglulu 		return 0;
690*91f16700Schasinglulu 
691*91f16700Schasinglulu 	/* check if skipping image request has already been made */
692*91f16700Schasinglulu 	if (mmio_read_32(SCRATCH_PAD_REG2) == SCRATCH_PAD_SKIP_VAL)
693*91f16700Schasinglulu 		return 0;
694*91f16700Schasinglulu 
695*91f16700Schasinglulu 	switch (skip_im->detection_method) {
696*91f16700Schasinglulu 	case GPIO:
697*91f16700Schasinglulu 		return ble_skip_image_gpio(skip_im);
698*91f16700Schasinglulu 	case I2C:
699*91f16700Schasinglulu 		return ble_skip_image_i2c(skip_im);
700*91f16700Schasinglulu 	case USER_DEFINED:
701*91f16700Schasinglulu 		return ble_skip_image_other(skip_im);
702*91f16700Schasinglulu 	}
703*91f16700Schasinglulu 
704*91f16700Schasinglulu 	return 0;
705*91f16700Schasinglulu }
706*91f16700Schasinglulu #endif
707*91f16700Schasinglulu 
708*91f16700Schasinglulu 
709*91f16700Schasinglulu int ble_plat_setup(int *skip)
710*91f16700Schasinglulu {
711*91f16700Schasinglulu 	int ret, cp;
712*91f16700Schasinglulu 	unsigned int freq_mode;
713*91f16700Schasinglulu 
714*91f16700Schasinglulu 	/* Power down unused CPUs */
715*91f16700Schasinglulu 	plat_marvell_early_cpu_powerdown();
716*91f16700Schasinglulu 
717*91f16700Schasinglulu 	/*
718*91f16700Schasinglulu 	 * Save the current CCU configuration and make required changes:
719*91f16700Schasinglulu 	 * - Allow access to DRAM larger than 4GB
720*91f16700Schasinglulu 	 * - Open memory access to all CPn peripherals
721*91f16700Schasinglulu 	 */
722*91f16700Schasinglulu 	ble_plat_mmap_config(MMAP_SAVE_AND_CONFIG);
723*91f16700Schasinglulu 
724*91f16700Schasinglulu #if PLAT_RECOVERY_IMAGE_ENABLE
725*91f16700Schasinglulu 	/* Check if there's a skip request to bootRom recovery Image */
726*91f16700Schasinglulu 	if (ble_skip_current_image()) {
727*91f16700Schasinglulu 		/* close memory access to all CPn peripherals. */
728*91f16700Schasinglulu 		ble_plat_mmap_config(MMAP_RESTORE_SAVED);
729*91f16700Schasinglulu 		*skip = 1;
730*91f16700Schasinglulu 		return 0;
731*91f16700Schasinglulu 	}
732*91f16700Schasinglulu #endif
733*91f16700Schasinglulu 	/* Do required CP-110 setups for BLE stage */
734*91f16700Schasinglulu 	cp110_ble_init(MVEBU_CP_REGS_BASE(0));
735*91f16700Schasinglulu 
736*91f16700Schasinglulu 	/* Config address for each cp other than cp0 */
737*91f16700Schasinglulu 	for (cp = 1; cp < CP_COUNT; cp++)
738*91f16700Schasinglulu 		update_cp110_default_win(cp);
739*91f16700Schasinglulu 
740*91f16700Schasinglulu 	/* Setup AVS */
741*91f16700Schasinglulu 	ble_plat_svc_config();
742*91f16700Schasinglulu 
743*91f16700Schasinglulu 	/* read clk option from sampled-at-reset register */
744*91f16700Schasinglulu 	freq_mode =
745*91f16700Schasinglulu 		SAR_CLOCK_FREQ_MODE(mmio_read_32(MVEBU_AP_SAR_REG_BASE(
746*91f16700Schasinglulu 						 FREQ_MODE_AP_SAR_REG_NUM)));
747*91f16700Schasinglulu 
748*91f16700Schasinglulu 	/* work with PLL clock driver in AP807 */
749*91f16700Schasinglulu 	if (ble_get_ap_type() == CHIP_ID_AP807)
750*91f16700Schasinglulu 		ap807_clocks_init(freq_mode);
751*91f16700Schasinglulu 
752*91f16700Schasinglulu 	/* Do required AP setups for BLE stage */
753*91f16700Schasinglulu 	ap_ble_init();
754*91f16700Schasinglulu 
755*91f16700Schasinglulu 	/* Update DRAM topology (scan DIMM SPDs) */
756*91f16700Schasinglulu 	plat_marvell_dram_update_topology();
757*91f16700Schasinglulu 
758*91f16700Schasinglulu 	/* Kick it in */
759*91f16700Schasinglulu 	ret = dram_init();
760*91f16700Schasinglulu 
761*91f16700Schasinglulu 	/* Restore the original CCU configuration before exit from BLE */
762*91f16700Schasinglulu 	ble_plat_mmap_config(MMAP_RESTORE_SAVED);
763*91f16700Schasinglulu 
764*91f16700Schasinglulu 	return ret;
765*91f16700Schasinglulu }
766