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