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