blob: 07d6cad9bebf7c386910e9d7b4e86d4b00a79f2b [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
44#define AVS_EN_CTRL_REG (MVEBU_AP_GEN_MGMT_BASE + 0x130)
45#define AVS_ENABLE_OFFSET (0)
46#define AVS_SOFT_RESET_OFFSET (2)
Konstantin Porotchkinf69ec582018-06-07 18:31:14 +030047#define AVS_TARGET_DELTA_OFFSET (21)
Christine Gharzuzi46a4fc62018-08-02 20:25:11 +030048
49#ifndef MVEBU_SOC_AP807
50 /* AP806 SVC bits */
51 #define AVS_LOW_VDD_LIMIT_OFFSET (4)
52 #define AVS_HIGH_VDD_LIMIT_OFFSET (12)
53 #define AVS_VDD_LOW_LIMIT_MASK (0xFF << AVS_LOW_VDD_LIMIT_OFFSET)
54 #define AVS_VDD_HIGH_LIMIT_MASK (0xFF << AVS_HIGH_VDD_LIMIT_OFFSET)
55#else
56 /* AP807 SVC bits */
57 #define AVS_LOW_VDD_LIMIT_OFFSET (3)
58 #define AVS_HIGH_VDD_LIMIT_OFFSET (13)
59 #define AVS_VDD_LOW_LIMIT_MASK (0x3FF << AVS_LOW_VDD_LIMIT_OFFSET)
60 #define AVS_VDD_HIGH_LIMIT_MASK (0x3FF << AVS_HIGH_VDD_LIMIT_OFFSET)
61#endif
62
Konstantin Porotchkinf69ec582018-06-07 18:31:14 +030063/* VDD limit is 0.9V for A70x0 @ CPU frequency < 1600MHz */
64#define AVS_A7K_LOW_CLK_VALUE ((0x80 << AVS_TARGET_DELTA_OFFSET) | \
65 (0x1A << AVS_HIGH_VDD_LIMIT_OFFSET) | \
66 (0x1A << AVS_LOW_VDD_LIMIT_OFFSET) | \
67 (0x1 << AVS_SOFT_RESET_OFFSET) | \
68 (0x1 << AVS_ENABLE_OFFSET))
69/* VDD limit is 1.0V for all A80x0 devices */
70#define AVS_A8K_CLK_VALUE ((0x80 << AVS_TARGET_DELTA_OFFSET) | \
71 (0x24 << AVS_HIGH_VDD_LIMIT_OFFSET) | \
72 (0x24 << AVS_LOW_VDD_LIMIT_OFFSET) | \
73 (0x1 << AVS_SOFT_RESET_OFFSET) | \
74 (0x1 << AVS_ENABLE_OFFSET))
75
76#define AVS_A3900_CLK_VALUE ((0x80 << 24) | \
77 (0x2c2 << 13) | \
78 (0x2c2 << 3) | \
79 (0x1 << AVS_SOFT_RESET_OFFSET) | \
80 (0x1 << AVS_ENABLE_OFFSET))
Christine Gharzuzi9a772df2018-06-25 13:39:37 +030081/* VDD is 0.88V for 2GHz clock */
82#define AVS_A3900_HIGH_CLK_VALUE ((0x80 << 24) | \
83 (0x2f5 << 13) | \
84 (0x2f5 << 3) | \
85 (0x1 << AVS_SOFT_RESET_OFFSET) | \
86 (0x1 << AVS_ENABLE_OFFSET))
Konstantin Porotchkinf69ec582018-06-07 18:31:14 +030087
88#define MVEBU_AP_EFUSE_SRV_CTRL_REG (MVEBU_AP_GEN_MGMT_BASE + 0x8)
89#define EFUSE_SRV_CTRL_LD_SELECT_OFFS 6
90#define EFUSE_SRV_CTRL_LD_SEL_USER_MASK (1 << EFUSE_SRV_CTRL_LD_SELECT_OFFS)
91
Konstantin Porotchkinf69ec582018-06-07 18:31:14 +030092
93/*
Konstantin Porotchkinf69ec582018-06-07 18:31:14 +030094 * - Identification information in the LD-0 eFuse:
95 * DRO: LD0[74:65] - Not used by the SW
96 * Revision: LD0[78:75] - Not used by the SW
97 * Bin: LD0[80:79] - Not used by the SW
98 * SW Revision: LD0[115:113]
99 * Cluster 1 PWR: LD0[193] - if set to 1, power down CPU Cluster-1
100 * resulting in 2 CPUs active only (7020)
101 */
102#define MVEBU_AP_LD_EFUSE_BASE (MVEBU_AP_GEN_MGMT_BASE + 0xF00)
103/* Bits [94:63] - 32 data bits total */
104#define MVEBU_AP_LD0_94_63_EFUSE_OFFS (MVEBU_AP_LD_EFUSE_BASE + 0x8)
105/* Bits [125:95] - 31 data bits total, 32nd bit is parity for bits [125:63] */
106#define MVEBU_AP_LD0_125_95_EFUSE_OFFS (MVEBU_AP_LD_EFUSE_BASE + 0xC)
107/* Bits [220:189] - 32 data bits total */
108#define MVEBU_AP_LD0_220_189_EFUSE_OFFS (MVEBU_AP_LD_EFUSE_BASE + 0x18)
109/* Offsets for the above 2 fields combined into single 64-bit value [125:63] */
110#define EFUSE_AP_LD0_DRO_OFFS 2 /* LD0[74:65] */
111#define EFUSE_AP_LD0_DRO_MASK 0x3FF
112#define EFUSE_AP_LD0_REVID_OFFS 12 /* LD0[78:75] */
113#define EFUSE_AP_LD0_REVID_MASK 0xF
114#define EFUSE_AP_LD0_BIN_OFFS 16 /* LD0[80:79] */
115#define EFUSE_AP_LD0_BIN_MASK 0x3
116#define EFUSE_AP_LD0_SWREV_OFFS 50 /* LD0[115:113] */
117#define EFUSE_AP_LD0_SWREV_MASK 0x7
118
Christine Gharzuzi46a4fc62018-08-02 20:25:11 +0300119#ifndef MVEBU_SOC_AP807
120 /* AP806 AVS work points in the LD0 eFuse
121 * SVC1 work point: LD0[88:81]
122 * SVC2 work point: LD0[96:89]
123 * SVC3 work point: LD0[104:97]
124 * SVC4 work point: LD0[112:105]
125 */
126 #define EFUSE_AP_LD0_SVC1_OFFS 18 /* LD0[88:81] */
127 #define EFUSE_AP_LD0_SVC2_OFFS 26 /* LD0[96:89] */
128 #define EFUSE_AP_LD0_SVC3_OFFS 34 /* LD0[104:97] */
129 #define EFUSE_AP_LD0_WP_MASK 0xFF
130#else
131 /* AP807 AVS work points in the LD0 eFuse
132 * SVC1 work point: LD0[91:81]
133 * SVC2 work point: LD0[102:92]
134 * SVC3 work point: LD0[113:103]
135 */
136 #define EFUSE_AP_LD0_SVC1_OFFS 17 /* LD0[91:81] */
137 #define EFUSE_AP_LD0_SVC2_OFFS 28 /* LD0[102:92] */
138 #define EFUSE_AP_LD0_SVC3_OFFS 39 /* LD0[113:103] */
139 #define EFUSE_AP_LD0_WP_MASK 0x3FF
140#endif
141
Christine Gharzuzi9a772df2018-06-25 13:39:37 +0300142#define EFUSE_AP_LD0_SVC4_OFFS 42 /* LD0[112:105] */
Konstantin Porotchkinf69ec582018-06-07 18:31:14 +0300143
Christine Gharzuzi9a772df2018-06-25 13:39:37 +0300144#define EFUSE_AP_LD0_CLUSTER_DOWN_OFFS 4
Konstantin Porotchkinf69ec582018-06-07 18:31:14 +0300145
146/* Return the AP revision of the chip */
147static unsigned int ble_get_ap_type(void)
148{
149 unsigned int chip_rev_id;
150
151 chip_rev_id = mmio_read_32(MVEBU_CSS_GWD_CTRL_IIDR2_REG);
152 chip_rev_id = ((chip_rev_id & GWD_IIDR2_CHIP_ID_MASK) >>
153 GWD_IIDR2_CHIP_ID_OFFSET);
154
155 return chip_rev_id;
156}
157
158/******************************************************************************
159 * The routine allows to save the CCU and IO windows configuration during DRAM
160 * setup and restore them afterwards before exiting the BLE stage.
161 * Such window configuration is required since not all default settings coming
162 * from the HW and the BootROM allow access to peripherals connected to
163 * all available CPn components.
164 * For instance, when the boot device is located on CP0, the IO window to CP1
165 * is not opened automatically by the HW and if the DRAM SPD is located on CP1
166 * i2c channel, it cannot be read at BLE stage.
167 * Therefore the DRAM init procedure have to provide access to all available
168 * CPn peripherals during the BLE stage by setting the CCU IO window to all
169 * CPnph addresses and by enabling the IO windows accordingly.
170 * Additionally this function configures the CCU GCR to DRAM, which allows
171 * usage or more than 4GB DRAM as it configured by the default CCU DRAM window.
172 *
173 * IN:
174 * MMAP_SAVE_AND_CONFIG - save the existing configuration and update it
175 * MMAP_RESTORE_SAVED - restore saved configuration
176 * OUT:
177 * NONE
178 ****************************************************************************
179 */
180static void ble_plat_mmap_config(int restore)
181{
182 if (restore == MMAP_RESTORE_SAVED) {
183 /* Restore all orig. settings that were modified by BLE stage */
184 ccu_restore_win_all(MVEBU_AP0);
185 /* Restore CCU */
186 iow_restore_win_all(MVEBU_AP0);
187 return;
188 }
189
190 /* Store original values */
191 ccu_save_win_all(MVEBU_AP0);
192 /* Save CCU */
193 iow_save_win_all(MVEBU_AP0);
194
195 init_ccu(MVEBU_AP0);
196 /* The configuration saved, now all the changes can be done */
197 init_io_win(MVEBU_AP0);
198}
199
200/****************************************************************************
201 * Setup Adaptive Voltage Switching - this is required for some platforms
202 ****************************************************************************
203 */
204static void ble_plat_avs_config(void)
205{
Christine Gharzuzi9a772df2018-06-25 13:39:37 +0300206 uint32_t freq_mode, device_id;
207 uint32_t avs_val = 0;
Konstantin Porotchkinf69ec582018-06-07 18:31:14 +0300208
Christine Gharzuzi9a772df2018-06-25 13:39:37 +0300209 freq_mode =
210 SAR_CLOCK_FREQ_MODE(mmio_read_32(MVEBU_AP_SAR_REG_BASE(
211 FREQ_MODE_AP_SAR_REG_NUM)));
Konstantin Porotchkinf69ec582018-06-07 18:31:14 +0300212 /* Check which SoC is running and act accordingly */
213 if (ble_get_ap_type() == CHIP_ID_AP807) {
Christine Gharzuzi9a772df2018-06-25 13:39:37 +0300214 /* Increase CPU voltage for higher CPU clock */
215 if (freq_mode == CPU_2000_DDR_1200_RCLK_1200)
216 avs_val = AVS_A3900_HIGH_CLK_VALUE;
217 else
218 avs_val = AVS_A3900_CLK_VALUE;
219 } else {
220 /* Check which SoC is running and act accordingly */
221 device_id = cp110_device_id_get(MVEBU_CP_REGS_BASE(0));
222 switch (device_id) {
223 case MVEBU_80X0_DEV_ID:
224 case MVEBU_80X0_CP115_DEV_ID:
225 /* Always fix the default AVS value on A80x0 */
226 avs_val = AVS_A8K_CLK_VALUE;
227 break;
228 case MVEBU_70X0_DEV_ID:
229 case MVEBU_70X0_CP115_DEV_ID:
230 /* Fix AVS for CPU clocks lower than 1600MHz on A70x0 */
231 if ((freq_mode > CPU_1600_DDR_900_RCLK_900_2) &&
232 (freq_mode < CPU_DDR_RCLK_INVALID))
233 avs_val = AVS_A7K_LOW_CLK_VALUE;
234 break;
235 default:
236 ERROR("Unsupported Device ID 0x%x\n", device_id);
237 return;
238 }
Konstantin Porotchkinf69ec582018-06-07 18:31:14 +0300239 }
240
Christine Gharzuzi9a772df2018-06-25 13:39:37 +0300241 if (avs_val) {
242 VERBOSE("AVS: Setting AVS CTRL to 0x%x\n", avs_val);
243 mmio_write_32(AVS_EN_CTRL_REG, avs_val);
Konstantin Porotchkinf69ec582018-06-07 18:31:14 +0300244 }
245}
246
247/****************************************************************************
248 * SVC flow - v0.10
249 * The feature is intended to configure AVS value according to eFuse values
250 * that are burned individually for each SoC during the test process.
251 * Primary AVS value is stored in HD efuse and processed on power on
252 * by the HW engine
253 * Secondary AVS value is located in LD efuse and contains 4 work points for
254 * various CPU frequencies.
255 * The Secondary AVS value is only taken into account if the SW Revision stored
256 * in the efuse is greater than 0 and the CPU is running in a certain speed.
257 ****************************************************************************
258 */
259static void ble_plat_svc_config(void)
260{
261 uint32_t reg_val, avs_workpoint, freq_pidi_mode;
262 uint64_t efuse;
263 uint32_t device_id, single_cluster;
Christine Gharzuzi46a4fc62018-08-02 20:25:11 +0300264 uint16_t svc[4], perr[4], i, sw_ver;
265 unsigned int ap_type;
Konstantin Porotchkinf69ec582018-06-07 18:31:14 +0300266
267 /* Set access to LD0 */
268 reg_val = mmio_read_32(MVEBU_AP_EFUSE_SRV_CTRL_REG);
269 reg_val &= ~EFUSE_SRV_CTRL_LD_SELECT_OFFS;
270 mmio_write_32(MVEBU_AP_EFUSE_SRV_CTRL_REG, reg_val);
271
272 /* Obtain the value of LD0[125:63] */
273 efuse = mmio_read_32(MVEBU_AP_LD0_125_95_EFUSE_OFFS);
274 efuse <<= 32;
275 efuse |= mmio_read_32(MVEBU_AP_LD0_94_63_EFUSE_OFFS);
276
277 /* SW Revision:
278 * Starting from SW revision 1 the SVC flow is supported.
279 * SW version 0 (efuse not programmed) should follow the
280 * regular AVS update flow.
281 */
282 sw_ver = (efuse >> EFUSE_AP_LD0_SWREV_OFFS) & EFUSE_AP_LD0_SWREV_MASK;
283 if (sw_ver < 1) {
284 NOTICE("SVC: SW Revision 0x%x. SVC is not supported\n", sw_ver);
285 ble_plat_avs_config();
286 return;
287 }
288
289 /* Frequency mode from SAR */
290 freq_pidi_mode = SAR_CLOCK_FREQ_MODE(
291 mmio_read_32(
292 MVEBU_AP_SAR_REG_BASE(
293 FREQ_MODE_AP_SAR_REG_NUM)));
294
295 /* Decode all SVC work points */
296 svc[0] = (efuse >> EFUSE_AP_LD0_SVC1_OFFS) & EFUSE_AP_LD0_WP_MASK;
297 svc[1] = (efuse >> EFUSE_AP_LD0_SVC2_OFFS) & EFUSE_AP_LD0_WP_MASK;
298 svc[2] = (efuse >> EFUSE_AP_LD0_SVC3_OFFS) & EFUSE_AP_LD0_WP_MASK;
Christine Gharzuzi46a4fc62018-08-02 20:25:11 +0300299
300 /* Fetch AP type to distinguish between AP806 and AP807 */
301 ap_type = ble_get_ap_type();
302
303 if (ap_type != CHIP_ID_AP807) {
304 svc[3] = (efuse >> EFUSE_AP_LD0_SVC4_OFFS)
305 & EFUSE_AP_LD0_WP_MASK;
306 INFO("SVC: Efuse WP: [0]=0x%x, [1]=0x%x, [2]=0x%x, [3]=0x%x\n",
307 svc[0], svc[1], svc[2], svc[3]);
308 } else {
309 INFO("SVC: Efuse WP: [0]=0x%x, [1]=0x%x, [2]=0x%x\n",
310 svc[0], svc[1], svc[2]);
311 }
Konstantin Porotchkinf69ec582018-06-07 18:31:14 +0300312
313 /* Validate parity of SVC workpoint values */
314 for (i = 0; i < 4; i++) {
315 uint8_t parity, bit;
316
317 perr[i] = 0;
318
319 for (bit = 1, parity = svc[i] & 1; bit < 7; bit++)
320 parity ^= (svc[i] >> bit) & 1;
321
322 /* Starting from SW version 2, the parity check is mandatory */
323 if ((sw_ver > 1) && (parity != ((svc[i] >> 7) & 1)))
324 perr[i] = 1; /* register the error */
325 }
326
327 single_cluster = mmio_read_32(MVEBU_AP_LD0_220_189_EFUSE_OFFS);
328 single_cluster = (single_cluster >> EFUSE_AP_LD0_CLUSTER_DOWN_OFFS) & 1;
329
330 device_id = cp110_device_id_get(MVEBU_CP_REGS_BASE(0));
331 if (device_id == MVEBU_80X0_DEV_ID ||
332 device_id == MVEBU_80X0_CP115_DEV_ID) {
333 /* A8040/A8020 */
334 NOTICE("SVC: DEV ID: %s, FREQ Mode: 0x%x\n",
335 single_cluster == 0 ? "8040" : "8020", freq_pidi_mode);
336 switch (freq_pidi_mode) {
337 case CPU_1800_DDR_1200_RCLK_1200:
338 case CPU_1800_DDR_1050_RCLK_1050:
339 if (perr[1])
340 goto perror;
341 avs_workpoint = svc[1];
342 break;
343 case CPU_1600_DDR_1050_RCLK_1050:
344 case CPU_1600_DDR_900_RCLK_900_2:
345 if (perr[2])
346 goto perror;
347 avs_workpoint = svc[2];
348 break;
349 case CPU_1300_DDR_800_RCLK_800:
350 case CPU_1300_DDR_650_RCLK_650:
351 if (perr[3])
352 goto perror;
353 avs_workpoint = svc[3];
354 break;
355 case CPU_2000_DDR_1200_RCLK_1200:
356 case CPU_2000_DDR_1050_RCLK_1050:
357 default:
358 if (perr[0])
359 goto perror;
360 avs_workpoint = svc[0];
361 break;
362 }
363 } else if (device_id == MVEBU_70X0_DEV_ID ||
364 device_id == MVEBU_70X0_CP115_DEV_ID) {
365 /* A7040/A7020/A6040 */
366 NOTICE("SVC: DEV ID: %s, FREQ Mode: 0x%x\n",
367 single_cluster == 0 ? "7040" : "7020", freq_pidi_mode);
368 switch (freq_pidi_mode) {
369 case CPU_1400_DDR_800_RCLK_800:
370 if (single_cluster) {/* 7020 */
371 if (perr[1])
372 goto perror;
373 avs_workpoint = svc[1];
374 } else {
375 if (perr[0])
376 goto perror;
377 avs_workpoint = svc[0];
378 }
379 break;
380 case CPU_1200_DDR_800_RCLK_800:
381 if (single_cluster) {/* 7020 */
382 if (perr[2])
383 goto perror;
384 avs_workpoint = svc[2];
385 } else {
386 if (perr[1])
387 goto perror;
388 avs_workpoint = svc[1];
389 }
390 break;
391 case CPU_800_DDR_800_RCLK_800:
392 case CPU_1000_DDR_800_RCLK_800:
393 if (single_cluster) {/* 7020 */
394 if (perr[3])
395 goto perror;
396 avs_workpoint = svc[3];
397 } else {
398 if (perr[2])
399 goto perror;
400 avs_workpoint = svc[2];
401 }
402 break;
403 case CPU_600_DDR_800_RCLK_800:
404 if (perr[3])
405 goto perror;
406 avs_workpoint = svc[3]; /* Same for 6040 and 7020 */
407 break;
408 case CPU_1600_DDR_800_RCLK_800: /* 7020 only */
409 default:
410 if (single_cluster) {/* 7020 */
411 if (perr[0])
412 goto perror;
413 avs_workpoint = svc[0];
414 } else
415 avs_workpoint = 0;
416 break;
417 }
Christine Gharzuzi46a4fc62018-08-02 20:25:11 +0300418 } else if (device_id == MVEBU_3900_DEV_ID) {
419 NOTICE("SVC: DEV ID: %s, FREQ Mode: 0x%x\n",
420 "3900", freq_pidi_mode);
421 switch (freq_pidi_mode) {
422 case CPU_1600_DDR_1200_RCLK_1200:
423 if (perr[0])
424 goto perror;
425 avs_workpoint = svc[0];
426 break;
427 case CPU_1300_DDR_800_RCLK_800:
428 if (perr[1])
429 goto perror;
430 avs_workpoint = svc[1];
431 break;
432 default:
433 if (perr[0])
434 goto perror;
435 avs_workpoint = svc[0];
436 break;
437 }
Konstantin Porotchkinf69ec582018-06-07 18:31:14 +0300438 } else {
439 ERROR("SVC: Unsupported Device ID 0x%x\n", device_id);
440 return;
441 }
442
443 /* Set AVS control if needed */
444 if (avs_workpoint == 0) {
445 ERROR("SVC: AVS work point not changed\n");
446 return;
447 }
448
449 /* Remove parity bit */
Christine Gharzuzi46a4fc62018-08-02 20:25:11 +0300450 if (ap_type != CHIP_ID_AP807)
451 avs_workpoint &= 0x7F;
Konstantin Porotchkinf69ec582018-06-07 18:31:14 +0300452
453 reg_val = mmio_read_32(AVS_EN_CTRL_REG);
454 NOTICE("SVC: AVS work point changed from 0x%x to 0x%x\n",
455 (reg_val & AVS_VDD_LOW_LIMIT_MASK) >> AVS_LOW_VDD_LIMIT_OFFSET,
456 avs_workpoint);
457 reg_val &= ~(AVS_VDD_LOW_LIMIT_MASK | AVS_VDD_HIGH_LIMIT_MASK);
458 reg_val |= 0x1 << AVS_ENABLE_OFFSET;
459 reg_val |= avs_workpoint << AVS_HIGH_VDD_LIMIT_OFFSET;
460 reg_val |= avs_workpoint << AVS_LOW_VDD_LIMIT_OFFSET;
461 mmio_write_32(AVS_EN_CTRL_REG, reg_val);
462 return;
463
464perror:
465 ERROR("Failed SVC WP[%d] parity check!\n", i);
466 ERROR("Ignoring the WP values\n");
467}
468
469#if PLAT_RECOVERY_IMAGE_ENABLE
470static int ble_skip_image_i2c(struct skip_image *skip_im)
471{
472 ERROR("skipping image using i2c is not supported\n");
473 /* not supported */
474 return 0;
475}
476
477static int ble_skip_image_other(struct skip_image *skip_im)
478{
479 ERROR("implementation missing for skip image request\n");
480 /* not supported, make your own implementation */
481 return 0;
482}
483
484static int ble_skip_image_gpio(struct skip_image *skip_im)
485{
486 unsigned int val;
487 unsigned int mpp_address = 0;
488 unsigned int offset = 0;
489
490 switch (skip_im->info.test.cp_ap) {
491 case(CP):
492 mpp_address = MVEBU_CP_GPIO_DATA_IN(skip_im->info.test.cp_index,
493 skip_im->info.gpio.num);
494 if (skip_im->info.gpio.num > NUM_OF_GPIO_PER_REG)
495 offset = skip_im->info.gpio.num - NUM_OF_GPIO_PER_REG;
496 else
497 offset = skip_im->info.gpio.num;
498 break;
499 case(AP):
500 mpp_address = MVEBU_AP_GPIO_DATA_IN;
501 offset = skip_im->info.gpio.num;
502 break;
503 }
504
505 val = mmio_read_32(mpp_address);
506 val &= (1 << offset);
507 if ((!val && skip_im->info.gpio.button_state == HIGH) ||
508 (val && skip_im->info.gpio.button_state == LOW)) {
509 mmio_write_32(SCRATCH_PAD_REG2, SCRATCH_PAD_SKIP_VAL);
510 return 1;
511 }
512
513 return 0;
514}
515
516/*
517 * This function checks if there's a skip image request:
518 * return values:
519 * 1: (true) images request been made.
520 * 0: (false) no image request been made.
521 */
522static int ble_skip_current_image(void)
523{
524 struct skip_image *skip_im;
525
526 /*fetching skip image info*/
527 skip_im = (struct skip_image *)plat_marvell_get_skip_image_data();
528
529 if (skip_im == NULL)
530 return 0;
531
532 /* check if skipping image request has already been made */
533 if (mmio_read_32(SCRATCH_PAD_REG2) == SCRATCH_PAD_SKIP_VAL)
534 return 0;
535
536 switch (skip_im->detection_method) {
537 case GPIO:
538 return ble_skip_image_gpio(skip_im);
539 case I2C:
540 return ble_skip_image_i2c(skip_im);
541 case USER_DEFINED:
542 return ble_skip_image_other(skip_im);
543 }
544
545 return 0;
546}
547#endif
548
Konstantin Porotchkinf69ec582018-06-07 18:31:14 +0300549
550int ble_plat_setup(int *skip)
551{
552 int ret;
Christine Gharzuzi9a772df2018-06-25 13:39:37 +0300553 unsigned int freq_mode;
Konstantin Porotchkinf69ec582018-06-07 18:31:14 +0300554
555 /* Power down unused CPUs */
556 plat_marvell_early_cpu_powerdown();
557
558 /*
559 * Save the current CCU configuration and make required changes:
560 * - Allow access to DRAM larger than 4GB
561 * - Open memory access to all CPn peripherals
562 */
563 ble_plat_mmap_config(MMAP_SAVE_AND_CONFIG);
564
565#if PLAT_RECOVERY_IMAGE_ENABLE
566 /* Check if there's a skip request to bootRom recovery Image */
567 if (ble_skip_current_image()) {
568 /* close memory access to all CPn peripherals. */
569 ble_plat_mmap_config(MMAP_RESTORE_SAVED);
570 *skip = 1;
571 return 0;
572 }
573#endif
574 /* Do required CP-110 setups for BLE stage */
575 cp110_ble_init(MVEBU_CP_REGS_BASE(0));
576
577 /* Setup AVS */
578 ble_plat_svc_config();
579
Christine Gharzuzi9a772df2018-06-25 13:39:37 +0300580 /* read clk option from sampled-at-reset register */
581 freq_mode =
582 SAR_CLOCK_FREQ_MODE(mmio_read_32(MVEBU_AP_SAR_REG_BASE(
583 FREQ_MODE_AP_SAR_REG_NUM)));
584
Konstantin Porotchkinf69ec582018-06-07 18:31:14 +0300585 /* work with PLL clock driver in AP807 */
586 if (ble_get_ap_type() == CHIP_ID_AP807)
Christine Gharzuzi9a772df2018-06-25 13:39:37 +0300587 ap807_clocks_init(freq_mode);
Konstantin Porotchkinf69ec582018-06-07 18:31:14 +0300588
589 /* Do required AP setups for BLE stage */
590 ap_ble_init();
591
592 /* Update DRAM topology (scan DIMM SPDs) */
593 plat_marvell_dram_update_topology();
594
595 /* Kick it in */
596 ret = dram_init();
597
598 /* Restore the original CCU configuration before exit from BLE */
599 ble_plat_mmap_config(MMAP_RESTORE_SAVED);
600
601 return ret;
602}