summaryrefslogtreecommitdiff
path: root/board/toradex/verdin-imx8mm/spl.c
diff options
context:
space:
mode:
authorMax Krummenacher <max.krummenacher@toradex.com>2019-11-01 10:05:15 +0100
committerMarcel Ziswiler <marcel.ziswiler@toradex.com>2019-11-27 17:40:45 +0100
commite335e8a18a1b250e545729ef97e51aa00ea31370 (patch)
treecfb55c9b8083d3d685300837dbf48dd43581a20d /board/toradex/verdin-imx8mm/spl.c
parentfa77d38d3958397e1db966e1cce59b92a73716a3 (diff)
board: toradex: add verdin imx8mm 2gb wb it v1.0a module support
This commit adds initial support for the Toradex Verdin iMX8MM 2GB WB IT V1.0A module. They are now strapped to boot from eFuses which are factory fused to properly boot from their on-module eMMC. U-Boot supports either booting from the on-module eMMC or may be used for recovery purpose using the universal update utility (uuu) aka mfgtools 3.0. Functionality wise the following is known to be working: - eMMC, 8-bit and 4-bit MMC/SD card slots - Gigabit Ethernet - GPIOs - I2C - USB_1 peripheral: fastboot or ums - USB_2 host: USB mass storage To prepare the program image for eMMC fastboot using imx-mkimage and subsequently flash it using U-Boot proceed as follows: cd imx-mkimage/ make SOC=iMX8MM flash_evk_emmc_fastboot load mmc 1:1 $loadaddr flash.bin setexpr blkcnt ${filesize} + 0x1ff && setexpr blkcnt ${blkcnt} / 0x200 mmc dev 0 1 mmc write ${loadaddr} 0x2 ${blkcnt} To prepare the program image for use with USB recovery aka serial downloader using imx-mkimage and subsequently download using uuu with an uuu.auto script proceed as follows: cd imx-mkimage/ make SOC=iMX8MM flash_evk uuu_version 1.3.34 SDP: boot -f flash.bin CFG: SDPU: -vid 0x0525 -pid 0xb4a4 SDPU: delay 1000 SDPU: write -f flash.bin -offset 0x57c00 SDPU: jump Fusing i.MX 8MM SoC and configuring eMMC for fastboot (already done during manufacturing): fuse prog 1 3 0x100020d6 (BT_FUSE_SEL, eMMC boot, SD1, fast boot, 4-bit DDR, high speed, 1.8V) fuse prog 2 2 0x00000001 (enable boot ack) mmc bootbus 0 1 0 2 (4-bit, reset bus width, DDR) mmc partconf 0 1 1 0 (booting from boot area partition 1, send acknowledge) SD manufaccture boot: SD manufacture boot only works as long as the module is un-fused and SD_1_PWR_EN is bypassed on the carrier board. cd imx-mkimage/ make SOC=iMX8MM flash_evk sudo dd if=iMX8M/flash.bin of=/dev/mmcblk0 bs=1024 seek=33 Signed-off-by: Max Krummenacher <max.krummenacher@toradex.com> Signed-off-by: Marcel Ziswiler <marcel.ziswiler@toradex.com>
Diffstat (limited to 'board/toradex/verdin-imx8mm/spl.c')
-rw-r--r--board/toradex/verdin-imx8mm/spl.c231
1 files changed, 231 insertions, 0 deletions
diff --git a/board/toradex/verdin-imx8mm/spl.c b/board/toradex/verdin-imx8mm/spl.c
new file mode 100644
index 0000000000..5f1bfbbc17
--- /dev/null
+++ b/board/toradex/verdin-imx8mm/spl.c
@@ -0,0 +1,231 @@
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * Copyright 2019 Toradex
+ */
+
+#include <common.h>
+#include <spl.h>
+#include <asm/io.h>
+#include <asm/arch/clock.h>
+#include <asm/arch/imx8m_ddr.h>
+#include <asm/arch/imx8mm_pins.h>
+#include <asm/arch/sys_proto.h>
+#include <asm/mach-imx/gpio.h>
+#include <asm/mach-imx/iomux-v3.h>
+#include <asm/mach-imx/mxc_i2c.h>
+#include <errno.h>
+#include <fsl_esdhc.h>
+#include <mmc.h>
+#include <power/pmic.h>
+#include <power/bd71837.h>
+
+DECLARE_GLOBAL_DATA_PTR;
+
+void spl_dram_init(void)
+{
+ ddr_init(&dram_timing);
+}
+
+#define I2C_PAD_CTRL (PAD_CTL_DSE6 | PAD_CTL_HYS | PAD_CTL_PUE | PAD_CTL_PE)
+#define PC MUX_PAD_CTRL(I2C_PAD_CTRL)
+struct i2c_pads_info i2c_pad_info1 = {
+ .scl = {
+ .i2c_mode = IMX8MM_PAD_I2C1_SCL_I2C1_SCL | PC,
+ .gpio_mode = IMX8MM_PAD_I2C1_SCL_GPIO5_IO14 | PC,
+ .gp = IMX_GPIO_NR(5, 14),
+ },
+ .sda = {
+ .i2c_mode = IMX8MM_PAD_I2C1_SDA_I2C1_SDA | PC,
+ .gpio_mode = IMX8MM_PAD_I2C1_SDA_GPIO5_IO15 | PC,
+ .gp = IMX_GPIO_NR(5, 15),
+ },
+};
+
+#define USDHC2_CD_GPIO IMX_GPIO_NR(2, 12)
+#define USDHC2_PWR_GPIO IMX_GPIO_NR(3, 5)
+
+#define USDHC_PAD_CTRL (PAD_CTL_DSE6 | PAD_CTL_HYS | PAD_CTL_PUE | PAD_CTL_PE | \
+ PAD_CTL_FSEL2)
+#define USDHC_GPIO_PAD_CTRL (PAD_CTL_HYS | PAD_CTL_DSE1)
+
+static iomux_v3_cfg_t const usdhc1_pads[] = {
+ IMX8MM_PAD_SD1_CLK_USDHC1_CLK | MUX_PAD_CTRL(USDHC_PAD_CTRL),
+ IMX8MM_PAD_SD1_CMD_USDHC1_CMD | MUX_PAD_CTRL(USDHC_PAD_CTRL),
+ IMX8MM_PAD_SD1_DATA0_USDHC1_DATA0 | MUX_PAD_CTRL(USDHC_PAD_CTRL),
+ IMX8MM_PAD_SD1_DATA1_USDHC1_DATA1 | MUX_PAD_CTRL(USDHC_PAD_CTRL),
+ IMX8MM_PAD_SD1_DATA2_USDHC1_DATA2 | MUX_PAD_CTRL(USDHC_PAD_CTRL),
+ IMX8MM_PAD_SD1_DATA3_USDHC1_DATA3 | MUX_PAD_CTRL(USDHC_PAD_CTRL),
+ IMX8MM_PAD_SD1_DATA4_USDHC1_DATA4 | MUX_PAD_CTRL(USDHC_PAD_CTRL),
+ IMX8MM_PAD_SD1_DATA5_USDHC1_DATA5 | MUX_PAD_CTRL(USDHC_PAD_CTRL),
+ IMX8MM_PAD_SD1_DATA6_USDHC1_DATA6 | MUX_PAD_CTRL(USDHC_PAD_CTRL),
+ IMX8MM_PAD_SD1_DATA7_USDHC1_DATA7 | MUX_PAD_CTRL(USDHC_PAD_CTRL),
+ IMX8MM_PAD_SD1_STROBE_USDHC1_STROBE | MUX_PAD_CTRL(USDHC_PAD_CTRL),
+};
+
+static iomux_v3_cfg_t const usdhc2_pads[] = {
+ IMX8MM_PAD_SD2_CLK_USDHC2_CLK | MUX_PAD_CTRL(USDHC_PAD_CTRL),
+ IMX8MM_PAD_SD2_CMD_USDHC2_CMD | MUX_PAD_CTRL(USDHC_PAD_CTRL),
+ IMX8MM_PAD_SD2_DATA0_USDHC2_DATA0 | MUX_PAD_CTRL(USDHC_PAD_CTRL),
+ IMX8MM_PAD_SD2_DATA1_USDHC2_DATA1 | MUX_PAD_CTRL(USDHC_PAD_CTRL),
+ IMX8MM_PAD_SD2_DATA2_USDHC2_DATA2 | MUX_PAD_CTRL(USDHC_PAD_CTRL),
+ IMX8MM_PAD_SD2_DATA3_USDHC2_DATA3 | MUX_PAD_CTRL(USDHC_PAD_CTRL),
+ IMX8MM_PAD_SD2_RESET_B_GPIO2_IO19 | MUX_PAD_CTRL(USDHC_GPIO_PAD_CTRL),
+ IMX8MM_PAD_SD2_CD_B_GPIO2_IO12 | MUX_PAD_CTRL(USDHC_GPIO_PAD_CTRL),
+ IMX8MM_PAD_NAND_CLE_GPIO3_IO5 | MUX_PAD_CTRL(USDHC_GPIO_PAD_CTRL),
+};
+
+static struct fsl_esdhc_cfg usdhc_cfg[2] = {
+ /* esdhc_base, sdhc_clk, max_bus_width */
+ {USDHC1_BASE_ADDR, 0, 8},
+ {USDHC2_BASE_ADDR, 0, 4},
+};
+
+int board_mmc_init(bd_t *bis)
+{
+ int i, ret;
+ /*
+ * According to the board_mmc_init() the following map is done:
+ * (U-Boot device node) (Physical Port)
+ * mmc0 USDHC1 (eMMC)
+ * mmc1 USDHC2 (SD card)
+ */
+ for (i = 0; i < CONFIG_SYS_FSL_USDHC_NUM; i++) {
+ switch (i) {
+ case 0:
+ usdhc_cfg[i].sdhc_clk = mxc_get_clock(MXC_ESDHC_CLK);
+ imx_iomux_v3_setup_multiple_pads(
+ usdhc1_pads, ARRAY_SIZE(usdhc1_pads));
+ break;
+ case 1:
+ usdhc_cfg[i].sdhc_clk = mxc_get_clock(MXC_ESDHC2_CLK);
+ imx_iomux_v3_setup_multiple_pads(
+ usdhc2_pads, ARRAY_SIZE(usdhc2_pads));
+ gpio_request(USDHC2_PWR_GPIO, "SD_1_PWR_EN");
+ gpio_direction_output(USDHC2_PWR_GPIO, 1);
+ break;
+ default:
+ printf("Warning: you configured more USDHC controllers"
+ "(%d) than supported by the board\n", i + 1);
+ return -EINVAL;
+ }
+
+ ret = fsl_esdhc_initialize(bis, &usdhc_cfg[i]);
+ if (ret)
+ return ret;
+ }
+
+ return 0;
+}
+
+int board_mmc_getcd(struct mmc *mmc)
+{
+ struct fsl_esdhc_cfg *cfg = (struct fsl_esdhc_cfg *)mmc->priv;
+ int ret = 0;
+
+ switch (cfg->esdhc_base) {
+ case USDHC1_BASE_ADDR:
+ ret = 1; /* eMMC */
+ break;
+ case USDHC2_BASE_ADDR:
+ gpio_request(USDHC2_CD_GPIO, "SD_1_CD#");
+ gpio_direction_input(USDHC2_CD_GPIO);
+ ret = !gpio_get_value(USDHC2_CD_GPIO);
+ return ret;
+ }
+
+ return 1;
+}
+
+#ifdef CONFIG_POWER
+#define I2C_PMIC 0
+int power_init_board(void)
+{
+ struct pmic *p;
+ int ret;
+
+ ret = power_bd71837_init(I2C_PMIC);
+ if (ret)
+ printf("power init failed");
+
+ p = pmic_get("BD71837");
+ pmic_probe(p);
+
+ /* decrease RESET key long push time from the default 10s to 10ms */
+ pmic_reg_write(p, BD71837_PWRONCONFIG1, 0x0);
+
+ /* unlock the PMIC regs */
+ pmic_reg_write(p, BD71837_REGLOCK, 0x1);
+
+ /* increase VDD_DRAM to 0.9v for 3Ghz DDR */
+ pmic_reg_write(p, BD71837_BUCK5_VOLT, 0x2);
+
+#ifndef CONFIG_IMX8M_LPDDR4
+ /* increase NVCC_DRAM_1V2 to 1.2v for DDR4 */
+ pmic_reg_write(p, BD71837_BUCK8_VOLT, 0x28);
+#endif
+
+ /* lock the PMIC regs */
+ pmic_reg_write(p, BD71837_REGLOCK, 0x11);
+
+ return 0;
+}
+#endif
+
+void spl_board_init(void)
+{
+#ifndef CONFIG_SPL_USB_SDP_SUPPORT
+ /* Serial download mode */
+ if (is_usb_boot()) {
+ puts("Back to ROM, SDP\n");
+ restore_boot_params();
+ }
+#endif
+ puts("Normal Boot\n");
+}
+
+#ifdef CONFIG_SPL_LOAD_FIT
+int board_fit_config_name_match(const char *name)
+{
+ /* Just empty function now - can't decide what to choose */
+ debug("%s: %s\n", __func__, name);
+
+ return 0;
+}
+#endif
+
+void board_init_f(ulong dummy)
+{
+ int ret;
+
+ /* Clear global data */
+ memset((void *)gd, 0, sizeof(gd_t));
+
+ arch_cpu_init();
+
+ board_early_init_f();
+
+ timer_init();
+
+ preloader_console_init();
+
+ /* Clear the BSS. */
+ memset(__bss_start, 0, __bss_end - __bss_start);
+
+ ret = spl_init();
+ if (ret) {
+ debug("spl_init() failed: %d\n", ret);
+ hang();
+ }
+
+ enable_tzc380();
+
+ /* Adjust pmic voltage to 1.0V for 800M */
+ setup_i2c(0, CONFIG_SYS_I2C_SPEED, 0x7f, &i2c_pad_info1);
+
+ power_init_board();
+
+ /* DDR initialization */
+ spl_dram_init();
+
+ board_init_r(NULL, 0);
+}