// SPDX-License-Identifier: GPL-2.0+ /* * Copyright 2020 Toradex */ #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #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) || (tdx_hw_tag.prodid == VERDIN_IMX8MPQ_2GB_WIFI_BT_IT) || (tdx_hw_tag.prodid == VERDIN_IMX8MPQ_8GB_WIFI_BT); #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); } } 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