1f29d1e0cSSheetal Tigadoli /* 2f29d1e0cSSheetal Tigadoli * Copyright (c) 2017 - 2020, Broadcom 3f29d1e0cSSheetal Tigadoli * 4f29d1e0cSSheetal Tigadoli * SPDX-License-Identifier: BSD-3-Clause 5f29d1e0cSSheetal Tigadoli */ 6f29d1e0cSSheetal Tigadoli 7f29d1e0cSSheetal Tigadoli #include <assert.h> 8f29d1e0cSSheetal Tigadoli #include <errno.h> 9f29d1e0cSSheetal Tigadoli #include <stdint.h> 10f29d1e0cSSheetal Tigadoli 11f29d1e0cSSheetal Tigadoli #include <common/debug.h> 12f29d1e0cSSheetal Tigadoli #include <drivers/delay_timer.h> 13f29d1e0cSSheetal Tigadoli #include <lib/mmio.h> 14f29d1e0cSSheetal Tigadoli 15f29d1e0cSSheetal Tigadoli #include <sr_utils.h> 16f29d1e0cSSheetal Tigadoli #include <swreg.h> 17f29d1e0cSSheetal Tigadoli 18f29d1e0cSSheetal Tigadoli #define MIN_VOLT 760000 19f29d1e0cSSheetal Tigadoli #define MAX_VOLT 1060000 20f29d1e0cSSheetal Tigadoli 21f29d1e0cSSheetal Tigadoli #define BSTI_WRITE 0x1 22f29d1e0cSSheetal Tigadoli #define BSTI_READ 0x2 23f29d1e0cSSheetal Tigadoli #define BSTI_COMMAND_TA 0x2 24f29d1e0cSSheetal Tigadoli #define BSTI_COMMAND_DATA 0xFF 25f29d1e0cSSheetal Tigadoli #define BSTI_CONTROL_VAL 0x81 26f29d1e0cSSheetal Tigadoli #define BSTI_CONTROL_BUSY 0x100 27f29d1e0cSSheetal Tigadoli #define BSTI_TOGGLE_BIT 0x2 28f29d1e0cSSheetal Tigadoli #define BSTI_CONFI_DONE_MASK 0xFFFFFFFD 29f29d1e0cSSheetal Tigadoli #define BSTI_REG_DATA_MASK 0xFFFF 30f29d1e0cSSheetal Tigadoli #define BSTI_CMD(sb, op, pa, ra, ta, data) \ 31f29d1e0cSSheetal Tigadoli ((((sb) & 0x3) << 30) | (((op) & 0x3) << 28) | \ 32f29d1e0cSSheetal Tigadoli (((pa) & 0x1F) << 23) | (((ra) & 0x1F) << 18) | \ 33f29d1e0cSSheetal Tigadoli (((ta) & 0x3) << 16) | (data)) 34f29d1e0cSSheetal Tigadoli 35f29d1e0cSSheetal Tigadoli #define PHY_REG0 0x0 36f29d1e0cSSheetal Tigadoli #define PHY_REG1 0x1 37f29d1e0cSSheetal Tigadoli #define PHY_REG4 0x4 38f29d1e0cSSheetal Tigadoli #define PHY_REG5 0x5 39f29d1e0cSSheetal Tigadoli #define PHY_REG6 0x6 40f29d1e0cSSheetal Tigadoli #define PHY_REG7 0x7 41f29d1e0cSSheetal Tigadoli #define PHY_REGC 0xc 42f29d1e0cSSheetal Tigadoli 43f29d1e0cSSheetal Tigadoli #define IHOST_VDDC_DATA 0x560 44f29d1e0cSSheetal Tigadoli #define DDR_CORE_DATA 0x2560 45f29d1e0cSSheetal Tigadoli #define UPDATE_POS_EDGE(data, set) ((data) | ((set) << 1)) 46f29d1e0cSSheetal Tigadoli 47f29d1e0cSSheetal Tigadoli /* 48f29d1e0cSSheetal Tigadoli * Formula for SR A2 reworked board: 49f29d1e0cSSheetal Tigadoli * step = ((vol/(1.4117 * 0.98)) - 500000)/3125 50f29d1e0cSSheetal Tigadoli * where, 51f29d1e0cSSheetal Tigadoli * vol - input voltage 52f29d1e0cSSheetal Tigadoli * 500000 - Reference voltage 53f29d1e0cSSheetal Tigadoli * 3125 - one step value 54f29d1e0cSSheetal Tigadoli */ 55f29d1e0cSSheetal Tigadoli #define A2_VOL_REF 500000 56f29d1e0cSSheetal Tigadoli #define ONE_STEP_VALUE 3125 57f29d1e0cSSheetal Tigadoli #define VOL_DIV(vol) (((vol*10000ull)/(14117*98ull)) * 100ull) 58f29d1e0cSSheetal Tigadoli #define STEP_VALUE(vol) \ 59f29d1e0cSSheetal Tigadoli ((((((VOL_DIV(vol)) - A2_VOL_REF) / ONE_STEP_VALUE) & 0xFF) << 8) | 4) 60f29d1e0cSSheetal Tigadoli 61f29d1e0cSSheetal Tigadoli #define B0_VOL_REF ((500000/100)*98) 62f29d1e0cSSheetal Tigadoli #define B0_ONE_STEP_VALUE 3125 63f29d1e0cSSheetal Tigadoli /* 64f29d1e0cSSheetal Tigadoli * Formula for SR B0 chip for IHOST12/03 and VDDC_CORE 65f29d1e0cSSheetal Tigadoli * step = ((vol/1.56) - (500000 * 0.98))/3125 66f29d1e0cSSheetal Tigadoli * where, 67f29d1e0cSSheetal Tigadoli * vol - input voltage 68f29d1e0cSSheetal Tigadoli * 500000 - Reference voltage 69f29d1e0cSSheetal Tigadoli * 3125 - one step value 70f29d1e0cSSheetal Tigadoli */ 71f29d1e0cSSheetal Tigadoli #define B0_VOL_DIV(vol) (((vol)*100ull)/156) 72f29d1e0cSSheetal Tigadoli #define B0_STEP_VALUE(vol) \ 73f29d1e0cSSheetal Tigadoli ((((((B0_VOL_DIV(vol)) - B0_VOL_REF) / B0_ONE_STEP_VALUE) \ 74f29d1e0cSSheetal Tigadoli & 0xFF) << 8) | 4) 75f29d1e0cSSheetal Tigadoli 76f29d1e0cSSheetal Tigadoli /* 77f29d1e0cSSheetal Tigadoli * Formula for SR B0 chip for DDR-CORE 78f29d1e0cSSheetal Tigadoli * step = ((vol/1) - (500000 * 0.98))/3125 79f29d1e0cSSheetal Tigadoli * where, 80f29d1e0cSSheetal Tigadoli * vol - input voltage 81f29d1e0cSSheetal Tigadoli * 500000 - Reference voltage 82f29d1e0cSSheetal Tigadoli * 3125 - one step value 83f29d1e0cSSheetal Tigadoli */ 84f29d1e0cSSheetal Tigadoli #define B0_DDR_VDDC_VOL_DIV(vol) ((vol)/1) 85f29d1e0cSSheetal Tigadoli #define B0_DDR_VDDC_STEP_VALUE(vol) \ 86f29d1e0cSSheetal Tigadoli ((((((B0_DDR_VDDC_VOL_DIV(vol)) - B0_VOL_REF) / B0_ONE_STEP_VALUE) \ 87f29d1e0cSSheetal Tigadoli & 0xFF) << 8) | 4) 88f29d1e0cSSheetal Tigadoli 89f29d1e0cSSheetal Tigadoli #define MAX_SWREG_CNT 8 90f29d1e0cSSheetal Tigadoli #define MAX_ADDR_PER_SWREG 16 91f29d1e0cSSheetal Tigadoli #define MAX_REG_ADDR 0xF 92f29d1e0cSSheetal Tigadoli #define MIN_REG_ADDR 0x0 93f29d1e0cSSheetal Tigadoli 94f29d1e0cSSheetal Tigadoli static const char *sw_reg_name[MAX_SWREG_CNT] = { 95f29d1e0cSSheetal Tigadoli "DDR_VDDC", 96f29d1e0cSSheetal Tigadoli "IHOST03", 97f29d1e0cSSheetal Tigadoli "IHOST12", 98f29d1e0cSSheetal Tigadoli "IHOST_ARRAY", 99f29d1e0cSSheetal Tigadoli "DDRIO_SLAVE", 100f29d1e0cSSheetal Tigadoli "VDDC_CORE", 101f29d1e0cSSheetal Tigadoli "VDDC1", 102f29d1e0cSSheetal Tigadoli "DDRIO_MASTER" 103f29d1e0cSSheetal Tigadoli }; 104f29d1e0cSSheetal Tigadoli 105f29d1e0cSSheetal Tigadoli /* firmware values for all SWREG for 3.3V input operation */ 106f29d1e0cSSheetal Tigadoli static const uint16_t swreg_fm_data_bx[MAX_SWREG_CNT][MAX_ADDR_PER_SWREG] = { 107f29d1e0cSSheetal Tigadoli /* DDR logic: Power Domains independent of 12v or 3p3v */ 108f29d1e0cSSheetal Tigadoli {0x25E0, 0x2D54, 0x0EC6, 0x01EC, 0x28BB, 0x1144, 0x0200, 0x69C0, 109f29d1e0cSSheetal Tigadoli 0x0010, 0x0EDF, 0x90D7, 0x8000, 0x820C, 0x0003, 0x0001, 0x0000}, 110f29d1e0cSSheetal Tigadoli 111f29d1e0cSSheetal Tigadoli /* ihost03, 3p3V */ 112f29d1e0cSSheetal Tigadoli {0x05E0, 0x39E5, 0x03C1, 0x007C, 0x8BA9, 0x4444, 0x3300, 0x6B80, 113f29d1e0cSSheetal Tigadoli 0x003F, 0x0FFF, 0x90D7, 0x8000, 0x240C, 0x0003, 0x0001, 0x0000}, 114f29d1e0cSSheetal Tigadoli 115f29d1e0cSSheetal Tigadoli /* ihost12 3p3v */ 116f29d1e0cSSheetal Tigadoli {0x05E0, 0x39E5, 0x03C1, 0x007C, 0x8BA9, 0x4444, 0x3300, 0x6B80, 117f29d1e0cSSheetal Tigadoli 0x003F, 0x0FFF, 0x90D7, 0x8000, 0x240C, 0x0003, 0x0001, 0x0000}, 118f29d1e0cSSheetal Tigadoli 119f29d1e0cSSheetal Tigadoli /* ihost array */ 120f29d1e0cSSheetal Tigadoli {0x25E0, 0x2D94, 0x0EC6, 0x01EC, 0x2ABB, 0x1144, 0x0340, 0x69C0, 121f29d1e0cSSheetal Tigadoli 0x0010, 0x0EDF, 0x90D7, 0x8000, 0x860C, 0x0003, 0x0001, 0x0000}, 122f29d1e0cSSheetal Tigadoli 123f29d1e0cSSheetal Tigadoli /* ddr io slave : 3p3v */ 124f29d1e0cSSheetal Tigadoli {0x0560, 0x4438, 0x0000, 0x001F, 0x8028, 0x4444, 0x0300, 0x4380, 125f29d1e0cSSheetal Tigadoli 0x003F, 0x0FFF, 0x10D7, 0x8000, 0xA70C, 0x0003, 0x0001, 0x0000}, 126f29d1e0cSSheetal Tigadoli 127f29d1e0cSSheetal Tigadoli /* core master 3p3v */ 128f29d1e0cSSheetal Tigadoli {0x05E0, 0x39E5, 0x03C1, 0x007C, 0x8BA9, 0x4444, 0x3300, 0x6B80, 129f29d1e0cSSheetal Tigadoli 0x003F, 0x0FFF, 0x90D7, 0x8000, 0x240C, 0x0003, 0x0001, 0x0000}, 130f29d1e0cSSheetal Tigadoli 131f29d1e0cSSheetal Tigadoli /* core slave 3p3v */ 132f29d1e0cSSheetal Tigadoli {0x0560, 0x4438, 0x0000, 0x001F, 0x8028, 0x4444, 0x0300, 0x4380, 133f29d1e0cSSheetal Tigadoli 0x003F, 0x0FFF, 0x10D7, 0x8000, 0x240C, 0x0003, 0x0001, 0x0000}, 134f29d1e0cSSheetal Tigadoli 135f29d1e0cSSheetal Tigadoli /* ddr io master : 3p3v */ 136f29d1e0cSSheetal Tigadoli {0x05E0, 0x39E5, 0x03C1, 0x007C, 0x8BA9, 0x4444, 0x3300, 0x6B80, 137f29d1e0cSSheetal Tigadoli 0x003F, 0x0FFF, 0x90D7, 0x8000, 0xA70C, 0x0003, 0x0001, 0x0000}, 138f29d1e0cSSheetal Tigadoli }; 139f29d1e0cSSheetal Tigadoli 140f29d1e0cSSheetal Tigadoli #define FM_DATA swreg_fm_data_bx 141f29d1e0cSSheetal Tigadoli 142f29d1e0cSSheetal Tigadoli static int swreg_poll(void) 143f29d1e0cSSheetal Tigadoli { 144f29d1e0cSSheetal Tigadoli uint32_t data; 145f29d1e0cSSheetal Tigadoli int retry = 100; 146f29d1e0cSSheetal Tigadoli 147f29d1e0cSSheetal Tigadoli do { 148f29d1e0cSSheetal Tigadoli data = mmio_read_32(BSTI_CONTROL_OFFSET); 149f29d1e0cSSheetal Tigadoli if ((data & BSTI_CONTROL_BUSY) != BSTI_CONTROL_BUSY) 150f29d1e0cSSheetal Tigadoli return 0; 151f29d1e0cSSheetal Tigadoli retry--; 152f29d1e0cSSheetal Tigadoli udelay(1); 153f29d1e0cSSheetal Tigadoli } while (retry > 0); 154f29d1e0cSSheetal Tigadoli 155f29d1e0cSSheetal Tigadoli return -ETIMEDOUT; 156f29d1e0cSSheetal Tigadoli } 157f29d1e0cSSheetal Tigadoli 158f29d1e0cSSheetal Tigadoli static int write_swreg_config(enum sw_reg reg_id, uint32_t addr, uint32_t data) 159f29d1e0cSSheetal Tigadoli { 160f29d1e0cSSheetal Tigadoli uint32_t cmd; 161f29d1e0cSSheetal Tigadoli int ret; 162f29d1e0cSSheetal Tigadoli 163f29d1e0cSSheetal Tigadoli cmd = BSTI_CMD(0x1, BSTI_WRITE, reg_id, addr, BSTI_COMMAND_TA, data); 164f29d1e0cSSheetal Tigadoli mmio_write_32(BSTI_CONTROL_OFFSET, BSTI_CONTROL_VAL); 165f29d1e0cSSheetal Tigadoli mmio_write_32(BSTI_COMMAND_OFFSET, cmd); 166f29d1e0cSSheetal Tigadoli ret = swreg_poll(); 167f29d1e0cSSheetal Tigadoli if (ret) { 168f29d1e0cSSheetal Tigadoli ERROR("Failed to write swreg %s addr 0x%x\n", 169f29d1e0cSSheetal Tigadoli sw_reg_name[reg_id-1], addr); 170f29d1e0cSSheetal Tigadoli return ret; 171f29d1e0cSSheetal Tigadoli } 172f29d1e0cSSheetal Tigadoli return ret; 173f29d1e0cSSheetal Tigadoli } 174f29d1e0cSSheetal Tigadoli 175f29d1e0cSSheetal Tigadoli static int read_swreg_config(enum sw_reg reg_id, uint32_t addr, uint32_t *data) 176f29d1e0cSSheetal Tigadoli { 177f29d1e0cSSheetal Tigadoli uint32_t cmd; 178f29d1e0cSSheetal Tigadoli int ret; 179f29d1e0cSSheetal Tigadoli 180f29d1e0cSSheetal Tigadoli cmd = BSTI_CMD(0x1, BSTI_READ, reg_id, addr, BSTI_COMMAND_TA, PHY_REG0); 181f29d1e0cSSheetal Tigadoli mmio_write_32(BSTI_CONTROL_OFFSET, BSTI_CONTROL_VAL); 182f29d1e0cSSheetal Tigadoli mmio_write_32(BSTI_COMMAND_OFFSET, cmd); 183f29d1e0cSSheetal Tigadoli ret = swreg_poll(); 184f29d1e0cSSheetal Tigadoli if (ret) { 185f29d1e0cSSheetal Tigadoli ERROR("Failed to read swreg %s addr 0x%x\n", 186f29d1e0cSSheetal Tigadoli sw_reg_name[reg_id-1], addr); 187f29d1e0cSSheetal Tigadoli return ret; 188f29d1e0cSSheetal Tigadoli } 189f29d1e0cSSheetal Tigadoli 190f29d1e0cSSheetal Tigadoli *data = mmio_read_32(BSTI_COMMAND_OFFSET); 191f29d1e0cSSheetal Tigadoli *data &= BSTI_REG_DATA_MASK; 192f29d1e0cSSheetal Tigadoli return ret; 193f29d1e0cSSheetal Tigadoli } 194f29d1e0cSSheetal Tigadoli 195f29d1e0cSSheetal Tigadoli static int swreg_config_done(enum sw_reg reg_id) 196f29d1e0cSSheetal Tigadoli { 197f29d1e0cSSheetal Tigadoli uint32_t read_data; 198f29d1e0cSSheetal Tigadoli int ret; 199f29d1e0cSSheetal Tigadoli 200f29d1e0cSSheetal Tigadoli ret = read_swreg_config(reg_id, PHY_REG0, &read_data); 201f29d1e0cSSheetal Tigadoli if (ret) 202f29d1e0cSSheetal Tigadoli return ret; 203f29d1e0cSSheetal Tigadoli 204f29d1e0cSSheetal Tigadoli read_data &= BSTI_CONFI_DONE_MASK; 205f29d1e0cSSheetal Tigadoli read_data |= BSTI_TOGGLE_BIT; 206f29d1e0cSSheetal Tigadoli ret = write_swreg_config(reg_id, PHY_REG0, read_data); 207f29d1e0cSSheetal Tigadoli if (ret) 208f29d1e0cSSheetal Tigadoli return ret; 209f29d1e0cSSheetal Tigadoli 210f29d1e0cSSheetal Tigadoli ret = read_swreg_config(reg_id, PHY_REG0, &read_data); 211f29d1e0cSSheetal Tigadoli if (ret) 212f29d1e0cSSheetal Tigadoli return ret; 213f29d1e0cSSheetal Tigadoli 214f29d1e0cSSheetal Tigadoli read_data &= BSTI_CONFI_DONE_MASK; 215f29d1e0cSSheetal Tigadoli ret = write_swreg_config(reg_id, PHY_REG0, read_data); 216f29d1e0cSSheetal Tigadoli if (ret) 217f29d1e0cSSheetal Tigadoli return ret; 218f29d1e0cSSheetal Tigadoli 219f29d1e0cSSheetal Tigadoli return ret; 220f29d1e0cSSheetal Tigadoli } 221f29d1e0cSSheetal Tigadoli 222f29d1e0cSSheetal Tigadoli #ifdef DUMP_SWREG 223f29d1e0cSSheetal Tigadoli static void dump_swreg_firmware(void) 224f29d1e0cSSheetal Tigadoli { 225f29d1e0cSSheetal Tigadoli enum sw_reg reg_id; 226f29d1e0cSSheetal Tigadoli uint32_t data; 227f29d1e0cSSheetal Tigadoli int addr; 228f29d1e0cSSheetal Tigadoli int ret; 229f29d1e0cSSheetal Tigadoli 230f29d1e0cSSheetal Tigadoli for (reg_id = DDR_VDDC; reg_id <= DDRIO_MASTER; reg_id++) { 231f29d1e0cSSheetal Tigadoli INFO("SWREG: %s\n", sw_reg_name[reg_id - 1]); 232f29d1e0cSSheetal Tigadoli for (addr = MIN_REG_ADDR; addr <= MAX_REG_ADDR; addr++) { 233f29d1e0cSSheetal Tigadoli ret = read_swreg_config(reg_id, addr, &data); 234f29d1e0cSSheetal Tigadoli if (ret) 235f29d1e0cSSheetal Tigadoli ERROR("Failed to read offset %d\n", addr); 236f29d1e0cSSheetal Tigadoli INFO("\t0x%x: 0x%04x\n", addr, data); 237f29d1e0cSSheetal Tigadoli } 238f29d1e0cSSheetal Tigadoli } 239f29d1e0cSSheetal Tigadoli } 240f29d1e0cSSheetal Tigadoli #endif 241f29d1e0cSSheetal Tigadoli 242f29d1e0cSSheetal Tigadoli int set_swreg(enum sw_reg reg_id, uint32_t micro_volts) 243f29d1e0cSSheetal Tigadoli { 244f29d1e0cSSheetal Tigadoli uint32_t step, programmed_step; 245f29d1e0cSSheetal Tigadoli uint32_t data = IHOST_VDDC_DATA; 246f29d1e0cSSheetal Tigadoli int ret; 247f29d1e0cSSheetal Tigadoli 248f29d1e0cSSheetal Tigadoli if ((micro_volts > MAX_VOLT) || (micro_volts < MIN_VOLT)) { 249f29d1e0cSSheetal Tigadoli ERROR("input voltage out-of-range\n"); 250f29d1e0cSSheetal Tigadoli ret = -EINVAL; 251f29d1e0cSSheetal Tigadoli goto failed; 252f29d1e0cSSheetal Tigadoli } 253f29d1e0cSSheetal Tigadoli 254f29d1e0cSSheetal Tigadoli ret = read_swreg_config(reg_id, PHY_REGC, &programmed_step); 255f29d1e0cSSheetal Tigadoli if (ret) 256f29d1e0cSSheetal Tigadoli goto failed; 257f29d1e0cSSheetal Tigadoli 258f29d1e0cSSheetal Tigadoli if (reg_id == DDR_VDDC) 259f29d1e0cSSheetal Tigadoli step = B0_DDR_VDDC_STEP_VALUE(micro_volts); 260f29d1e0cSSheetal Tigadoli else 261f29d1e0cSSheetal Tigadoli step = B0_STEP_VALUE(micro_volts); 262f29d1e0cSSheetal Tigadoli 263f29d1e0cSSheetal Tigadoli if ((step >> 8) != (programmed_step >> 8)) { 264f29d1e0cSSheetal Tigadoli ret = write_swreg_config(reg_id, PHY_REGC, step); 265f29d1e0cSSheetal Tigadoli if (ret) 266f29d1e0cSSheetal Tigadoli goto failed; 267f29d1e0cSSheetal Tigadoli 268f29d1e0cSSheetal Tigadoli if (reg_id == DDR_VDDC) 269f29d1e0cSSheetal Tigadoli data = DDR_CORE_DATA; 270f29d1e0cSSheetal Tigadoli 271f29d1e0cSSheetal Tigadoli ret = write_swreg_config(reg_id, PHY_REG0, 272f29d1e0cSSheetal Tigadoli UPDATE_POS_EDGE(data, 1)); 273f29d1e0cSSheetal Tigadoli if (ret) 274f29d1e0cSSheetal Tigadoli goto failed; 275f29d1e0cSSheetal Tigadoli 276f29d1e0cSSheetal Tigadoli ret = write_swreg_config(reg_id, PHY_REG0, 277f29d1e0cSSheetal Tigadoli UPDATE_POS_EDGE(data, 0)); 278f29d1e0cSSheetal Tigadoli if (ret) 279f29d1e0cSSheetal Tigadoli goto failed; 280f29d1e0cSSheetal Tigadoli } 281f29d1e0cSSheetal Tigadoli 282f29d1e0cSSheetal Tigadoli INFO("%s voltage updated to %duV\n", sw_reg_name[reg_id-1], 283f29d1e0cSSheetal Tigadoli micro_volts); 284f29d1e0cSSheetal Tigadoli return ret; 285f29d1e0cSSheetal Tigadoli 286f29d1e0cSSheetal Tigadoli failed: 287f29d1e0cSSheetal Tigadoli /* 288f29d1e0cSSheetal Tigadoli * Stop booting if voltages are not set 289f29d1e0cSSheetal Tigadoli * correctly. Booting will fail at random point 290f29d1e0cSSheetal Tigadoli * if we continue with wrong voltage settings. 291f29d1e0cSSheetal Tigadoli */ 292f29d1e0cSSheetal Tigadoli ERROR("Failed to set %s voltage to %duV\n", sw_reg_name[reg_id-1], 293f29d1e0cSSheetal Tigadoli micro_volts); 294f29d1e0cSSheetal Tigadoli assert(0); 295f29d1e0cSSheetal Tigadoli 296f29d1e0cSSheetal Tigadoli return ret; 297f29d1e0cSSheetal Tigadoli } 298f29d1e0cSSheetal Tigadoli 299*1b491eeaSElyes Haouas /* Update SWREG firmware for all power domain for A2 chip */ 300f29d1e0cSSheetal Tigadoli int swreg_firmware_update(void) 301f29d1e0cSSheetal Tigadoli { 302f29d1e0cSSheetal Tigadoli enum sw_reg reg_id; 303f29d1e0cSSheetal Tigadoli uint32_t data; 304f29d1e0cSSheetal Tigadoli int addr; 305f29d1e0cSSheetal Tigadoli int ret; 306f29d1e0cSSheetal Tigadoli 307f29d1e0cSSheetal Tigadoli /* write firmware values */ 308f29d1e0cSSheetal Tigadoli for (reg_id = DDR_VDDC; reg_id <= DDRIO_MASTER; reg_id++) { 309f29d1e0cSSheetal Tigadoli /* write higher location first */ 310f29d1e0cSSheetal Tigadoli for (addr = MAX_REG_ADDR; addr >= MIN_REG_ADDR; addr--) { 311f29d1e0cSSheetal Tigadoli ret = write_swreg_config(reg_id, addr, 312f29d1e0cSSheetal Tigadoli FM_DATA[reg_id - 1][addr]); 313f29d1e0cSSheetal Tigadoli if (ret) 314f29d1e0cSSheetal Tigadoli goto exit; 315f29d1e0cSSheetal Tigadoli } 316f29d1e0cSSheetal Tigadoli } 317f29d1e0cSSheetal Tigadoli 318f29d1e0cSSheetal Tigadoli /* trigger SWREG firmware update */ 319f29d1e0cSSheetal Tigadoli for (reg_id = DDR_VDDC; reg_id <= DDRIO_MASTER; reg_id++) { 320f29d1e0cSSheetal Tigadoli /* 321f29d1e0cSSheetal Tigadoli * Slave regulator doesn't have to be updated, 322f29d1e0cSSheetal Tigadoli * Updating Master is enough 323f29d1e0cSSheetal Tigadoli */ 324f29d1e0cSSheetal Tigadoli if ((reg_id == DDRIO_SLAVE) || (reg_id == VDDC1)) 325f29d1e0cSSheetal Tigadoli continue; 326f29d1e0cSSheetal Tigadoli 327f29d1e0cSSheetal Tigadoli ret = swreg_config_done(reg_id); 328f29d1e0cSSheetal Tigadoli if (ret) { 329f29d1e0cSSheetal Tigadoli ERROR("Failed to trigger SWREG firmware update for %s\n" 330f29d1e0cSSheetal Tigadoli , sw_reg_name[reg_id-1]); 331f29d1e0cSSheetal Tigadoli return ret; 332f29d1e0cSSheetal Tigadoli } 333f29d1e0cSSheetal Tigadoli } 334f29d1e0cSSheetal Tigadoli 335f29d1e0cSSheetal Tigadoli for (reg_id = DDR_VDDC; reg_id <= DDRIO_MASTER; reg_id++) { 336f29d1e0cSSheetal Tigadoli /* 337f29d1e0cSSheetal Tigadoli * IHOST_ARRAY will be used on some boards like STRATUS and 338f29d1e0cSSheetal Tigadoli * there will not be any issue even if it is updated on other 339f29d1e0cSSheetal Tigadoli * boards where it is not used. 340f29d1e0cSSheetal Tigadoli */ 341f29d1e0cSSheetal Tigadoli if (reg_id == IHOST_ARRAY) 342f29d1e0cSSheetal Tigadoli continue; 343f29d1e0cSSheetal Tigadoli 344f29d1e0cSSheetal Tigadoli for (addr = MIN_REG_ADDR; addr <= MAX_REG_ADDR; addr++) { 345f29d1e0cSSheetal Tigadoli ret = read_swreg_config(reg_id, addr, &data); 346f29d1e0cSSheetal Tigadoli if (ret || (!ret && 347f29d1e0cSSheetal Tigadoli (data != FM_DATA[reg_id - 1][addr]))) { 348f29d1e0cSSheetal Tigadoli ERROR("swreg fm update failed: %s at off %d\n", 349f29d1e0cSSheetal Tigadoli sw_reg_name[reg_id - 1], addr); 350f29d1e0cSSheetal Tigadoli ERROR("Read val: 0x%x, expected val: 0x%x\n", 351f29d1e0cSSheetal Tigadoli data, FM_DATA[reg_id - 1][addr]); 352f29d1e0cSSheetal Tigadoli return -1; 353f29d1e0cSSheetal Tigadoli } 354f29d1e0cSSheetal Tigadoli } 355f29d1e0cSSheetal Tigadoli } 356f29d1e0cSSheetal Tigadoli 357f29d1e0cSSheetal Tigadoli INFO("Updated SWREG firmware\n"); 358f29d1e0cSSheetal Tigadoli 359f29d1e0cSSheetal Tigadoli #ifdef DUMP_SWREG 360f29d1e0cSSheetal Tigadoli dump_swreg_firmware(); 361f29d1e0cSSheetal Tigadoli #endif 362f29d1e0cSSheetal Tigadoli return ret; 363f29d1e0cSSheetal Tigadoli 364f29d1e0cSSheetal Tigadoli exit: 365f29d1e0cSSheetal Tigadoli /* 366f29d1e0cSSheetal Tigadoli * Stop booting if swreg firmware update fails. 367f29d1e0cSSheetal Tigadoli * Booting will fail at random point if we 368f29d1e0cSSheetal Tigadoli * continue with wrong voltage settings. 369f29d1e0cSSheetal Tigadoli */ 370f29d1e0cSSheetal Tigadoli ERROR("Failed to update firmware for %s SWREG\n", 371f29d1e0cSSheetal Tigadoli sw_reg_name[reg_id-1]); 372f29d1e0cSSheetal Tigadoli assert(0); 373f29d1e0cSSheetal Tigadoli 374f29d1e0cSSheetal Tigadoli return ret; 375f29d1e0cSSheetal Tigadoli } 376