summaryrefslogtreecommitdiff
path: root/board/toradex/verdin-imx8mp/verdin-imx8mp.c
diff options
context:
space:
mode:
authorMarcel Ziswiler <marcel.ziswiler@toradex.com>2020-11-12 18:34:50 +0100
committerMarcel Ziswiler <marcel.ziswiler@toradex.com>2020-11-19 20:31:31 +0100
commited39664c84cf4936ba37f2dc6da34bc0c4f4c4a5 (patch)
tree2f0c514195ed76c4ce5fa3f74b7e2a7ed6a0bb68 /board/toradex/verdin-imx8mp/verdin-imx8mp.c
parent416025ff878ba7d4c2723a3ff5420b32b424b681 (diff)
board: toradex: add verdin imx8m plus support
This adds initial minimal support for the Toradex Verdin iMX8M Plus Quad 4GB WB IT V1.0A and Toradex Verdin iMX8M Plus Quad 2GB V1.0A modules. They are 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 or, if the recovery button/pin is asserted, via USB serial download aka SDP support. Functionality wise the following is known to be working: - eMMC, 8-bit and 4-bit MMC/SD card slots - Ethernet (but only 2nd one available on the Verdin Development board) - 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.04-00217-gfad48768ba (Nov 18 2020 - 14:22:31 +0100) DDRINFO: start DRAM init DDRINFO: DRAM rate 4000MTS DDRINFO:ddrphy calibration done DDRINFO: ddrmix config done Normal Boot Trying to boot from BOOTROM Find FIT header 0x4803afa0, size 855 Need continue download 1024 Download 833424, total fit 834544 NOTICE: BL31: v2.2(release):imx_5.4.24_er3-6-g0a236bda5 NOTICE: BL31: Built : 13:40:19, Nov 12 2020 U-Boot 2020.04-00217-gfad48768ba (Nov 18 2020 - 14:22:31 +0100) alloc_simple() alloc space exhausted CPU: i.MX8MP[8] rev1.0 1800 MHz (running at 1200 MHz) CPU: Commercial temperature grade (0C to 95C) at 46C Reset cause: POR DRAM: 4 GiB MMC: FSL_SDHC: 1, FSL_SDHC: 2 In: serial Out: serial Err: serial Model: Toradex Verdin iMX8M Plus Quad 4GB Wi-Fi / BT IT V1.0A, Serial# 06775455 MISSING TORADEX CARRIER CONFIG BLOCKS BuildInfo: - ATF 0a236bd - U-Boot 2020.04-00217-gfad48768ba Detect USB boot. Will enter fastboot mode! Net: Warning: ethernet@30bf0000 (eth1) using random MAC address - 56:c0:c6:84:63:a0 eth0: ethernet@30be0000, eth1: ethernet@30bf0000 [PRIME] Fastboot: Normal Boot from USB for mfgtools *** Warning - Use default environment for mfgtools , using default environment Run bootcmd_mfg: fastboot 0 Hit any key to stop autoboot: 0 Verdin iMX8MP # Related-to: ELB-3208 Signed-off-by: Marcel Ziswiler <marcel.ziswiler@toradex.com>
Diffstat (limited to 'board/toradex/verdin-imx8mp/verdin-imx8mp.c')
-rw-r--r--board/toradex/verdin-imx8mp/verdin-imx8mp.c418
1 files changed, 418 insertions, 0 deletions
diff --git a/board/toradex/verdin-imx8mp/verdin-imx8mp.c b/board/toradex/verdin-imx8mp/verdin-imx8mp.c
new file mode 100644
index 0000000000..f1d5f889b5
--- /dev/null
+++ b/board/toradex/verdin-imx8mp/verdin-imx8mp.c
@@ -0,0 +1,418 @@
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * Copyright 2020 Toradex
+ */
+
+#include <common.h>
+#include <asm/io.h>
+#include <asm/arch/clock.h>
+#include <asm/arch/imx8mp_pins.h>
+#include <asm/arch/sys_proto.h>
+#include <asm-generic/gpio.h>
+#include <asm/mach-imx/dma.h>
+#include <asm/mach-imx/iomux-v3.h>
+#include <asm/mach-imx/gpio.h>
+#include <asm/mach-imx/mxc_i2c.h>
+#include <dwc3-uboot.h>
+#include <errno.h>
+#include <micrel.h>
+#include <miiphy.h>
+#include <netdev.h>
+#include <power/pmic.h>
+#include <spl.h>
+#include <usb.h>
+
+#include "../common/tdx-cfg-block.h"
+
+DECLARE_GLOBAL_DATA_PTR;
+
+#define GPIO_PAD_CTRL (PAD_CTL_HYS | PAD_CTL_PUE | PAD_CTL_PE | PAD_CTL_DSE4)
+#define UART_PAD_CTRL (PAD_CTL_DSE6 | PAD_CTL_FSEL1)
+#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[] = {
+ MX8MP_PAD_UART3_RXD__UART3_DCE_RX | MUX_PAD_CTRL(UART_PAD_CTRL),
+ MX8MP_PAD_UART3_TXD__UART3_DCE_TX | MUX_PAD_CTRL(UART_PAD_CTRL),
+};
+
+static iomux_v3_cfg_t const wdog_pads[] = {
+ MX8MP_PAD_GPIO1_IO02__WDOG1_WDOG_B | MUX_PAD_CTRL(WDOG_PAD_CTRL),
+};
+
+static iomux_v3_cfg_t const sleep_moci_pads[] = {
+ MX8MP_PAD_SAI3_RXC__GPIO4_IO29 | MUX_PAD_CTRL(GPIO_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));
+
+ init_uart_clk(2);
+
+ return 0;
+}
+
+#ifdef CONFIG_OF_BOARD_SETUP
+int ft_board_setup(void *blob, bd_t *bd)
+{
+#ifdef CONFIG_IMX8M_DRAM_INLINE_ECC
+ int rc;
+ phys_addr_t ecc0_start = 0xb0000000;
+ phys_addr_t ecc1_start = 0x130000000;
+ phys_addr_t ecc2_start = 0x1b0000000;
+ size_t ecc_size = 0x10000000;
+
+ rc = add_res_mem_dt_node(blob, "ecc", ecc0_start, ecc_size);
+ if (rc < 0) {
+ printf("Could not create ecc0 reserved-memory node.\n");
+ return rc;
+ }
+
+ rc = add_res_mem_dt_node(blob, "ecc", ecc1_start, ecc_size);
+ if (rc < 0) {
+ printf("Could not create ecc1 reserved-memory node.\n");
+ return rc;
+ }
+
+ rc = add_res_mem_dt_node(blob, "ecc", ecc2_start, ecc_size);
+ if (rc < 0) {
+ printf("Could not create ecc2 reserved-memory node.\n");
+ return rc;
+ }
+#endif
+
+ return ft_common_board_setup(blob, bd);
+}
+#endif
+
+#ifdef CONFIG_FEC_MXC
+static int setup_fec(void)
+{
+ struct iomuxc_gpr_base_regs *gpr =
+ (struct iomuxc_gpr_base_regs *)IOMUXC_GPR_BASE_ADDR;
+
+ /* Enable RGMII TX clk output */
+ setbits_le32(&gpr->gpr[1], BIT(22));
+
+ return 0;
+}
+#endif
+
+#ifdef CONFIG_DWC_ETH_QOS
+static int setup_eqos(void)
+{
+ struct iomuxc_gpr_base_regs *gpr =
+ (struct iomuxc_gpr_base_regs *)IOMUXC_GPR_BASE_ADDR;
+
+ /* set INTF as RGMII, enable RGMII TXC clock */
+ clrsetbits_le32(&gpr->gpr[1],
+ IOMUXC_GPR_GPR1_GPR_ENET_QOS_INTF_SEL_MASK, BIT(16));
+ setbits_le32(&gpr->gpr[1], BIT(19) | BIT(21));
+
+ return set_clk_eqos(ENET_125MHZ);
+}
+#endif
+
+#if defined(CONFIG_FEC_MXC) || defined(CONFIG_DWC_ETH_QOS)
+int board_phy_config(struct phy_device *phydev)
+{
+ int tmp;
+
+ switch(ksz9xx1_phy_get_id(phydev) & MII_KSZ9x31_SILICON_REV_MASK) {
+ case PHY_ID_KSZ9031:
+ /*
+ * The PHY adds 1.2ns for the RXC and 0ns for TXC clock by default. The MAC
+ * and the layout don't add a skew between clock and data.
+ * Add 0.3ns for the RXC path and 0.96 + 0.42 ns (1.38 ns) for the TXC path
+ * to get the required clock skews.
+ */
+ /* control data pad skew - devaddr = 0x02, register = 0x04 */
+ ksz9031_phy_extended_write(phydev, 0x02,
+ MII_KSZ9031_EXT_RGMII_CTRL_SIG_SKEW,
+ MII_KSZ9031_MOD_DATA_NO_POST_INC, 0x0070);
+ /* rx data pad skew - devaddr = 0x02, register = 0x05 */
+ ksz9031_phy_extended_write(phydev, 0x02,
+ MII_KSZ9031_EXT_RGMII_RX_DATA_SKEW,
+ MII_KSZ9031_MOD_DATA_NO_POST_INC, 0x7777);
+ /* tx data pad skew - devaddr = 0x02, register = 0x06 */
+ ksz9031_phy_extended_write(phydev, 0x02,
+ MII_KSZ9031_EXT_RGMII_TX_DATA_SKEW,
+ MII_KSZ9031_MOD_DATA_NO_POST_INC, 0x0000);
+ /* gtx and rx clock pad skew - devaddr = 0x02, register = 0x08 */
+ ksz9031_phy_extended_write(phydev, 0x02,
+ MII_KSZ9031_EXT_RGMII_CLOCK_SKEW,
+ MII_KSZ9031_MOD_DATA_NO_POST_INC, 0x03f4);
+ break;
+ case PHY_ID_KSZ9131:
+ default:
+ /* read rxc dll control - devaddr = 0x2, register = 0x4c */
+ tmp = ksz9031_phy_extended_read(phydev, 0x02,
+ MII_KSZ9131_EXT_RGMII_2NS_SKEW_RXDLL,
+ MII_KSZ9031_MOD_DATA_NO_POST_INC);
+ /* disable rxdll bypass (enable 2ns skew delay on RXC) */
+ tmp &= ~MII_KSZ9131_RXTXDLL_BYPASS;
+ /* rxc data pad skew 2ns - devaddr = 0x02, register = 0x4c */
+ tmp = ksz9031_phy_extended_write(phydev, 0x02,
+ MII_KSZ9131_EXT_RGMII_2NS_SKEW_RXDLL,
+ MII_KSZ9031_MOD_DATA_NO_POST_INC, tmp);
+ /* read txc dll control - devaddr = 0x02, register = 0x4d */
+ tmp = ksz9031_phy_extended_read(phydev, 0x02,
+ MII_KSZ9131_EXT_RGMII_2NS_SKEW_TXDLL,
+ MII_KSZ9031_MOD_DATA_NO_POST_INC);
+ /* disable txdll bypass (enable 2ns skew delay on TXC) */
+ tmp &= ~MII_KSZ9131_RXTXDLL_BYPASS;
+ /* rxc data pad skew 2ns - devaddr = 0x02, register = 0x4d */
+ tmp = ksz9031_phy_extended_write(phydev, 0x02,
+ MII_KSZ9131_EXT_RGMII_2NS_SKEW_TXDLL,
+ MII_KSZ9031_MOD_DATA_NO_POST_INC, tmp);
+ break;
+ }
+
+ if (phydev->drv->config)
+ phydev->drv->config(phydev);
+ return 0;
+}
+#endif
+
+#ifdef CONFIG_USB_DWC3
+
+#define USB_PHY_CTRL0 0xF0040
+#define USB_PHY_CTRL0_REF_SSP_EN BIT(2)
+
+#define USB_PHY_CTRL1 0xF0044
+#define USB_PHY_CTRL1_RESET BIT(0)
+#define USB_PHY_CTRL1_COMMONONN BIT(1)
+#define USB_PHY_CTRL1_ATERESET BIT(3)
+#define USB_PHY_CTRL1_VDATSRCENB0 BIT(19)
+#define USB_PHY_CTRL1_VDATDETENB0 BIT(20)
+
+#define USB_PHY_CTRL2 0xF0048
+#define USB_PHY_CTRL2_TXENABLEN0 BIT(8)
+
+#define USB_PHY_CTRL6 0xF0058
+
+#define HSIO_GPR_BASE (0x32F10000U)
+#define HSIO_GPR_REG_0 (HSIO_GPR_BASE)
+#define HSIO_GPR_REG_0_USB_CLOCK_MODULE_EN_SHIFT (1)
+#define HSIO_GPR_REG_0_USB_CLOCK_MODULE_EN (0x1U << HSIO_GPR_REG_0_USB_CLOCK_MODULE_EN_SHIFT)
+
+static struct dwc3_device dwc3_device_data = {
+#ifdef CONFIG_SPL_BUILD
+ .maximum_speed = USB_SPEED_HIGH,
+#else
+ .maximum_speed = USB_SPEED_SUPER,
+#endif
+ .base = USB1_BASE_ADDR,
+ .dr_mode = USB_DR_MODE_PERIPHERAL,
+ .index = 0,
+ .power_down_scale = 2,
+};
+
+int usb_gadget_handle_interrupts(void)
+{
+ dwc3_uboot_handle_interrupt(0);
+ return 0;
+}
+
+static void dwc3_nxp_usb_phy_init(struct dwc3_device *dwc3)
+{
+ u32 RegData;
+
+ /* enable usb clock via hsio gpr */
+ RegData = readl(HSIO_GPR_REG_0);
+ RegData |= HSIO_GPR_REG_0_USB_CLOCK_MODULE_EN;
+ writel(RegData, HSIO_GPR_REG_0);
+
+ /* USB3.0 PHY signal fsel for 100M ref */
+ RegData = readl(dwc3->base + USB_PHY_CTRL0);
+ RegData = (RegData & 0xfffff81f) | (0x2a<<5);
+ writel(RegData, dwc3->base + USB_PHY_CTRL0);
+
+ RegData = readl(dwc3->base + USB_PHY_CTRL6);
+ RegData &=~0x1;
+ writel(RegData, dwc3->base + USB_PHY_CTRL6);
+
+ RegData = readl(dwc3->base + USB_PHY_CTRL1);
+ RegData &= ~(USB_PHY_CTRL1_VDATSRCENB0 | USB_PHY_CTRL1_VDATDETENB0 |
+ USB_PHY_CTRL1_COMMONONN);
+ RegData |= USB_PHY_CTRL1_RESET | USB_PHY_CTRL1_ATERESET;
+ writel(RegData, dwc3->base + USB_PHY_CTRL1);
+
+ RegData = readl(dwc3->base + USB_PHY_CTRL0);
+ RegData |= USB_PHY_CTRL0_REF_SSP_EN;
+ writel(RegData, dwc3->base + USB_PHY_CTRL0);
+
+ RegData = readl(dwc3->base + USB_PHY_CTRL2);
+ RegData |= USB_PHY_CTRL2_TXENABLEN0;
+ writel(RegData, dwc3->base + USB_PHY_CTRL2);
+
+ RegData = readl(dwc3->base + USB_PHY_CTRL1);
+ RegData &= ~(USB_PHY_CTRL1_RESET | USB_PHY_CTRL1_ATERESET);
+ writel(RegData, dwc3->base + USB_PHY_CTRL1);
+}
+#endif
+
+#if defined(CONFIG_USB_DWC3) || defined(CONFIG_USB_XHCI_IMX8M)
+#define USB2_PWR_EN IMX_GPIO_NR(1, 14)
+int board_usb_init(int index, enum usb_init_type init)
+{
+ int ret = 0;
+ imx8m_usb_power(index, true);
+
+ if (index == 0 && init == USB_INIT_DEVICE) {
+#ifdef CONFIG_USB_TCPC
+ ret = tcpc_setup_ufp_mode(&port1);
+ if (ret)
+ return ret;
+#endif
+ dwc3_nxp_usb_phy_init(&dwc3_device_data);
+ return dwc3_uboot_init(&dwc3_device_data);
+ } else if (index == 0 && init == USB_INIT_HOST) {
+#ifdef CONFIG_USB_TCPC
+ ret = tcpc_setup_dfp_mode(&port1);
+#endif
+ return ret;
+ } else if (index == 1 && init == USB_INIT_HOST) {
+ /* Enable GPIO1_IO14 for 5V VBUS */
+ gpio_request(USB2_PWR_EN, "usb2_pwr");
+ gpio_direction_output(USB2_PWR_EN, 1);
+ }
+
+ return 0;
+}
+
+int board_usb_cleanup(int index, enum usb_init_type init)
+{
+ int ret = 0;
+ if (index == 0 && init == USB_INIT_DEVICE) {
+ dwc3_uboot_exit(index);
+ } else if (index == 0 && init == USB_INIT_HOST) {
+#ifdef CONFIG_USB_TCPC
+ ret = tcpc_disable_src_vbus(&port1);
+#endif
+ } else if (index == 1 && init == USB_INIT_HOST) {
+ /* Disable GPIO1_IO14 for 5V VBUS */
+ gpio_direction_output(USB2_PWR_EN, 0);
+ }
+
+ imx8m_usb_power(index, false);
+
+ return ret;
+}
+
+#endif
+
+#define FSL_SIP_GPC 0xC2000000
+#define FSL_SIP_CONFIG_GPC_PM_DOMAIN 0x3
+#define DISPMIX 13
+#define MIPI 15
+
+int board_init(void)
+{
+#ifdef CONFIG_FEC_MXC
+ setup_fec();
+#endif
+
+#ifdef CONFIG_DWC_ETH_QOS
+ /* clock, pin, gpr */
+ setup_eqos();
+#endif
+
+#if defined(CONFIG_USB_DWC3) || defined(CONFIG_USB_XHCI_IMX8M)
+ init_usb_clk();
+#endif
+
+ return 0;
+}
+
+static void select_dt_from_module_version(void)
+{
+ char variant[32];
+ char *env_variant = env_get("variant");
+ int is_wifi = 0;
+
+#ifdef CONFIG_TDX_CFG_BLOCK
+ /*
+ * If we have a valid config block and it says we are a module with
+ * Wi-Fi/Bluetooth make sure we use the -wifi device tree.
+ */
+ is_wifi = (tdx_hw_tag.prodid == VERDIN_IMX8MPQ_WIFI_BT_IT);
+#endif
+
+ if (is_wifi)
+ strncpy(&variant[0], "wifi", sizeof(variant));
+ else
+ strncpy(&variant[0], "nonwifi", sizeof(variant));
+
+ if (strcmp(variant, env_variant)) {
+ printf("Setting variant to %s\n", variant);
+ env_set("variant", variant);
+#ifndef CONFIG_ENV_IS_NOWHERE
+ env_save();
+#endif
+ }
+}
+
+int board_late_init(void)
+{
+ select_dt_from_module_version();
+
+ /* Power up carrier board HW, e.g. USB */
+ imx_iomux_v3_setup_multiple_pads(sleep_moci_pads, ARRAY_SIZE(sleep_moci_pads));
+ gpio_request(IMX_GPIO_NR(4, 29), "SLEEP_MOCI#");
+ gpio_direction_output(IMX_GPIO_NR(4, 29), 1);
+
+ return 0;
+}
+
+int board_phys_sdram_size(phys_size_t *bank1_size, phys_size_t *bank2_size)
+{
+ if (!bank1_size || !bank2_size)
+ return -EINVAL;
+
+ /* i.MX 8M Plus supports max. 8GB memory in two albeit concecutive banks */
+ *bank1_size = get_ram_size((long *)PHYS_SDRAM, 0x200000000);
+
+ if (*bank1_size > PHYS_SDRAM_SIZE) {
+ *bank2_size = *bank1_size - PHYS_SDRAM_SIZE;
+ *bank1_size = PHYS_SDRAM_SIZE;
+ }
+
+ return 0;
+}
+
+#ifdef CONFIG_FSL_FASTBOOT
+#ifdef CONFIG_ANDROID_RECOVERY
+int is_recovery_key_pressing(void)
+{
+ return 0; /* TODO */
+}
+#endif /*CONFIG_ANDROID_RECOVERY*/
+#endif /*CONFIG_FSL_FASTBOOT*/
+
+#ifdef CONFIG_ANDROID_SUPPORT
+bool is_power_key_pressed(void) {
+ return (bool)(!!(readl(SNVS_HPSR) & (0x1 << 6)));
+}
+#endif
+
+#ifdef CONFIG_SPL_MMC_SUPPORT
+#define UBOOT_RAW_SECTOR_OFFSET 0x40
+unsigned long spl_mmc_get_uboot_raw_sector(struct mmc *mmc)
+{
+ u32 boot_dev = spl_boot_device();
+ switch (boot_dev) {
+ case BOOT_DEVICE_MMC2:
+ return CONFIG_SYS_MMCSD_RAW_MODE_U_BOOT_SECTOR - UBOOT_RAW_SECTOR_OFFSET;
+ default:
+ return CONFIG_SYS_MMCSD_RAW_MODE_U_BOOT_SECTOR;
+ }
+}
+#endif