summaryrefslogtreecommitdiffstats
path: root/arch/arm/mach-mvebu/serdes/a38x/sys_env_lib.c
diff options
context:
space:
mode:
Diffstat (limited to 'arch/arm/mach-mvebu/serdes/a38x/sys_env_lib.c')
-rw-r--r--arch/arm/mach-mvebu/serdes/a38x/sys_env_lib.c388
1 files changed, 388 insertions, 0 deletions
diff --git a/arch/arm/mach-mvebu/serdes/a38x/sys_env_lib.c b/arch/arm/mach-mvebu/serdes/a38x/sys_env_lib.c
new file mode 100644
index 0000000000..efd3873203
--- /dev/null
+++ b/arch/arm/mach-mvebu/serdes/a38x/sys_env_lib.c
@@ -0,0 +1,388 @@
+/*
+ * Copyright (C) Marvell International Ltd. and its affiliates
+ *
+ * SPDX-License-Identifier: GPL-2.0
+ */
+
+#include <common.h>
+#include <i2c.h>
+#include <spl.h>
+#include <asm/io.h>
+#include <asm/arch/cpu.h>
+#include <asm/arch/soc.h>
+
+#include "seq_exec.h"
+#include "sys_env_lib.h"
+
+#include "../../../drivers/ddr/marvell/a38x/ddr3_a38x.h"
+
+#ifdef CONFIG_ARMADA_38X
+enum unit_id sys_env_soc_unit_nums[MAX_UNITS_ID][MAX_DEV_ID_NUM] = {
+/* 6820 6810 6811 6828 */
+/* PEX_UNIT_ID */ { 4, 3, 3, 4},
+/* ETH_GIG_UNIT_ID */ { 3, 2, 3, 3},
+/* USB3H_UNIT_ID */ { 2, 2, 2, 2},
+/* USB3D_UNIT_ID */ { 1, 1, 1, 1},
+/* SATA_UNIT_ID */ { 2, 2, 2, 4},
+/* QSGMII_UNIT_ID */ { 1, 0, 0, 1},
+/* XAUI_UNIT_ID */ { 0, 0, 0, 0},
+/* RXAUI_UNIT_ID */ { 0, 0, 0, 0}
+};
+#else /* if (CONFIG_ARMADA_39X) */
+enum unit_id sys_env_soc_unit_nums[MAX_UNITS_ID][MAX_DEV_ID_NUM] = {
+/* 6920 6928 */
+/* PEX_UNIT_ID */ { 4, 4},
+/* ETH_GIG_UNIT_ID */ { 3, 4},
+/* USB3H_UNIT_ID */ { 1, 2},
+/* USB3D_UNIT_ID */ { 0, 1},
+/* SATA_UNIT_ID */ { 0, 4},
+/* QSGMII_UNIT_ID */ { 0, 1},
+/* XAUI_UNIT_ID */ { 1, 1},
+/* RXAUI_UNIT_ID */ { 1, 1}
+};
+#endif
+
+u32 g_dev_id = -1;
+
+u32 mv_board_id_get(void)
+{
+#if defined(CONFIG_DB_88F6820_GP)
+ return DB_GP_68XX_ID;
+#else
+ /*
+ * Return 0 here for custom board as this should not be used
+ * for custom boards.
+ */
+ return 0;
+#endif
+}
+
+u32 mv_board_tclk_get(void)
+{
+ u32 value;
+
+ value = (reg_read(DEVICE_SAMPLE_AT_RESET1_REG) >> 15) & 0x1;
+
+ switch (value) {
+ case (0x0):
+ return 250000000;
+ case (0x1):
+ return 200000000;
+ default:
+ return 0xffffffff;
+ }
+}
+
+u32 mv_board_id_index_get(u32 board_id)
+{
+ /*
+ * Marvell Boards use 0x10 as base for Board ID:
+ * mask MSB to receive index for board ID
+ */
+ return board_id & (MARVELL_BOARD_ID_MASK - 1);
+}
+
+/*
+ * sys_env_suspend_wakeup_check
+ * DESCRIPTION: Reads GPIO input for suspend-wakeup indication.
+ * INPUT: None.
+ * OUTPUT:
+ * RETURNS: u32 indicating suspend wakeup status:
+ * 0 - Not supported,
+ * 1 - supported: read magic word detect wakeup,
+ * 2 - detected wakeup from GPIO.
+ */
+enum suspend_wakeup_status sys_env_suspend_wakeup_check(void)
+{
+ u32 reg, board_id_index, gpio;
+ struct board_wakeup_gpio board_gpio[] = MV_BOARD_WAKEUP_GPIO_INFO;
+
+ board_id_index = mv_board_id_index_get(mv_board_id_get());
+ if (!(sizeof(board_gpio) / sizeof(struct board_wakeup_gpio) >
+ board_id_index)) {
+ printf("\n_failed loading Suspend-Wakeup information (invalid board ID)\n");
+ return SUSPEND_WAKEUP_DISABLED;
+ }
+
+ /*
+ * - Detect if Suspend-Wakeup is supported on current board
+ * - Fetch the GPIO number for wakeup status input indication
+ */
+ if (board_gpio[board_id_index].gpio_num == -1) {
+ /* Suspend to RAM is not supported */
+ return SUSPEND_WAKEUP_DISABLED;
+ } else if (board_gpio[board_id_index].gpio_num == -2) {
+ /*
+ * Suspend to RAM is supported but GPIO indication is
+ * not implemented - Skip
+ */
+ return SUSPEND_WAKEUP_ENABLED;
+ } else {
+ gpio = board_gpio[board_id_index].gpio_num;
+ }
+
+ /* Initialize MPP for GPIO (set MPP = 0x0) */
+ reg = reg_read(MPP_CONTROL_REG(MPP_REG_NUM(gpio)));
+ /* reset MPP21 to 0x0, keep rest of MPP settings*/
+ reg &= ~MPP_MASK(gpio);
+ reg_write(MPP_CONTROL_REG(MPP_REG_NUM(gpio)), reg);
+
+ /* Initialize GPIO as input */
+ reg = reg_read(GPP_DATA_OUT_EN_REG(GPP_REG_NUM(gpio)));
+ reg |= GPP_MASK(gpio);
+ reg_write(GPP_DATA_OUT_EN_REG(GPP_REG_NUM(gpio)), reg);
+
+ /*
+ * Check GPP for input status from PIC: 0 - regular init,
+ * 1 - suspend wakeup
+ */
+ reg = reg_read(GPP_DATA_IN_REG(GPP_REG_NUM(gpio)));
+
+ /* if GPIO is ON: wakeup from S2RAM indication detected */
+ return (reg & GPP_MASK(gpio)) ? SUSPEND_WAKEUP_ENABLED_GPIO_DETECTED :
+ SUSPEND_WAKEUP_DISABLED;
+}
+
+/*
+ * mv_ctrl_dev_id_index_get
+ *
+ * DESCRIPTION: return SOC device index
+ * INPUT: None
+ * OUTPUT: None
+ * RETURN:
+ * return SOC device index
+ */
+u32 sys_env_id_index_get(u32 ctrl_model)
+{
+ switch (ctrl_model) {
+ case MV_6820_DEV_ID:
+ return MV_6820_INDEX;
+ case MV_6810_DEV_ID:
+ return MV_6810_INDEX;
+ case MV_6811_DEV_ID:
+ return MV_6811_INDEX;
+ case MV_6828_DEV_ID:
+ return MV_6828_INDEX;
+ case MV_6920_DEV_ID:
+ return MV_6920_INDEX;
+ case MV_6928_DEV_ID:
+ return MV_6928_INDEX;
+ default:
+ return MV_6820_INDEX;
+ }
+}
+
+u32 sys_env_unit_max_num_get(enum unit_id unit)
+{
+ u32 dev_id_index;
+
+ if (unit >= MAX_UNITS_ID) {
+ printf("%s: Error: Wrong unit type (%u)\n", __func__, unit);
+ return 0;
+ }
+
+ dev_id_index = sys_env_id_index_get(sys_env_model_get());
+ return sys_env_soc_unit_nums[unit][dev_id_index];
+}
+
+/*
+ * sys_env_model_get
+ * DESCRIPTION: Returns 16bit describing the device model (ID) as defined
+ * in Vendor ID configuration register
+ */
+u16 sys_env_model_get(void)
+{
+ u32 default_ctrl_id, ctrl_id = reg_read(DEV_ID_REG);
+ ctrl_id = (ctrl_id & (DEV_ID_REG_DEVICE_ID_MASK)) >>
+ DEV_ID_REG_DEVICE_ID_OFFS;
+
+ switch (ctrl_id) {
+ case MV_6820_DEV_ID:
+ case MV_6810_DEV_ID:
+ case MV_6811_DEV_ID:
+ case MV_6828_DEV_ID:
+ case MV_6920_DEV_ID:
+ case MV_6928_DEV_ID:
+ return ctrl_id;
+ default:
+ /* Device ID Default for A38x: 6820 , for A39x: 6920 */
+ #ifdef CONFIG_ARMADA_38X
+ default_ctrl_id = MV_6820_DEV_ID;
+ #else
+ default_ctrl_id = MV_6920_DEV_ID;
+ #endif
+ printf("%s: Error retrieving device ID (%x), using default ID = %x\n",
+ __func__, ctrl_id, default_ctrl_id);
+ return default_ctrl_id;
+ }
+}
+
+/*
+ * sys_env_device_id_get
+ * DESCRIPTION: Returns enum (0..7) index of the device model (ID)
+ */
+u32 sys_env_device_id_get(void)
+{
+ char *device_id_str[7] = {
+ "6810", "6820", "6811", "6828", "NONE", "6920", "6928"
+ };
+
+ if (g_dev_id != -1)
+ return g_dev_id;
+
+ g_dev_id = reg_read(DEVICE_SAMPLE_AT_RESET1_REG);
+ g_dev_id = g_dev_id >> SAR_DEV_ID_OFFS & SAR_DEV_ID_MASK;
+ printf("Detected Device ID %s\n", device_id_str[g_dev_id]);
+
+ return g_dev_id;
+}
+
+#ifdef MV_DDR_TOPOLOGY_UPDATE_FROM_TWSI
+/*
+* sys_env_get_topology_update_info
+* DESCRIPTION: Read TWSI fields to update DDR topology structure
+* INPUT: None
+* OUTPUT: None, 0 means no topology update
+* RETURN:
+* Bit mask of changes topology features
+*/
+#ifdef CONFIG_ARMADA_39X
+u32 sys_env_get_topology_update_info(
+ struct topology_update_info *tui)
+{
+ /* Set 16/32 bit configuration*/
+ tui->update_width = 1;
+ tui->width = TOPOLOGY_UPDATE_WIDTH_32BIT;
+
+#ifdef CONFIG_DDR3
+ if (1 == sys_env_config_get(MV_CONFIG_DDR_BUSWIDTH)) {
+ /* 16bit */
+ tui->width = TOPOLOGY_UPDATE_WIDTH_16BIT;
+ } else {
+ /* 32bit */
+ tui->width = TOPOLOGY_UPDATE_WIDTH_32BIT;
+ }
+#endif
+
+ /* Set ECC/no ECC bit configuration */
+ tui->update_ecc = 1;
+ if (0 == sys_env_config_get(MV_CONFIG_DDR_ECC_EN)) {
+ /* NO ECC */
+ tui->ecc = TOPOLOGY_UPDATE_ECC_OFF;
+ } else {
+ /* ECC */
+ tui->ecc = TOPOLOGY_UPDATE_ECC_ON;
+ }
+
+ tui->update_ecc_pup3_mode = 1;
+ tui->ecc_pup_mode_offset = TOPOLOGY_UPDATE_ECC_OFFSET_PUP4;
+
+ return MV_OK;
+}
+#else /*CONFIG_ARMADA_38X*/
+u32 sys_env_get_topology_update_info(
+ struct topology_update_info *tui)
+{
+ u8 config_val;
+ u8 ecc_mode[A38X_MV_MAX_MARVELL_BOARD_ID -
+ A38X_MARVELL_BOARD_ID_BASE][5] = TOPOLOGY_UPDATE;
+ u8 board_id = mv_board_id_get();
+ int ret;
+
+ board_id = mv_board_id_index_get(board_id);
+ ret = i2c_read(EEPROM_I2C_ADDR, 0, 2, &config_val, 1);
+ if (ret) {
+ DEBUG_INIT_S("sys_env_get_topology_update_info: TWSI Read failed\n");
+ return 0;
+ }
+
+ /* Set 16/32 bit configuration */
+ if ((0 == (config_val & DDR_SATR_CONFIG_MASK_WIDTH)) ||
+ (ecc_mode[board_id][TOPOLOGY_UPDATE_32BIT] == 0)) {
+ /* 16bit by SatR of 32bit mode not supported for the board */
+ if ((ecc_mode[board_id][TOPOLOGY_UPDATE_16BIT] != 0)) {
+ tui->update_width = 1;
+ tui->width = TOPOLOGY_UPDATE_WIDTH_16BIT;
+ }
+ } else {
+ /* 32bit */
+ if ((ecc_mode[board_id][TOPOLOGY_UPDATE_32BIT] != 0)) {
+ tui->update_width = 1;
+ tui->width = TOPOLOGY_UPDATE_WIDTH_32BIT;
+ }
+ }
+
+ /* Set ECC/no ECC bit configuration */
+ if (0 == (config_val & DDR_SATR_CONFIG_MASK_ECC)) {
+ /* NO ECC */
+ tui->update_ecc = 1;
+ tui->ecc = TOPOLOGY_UPDATE_ECC_OFF;
+ } else {
+ /* ECC */
+ if ((ecc_mode[board_id][TOPOLOGY_UPDATE_32BIT_ECC] != 0) ||
+ (ecc_mode[board_id][TOPOLOGY_UPDATE_16BIT_ECC] != 0) ||
+ (ecc_mode[board_id][TOPOLOGY_UPDATE_16BIT_ECC_PUP3] != 0)) {
+ tui->update_ecc = 1;
+ tui->ecc = TOPOLOGY_UPDATE_ECC_ON;
+ }
+ }
+
+ /* Set ECC pup bit configuration */
+ if (0 == (config_val & DDR_SATR_CONFIG_MASK_ECC_PUP)) {
+ /* PUP3 */
+ /*
+ * Check if PUP3 configuration allowed, if not -
+ * force Pup4 with warning message
+ */
+ if ((ecc_mode[board_id][TOPOLOGY_UPDATE_16BIT_ECC_PUP3] != 0)) {
+ if (tui->width == TOPOLOGY_UPDATE_WIDTH_16BIT) {
+ tui->update_ecc_pup3_mode = 1;
+ tui->ecc_pup_mode_offset =
+ TOPOLOGY_UPDATE_ECC_OFFSET_PUP3;
+ } else {
+ if ((ecc_mode[board_id][TOPOLOGY_UPDATE_32BIT_ECC] != 0)) {
+ printf("DDR Topology Update: ECC PUP3 not valid for 32bit mode, force ECC in PUP4\n");
+ tui->update_ecc_pup3_mode = 1;
+ tui->ecc_pup_mode_offset =
+ TOPOLOGY_UPDATE_ECC_OFFSET_PUP4;
+ }
+ }
+ } else {
+ if (ecc_mode[board_id][TOPOLOGY_UPDATE_16BIT_ECC] !=
+ 0) {
+ printf("DDR Topology Update: ECC on PUP3 not supported, force ECC on PUP4\n");
+ tui->update_ecc_pup3_mode = 1;
+ tui->ecc_pup_mode_offset =
+ TOPOLOGY_UPDATE_ECC_OFFSET_PUP4;
+ }
+ }
+ } else {
+ /* PUP4 */
+ if ((ecc_mode[board_id][TOPOLOGY_UPDATE_32BIT_ECC] != 0) ||
+ (ecc_mode[board_id][TOPOLOGY_UPDATE_16BIT_ECC] != 0)) {
+ tui->update_ecc_pup3_mode = 1;
+ tui->ecc_pup_mode_offset =
+ TOPOLOGY_UPDATE_ECC_OFFSET_PUP4;
+ }
+ }
+
+ /*
+ * Check for forbidden ECC mode,
+ * if by default width and pup selection set 32bit ECC mode and this
+ * mode not supported for the board - config 16bit with ECC on PUP3
+ */
+ if ((tui->ecc == TOPOLOGY_UPDATE_ECC_ON) &&
+ (tui->width == TOPOLOGY_UPDATE_WIDTH_32BIT)) {
+ if (ecc_mode[board_id][TOPOLOGY_UPDATE_32BIT_ECC] == 0) {
+ printf("DDR Topology Update: 32bit mode with ECC not allowed on this board, forced 16bit with ECC on PUP3\n");
+ tui->width = TOPOLOGY_UPDATE_WIDTH_16BIT;
+ tui->update_ecc_pup3_mode = 1;
+ tui->ecc_pup_mode_offset =
+ TOPOLOGY_UPDATE_ECC_OFFSET_PUP3;
+ }
+ }
+
+ return MV_OK;
+}
+#endif /* CONFIG_ARMADA_38X */
+#endif /* MV_DDR_TOPOLOGY_UPDATE_FROM_TWSI */
OpenPOWER on IntegriCloud