board: toradex: Add Verdin iMX8M Mini support

This adds initial minimal support for the Toradex Verdin iMX8M Mini Quad
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 booting from the on-module eMMC only, SDP support is disabled
for now due to missing i.MX 8M Mini USB support.

Functionality wise the following is known to be working:
- eMMC, 8-bit and 4-bit MMC/SD card slots
- Ethernet
- GPIOs
- I2C

Boot sequence is:
SPL ---> ATF (TF-A) ---> U-boot proper

ATF, U-boot proper and u-boot.dtb images are packed into a FIT image,
loaded by SPL.

Boot:
U-Boot SPL 2020.01-00187-gd411d164e5 (Jan 26 2020 - 04:47:26 +0100)
Normal Boot
Trying to boot from MMC1
NOTICE:  Configuring TZASC380
NOTICE:  RDC off
NOTICE:  BL31: v2.0(release):rel_imx_4.14.98_2.3.0-0-g09c5cc994-dirty
NOTICE:  BL31: Built : 01:11:41, Jan 25 2020
NOTICE:  sip svc init

U-Boot 2020.01-00187-gd411d164e5 (Jan 26 2020 - 04:47:26 +0100)

CPU:   Freescale i.MX8MMQ rev1.0 at 0 MHz
Reset cause: POR
DRAM:  2 GiB
MMC:   FSL_SDHC: 0, FSL_SDHC: 1, FSL_SDHC: 2
Loading Environment from MMC... OK
In:    serial
Out:   serial
Err:   serial
Model: Toradex Verdin iMX8M Mini Quad 2GB Wi-Fi / BT IT V1.0A, Serial#
 06535149
Net:   eth0: ethernet@30be0000
Hit any key to stop autoboot:  0
Verdin iMX8MM #

Signed-off-by: Igor Opaniuk <igor.opaniuk@toradex.com>
Signed-off-by: Max Krummenacher <max.krummenacher@toradex.com>
Signed-off-by: Marcel Ziswiler <marcel.ziswiler@toradex.com>
Reviewed-by: Oleksandr Suvorov <oleksandr.suvorov@toradex.com>
This commit is contained in:
Igor Opaniuk
2020-01-28 14:42:25 +01:00
committed by Stefano Babic
parent c0c3978cba
commit 14d5aeff77
12 changed files with 3504 additions and 0 deletions

View File

@@ -0,0 +1,30 @@
if TARGET_VERDIN_IMX8MM
config SYS_BOARD
default "verdin-imx8mm"
config SYS_VENDOR
default "toradex"
config SYS_CONFIG_NAME
default "verdin-imx8mm"
config TDX_CFG_BLOCK
default y
config TDX_HAVE_MMC
default y
config TDX_CFG_BLOCK_DEV
default "0"
config TDX_CFG_BLOCK_PART
default "1"
# Toradex config block in eMMC, at the end of 1st "boot sector"
config TDX_CFG_BLOCK_OFFSET
default "-512"
source "board/toradex/common/Kconfig"
endif

View File

@@ -0,0 +1,11 @@
# SPDX-License-Identifier: GPL-2.0+
#
# Copyright 2020 Toradex
#
obj-y += verdin-imx8mm.o
ifdef CONFIG_SPL_BUILD
obj-y += spl.o
obj-$(CONFIG_IMX8M_LPDDR4) += lpddr4_timing.o
endif

View File

@@ -0,0 +1,16 @@
/* SPDX-License-Identifier: GPL-2.0+ */
/*
* Copyright 2020 Toradex
*/
#define __ASSEMBLY__
FIT
BOOT_FROM emmc_fastboot
LOADER spl/u-boot-spl-ddr.bin 0x7E1000
SECOND_LOADER u-boot.itb 0x40200000 0x60000
DDR_FW lpddr4_pmu_train_1d_imem.bin
DDR_FW lpddr4_pmu_train_1d_dmem.bin
DDR_FW lpddr4_pmu_train_2d_imem.bin
DDR_FW lpddr4_pmu_train_2d_dmem.bin

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,180 @@
// SPDX-License-Identifier: GPL-2.0+
/*
* Copyright 2020 Toradex
*/
#include <common.h>
#include <asm/arch/clock.h>
#include <asm/arch/ddr.h>
#include <asm/arch/imx8mm_pins.h>
#include <asm/arch/sys_proto.h>
#include <asm/io.h>
#include <asm/mach-imx/boot_mode.h>
#include <asm/mach-imx/iomux-v3.h>
#include <cpu_func.h>
#include <dm/device.h>
#include <dm/device-internal.h>
#include <dm/uclass.h>
#include <dm/uclass-internal.h>
#include <hang.h>
#include <power/bd71837.h>
#include <power/pmic.h>
#include <spl.h>
DECLARE_GLOBAL_DATA_PTR;
int spl_board_boot_device(enum boot_device boot_dev_spl)
{
switch (boot_dev_spl) {
case MMC1_BOOT:
return BOOT_DEVICE_MMC1;
case SD2_BOOT:
case MMC2_BOOT:
return BOOT_DEVICE_MMC2;
case SD3_BOOT:
case MMC3_BOOT:
return BOOT_DEVICE_MMC1;
case USB_BOOT:
return BOOT_DEVICE_BOARD;
default:
return BOOT_DEVICE_NONE;
}
}
void spl_dram_init(void)
{
ddr_init(&dram_timing);
}
void spl_board_init(void)
{
/* Serial download mode */
if (is_usb_boot()) {
puts("Back to ROM, SDP\n");
restore_boot_params();
}
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
#define UART_PAD_CTRL (PAD_CTL_PUE | PAD_CTL_PE | PAD_CTL_DSE4)
#define WDOG_PAD_CTRL (PAD_CTL_DSE6 | PAD_CTL_ODE | PAD_CTL_PUE | PAD_CTL_PE)
/* Verdin UART_3, Console/Debug UART */
static iomux_v3_cfg_t const uart_pads[] = {
IMX8MM_PAD_SAI2_RXFS_UART1_TX | MUX_PAD_CTRL(UART_PAD_CTRL),
IMX8MM_PAD_SAI2_RXC_UART1_RX | MUX_PAD_CTRL(UART_PAD_CTRL),
};
static iomux_v3_cfg_t const wdog_pads[] = {
IMX8MM_PAD_GPIO1_IO02_WDOG1_WDOG_B | MUX_PAD_CTRL(WDOG_PAD_CTRL),
};
int board_early_init_f(void)
{
struct wdog_regs *wdog = (struct wdog_regs *)WDOG1_BASE_ADDR;
imx_iomux_v3_setup_multiple_pads(wdog_pads, ARRAY_SIZE(wdog_pads));
set_wdog_reset(wdog);
imx_iomux_v3_setup_multiple_pads(uart_pads, ARRAY_SIZE(uart_pads));
return 0;
}
int power_init_board(void)
{
struct udevice *dev;
int ret;
ret = pmic_get("pmic@4b", &dev);
if (ret == -ENODEV) {
puts("No pmic\n");
return 0;
}
if (ret != 0)
return ret;
/* decrease RESET key long push time from the default 10s to 10ms */
pmic_reg_write(dev, BD718XX_PWRONCONFIG1, 0x0);
/* unlock the PMIC regs */
pmic_reg_write(dev, BD718XX_REGLOCK, 0x1);
/* increase VDD_SOC to typical value 0.85v before first DRAM access */
pmic_reg_write(dev, BD718XX_BUCK1_VOLT_RUN, 0x0f);
/* increase VDD_DRAM to 0.975v for 3Ghz DDR */
pmic_reg_write(dev, BD718XX_1ST_NODVS_BUCK_VOLT, 0x83);
#ifndef CONFIG_IMX8M_LPDDR4
/* increase NVCC_DRAM_1V2 to 1.2v for DDR4 */
pmic_reg_write(dev, BD718XX_4TH_NODVS_BUCK_VOLT, 0x28);
#endif
/* lock the PMIC regs */
pmic_reg_write(dev, BD718XX_REGLOCK, 0x11);
return 0;
}
void board_init_f(ulong dummy)
{
struct udevice *dev;
int ret;
arch_cpu_init();
init_uart_clk(0);
board_early_init_f();
timer_init();
preloader_console_init();
/* Clear the BSS. */
memset(__bss_start, 0, __bss_end - __bss_start);
ret = spl_early_init();
if (ret) {
debug("spl_early_init() failed: %d\n", ret);
hang();
}
ret = uclass_get_device_by_name(UCLASS_CLK,
"clock-controller@30380000",
&dev);
if (ret < 0) {
printf("Failed to find clock node. Check device tree\n");
hang();
}
enable_tzc380();
power_init_board();
/* DDR initialization */
spl_dram_init();
board_init_r(NULL, 0);
}
int do_reset(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[])
{
puts("resetting ...\n");
reset_cpu(WDOG1_BASE_ADDR);
return 0;
}

View File

@@ -0,0 +1,73 @@
// SPDX-License-Identifier: GPL-2.0+
/*
* Copyright 2020 Toradex
*/
#include <common.h>
#include <asm/arch/clock.h>
#include <asm/io.h>
#include <miiphy.h>
#include <netdev.h>
DECLARE_GLOBAL_DATA_PTR;
int dram_init(void)
{
gd->ram_size = get_ram_size((void *)PHYS_SDRAM, PHYS_SDRAM_SIZE);
return 0;
}
#if IS_ENABLED(CONFIG_FEC_MXC)
static int setup_fec(void)
{
struct iomuxc_gpr_base_regs *gpr =
(struct iomuxc_gpr_base_regs *)IOMUXC_GPR_BASE_ADDR;
/* Use 125M anatop REF_CLK1 for ENET1, not from external */
clrsetbits_le32(&gpr->gpr[1], 0x2000, 0);
return 0;
}
int board_phy_config(struct phy_device *phydev)
{
/* enable rgmii rxc skew and phy mode select to RGMII copper */
phy_write(phydev, MDIO_DEVAD_NONE, 0x1d, 0x1f);
phy_write(phydev, MDIO_DEVAD_NONE, 0x1e, 0x8);
phy_write(phydev, MDIO_DEVAD_NONE, 0x1d, 0x00);
phy_write(phydev, MDIO_DEVAD_NONE, 0x1e, 0x82ee);
phy_write(phydev, MDIO_DEVAD_NONE, 0x1d, 0x05);
phy_write(phydev, MDIO_DEVAD_NONE, 0x1e, 0x100);
if (phydev->drv->config)
phydev->drv->config(phydev);
return 0;
}
#endif
int board_init(void)
{
if (IS_ENABLED(CONFIG_FEC_MXC))
setup_fec();
return 0;
}
int board_mmc_get_env_dev(int devno)
{
return devno;
}
int board_late_init(void)
{
return 0;
}
#if defined(CONFIG_OF_LIBFDT) && defined(CONFIG_OF_BOARD_SETUP)
int ft_board_setup(void *blob, bd_t *bd)
{
return 0;
}
#endif