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