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