Sheetal Tigadoli | ad0943e | 2019-12-18 19:44:43 +0530 | [diff] [blame] | 1 | /* |
| 2 | * Copyright (c) 2016-2020, Broadcom |
| 3 | * |
| 4 | * SPDX-License-Identifier: BSD-3-Clause |
| 5 | */ |
| 6 | |
| 7 | #include <arch_helpers.h> |
| 8 | #include <common/bl_common.h> |
| 9 | #include <common/debug.h> |
| 10 | #include <drivers/arm/sp805.h> |
| 11 | #include <drivers/delay_timer.h> |
| 12 | #include <lib/mmio.h> |
| 13 | |
| 14 | #include <chimp.h> |
| 15 | #include <chip_id.h> |
| 16 | #include <cmn_plat_util.h> |
| 17 | #include <dmu.h> |
Sheetal Tigadoli | b015670 | 2020-01-05 14:59:04 +0530 | [diff] [blame] | 18 | #include <emmc_api.h> |
Sheetal Tigadoli | ad0943e | 2019-12-18 19:44:43 +0530 | [diff] [blame] | 19 | #include <fru.h> |
| 20 | #ifdef USE_GPIO |
| 21 | #include <drivers/gpio.h> |
| 22 | #include <iproc_gpio.h> |
| 23 | #endif |
| 24 | #include <platform_def.h> |
| 25 | #include <sotp.h> |
| 26 | #include <swreg.h> |
| 27 | #include <sr_utils.h> |
| 28 | #ifdef USE_DDR |
| 29 | #include <ddr_init.h> |
| 30 | #else |
| 31 | #include <ext_sram_init.h> |
| 32 | #endif |
| 33 | #if DRIVER_OCOTP_ENABLE |
| 34 | #include <ocotp.h> |
| 35 | #endif |
| 36 | #include "board_info.h" |
| 37 | |
| 38 | #define WORD_SIZE 8 |
| 39 | #define SWREG_AVS_OTP_OFFSET (13 * WORD_SIZE) /* 13th row byte offset */ |
| 40 | #define AON_GPIO_OTP_OFFSET (28 * WORD_SIZE) /* 28th row byte offset */ |
| 41 | #define BYTES_TO_READ 8 |
| 42 | |
| 43 | /* OTP voltage step definitions */ |
| 44 | #define MVOLT_STEP_MAX 0x18 /* 1v */ |
| 45 | #define MVOLT_PER_STEP 10 /* 0.01mv per step */ |
| 46 | #define MVOLT_BASE 760 /* 0.76v */ |
| 47 | |
| 48 | #define STEP_TO_UVOLTS(step) \ |
| 49 | ((MVOLT_BASE + (MVOLT_PER_STEP * (step))) * 1000) |
| 50 | |
| 51 | #define GET_BITS(first, last, data) \ |
| 52 | ((data >> first) & ((1 << (last - first + 1)) - 1)) |
| 53 | |
| 54 | /* |
| 55 | * SW-REG OTP encoding: |
| 56 | * |
| 57 | * SWREG_bits[11:0] = OTP 13th row 12 bits[55:44] |
| 58 | * SWREG_bits[11:10] - Valid Bits (0x2 - valid, if not 0x2 - Invalid) |
| 59 | * SWREG_bits[9:5] - iHost03, iHost12 |
| 60 | * SWREG_bits[4:0] - Core VDDC |
| 61 | */ |
| 62 | #define SWREG_OTP_BITS_START 12 /* 44th bit in MSB 32-bits */ |
| 63 | #define SWREG_OTP_BITS_END 23 /* 55th bit in MSB 32-bits */ |
| 64 | #define SWREG_VDDC_FIELD_START 0 |
| 65 | #define SWREG_VDDC_FIELD_END 4 |
| 66 | #define SWREG_IHOST_FIELD_START 5 |
| 67 | #define SWREG_IHOST_FIELD_END 9 |
| 68 | #define SWREG_VALID_BIT_START 10 |
| 69 | #define SWREG_VALID_BIT_END 11 |
| 70 | #define SWREG_VALID_BITS 0x2 |
| 71 | |
| 72 | /* |
| 73 | * Row 13 bit 56 is programmed as '1' today. It is not being used, so plan |
| 74 | * is to flip this bit to '0' for B1 rev. Hence SW can leverage this bit |
| 75 | * to identify Bx chip to program different sw-regulators. |
| 76 | */ |
| 77 | #define SPARE_BIT 24 |
| 78 | |
| 79 | #define IS_SR_B0(data) (((data) >> SPARE_BIT) & 0x1) |
| 80 | |
| 81 | #if DRIVER_OCOTP_ENABLE |
| 82 | static struct otpc_map otp_stingray_map = { |
| 83 | .otpc_row_size = 2, |
| 84 | .data_r_offset = {0x10, 0x5c}, |
| 85 | .data_w_offset = {0x2c, 0x64}, |
| 86 | .word_size = 8, |
| 87 | .stride = 8, |
| 88 | }; |
| 89 | #endif |
| 90 | |
| 91 | void plat_bcm_bl2_early_platform_setup(void) |
| 92 | { |
| 93 | /* Select UART0 for AP via mux setting*/ |
| 94 | if (PLAT_BRCM_BOOT_UART_BASE == UART0_BASE_ADDR) { |
| 95 | mmio_write_32(UART0_SIN_MODE_SEL_CONTROL, 1); |
| 96 | mmio_write_32(UART0_SOUT_MODE_SEL_CONTROL, 1); |
| 97 | } |
| 98 | } |
| 99 | |
| 100 | #ifdef USE_NAND |
| 101 | static void brcm_stingray_nand_init(void) |
| 102 | { |
| 103 | unsigned int val; |
| 104 | unsigned int nand_idm_reset_control = 0x68e0a800; |
| 105 | |
| 106 | VERBOSE(" stingray nand init start.\n"); |
| 107 | |
| 108 | /* Reset NAND */ |
| 109 | VERBOSE(" - reset nand\n"); |
| 110 | val = mmio_read_32((uintptr_t)(nand_idm_reset_control + 0x0)); |
| 111 | mmio_write_32((uintptr_t)(nand_idm_reset_control + 0x0), val | 0x1); |
| 112 | udelay(500); |
| 113 | val = mmio_read_32((uintptr_t)(nand_idm_reset_control + 0x0)); |
| 114 | mmio_write_32((uintptr_t)(nand_idm_reset_control + 0x0), val & ~0x1); |
| 115 | udelay(500); |
| 116 | |
| 117 | VERBOSE(" stingray nand init done.\n"); |
| 118 | } |
| 119 | #endif |
| 120 | |
| 121 | #if defined(USE_PAXB) || defined(USE_PAXC) || defined(USE_SATA) |
| 122 | #define PCIE_RESCAL_CFG_0 0x40000130 |
| 123 | #define PCIE_CFG_RESCAL_RSTB_R (1 << 16) |
| 124 | #define PCIE_CFG_RESCAL_PWRDNB_R (1 << 8) |
| 125 | #define PCIE_RESCAL_STATUS_0 0x4000014c |
| 126 | #define PCIE_STAT_PON_VALID_R (1 << 0) |
| 127 | #define PCIE_RESCAL_OUTPUT_STATUS 0x40000154 |
| 128 | #define CDRU_PCIE_RESET_N_R (1 << CDRU_MISC_RESET_CONTROL__CDRU_PCIE_RESET_N_R) |
| 129 | |
| 130 | #ifdef EMULATION_SETUP |
| 131 | static void brcm_stingray_pcie_reset(void) |
| 132 | { |
| 133 | } |
| 134 | #else |
| 135 | static void brcm_stingray_pcie_reset(void) |
| 136 | { |
| 137 | unsigned int data; |
| 138 | int try; |
| 139 | |
| 140 | if (bcm_chimp_is_nic_mode()) { |
| 141 | INFO("NIC mode detected; PCIe reset/rescal not executed\n"); |
| 142 | return; |
| 143 | } |
| 144 | |
| 145 | mmio_clrbits_32(CDRU_MISC_RESET_CONTROL, CDRU_PCIE_RESET_N_R); |
| 146 | mmio_setbits_32(CDRU_MISC_RESET_CONTROL, CDRU_PCIE_RESET_N_R); |
| 147 | /* Release reset */ |
| 148 | mmio_setbits_32(PCIE_RESCAL_CFG_0, PCIE_CFG_RESCAL_RSTB_R); |
| 149 | mdelay(1); |
| 150 | /* Power UP */ |
| 151 | mmio_setbits_32(PCIE_RESCAL_CFG_0, |
| 152 | (PCIE_CFG_RESCAL_RSTB_R | PCIE_CFG_RESCAL_PWRDNB_R)); |
| 153 | |
| 154 | try = 1000; |
| 155 | do { |
| 156 | udelay(1); |
| 157 | data = mmio_read_32(PCIE_RESCAL_STATUS_0); |
| 158 | try--; |
| 159 | } while ((data & PCIE_STAT_PON_VALID_R) == 0x0 && (try > 0)); |
| 160 | |
| 161 | if (try <= 0) |
| 162 | ERROR("PCIE_RESCAL_STATUS_0: 0x%x\n", data); |
| 163 | |
| 164 | VERBOSE("PCIE_SATA_RESCAL_STATUS_0 0x%x.\n", |
| 165 | mmio_read_32(PCIE_RESCAL_STATUS_0)); |
| 166 | VERBOSE("PCIE_SATA_RESCAL_OUTPUT_STATUS 0x%x.\n", |
| 167 | mmio_read_32(PCIE_RESCAL_OUTPUT_STATUS)); |
| 168 | INFO("PCIE SATA Rescal Init done\n"); |
| 169 | } |
| 170 | #endif /* EMULATION_SETUP */ |
| 171 | #endif /* USE_PAXB || USE_PAXC || USE_SATA */ |
| 172 | |
| 173 | #ifdef USE_PAXC |
| 174 | void brcm_stingray_chimp_check_and_fastboot(void) |
| 175 | { |
| 176 | int fastboot_init_result; |
| 177 | |
| 178 | if (bcm_chimp_is_nic_mode()) |
| 179 | /* Do not wait here */ |
| 180 | return; |
| 181 | |
| 182 | #if WARMBOOT_DDR_S3_SUPPORT |
| 183 | /* |
| 184 | * Currently DDR shmoo parameters and QSPI boot source are |
| 185 | * tied. DDR shmoo parameters are stored in QSPI, which is |
| 186 | * used for warmboot. |
| 187 | * Do not reset nitro for warmboot |
| 188 | */ |
| 189 | if (is_warmboot() && (boot_source_get() == BOOT_SOURCE_QSPI)) |
| 190 | return; |
| 191 | #endif /* WARMBOOT_DDR_S3_SUPPORT */ |
| 192 | |
| 193 | /* |
| 194 | * Not in NIC mode, |
| 195 | * initiate fastboot (if enabled) |
| 196 | */ |
| 197 | if (FASTBOOT_TYPE == CHIMP_FASTBOOT_NITRO_RESET) { |
| 198 | |
| 199 | VERBOSE("Bring up Nitro/ChiMP\n"); |
| 200 | |
| 201 | if (boot_source_get() == BOOT_SOURCE_QSPI) |
| 202 | WARN("Nitro boots from QSPI when AP has booted from QSPI.\n"); |
| 203 | brcm_stingray_set_qspi_mux(0); |
| 204 | VERBOSE("Nitro controls the QSPI\n"); |
| 205 | } |
| 206 | |
| 207 | fastboot_init_result = bcm_chimp_initiate_fastboot(FASTBOOT_TYPE); |
| 208 | if (fastboot_init_result && boot_source_get() != BOOT_SOURCE_QSPI) |
| 209 | ERROR("Nitro init error %d. Status: 0x%x; bpe_mod reg: 0x%x\n" |
| 210 | "fastboot register: 0x%x; handshake register 0x%x\n", |
| 211 | fastboot_init_result, |
| 212 | bcm_chimp_read_ctrl(CHIMP_REG_CTRL_BPE_STAT_REG), |
| 213 | bcm_chimp_read_ctrl(CHIMP_REG_CTRL_BPE_MODE_REG), |
| 214 | bcm_chimp_read_ctrl(CHIMP_REG_CTRL_FSTBOOT_PTR_REG), |
| 215 | bcm_chimp_read(CHIMP_REG_ECO_RESERVED)); |
| 216 | |
| 217 | /* |
| 218 | * CRMU watchdog kicks is an example, which is L1 reset, |
| 219 | * does not clear Nitro scratch pad ram. |
| 220 | * For Nitro resets: Clear the Nitro health status memory. |
| 221 | */ |
| 222 | bcm_chimp_write((CHIMP_REG_CHIMP_SCPAD + CHIMP_HEALTH_STATUS_OFFSET), |
| 223 | 0); |
| 224 | } |
| 225 | #endif |
| 226 | |
| 227 | void set_ihost_vddc_swreg(uint32_t ihost_uvolts, uint32_t vddc_uvolts) |
| 228 | { |
| 229 | NOTICE("ihost_uvolts: %duv, vddc_uvolts: %duv\n", |
| 230 | ihost_uvolts, vddc_uvolts); |
| 231 | |
| 232 | set_swreg(VDDC_CORE, vddc_uvolts); |
| 233 | set_swreg(IHOST03, ihost_uvolts); |
| 234 | set_swreg(IHOST12, ihost_uvolts); |
| 235 | } |
| 236 | |
| 237 | /* |
| 238 | * Reads SWREG AVS OTP bits (13th row) with ECC enabled and get voltage |
| 239 | * defined in OTP if valid OTP is found |
| 240 | */ |
| 241 | void read_avs_otp_bits(uint32_t *ihost_uvolts, uint32_t *vddc_uvolts) |
| 242 | { |
| 243 | uint32_t offset = SWREG_AVS_OTP_OFFSET; |
| 244 | uint32_t ihost_step, vddc_step; |
| 245 | uint32_t avs_bits; |
| 246 | uint32_t buf[2]; |
| 247 | |
| 248 | if (bcm_otpc_read(offset, &buf[0], BYTES_TO_READ, 1) == -1) |
| 249 | return; |
| 250 | |
| 251 | VERBOSE("AVS OTP %d ROW: 0x%x.0x%x\n", |
| 252 | offset/WORD_SIZE, buf[1], buf[0]); |
| 253 | |
| 254 | /* get voltage readings from AVS OTP bits */ |
| 255 | avs_bits = GET_BITS(SWREG_OTP_BITS_START, |
| 256 | SWREG_OTP_BITS_END, |
| 257 | buf[1]); |
| 258 | |
| 259 | /* check for valid otp bits */ |
| 260 | if (GET_BITS(SWREG_VALID_BIT_START, SWREG_VALID_BIT_END, avs_bits) != |
| 261 | SWREG_VALID_BITS) { |
| 262 | WARN("Invalid AVS OTP bits at %d row\n", offset/WORD_SIZE); |
| 263 | return; |
| 264 | } |
| 265 | |
| 266 | /* get ihost and vddc step value */ |
| 267 | vddc_step = GET_BITS(SWREG_VDDC_FIELD_START, |
| 268 | SWREG_VDDC_FIELD_END, |
| 269 | avs_bits); |
| 270 | |
| 271 | ihost_step = GET_BITS(SWREG_IHOST_FIELD_START, |
| 272 | SWREG_IHOST_FIELD_END, |
| 273 | avs_bits); |
| 274 | |
| 275 | if ((ihost_step > MVOLT_STEP_MAX) || (vddc_step > MVOLT_STEP_MAX)) { |
| 276 | WARN("OTP entry invalid\n"); |
| 277 | return; |
| 278 | } |
| 279 | |
| 280 | /* get voltage in micro-volts */ |
| 281 | *ihost_uvolts = STEP_TO_UVOLTS(ihost_step); |
| 282 | *vddc_uvolts = STEP_TO_UVOLTS(vddc_step); |
| 283 | } |
| 284 | |
| 285 | /* |
| 286 | * This api reads otp bits and program internal swreg's - ihos12, ihost03, |
| 287 | * vddc_core and ddr_core based on different chip. External swreg's |
| 288 | * programming will be done from crmu. |
| 289 | * |
| 290 | * For A2 chip: |
| 291 | * Read OTP row 20, bit 50. This bit will be set for A2 chip. Once A2 chip is |
| 292 | * found, read AVS OTP row 13, 12bits[55:44], if valid otp bits are found |
| 293 | * then set ihost and vddc according to avs otp bits else set them to 0.94v |
| 294 | * and 0.91v respectively. Also update the firmware after setting voltage. |
| 295 | * |
| 296 | * For B0 chip: |
| 297 | * Read OTP row 13, bit 56. This bit will be set for B0 chip. Once B0 chip is |
| 298 | * found then set ihost and vddc to 0.95v and ddr_core to 1v. No AVS OTP bits |
| 299 | * are used get ihost/vddc voltages. |
| 300 | * |
| 301 | * For B1 chip: |
| 302 | * Read AVS OTP row 13, 12bits[55:44], if valid otp bits are found then set |
| 303 | * ihost and vddc according to avs otp bits else set them to 0.94v and 0.91v |
| 304 | * respectively. |
| 305 | */ |
| 306 | void set_swreg_based_on_otp(void) |
| 307 | { |
| 308 | /* default voltage if no valid OTP */ |
| 309 | uint32_t vddc_uvolts = VDDC_CORE_DEF_VOLT; |
| 310 | uint32_t ihost_uvolts = IHOST_DEF_VOLT; |
| 311 | uint32_t ddrc_uvolts; |
| 312 | uint32_t offset; |
| 313 | uint32_t buf[2]; |
| 314 | |
| 315 | offset = SWREG_AVS_OTP_OFFSET; |
| 316 | if (bcm_otpc_read(offset, &buf[0], BYTES_TO_READ, 1) == -1) |
| 317 | return; |
| 318 | |
| 319 | VERBOSE("OTP %d ROW: 0x%x.0x%x\n", |
| 320 | offset/WORD_SIZE, buf[1], buf[0]); |
| 321 | |
| 322 | if (IS_SR_B0(buf[1])) { |
| 323 | /* don't read AVS OTP for B0 */ |
| 324 | ihost_uvolts = B0_IHOST_DEF_VOLT; |
| 325 | vddc_uvolts = B0_VDDC_CORE_DEF_VOLT; |
| 326 | ddrc_uvolts = B0_DDR_VDDC_DEF_VOLT; |
| 327 | } else { |
| 328 | read_avs_otp_bits(&ihost_uvolts, &vddc_uvolts); |
| 329 | } |
| 330 | |
| 331 | #if (IHOST_REG_TYPE == IHOST_REG_INTEGRATED) && \ |
| 332 | (VDDC_REG_TYPE == VDDC_REG_INTEGRATED) |
| 333 | /* enable IHOST12 cluster before changing voltage */ |
| 334 | NOTICE("Switching on the Regulator idx: %u\n", |
| 335 | SWREG_IHOST1_DIS); |
| 336 | mmio_clrsetbits_32(CRMU_SWREG_CTRL_ADDR, |
| 337 | BIT(SWREG_IHOST1_DIS), |
| 338 | BIT(SWREG_IHOST1_REG_RESETB)); |
| 339 | |
| 340 | /* wait for regulator supply gets stable */ |
| 341 | while (!(mmio_read_32(CRMU_SWREG_STATUS_ADDR) & |
| 342 | (1 << SWREG_IHOST1_PMU_STABLE))) |
| 343 | ; |
| 344 | |
| 345 | INFO("Regulator supply got stable\n"); |
| 346 | |
| 347 | #ifndef DEFAULT_SWREG_CONFIG |
| 348 | swreg_firmware_update(); |
| 349 | #endif |
| 350 | |
| 351 | set_ihost_vddc_swreg(ihost_uvolts, vddc_uvolts); |
| 352 | #endif |
| 353 | if (IS_SR_B0(buf[1])) { |
| 354 | NOTICE("ddrc_uvolts: %duv\n", ddrc_uvolts); |
| 355 | set_swreg(DDR_VDDC, ddrc_uvolts); |
| 356 | } |
| 357 | } |
| 358 | |
| 359 | #ifdef USE_DDR |
| 360 | static struct ddr_info ddr_info; |
| 361 | #endif |
| 362 | #ifdef USE_FRU |
| 363 | static struct fru_area_info fru_area[FRU_MAX_NR_AREAS]; |
| 364 | static struct fru_board_info board_info; |
| 365 | static struct fru_time fru_tm; |
| 366 | static uint8_t fru_tbl[BCM_MAX_FRU_LEN]; |
| 367 | |
| 368 | static void board_detect_fru(void) |
| 369 | { |
| 370 | uint32_t i, result; |
| 371 | int ret = -1; |
| 372 | |
| 373 | result = bcm_emmc_init(false); |
| 374 | if (!result) { |
| 375 | ERROR("eMMC init failed\n"); |
| 376 | return; |
| 377 | } |
| 378 | |
| 379 | /* go through eMMC boot partitions looking for FRU table */ |
| 380 | for (i = EMMC_BOOT_PARTITION1; i <= EMMC_BOOT_PARTITION2; i++) { |
| 381 | result = emmc_partition_select(i); |
| 382 | if (!result) { |
| 383 | ERROR("Switching to eMMC part %u failed\n", i); |
| 384 | return; |
| 385 | } |
| 386 | |
| 387 | result = emmc_read(BCM_FRU_TBL_OFFSET, (uintptr_t)fru_tbl, |
| 388 | BCM_MAX_FRU_LEN, BCM_MAX_FRU_LEN); |
| 389 | if (!result) { |
| 390 | ERROR("Failed to read from eMMC part %u\n", i); |
| 391 | return; |
| 392 | } |
| 393 | |
| 394 | /* |
| 395 | * Run sanity check and checksum to make sure valid FRU table |
| 396 | * is detected |
| 397 | */ |
| 398 | ret = fru_validate(fru_tbl, fru_area); |
| 399 | if (ret < 0) { |
| 400 | WARN("FRU table not found in eMMC part %u\n", i); |
| 401 | continue; |
| 402 | } |
| 403 | |
| 404 | /* parse DDR information from FRU table */ |
| 405 | ret = fru_parse_ddr(fru_tbl, &fru_area[FRU_AREA_INTERNAL], |
| 406 | &ddr_info); |
| 407 | if (ret < 0) { |
| 408 | WARN("No FRU DDR info found in eMMC part %u\n", i); |
| 409 | continue; |
| 410 | } |
| 411 | |
| 412 | /* parse board information from FRU table */ |
| 413 | ret = fru_parse_board(fru_tbl, &fru_area[FRU_AREA_BOARD_INFO], |
| 414 | &board_info); |
| 415 | if (ret < 0) { |
| 416 | WARN("No FRU board info found in eMMC part %u\n", i); |
| 417 | continue; |
| 418 | } |
| 419 | |
| 420 | /* if we reach here, valid FRU table is parsed */ |
| 421 | break; |
| 422 | } |
| 423 | |
| 424 | if (ret < 0) { |
| 425 | WARN("FRU table missing for this board\n"); |
| 426 | return; |
| 427 | } |
| 428 | |
| 429 | for (i = 0; i < BCM_MAX_NR_DDR; i++) { |
| 430 | INFO("DDR channel index: %d\n", ddr_info.mcb[i].idx); |
| 431 | INFO("DDR size %u GB\n", ddr_info.mcb[i].size_mb / 1024); |
| 432 | INFO("DDR ref ID by SW (Not MCB Ref ID) 0x%x\n", |
| 433 | ddr_info.mcb[i].ref_id); |
| 434 | } |
| 435 | |
| 436 | fru_format_time(board_info.mfg_date, &fru_tm); |
| 437 | |
| 438 | INFO("**** FRU board information ****\n"); |
| 439 | INFO("Language 0x%x\n", board_info.lang); |
| 440 | INFO("Manufacturing Date %u.%02u.%02u, %02u:%02u\n", |
| 441 | fru_tm.year, fru_tm.month, fru_tm.day, |
| 442 | fru_tm.hour, fru_tm.min); |
| 443 | INFO("Manufacturing Date(Raw) 0x%x\n", board_info.mfg_date); |
| 444 | INFO("Manufacturer %s\n", board_info.manufacturer); |
| 445 | INFO("Product Name %s\n", board_info.product_name); |
| 446 | INFO("Serial number %s\n", board_info.serial_number); |
| 447 | INFO("Part number %s\n", board_info.part_number); |
| 448 | INFO("File ID %s\n", board_info.file_id); |
| 449 | } |
| 450 | #endif /* USE_FRU */ |
| 451 | |
| 452 | #ifdef USE_GPIO |
| 453 | |
| 454 | #define INVALID_GPIO 0xffff |
| 455 | |
| 456 | static const int gpio_cfg_bitmap[MAX_NR_GPIOS] = { |
| 457 | #ifdef BRD_DETECT_GPIO_BIT0 |
| 458 | BRD_DETECT_GPIO_BIT0, |
| 459 | #else |
| 460 | INVALID_GPIO, |
| 461 | #endif |
| 462 | #ifdef BRD_DETECT_GPIO_BIT1 |
| 463 | BRD_DETECT_GPIO_BIT1, |
| 464 | #else |
| 465 | INVALID_GPIO, |
| 466 | #endif |
| 467 | #ifdef BRD_DETECT_GPIO_BIT2 |
| 468 | BRD_DETECT_GPIO_BIT2, |
| 469 | #else |
| 470 | INVALID_GPIO, |
| 471 | #endif |
| 472 | #ifdef BRD_DETECT_GPIO_BIT3 |
| 473 | BRD_DETECT_GPIO_BIT3, |
| 474 | #else |
| 475 | INVALID_GPIO, |
| 476 | #endif |
| 477 | }; |
| 478 | |
| 479 | static uint8_t gpio_bitmap; |
| 480 | |
| 481 | /* |
| 482 | * Use an odd number to avoid potential conflict with public GPIO level |
| 483 | * defines |
| 484 | */ |
| 485 | #define GPIO_STATE_FLOAT 15 |
| 486 | |
| 487 | /* |
| 488 | * If GPIO_SUPPORT_FLOAT_DETECTION is disabled, simply return GPIO level |
| 489 | * |
| 490 | * If GPIO_SUPPORT_FLOAT_DETECTION is enabled, add additional test for possible |
| 491 | * pin floating (unconnected) scenario. This support is assuming externally |
| 492 | * applied pull up / pull down will have a stronger pull than the internal pull |
| 493 | * up / pull down. |
| 494 | */ |
| 495 | static uint8_t gpio_get_state(int gpio) |
| 496 | { |
| 497 | uint8_t val; |
| 498 | |
| 499 | /* set direction to GPIO input */ |
| 500 | gpio_set_direction(gpio, GPIO_DIR_IN); |
| 501 | |
| 502 | #ifndef GPIO_SUPPORT_FLOAT_DETECTION |
| 503 | if (gpio_get_value(gpio) == GPIO_LEVEL_HIGH) |
| 504 | val = GPIO_LEVEL_HIGH; |
| 505 | else |
| 506 | val = GPIO_LEVEL_LOW; |
| 507 | |
| 508 | return val; |
| 509 | #else |
| 510 | /* |
| 511 | * Enable internal pull down. If GPIO level is still high, there must |
| 512 | * be an external pull up |
| 513 | */ |
| 514 | gpio_set_pull(gpio, GPIO_PULL_DOWN); |
| 515 | if (gpio_get_value(gpio) == GPIO_LEVEL_HIGH) { |
| 516 | val = GPIO_LEVEL_HIGH; |
| 517 | goto exit; |
| 518 | } |
| 519 | |
| 520 | /* |
| 521 | * Enable internal pull up. If GPIO level is still low, there must |
| 522 | * be an external pull down |
| 523 | */ |
| 524 | gpio_set_pull(gpio, GPIO_PULL_UP); |
| 525 | if (gpio_get_value(gpio) == GPIO_LEVEL_LOW) { |
| 526 | val = GPIO_LEVEL_LOW; |
| 527 | goto exit; |
| 528 | } |
| 529 | |
| 530 | /* if reached here, the pin must be not connected */ |
| 531 | val = GPIO_STATE_FLOAT; |
| 532 | |
| 533 | exit: |
| 534 | /* make sure internall pull is disabled */ |
| 535 | if (gpio_get_pull(gpio) != GPIO_PULL_NONE) |
| 536 | gpio_set_pull(gpio, GPIO_PULL_NONE); |
| 537 | |
| 538 | return val; |
| 539 | #endif |
| 540 | } |
| 541 | |
| 542 | static void board_detect_gpio(void) |
| 543 | { |
| 544 | unsigned int i, val; |
| 545 | int gpio; |
| 546 | |
| 547 | iproc_gpio_init(IPROC_GPIO_S_BASE, IPROC_GPIO_NR, |
| 548 | IPROC_IOPAD_MODE_BASE, HSLS_IOPAD_BASE); |
| 549 | |
| 550 | gpio_bitmap = 0; |
| 551 | for (i = 0; i < MAX_NR_GPIOS; i++) { |
| 552 | if (gpio_cfg_bitmap[i] == INVALID_GPIO) |
| 553 | continue; |
| 554 | |
| 555 | /* |
| 556 | * Construct the bitmap based on GPIO value. Floating pin |
| 557 | * detection is a special case. As soon as a floating pin is |
| 558 | * detected, a special value of MAX_GPIO_BITMAP_VAL is |
| 559 | * assigned and we break out of the loop immediately |
| 560 | */ |
| 561 | gpio = gpio_cfg_bitmap[i]; |
| 562 | val = gpio_get_state(gpio); |
| 563 | if (val == GPIO_STATE_FLOAT) { |
| 564 | gpio_bitmap = MAX_GPIO_BITMAP_VAL; |
| 565 | break; |
| 566 | } |
| 567 | |
| 568 | if (val == GPIO_LEVEL_HIGH) |
| 569 | gpio_bitmap |= BIT(i); |
| 570 | } |
| 571 | |
| 572 | memcpy(&ddr_info, &gpio_ddr_info[gpio_bitmap], sizeof(ddr_info)); |
| 573 | INFO("Board detection GPIO bitmap = 0x%x\n", gpio_bitmap); |
| 574 | } |
| 575 | #endif /* USE_GPIO */ |
| 576 | |
| 577 | static void bcm_board_detect(void) |
| 578 | { |
| 579 | #ifdef DDR_LEGACY_MCB_SUPPORTED |
| 580 | /* Loading default DDR info */ |
| 581 | memcpy(&ddr_info, &default_ddr_info, sizeof(ddr_info)); |
| 582 | #endif |
| 583 | #ifdef USE_FRU |
| 584 | board_detect_fru(); |
| 585 | #endif |
| 586 | #ifdef USE_GPIO |
| 587 | board_detect_gpio(); |
| 588 | #endif |
| 589 | } |
| 590 | |
| 591 | static void dump_persistent_regs(void) |
| 592 | { |
| 593 | NOTICE("pr0: %x\n", mmio_read_32(CRMU_IHOST_SW_PERSISTENT_REG0)); |
| 594 | NOTICE("pr1: %x\n", mmio_read_32(CRMU_IHOST_SW_PERSISTENT_REG1)); |
| 595 | NOTICE("pr2: %x\n", mmio_read_32(CRMU_IHOST_SW_PERSISTENT_REG2)); |
| 596 | NOTICE("pr3: %x\n", mmio_read_32(CRMU_IHOST_SW_PERSISTENT_REG3)); |
| 597 | NOTICE("pr4: %x\n", mmio_read_32(CRMU_IHOST_SW_PERSISTENT_REG4)); |
| 598 | NOTICE("pr5: %x\n", mmio_read_32(CRMU_IHOST_SW_PERSISTENT_REG5)); |
| 599 | NOTICE("pr6: %x\n", mmio_read_32(CRMU_IHOST_SW_PERSISTENT_REG6)); |
| 600 | NOTICE("pr7: %x\n", mmio_read_32(CRMU_IHOST_SW_PERSISTENT_REG7)); |
| 601 | NOTICE("pr8: %x\n", mmio_read_32(CRMU_IHOST_SW_PERSISTENT_REG8)); |
| 602 | NOTICE("pr9: %x\n", mmio_read_32(CRMU_IHOST_SW_PERSISTENT_REG9)); |
| 603 | NOTICE("pr10: %x\n", mmio_read_32(CRMU_IHOST_SW_PERSISTENT_REG10)); |
| 604 | NOTICE("pr11: %x\n", mmio_read_32(CRMU_IHOST_SW_PERSISTENT_REG11)); |
| 605 | } |
| 606 | |
| 607 | void plat_bcm_bl2_plat_arch_setup(void) |
| 608 | { |
| 609 | if (chip_get_rev_id_major() == CHIP_REV_MAJOR_AX) { |
| 610 | if (!(sotp_mem_read(SOTP_ATF_CFG_ROW_ID, SOTP_ROW_NO_ECC) & |
| 611 | SOTP_ATF_WATCHDOG_ENABLE_MASK)) { |
| 612 | /* |
| 613 | * Stop sp805 watchdog timer immediately. |
| 614 | * It might has been set up by MCU patch earlier for |
| 615 | * eMMC workaround. |
| 616 | * |
| 617 | * Note the watchdog timer started in CRMU has a very |
| 618 | * short timeout and needs to be stopped immediately. |
| 619 | * Down below we restart it with a much longer timeout |
| 620 | * for BL2 and BL31 |
| 621 | */ |
| 622 | sp805_stop(ARM_SP805_TWDG_BASE); |
| 623 | } |
| 624 | } |
| 625 | |
| 626 | #if !BRCM_DISABLE_TRUSTED_WDOG |
| 627 | /* |
| 628 | * start secure watchdog for BL2 and BL31. |
| 629 | * Note that UART download can take a longer time, |
| 630 | * so do not allow watchdog for UART download, |
| 631 | * as this boot source is not a standard modus operandi. |
| 632 | */ |
| 633 | if (boot_source_get() != BOOT_SOURCE_UART) |
| 634 | sp805_start(ARM_SP805_TWDG_BASE, ARM_TWDG_LOAD_VAL); |
| 635 | #endif |
| 636 | |
| 637 | #ifdef BCM_ELOG |
| 638 | /* Ensure logging is started out fresh in BL2. */ |
| 639 | mmio_write_32(BCM_ELOG_BL2_BASE, 0); |
| 640 | #endif |
| 641 | /* |
| 642 | * In BL2, since we have very limited space to store logs, we only |
| 643 | * save logs that are >= the WARNING level. |
| 644 | */ |
| 645 | bcm_elog_init((void *)BCM_ELOG_BL2_BASE, BCM_ELOG_BL2_SIZE, |
| 646 | LOG_LEVEL_WARNING); |
| 647 | |
| 648 | dump_persistent_regs(); |
| 649 | |
| 650 | /* Read CRMU mailbox 0 */ |
| 651 | NOTICE("RESET (reported by CRMU): 0x%x\n", |
| 652 | mmio_read_32(CRMU_READ_MAIL_BOX0)); |
| 653 | |
| 654 | /* |
| 655 | * All non-boot-source PADs are in forced input-mode at |
| 656 | * reset so clear the force on non-boot-source PADs using |
| 657 | * CDRU register. |
| 658 | */ |
| 659 | mmio_clrbits_32((uintptr_t)CDRU_CHIP_IO_PAD_CONTROL, |
| 660 | (1 << CDRU_CHIP_IO_PAD_CONTROL__CDRU_IOMUX_FORCE_PAD_IN_R)); |
| 661 | |
| 662 | #if DRIVER_OCOTP_ENABLE |
| 663 | bcm_otpc_init(&otp_stingray_map); |
| 664 | #endif |
| 665 | |
| 666 | set_swreg_based_on_otp(); |
| 667 | |
| 668 | #if IHOST_PLL_FREQ != 0 |
| 669 | bcm_set_ihost_pll_freq(0x0, IHOST_PLL_FREQ); |
| 670 | #endif |
| 671 | |
| 672 | #ifdef INCLUDE_EMMC_DRIVER_ERASE_CODE |
| 673 | /* The erasable unit of the eMMC is the "Erase Group"; |
| 674 | * Erase group is measured in write blocks which are the |
| 675 | * basic writable units of the Device. |
| 676 | * The size of the Erase Group is a Device specific parameter |
| 677 | */ |
| 678 | emmc_erase(EMMC_ERASE_START_BLOCK, EMMC_ERASE_BLOCK_COUNT, |
| 679 | EMMC_ERASE_PARTITION); |
| 680 | #endif |
| 681 | |
| 682 | bcm_board_detect(); |
| 683 | #ifdef DRIVER_EMMC_ENABLE |
| 684 | /* Initialize the card, if it is not */ |
Sheetal Tigadoli | fcd106c | 2020-04-13 18:43:29 +0530 | [diff] [blame] | 685 | if (bcm_emmc_init(true) == 0) |
Sheetal Tigadoli | ad0943e | 2019-12-18 19:44:43 +0530 | [diff] [blame] | 686 | WARN("eMMC Card Initialization Failed!!!\n"); |
| 687 | #endif |
| 688 | |
| 689 | #if BL2_TEST_I2C |
| 690 | i2c_test(); |
| 691 | #endif |
| 692 | |
| 693 | #ifdef USE_DDR |
| 694 | ddr_initialize(&ddr_info); |
| 695 | |
| 696 | ddr_secure_region_config(SECURE_DDR_BASE_ADDRESS, |
| 697 | SECURE_DDR_END_ADDRESS); |
| 698 | #ifdef NITRO_SECURE_ACCESS |
| 699 | ddr_secure_region_config(DDR_NITRO_SECURE_REGION_START, |
| 700 | DDR_NITRO_SECURE_REGION_END); |
| 701 | #endif |
| 702 | #else |
| 703 | ext_sram_init(); |
| 704 | #endif |
| 705 | |
| 706 | #if BL2_TEST_MEM |
| 707 | ddr_test(); |
| 708 | #endif |
| 709 | |
| 710 | #ifdef USE_NAND |
| 711 | brcm_stingray_nand_init(); |
| 712 | #endif |
| 713 | |
| 714 | #if defined(USE_PAXB) || defined(USE_PAXC) || defined(USE_SATA) |
| 715 | brcm_stingray_pcie_reset(); |
| 716 | #endif |
| 717 | |
| 718 | #ifdef USE_PAXC |
| 719 | if (boot_source_get() != BOOT_SOURCE_QSPI) |
| 720 | brcm_stingray_chimp_check_and_fastboot(); |
| 721 | #endif |
| 722 | |
| 723 | #if ((!CLEAN_DDR || MMU_DISABLED)) |
| 724 | /* |
| 725 | * Now DDR has been initialized. We want to copy all the logs in SRAM |
| 726 | * into DDR so we will have much more space to store the logs in the |
| 727 | * next boot stage |
| 728 | */ |
| 729 | bcm_elog_copy_log((void *)BCM_ELOG_BL31_BASE, |
| 730 | MIN(BCM_ELOG_BL2_SIZE, BCM_ELOG_BL31_SIZE) |
| 731 | ); |
| 732 | |
| 733 | /* |
| 734 | * We are not yet at the end of BL2, but we can stop log here so we do |
| 735 | * not need to add 'bcm_elog_exit' to the standard BL2 code. The |
| 736 | * benefit of capturing BL2 logs after this is very minimal in a |
| 737 | * production system |
| 738 | * NOTE: BL2 logging must be exited before going forward to setup |
| 739 | * page tables |
| 740 | */ |
| 741 | bcm_elog_exit(); |
| 742 | #endif |
| 743 | } |