Add BL2 support for Broadcom stingray platform
Change-Id: I5daa3f2b4b9d85cb857547a588571a9aa8ad05c2
Signed-off-by: Sheetal Tigadoli <sheetal.tigadoli@broadcom.com>
diff --git a/plat/brcm/board/stingray/driver/ddr/soc/include/board_family.h b/plat/brcm/board/stingray/driver/ddr/soc/include/board_family.h
new file mode 100644
index 0000000..b2427cf
--- /dev/null
+++ b/plat/brcm/board/stingray/driver/ddr/soc/include/board_family.h
@@ -0,0 +1,33 @@
+/*
+ * Copyright (c) 2019-2020, Broadcom
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#ifndef BOARD_FAMILY_H
+#define BOARD_FAMILY_H
+
+#if defined(DRIVER_SPD_ENABLE) && !defined(DRIVER_SPD_SPOOF)
+#include <spd.h>
+#endif
+
+#ifdef USE_GPIO
+/* max number of supported GPIOs to construct the bitmap for board detection */
+#define MAX_NR_GPIOS 4
+
+/* max GPIO bitmap value */
+#define MAX_GPIO_BITMAP_VAL (BIT(MAX_NR_GPIOS) - 1)
+#endif
+
+struct mcb_ref_group {
+ uint32_t mcb_ref;
+ unsigned int *mcb_cfg;
+};
+
+#define MCB_REF_GROUP(ref) \
+{ \
+ .mcb_ref = 0x ## ref, \
+ .mcb_cfg = mcb_ ## ref, \
+}
+
+#endif
diff --git a/plat/brcm/board/stingray/driver/ext_sram_init/ext_sram_init.c b/plat/brcm/board/stingray/driver/ext_sram_init/ext_sram_init.c
new file mode 100644
index 0000000..74d2077
--- /dev/null
+++ b/plat/brcm/board/stingray/driver/ext_sram_init/ext_sram_init.c
@@ -0,0 +1,302 @@
+/*
+ * Copyright (c) 2016-2020, Broadcom
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <assert.h>
+
+#include <arch_helpers.h>
+#include <common/bl_common.h>
+#include <common/debug.h>
+#include <drivers/delay_timer.h>
+#include <lib/mmio.h>
+
+#include <platform_def.h>
+
+static void brcm_stingray_pnor_pinmux_init(void)
+{
+ unsigned int i;
+
+ INFO(" - pnor pinmux init start.\n");
+
+ /* Set PNOR_ADV_N_MODE_SEL_CONTROL.fsel = 0x2 */
+ mmio_clrsetbits_32((uintptr_t)(HSLS_IOPAD_BASE + 0x2dc),
+ MODE_SEL_CONTROL_FSEL_MASK,
+ MODE_SEL_CONTROL_FSEL_MODE2);
+
+ /* Set PNOR_BAA_N_MODE_SEL_CONTROL.fsel = 0x2 */
+ mmio_clrsetbits_32((uintptr_t)(HSLS_IOPAD_BASE + 0x2e0),
+ MODE_SEL_CONTROL_FSEL_MASK,
+ MODE_SEL_CONTROL_FSEL_MODE2);
+
+ /* Set PNOR_BLS_0_N_MODE_SEL_CONTROL.fsel = 0x2 */
+ mmio_clrsetbits_32((uintptr_t)(HSLS_IOPAD_BASE + 0x2e4),
+ MODE_SEL_CONTROL_FSEL_MASK,
+ MODE_SEL_CONTROL_FSEL_MODE2);
+
+ /* Set PNOR_BLS_1_N_MODE_SEL_CONTROL.fsel = 0x2 */
+ mmio_clrsetbits_32((uintptr_t)(HSLS_IOPAD_BASE + 0x2e8),
+ MODE_SEL_CONTROL_FSEL_MASK,
+ MODE_SEL_CONTROL_FSEL_MODE2);
+
+ /* Set PNOR_CRE_MODE_SEL_CONTROL.fsel = 0x2 */
+ mmio_clrsetbits_32((uintptr_t)(HSLS_IOPAD_BASE + 0x2ec),
+ MODE_SEL_CONTROL_FSEL_MASK,
+ MODE_SEL_CONTROL_FSEL_MODE2);
+
+ /* Set PNOR_CS_2_N_MODE_SEL_CONTROL.fsel = 0x2 */
+ mmio_clrsetbits_32((uintptr_t)(HSLS_IOPAD_BASE + 0x2f0),
+ MODE_SEL_CONTROL_FSEL_MASK,
+ MODE_SEL_CONTROL_FSEL_MODE2);
+
+ /* Set PNOR_CS_1_N_MODE_SEL_CONTROL.fsel = 0x2 */
+ mmio_clrsetbits_32((uintptr_t)(HSLS_IOPAD_BASE + 0x2f4),
+ MODE_SEL_CONTROL_FSEL_MASK,
+ MODE_SEL_CONTROL_FSEL_MODE2);
+
+ /* Set PNOR_CS_0_N_MODE_SEL_CONTROL.fsel = 0x2 */
+ mmio_clrsetbits_32((uintptr_t)(HSLS_IOPAD_BASE + 0x2f8),
+ MODE_SEL_CONTROL_FSEL_MASK,
+ MODE_SEL_CONTROL_FSEL_MODE2);
+
+ /* Set PNOR_WE_N_MODE_SEL_CONTROL.fsel = 0x2 */
+ mmio_clrsetbits_32((uintptr_t)(HSLS_IOPAD_BASE + 0x2fc),
+ MODE_SEL_CONTROL_FSEL_MASK,
+ MODE_SEL_CONTROL_FSEL_MODE2);
+
+ /* Set PNOR_OE_N_MODE_SEL_CONTROL.fsel = 0x2 */
+ mmio_clrsetbits_32((uintptr_t)(HSLS_IOPAD_BASE + 0x300),
+ MODE_SEL_CONTROL_FSEL_MASK,
+ MODE_SEL_CONTROL_FSEL_MODE2);
+
+ /* Set PNOR_INTR_MODE_SEL_CONTROL.fsel = 0x2 */
+ mmio_clrsetbits_32((uintptr_t)(HSLS_IOPAD_BASE + 0x304),
+ MODE_SEL_CONTROL_FSEL_MASK,
+ MODE_SEL_CONTROL_FSEL_MODE2);
+
+ /* Set PNOR_DAT_x_MODE_SEL_CONTROL.fsel = 0x2 */
+ for (i = 0; i < 0x40; i += 0x4) {
+ mmio_clrsetbits_32((uintptr_t)(HSLS_IOPAD_BASE + 0x308 + i),
+ MODE_SEL_CONTROL_FSEL_MASK,
+ MODE_SEL_CONTROL_FSEL_MODE2);
+ }
+
+ /* Set NAND_CE1_N_MODE_SEL_CONTROL.fsel = 0x2 */
+ mmio_clrsetbits_32((uintptr_t)(HSLS_IOPAD_BASE + 0x348),
+ MODE_SEL_CONTROL_FSEL_MASK,
+ MODE_SEL_CONTROL_FSEL_MODE2);
+
+ /* Set NAND_CE0_N_MODE_SEL_CONTROL.fsel = 0x2 */
+ mmio_clrsetbits_32((uintptr_t)(HSLS_IOPAD_BASE + 0x34c),
+ MODE_SEL_CONTROL_FSEL_MASK,
+ MODE_SEL_CONTROL_FSEL_MODE2);
+
+ /* Set NAND_WE_N_MODE_SEL_CONTROL.fsel = 0x2 */
+ mmio_clrsetbits_32((uintptr_t)(HSLS_IOPAD_BASE + 0x350),
+ MODE_SEL_CONTROL_FSEL_MASK,
+ MODE_SEL_CONTROL_FSEL_MODE2);
+
+ /* Set NAND_WP_N_MODE_SEL_CONTROL.fsel = 0x2 */
+ mmio_clrsetbits_32((uintptr_t)(HSLS_IOPAD_BASE + 0x354),
+ MODE_SEL_CONTROL_FSEL_MASK,
+ MODE_SEL_CONTROL_FSEL_MODE2);
+
+ /* Set NAND_RE_N_MODE_SEL_CONTROL.fsel = 0x2 */
+ mmio_clrsetbits_32((uintptr_t)(HSLS_IOPAD_BASE + 0x358),
+ MODE_SEL_CONTROL_FSEL_MASK,
+ MODE_SEL_CONTROL_FSEL_MODE2);
+
+ /* Set NAND_RDY_BSY_N_MODE_SEL_CONTROL.fsel = 0x2 */
+ mmio_clrsetbits_32((uintptr_t)(HSLS_IOPAD_BASE + 0x35c),
+ MODE_SEL_CONTROL_FSEL_MASK,
+ MODE_SEL_CONTROL_FSEL_MODE2);
+
+ /* Set NAND_IOx_0_MODE_SEL_CONTROL.fsel = 0x2 */
+ for (i = 0; i < 0x40; i += 0x4) {
+ mmio_clrsetbits_32((uintptr_t)(HSLS_IOPAD_BASE + 0x360 + i),
+ MODE_SEL_CONTROL_FSEL_MASK,
+ MODE_SEL_CONTROL_FSEL_MODE2);
+ }
+
+ /* Set NAND_ALE_MODE_SEL_CONTROL.fsel = 0x2 */
+ mmio_clrsetbits_32((uintptr_t)(HSLS_IOPAD_BASE + 0x3a0),
+ MODE_SEL_CONTROL_FSEL_MASK,
+ MODE_SEL_CONTROL_FSEL_MODE2);
+
+ /* Set NAND_CLE_MODE_SEL_CONTROL.fsel = 0x2 */
+ mmio_clrsetbits_32((uintptr_t)(HSLS_IOPAD_BASE + 0x3a4),
+ MODE_SEL_CONTROL_FSEL_MASK,
+ MODE_SEL_CONTROL_FSEL_MODE2);
+
+ mmio_clrsetbits_32((uintptr_t)(HSLS_IOPAD_BASE + 0x40), (7 << 1), 0x8);
+ mmio_clrsetbits_32((uintptr_t)(HSLS_IOPAD_BASE + 0x44), (7 << 1), 0x8);
+ mmio_clrsetbits_32((uintptr_t)(HSLS_IOPAD_BASE + 0x48), (7 << 1), 0x8);
+ mmio_clrsetbits_32((uintptr_t)(HSLS_IOPAD_BASE + 0x4c), (7 << 1), 0x8);
+ mmio_clrsetbits_32((uintptr_t)(HSLS_IOPAD_BASE + 0x50), (7 << 1), 0x8);
+ mmio_clrsetbits_32((uintptr_t)(HSLS_IOPAD_BASE + 0x54), (7 << 1), 0x8);
+ mmio_clrsetbits_32((uintptr_t)(HSLS_IOPAD_BASE + 0x58), (7 << 1), 0x8);
+ mmio_clrsetbits_32((uintptr_t)(HSLS_IOPAD_BASE + 0x5c), (7 << 1), 0x8);
+ mmio_clrsetbits_32((uintptr_t)(HSLS_IOPAD_BASE + 0x60), (7 << 1), 0x8);
+ mmio_clrsetbits_32((uintptr_t)(HSLS_IOPAD_BASE + 0x64), (7 << 1), 0x8);
+ mmio_clrsetbits_32((uintptr_t)(HSLS_IOPAD_BASE + 0x68), (7 << 1), 0x8);
+ mmio_clrsetbits_32((uintptr_t)(HSLS_IOPAD_BASE + 0x6c), (7 << 1), 0x8);
+ mmio_clrsetbits_32((uintptr_t)(HSLS_IOPAD_BASE + 0x70), (7 << 1), 0x8);
+ mmio_clrsetbits_32((uintptr_t)(HSLS_IOPAD_BASE + 0x74), (7 << 1), 0x8);
+ mmio_clrsetbits_32((uintptr_t)(HSLS_IOPAD_BASE + 0x78), (7 << 1), 0x8);
+ mmio_clrsetbits_32((uintptr_t)(HSLS_IOPAD_BASE + 0x7c), (7 << 1), 0x8);
+ mmio_clrsetbits_32((uintptr_t)(HSLS_IOPAD_BASE + 0x80), (7 << 1), 0x8);
+ mmio_clrsetbits_32((uintptr_t)(HSLS_IOPAD_BASE + 0x84), (7 << 1), 0x8);
+ mmio_clrsetbits_32((uintptr_t)(HSLS_IOPAD_BASE + 0x88), (7 << 1), 0x8);
+ mmio_clrsetbits_32((uintptr_t)(HSLS_IOPAD_BASE + 0x8c), (7 << 1), 0x8);
+ mmio_clrsetbits_32((uintptr_t)(HSLS_IOPAD_BASE + 0x90), (7 << 1), 0x8);
+ mmio_clrsetbits_32((uintptr_t)(HSLS_IOPAD_BASE + 0x94), (7 << 1), 0x8);
+ mmio_clrsetbits_32((uintptr_t)(HSLS_IOPAD_BASE + 0x98), (7 << 1), 0x8);
+ mmio_clrsetbits_32((uintptr_t)(HSLS_IOPAD_BASE + 0x9c), (7 << 1), 0x8);
+ mmio_clrsetbits_32((uintptr_t)(HSLS_IOPAD_BASE + 0xa0), (7 << 1), 0x8);
+ mmio_clrsetbits_32((uintptr_t)(HSLS_IOPAD_BASE + 0xa4), (7 << 1), 0x8);
+ mmio_clrsetbits_32((uintptr_t)(HSLS_IOPAD_BASE + 0xa8), (7 << 1), 0x8);
+
+ INFO(" - pnor pinmux init done.\n");
+}
+
+#if BL2_TEST_EXT_SRAM
+#define SRAM_CHECKS_GRANUL 0x100000
+#define SRAM_CHECKS_CNT 8
+static unsigned int sram_checks[SRAM_CHECKS_CNT] = {
+ /* offset, magic */
+ 0xd00dfeed,
+ 0xfadebabe,
+ 0xc001d00d,
+ 0xa5a5b5b5,
+ 0x5a5a5b5b,
+ 0xc5c5d5d5,
+ 0x5c5c5d5d,
+ 0xe5e5f5f5,
+};
+#endif
+
+static void brcm_stingray_pnor_sram_init(void)
+{
+ unsigned int val, tmp;
+#if BL2_TEST_EXT_SRAM
+ unsigned int off, i;
+#endif
+ INFO(" - pnor sram init start.\n");
+
+ /* Enable PNOR Clock */
+ INFO(" -- enable pnor clock\n");
+ mmio_write_32((uintptr_t)(PNOR_IDM_IO_CONTROL_DIRECT), 0x1);
+ udelay(500);
+
+ /* Reset PNOR */
+ INFO(" -- reset pnor\n");
+ mmio_setbits_32((uintptr_t)(PNOR_IDM_IO_RESET_CONTROL), 0x1);
+ udelay(500);
+ mmio_clrbits_32((uintptr_t)(PNOR_IDM_IO_RESET_CONTROL), 0x1);
+ udelay(500);
+
+ /* Configure slave address to chip-select mapping */
+ INFO(" -- configure pnor slave address to chip-select mapping\n");
+ /* 0x74000000-0x75ffffff => CS0 (32MB) */
+ val = (0xfe << PNOR_ICFG_CS_x_MASK0_SHIFT);
+ val |= (0x74);
+ mmio_write_32((uintptr_t)(PNOR_ICFG_CS_0), val);
+ /* 0x76000000-0x77ffffff => CS1 (32MB) */
+ val = (0xfe << PNOR_ICFG_CS_x_MASK0_SHIFT);
+ val |= (0x76);
+ mmio_write_32((uintptr_t)(PNOR_ICFG_CS_1), val);
+ /* 0xffffffff-0xffffffff => CS2 (0MB) */
+ val = (0x00 << PNOR_ICFG_CS_x_MASK0_SHIFT);
+ val |= (0xff);
+ mmio_write_32((uintptr_t)(PNOR_ICFG_CS_2), val);
+
+ /* Print PNOR ID */
+ tmp = 0x0;
+ val = mmio_read_32((uintptr_t)(PNOR_REG_PERIPH_ID0));
+ tmp |= (val & PNOR_REG_PERIPH_IDx_MASK);
+ val = mmio_read_32((uintptr_t)(PNOR_REG_PERIPH_ID1));
+ tmp |= ((val & PNOR_REG_PERIPH_IDx_MASK) << 8);
+ val = mmio_read_32((uintptr_t)(PNOR_REG_PERIPH_ID2));
+ tmp |= ((val & PNOR_REG_PERIPH_IDx_MASK) << 16);
+ val = mmio_read_32((uintptr_t)(PNOR_REG_PERIPH_ID3));
+ tmp |= ((val & PNOR_REG_PERIPH_IDx_MASK) << 24);
+ INFO(" -- pnor primecell_id = 0x%x\n", tmp);
+
+ /* PNOR set_cycles */
+#ifdef EMULATION_SETUP
+ val = 0x00129A44;
+#else
+ val = 0x00125954; /* 0x00002DEF; */
+#endif
+ mmio_write_32((uintptr_t)(PNOR_REG_SET_CYCLES), val);
+ INFO(" -- pnor set_cycles = 0x%x\n", val);
+
+ /* PNOR set_opmode */
+ val = 0x0;
+#ifdef EMULATION_SETUP
+ /* TODO: Final values to be provided by DV folks */
+ val &= ~(0x7 << 7); /* set_wr_bl */
+ val &= ~(0x7 << 3); /* set_rd_bl */
+ val &= ~(0x3);
+ val |= (0x1); /* set_mw */
+#else
+ /* TODO: Final values to be provided by DV folks */
+ val &= ~(0x7 << 7); /* set_wr_bl */
+ val &= ~(0x7 << 3); /* set_rd_bl */
+ val &= ~(0x3);
+ val |= (0x1); /* set_mw */
+#endif
+ mmio_write_32((uintptr_t)(PNOR_REG_SET_OPMODE), val);
+ INFO(" -- pnor set_opmode = 0x%x\n", val);
+
+#ifndef EMULATION_SETUP
+ /* Actual SRAM chip will require self-refresh */
+ val = 0x1;
+ mmio_write_32((uintptr_t)(PNOR_REG_REFRESH_0), val);
+ INFO(" -- pnor refresh_0 = 0x%x\n", val);
+#endif
+
+#if BL2_TEST_EXT_SRAM
+ /* Check PNOR SRAM access */
+ for (off = 0; off < NOR_SIZE; off += SRAM_CHECKS_GRANUL) {
+ i = (off / SRAM_CHECKS_GRANUL) % SRAM_CHECKS_CNT;
+ val = sram_checks[i];
+ INFO(" -- pnor sram write addr=0x%lx value=0x%lx\n",
+ (unsigned long)(NOR_BASE_ADDR + off),
+ (unsigned long)val);
+ mmio_write_32((uintptr_t)(NOR_BASE_ADDR + off), val);
+ }
+ tmp = 0;
+ for (off = 0; off < NOR_SIZE; off += SRAM_CHECKS_GRANUL) {
+ i = (off / SRAM_CHECKS_GRANUL) % SRAM_CHECKS_CNT;
+ val = mmio_read_32((uintptr_t)(NOR_BASE_ADDR + off));
+ INFO(" -- pnor sram read addr=0x%lx value=0x%lx\n",
+ (unsigned long)(NOR_BASE_ADDR + off),
+ (unsigned long)val);
+ if (val == sram_checks[i])
+ tmp++;
+ }
+ INFO(" -- pnor sram checks pass=%d total=%d\n",
+ tmp, (NOR_SIZE / SRAM_CHECKS_GRANUL));
+
+ if (tmp != (NOR_SIZE / SRAM_CHECKS_GRANUL)) {
+ INFO(" - pnor sram init failed.\n");
+ while (1)
+ ;
+ } else {
+ INFO(" - pnor sram init done.\n");
+ }
+#endif
+}
+
+void ext_sram_init(void)
+{
+ INFO("%s start.\n", __func__);
+
+ brcm_stingray_pnor_pinmux_init();
+
+ brcm_stingray_pnor_sram_init();
+
+ INFO("%s done.\n", __func__);
+}
diff --git a/plat/brcm/board/stingray/driver/ext_sram_init/ext_sram_init.h b/plat/brcm/board/stingray/driver/ext_sram_init/ext_sram_init.h
new file mode 100644
index 0000000..8508653
--- /dev/null
+++ b/plat/brcm/board/stingray/driver/ext_sram_init/ext_sram_init.h
@@ -0,0 +1,11 @@
+/*
+ * Copyright (c) 2016-2020, Broadcom
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#ifndef EXT_SRAM_INIT_H
+#define EXT_SRAM_INIT_H
+
+void ext_sram_init(void);
+#endif
diff --git a/plat/brcm/board/stingray/driver/swreg.c b/plat/brcm/board/stingray/driver/swreg.c
new file mode 100644
index 0000000..2b7c53b
--- /dev/null
+++ b/plat/brcm/board/stingray/driver/swreg.c
@@ -0,0 +1,375 @@
+/*
+ * Copyright (c) 2017 - 2020, Broadcom
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <assert.h>
+#include <errno.h>
+#include <stdint.h>
+
+#include <common/debug.h>
+#include <drivers/delay_timer.h>
+#include <lib/mmio.h>
+
+#include <sr_utils.h>
+#include <swreg.h>
+
+#define MIN_VOLT 760000
+#define MAX_VOLT 1060000
+
+#define BSTI_WRITE 0x1
+#define BSTI_READ 0x2
+#define BSTI_COMMAND_TA 0x2
+#define BSTI_COMMAND_DATA 0xFF
+#define BSTI_CONTROL_VAL 0x81
+#define BSTI_CONTROL_BUSY 0x100
+#define BSTI_TOGGLE_BIT 0x2
+#define BSTI_CONFI_DONE_MASK 0xFFFFFFFD
+#define BSTI_REG_DATA_MASK 0xFFFF
+#define BSTI_CMD(sb, op, pa, ra, ta, data) \
+ ((((sb) & 0x3) << 30) | (((op) & 0x3) << 28) | \
+ (((pa) & 0x1F) << 23) | (((ra) & 0x1F) << 18) | \
+ (((ta) & 0x3) << 16) | (data))
+
+#define PHY_REG0 0x0
+#define PHY_REG1 0x1
+#define PHY_REG4 0x4
+#define PHY_REG5 0x5
+#define PHY_REG6 0x6
+#define PHY_REG7 0x7
+#define PHY_REGC 0xc
+
+#define IHOST_VDDC_DATA 0x560
+#define DDR_CORE_DATA 0x2560
+#define UPDATE_POS_EDGE(data, set) ((data) | ((set) << 1))
+
+/*
+ * Formula for SR A2 reworked board:
+ * step = ((vol/(1.4117 * 0.98)) - 500000)/3125
+ * where,
+ * vol - input voltage
+ * 500000 - Reference voltage
+ * 3125 - one step value
+ */
+#define A2_VOL_REF 500000
+#define ONE_STEP_VALUE 3125
+#define VOL_DIV(vol) (((vol*10000ull)/(14117*98ull)) * 100ull)
+#define STEP_VALUE(vol) \
+ ((((((VOL_DIV(vol)) - A2_VOL_REF) / ONE_STEP_VALUE) & 0xFF) << 8) | 4)
+
+#define B0_VOL_REF ((500000/100)*98)
+#define B0_ONE_STEP_VALUE 3125
+/*
+ * Formula for SR B0 chip for IHOST12/03 and VDDC_CORE
+ * step = ((vol/1.56) - (500000 * 0.98))/3125
+ * where,
+ * vol - input voltage
+ * 500000 - Reference voltage
+ * 3125 - one step value
+ */
+#define B0_VOL_DIV(vol) (((vol)*100ull)/156)
+#define B0_STEP_VALUE(vol) \
+ ((((((B0_VOL_DIV(vol)) - B0_VOL_REF) / B0_ONE_STEP_VALUE) \
+ & 0xFF) << 8) | 4)
+
+/*
+ * Formula for SR B0 chip for DDR-CORE
+ * step = ((vol/1) - (500000 * 0.98))/3125
+ * where,
+ * vol - input voltage
+ * 500000 - Reference voltage
+ * 3125 - one step value
+ */
+#define B0_DDR_VDDC_VOL_DIV(vol) ((vol)/1)
+#define B0_DDR_VDDC_STEP_VALUE(vol) \
+ ((((((B0_DDR_VDDC_VOL_DIV(vol)) - B0_VOL_REF) / B0_ONE_STEP_VALUE) \
+ & 0xFF) << 8) | 4)
+
+#define MAX_SWREG_CNT 8
+#define MAX_ADDR_PER_SWREG 16
+#define MAX_REG_ADDR 0xF
+#define MIN_REG_ADDR 0x0
+
+static const char *sw_reg_name[MAX_SWREG_CNT] = {
+ "DDR_VDDC",
+ "IHOST03",
+ "IHOST12",
+ "IHOST_ARRAY",
+ "DDRIO_SLAVE",
+ "VDDC_CORE",
+ "VDDC1",
+ "DDRIO_MASTER"
+};
+
+/* firmware values for all SWREG for 3.3V input operation */
+static const uint16_t swreg_fm_data_bx[MAX_SWREG_CNT][MAX_ADDR_PER_SWREG] = {
+ /* DDR logic: Power Domains independent of 12v or 3p3v */
+ {0x25E0, 0x2D54, 0x0EC6, 0x01EC, 0x28BB, 0x1144, 0x0200, 0x69C0,
+ 0x0010, 0x0EDF, 0x90D7, 0x8000, 0x820C, 0x0003, 0x0001, 0x0000},
+
+ /* ihost03, 3p3V */
+ {0x05E0, 0x39E5, 0x03C1, 0x007C, 0x8BA9, 0x4444, 0x3300, 0x6B80,
+ 0x003F, 0x0FFF, 0x90D7, 0x8000, 0x240C, 0x0003, 0x0001, 0x0000},
+
+ /* ihost12 3p3v */
+ {0x05E0, 0x39E5, 0x03C1, 0x007C, 0x8BA9, 0x4444, 0x3300, 0x6B80,
+ 0x003F, 0x0FFF, 0x90D7, 0x8000, 0x240C, 0x0003, 0x0001, 0x0000},
+
+ /* ihost array */
+ {0x25E0, 0x2D94, 0x0EC6, 0x01EC, 0x2ABB, 0x1144, 0x0340, 0x69C0,
+ 0x0010, 0x0EDF, 0x90D7, 0x8000, 0x860C, 0x0003, 0x0001, 0x0000},
+
+ /* ddr io slave : 3p3v */
+ {0x0560, 0x4438, 0x0000, 0x001F, 0x8028, 0x4444, 0x0300, 0x4380,
+ 0x003F, 0x0FFF, 0x10D7, 0x8000, 0xA70C, 0x0003, 0x0001, 0x0000},
+
+ /* core master 3p3v */
+ {0x05E0, 0x39E5, 0x03C1, 0x007C, 0x8BA9, 0x4444, 0x3300, 0x6B80,
+ 0x003F, 0x0FFF, 0x90D7, 0x8000, 0x240C, 0x0003, 0x0001, 0x0000},
+
+ /* core slave 3p3v */
+ {0x0560, 0x4438, 0x0000, 0x001F, 0x8028, 0x4444, 0x0300, 0x4380,
+ 0x003F, 0x0FFF, 0x10D7, 0x8000, 0x240C, 0x0003, 0x0001, 0x0000},
+
+ /* ddr io master : 3p3v */
+ {0x05E0, 0x39E5, 0x03C1, 0x007C, 0x8BA9, 0x4444, 0x3300, 0x6B80,
+ 0x003F, 0x0FFF, 0x90D7, 0x8000, 0xA70C, 0x0003, 0x0001, 0x0000},
+};
+
+#define FM_DATA swreg_fm_data_bx
+
+static int swreg_poll(void)
+{
+ uint32_t data;
+ int retry = 100;
+
+ do {
+ data = mmio_read_32(BSTI_CONTROL_OFFSET);
+ if ((data & BSTI_CONTROL_BUSY) != BSTI_CONTROL_BUSY)
+ return 0;
+ retry--;
+ udelay(1);
+ } while (retry > 0);
+
+ return -ETIMEDOUT;
+}
+
+static int write_swreg_config(enum sw_reg reg_id, uint32_t addr, uint32_t data)
+{
+ uint32_t cmd;
+ int ret;
+
+ cmd = BSTI_CMD(0x1, BSTI_WRITE, reg_id, addr, BSTI_COMMAND_TA, data);
+ mmio_write_32(BSTI_CONTROL_OFFSET, BSTI_CONTROL_VAL);
+ mmio_write_32(BSTI_COMMAND_OFFSET, cmd);
+ ret = swreg_poll();
+ if (ret) {
+ ERROR("Failed to write swreg %s addr 0x%x\n",
+ sw_reg_name[reg_id-1], addr);
+ return ret;
+ }
+ return ret;
+}
+
+static int read_swreg_config(enum sw_reg reg_id, uint32_t addr, uint32_t *data)
+{
+ uint32_t cmd;
+ int ret;
+
+ cmd = BSTI_CMD(0x1, BSTI_READ, reg_id, addr, BSTI_COMMAND_TA, PHY_REG0);
+ mmio_write_32(BSTI_CONTROL_OFFSET, BSTI_CONTROL_VAL);
+ mmio_write_32(BSTI_COMMAND_OFFSET, cmd);
+ ret = swreg_poll();
+ if (ret) {
+ ERROR("Failed to read swreg %s addr 0x%x\n",
+ sw_reg_name[reg_id-1], addr);
+ return ret;
+ }
+
+ *data = mmio_read_32(BSTI_COMMAND_OFFSET);
+ *data &= BSTI_REG_DATA_MASK;
+ return ret;
+}
+
+static int swreg_config_done(enum sw_reg reg_id)
+{
+ uint32_t read_data;
+ int ret;
+
+ ret = read_swreg_config(reg_id, PHY_REG0, &read_data);
+ if (ret)
+ return ret;
+
+ read_data &= BSTI_CONFI_DONE_MASK;
+ read_data |= BSTI_TOGGLE_BIT;
+ ret = write_swreg_config(reg_id, PHY_REG0, read_data);
+ if (ret)
+ return ret;
+
+ ret = read_swreg_config(reg_id, PHY_REG0, &read_data);
+ if (ret)
+ return ret;
+
+ read_data &= BSTI_CONFI_DONE_MASK;
+ ret = write_swreg_config(reg_id, PHY_REG0, read_data);
+ if (ret)
+ return ret;
+
+ return ret;
+}
+
+#ifdef DUMP_SWREG
+static void dump_swreg_firmware(void)
+{
+ enum sw_reg reg_id;
+ uint32_t data;
+ int addr;
+ int ret;
+
+ for (reg_id = DDR_VDDC; reg_id <= DDRIO_MASTER; reg_id++) {
+ INFO("SWREG: %s\n", sw_reg_name[reg_id - 1]);
+ for (addr = MIN_REG_ADDR; addr <= MAX_REG_ADDR; addr++) {
+ ret = read_swreg_config(reg_id, addr, &data);
+ if (ret)
+ ERROR("Failed to read offset %d\n", addr);
+ INFO("\t0x%x: 0x%04x\n", addr, data);
+ }
+ }
+}
+#endif
+
+int set_swreg(enum sw_reg reg_id, uint32_t micro_volts)
+{
+ uint32_t step, programmed_step;
+ uint32_t data = IHOST_VDDC_DATA;
+ int ret;
+
+ if ((micro_volts > MAX_VOLT) || (micro_volts < MIN_VOLT)) {
+ ERROR("input voltage out-of-range\n");
+ ret = -EINVAL;
+ goto failed;
+ }
+
+ ret = read_swreg_config(reg_id, PHY_REGC, &programmed_step);
+ if (ret)
+ goto failed;
+
+ if (reg_id == DDR_VDDC)
+ step = B0_DDR_VDDC_STEP_VALUE(micro_volts);
+ else
+ step = B0_STEP_VALUE(micro_volts);
+
+ if ((step >> 8) != (programmed_step >> 8)) {
+ ret = write_swreg_config(reg_id, PHY_REGC, step);
+ if (ret)
+ goto failed;
+
+ if (reg_id == DDR_VDDC)
+ data = DDR_CORE_DATA;
+
+ ret = write_swreg_config(reg_id, PHY_REG0,
+ UPDATE_POS_EDGE(data, 1));
+ if (ret)
+ goto failed;
+
+ ret = write_swreg_config(reg_id, PHY_REG0,
+ UPDATE_POS_EDGE(data, 0));
+ if (ret)
+ goto failed;
+ }
+
+ INFO("%s voltage updated to %duV\n", sw_reg_name[reg_id-1],
+ micro_volts);
+ return ret;
+
+failed:
+ /*
+ * Stop booting if voltages are not set
+ * correctly. Booting will fail at random point
+ * if we continue with wrong voltage settings.
+ */
+ ERROR("Failed to set %s voltage to %duV\n", sw_reg_name[reg_id-1],
+ micro_volts);
+ assert(0);
+
+ return ret;
+}
+
+/* Update SWREG firmware for all power doman for A2 chip */
+int swreg_firmware_update(void)
+{
+ enum sw_reg reg_id;
+ uint32_t data;
+ int addr;
+ int ret;
+
+ /* write firmware values */
+ for (reg_id = DDR_VDDC; reg_id <= DDRIO_MASTER; reg_id++) {
+ /* write higher location first */
+ for (addr = MAX_REG_ADDR; addr >= MIN_REG_ADDR; addr--) {
+ ret = write_swreg_config(reg_id, addr,
+ FM_DATA[reg_id - 1][addr]);
+ if (ret)
+ goto exit;
+ }
+ }
+
+ /* trigger SWREG firmware update */
+ for (reg_id = DDR_VDDC; reg_id <= DDRIO_MASTER; reg_id++) {
+ /*
+ * Slave regulator doesn't have to be updated,
+ * Updating Master is enough
+ */
+ if ((reg_id == DDRIO_SLAVE) || (reg_id == VDDC1))
+ continue;
+
+ ret = swreg_config_done(reg_id);
+ if (ret) {
+ ERROR("Failed to trigger SWREG firmware update for %s\n"
+ , sw_reg_name[reg_id-1]);
+ return ret;
+ }
+ }
+
+ for (reg_id = DDR_VDDC; reg_id <= DDRIO_MASTER; reg_id++) {
+ /*
+ * IHOST_ARRAY will be used on some boards like STRATUS and
+ * there will not be any issue even if it is updated on other
+ * boards where it is not used.
+ */
+ if (reg_id == IHOST_ARRAY)
+ continue;
+
+ for (addr = MIN_REG_ADDR; addr <= MAX_REG_ADDR; addr++) {
+ ret = read_swreg_config(reg_id, addr, &data);
+ if (ret || (!ret &&
+ (data != FM_DATA[reg_id - 1][addr]))) {
+ ERROR("swreg fm update failed: %s at off %d\n",
+ sw_reg_name[reg_id - 1], addr);
+ ERROR("Read val: 0x%x, expected val: 0x%x\n",
+ data, FM_DATA[reg_id - 1][addr]);
+ return -1;
+ }
+ }
+ }
+
+ INFO("Updated SWREG firmware\n");
+
+#ifdef DUMP_SWREG
+ dump_swreg_firmware();
+#endif
+ return ret;
+
+exit:
+ /*
+ * Stop booting if swreg firmware update fails.
+ * Booting will fail at random point if we
+ * continue with wrong voltage settings.
+ */
+ ERROR("Failed to update firmware for %s SWREG\n",
+ sw_reg_name[reg_id-1]);
+ assert(0);
+
+ return ret;
+}