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