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