summaryrefslogtreecommitdiff
path: root/board/toradex/verdin-imx8mp/verdin-imx8mp.c
diff options
context:
space:
mode:
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