// SPDX-License-Identifier: GPL-2.0+ /* * Copyright 2018 NXP */ #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include "../common/tcpc.h" #include #include DECLARE_GLOBAL_DATA_PTR; #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) static iomux_v3_cfg_t const uart_pads[] = { IMX8MM_PAD_UART2_RXD_UART2_RX | MUX_PAD_CTRL(UART_PAD_CTRL), IMX8MM_PAD_UART2_TXD_UART2_TX | MUX_PAD_CTRL(UART_PAD_CTRL), }; #ifndef CONFIG_TARGET_IMX8MM_DDR3L_VAL static iomux_v3_cfg_t const wdog_pads[] = { IMX8MM_PAD_GPIO1_IO02_WDOG1_WDOG_B | MUX_PAD_CTRL(WDOG_PAD_CTRL), }; #endif #ifdef CONFIG_MXC_SPI #define SPI_PAD_CTRL (PAD_CTL_DSE2 | PAD_CTL_HYS) static iomux_v3_cfg_t const ecspi1_pads[] = { IMX8MM_PAD_ECSPI1_SCLK_ECSPI1_SCLK | MUX_PAD_CTRL(SPI_PAD_CTRL), IMX8MM_PAD_ECSPI1_MOSI_ECSPI1_MOSI | MUX_PAD_CTRL(SPI_PAD_CTRL), IMX8MM_PAD_ECSPI1_MISO_ECSPI1_MISO | MUX_PAD_CTRL(SPI_PAD_CTRL), IMX8MM_PAD_ECSPI1_SS0_GPIO5_IO9 | MUX_PAD_CTRL(NO_PAD_CTRL), }; static void setup_spi(void) { imx_iomux_v3_setup_multiple_pads(ecspi1_pads, ARRAY_SIZE(ecspi1_pads)); gpio_request(IMX_GPIO_NR(5, 9), "ECSPI1 CS"); init_clk_ecspi(0); } int board_spi_cs_gpio(unsigned bus, unsigned cs) { return IMX_GPIO_NR(5, 9); } #endif #ifdef CONFIG_NAND_MXS #define NAND_PAD_CTRL (PAD_CTL_DSE6 | PAD_CTL_FSEL2 | PAD_CTL_HYS) #define NAND_PAD_READY0_CTRL (PAD_CTL_DSE6 | PAD_CTL_FSEL2 | PAD_CTL_PUE) static iomux_v3_cfg_t const gpmi_pads[] = { IMX8MM_PAD_NAND_ALE_RAWNAND_ALE | MUX_PAD_CTRL(NAND_PAD_CTRL), IMX8MM_PAD_NAND_CE0_B_RAWNAND_CE0_B | MUX_PAD_CTRL(NAND_PAD_CTRL), IMX8MM_PAD_NAND_CLE_RAWNAND_CLE | MUX_PAD_CTRL(NAND_PAD_CTRL), IMX8MM_PAD_NAND_DATA00_RAWNAND_DATA00 | MUX_PAD_CTRL(NAND_PAD_CTRL), IMX8MM_PAD_NAND_DATA01_RAWNAND_DATA01 | MUX_PAD_CTRL(NAND_PAD_CTRL), IMX8MM_PAD_NAND_DATA02_RAWNAND_DATA02 | MUX_PAD_CTRL(NAND_PAD_CTRL), IMX8MM_PAD_NAND_DATA03_RAWNAND_DATA03 | MUX_PAD_CTRL(NAND_PAD_CTRL), IMX8MM_PAD_NAND_DATA04_RAWNAND_DATA04 | MUX_PAD_CTRL(NAND_PAD_CTRL), IMX8MM_PAD_NAND_DATA05_RAWNAND_DATA05 | MUX_PAD_CTRL(NAND_PAD_CTRL), IMX8MM_PAD_NAND_DATA06_RAWNAND_DATA06 | MUX_PAD_CTRL(NAND_PAD_CTRL), IMX8MM_PAD_NAND_DATA07_RAWNAND_DATA07 | MUX_PAD_CTRL(NAND_PAD_CTRL), IMX8MM_PAD_NAND_RE_B_RAWNAND_RE_B | MUX_PAD_CTRL(NAND_PAD_CTRL), IMX8MM_PAD_NAND_READY_B_RAWNAND_READY_B | MUX_PAD_CTRL(NAND_PAD_READY0_CTRL), IMX8MM_PAD_NAND_WE_B_RAWNAND_WE_B | MUX_PAD_CTRL(NAND_PAD_CTRL), IMX8MM_PAD_NAND_WP_B_RAWNAND_WP_B | MUX_PAD_CTRL(NAND_PAD_CTRL), }; static void setup_gpmi_nand(void) { imx_iomux_v3_setup_multiple_pads(gpmi_pads, ARRAY_SIZE(gpmi_pads)); init_nand_clk(); } #endif int board_early_init_f(void) { #ifndef CONFIG_TARGET_IMX8MM_DDR3L_VAL 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); #endif imx_iomux_v3_setup_multiple_pads(uart_pads, ARRAY_SIZE(uart_pads)); init_uart_clk(1); #ifdef CONFIG_NAND_MXS setup_gpmi_nand(); /* SPL will call the board_early_init_f */ #endif return 0; } #if IS_ENABLED(CONFIG_FEC_MXC) #ifndef CONFIG_TARGET_IMX8MM_DDR3L_VAL #define FEC_RST_PAD IMX_GPIO_NR(4, 22) static iomux_v3_cfg_t const fec1_rst_pads[] = { IMX8MM_PAD_SAI2_RXC_GPIO4_IO22 | MUX_PAD_CTRL(NO_PAD_CTRL), }; static void setup_iomux_fec(void) { imx_iomux_v3_setup_multiple_pads(fec1_rst_pads, ARRAY_SIZE(fec1_rst_pads)); gpio_request(FEC_RST_PAD, "fec1_rst"); gpio_direction_output(FEC_RST_PAD, 0); udelay(500); gpio_direction_output(FEC_RST_PAD, 1); } #endif static int setup_fec(void) { #ifdef CONFIG_TARGET_IMX8MM_DDR3L_VAL struct iomuxc_gpr_base_regs *gpr = (struct iomuxc_gpr_base_regs *) IOMUXC_GPR_BASE_ADDR; /* * GPR1 bit 13: * 1:enet1 rmii clock comes from ccm->pad->loopback, SION bit for the pad (iomuxc_sw_input_on_pad_enet_td2) should be set also; * 0:enet1 rmii clock comes from external phy or osc */ setbits_le32(&gpr->gpr[1], IOMUXC_GPR_GPR1_GPR_ENET1_TX_CLK_SEL_MASK); return set_clk_enet(ENET_50MHZ); #else struct iomuxc_gpr_base_regs *gpr = (struct iomuxc_gpr_base_regs *) IOMUXC_GPR_BASE_ADDR; setup_iomux_fec(); /* Use 125M anatop REF_CLK1 for ENET1, not from external */ clrsetbits_le32(&gpr->gpr[1], IOMUXC_GPR_GPR1_GPR_ENET1_TX_CLK_SEL_MASK, 0); return set_clk_enet(ENET_125MHZ); #endif } int board_phy_config(struct phy_device *phydev) { #ifndef CONFIG_TARGET_IMX8MM_DDR3L_VAL /* 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); #endif if (phydev->drv->config) phydev->drv->config(phydev); return 0; } #endif #ifdef CONFIG_USB_TCPC struct tcpc_port port1; struct tcpc_port port2; static int setup_pd_switch(uint8_t i2c_bus, uint8_t addr) { struct udevice *bus; struct udevice *i2c_dev = NULL; int ret; uint8_t valb; ret = uclass_get_device_by_seq(UCLASS_I2C, i2c_bus, &bus); if (ret) { printf("%s: Can't find bus\n", __func__); return -EINVAL; } ret = dm_i2c_probe(bus, addr, 0, &i2c_dev); if (ret) { printf("%s: Can't find device id=0x%x\n", __func__, addr); return -ENODEV; } ret = dm_i2c_read(i2c_dev, 0xB, &valb, 1); if (ret) { printf("%s dm_i2c_read failed, err %d\n", __func__, ret); return -EIO; } valb |= 0x4; /* Set DB_EXIT to exit dead battery mode */ ret = dm_i2c_write(i2c_dev, 0xB, (const uint8_t *)&valb, 1); if (ret) { printf("%s dm_i2c_write failed, err %d\n", __func__, ret); return -EIO; } /* Set OVP threshold to 23V */ valb = 0x6; ret = dm_i2c_write(i2c_dev, 0x8, (const uint8_t *)&valb, 1); if (ret) { printf("%s dm_i2c_write failed, err %d\n", __func__, ret); return -EIO; } return 0; } int pd_switch_snk_enable(struct tcpc_port *port) { if (port == &port1) { debug("Setup pd switch on port 1\n"); return setup_pd_switch(1, 0x72); } else if (port == &port2) { debug("Setup pd switch on port 2\n"); return setup_pd_switch(1, 0x73); } else return -EINVAL; } struct tcpc_port_config port1_config = { .i2c_bus = 1, /*i2c2*/ .addr = 0x50, .port_type = TYPEC_PORT_UFP, .max_snk_mv = 5000, .max_snk_ma = 3000, .max_snk_mw = 40000, .op_snk_mv = 9000, .switch_setup_func = &pd_switch_snk_enable, }; struct tcpc_port_config port2_config = { .i2c_bus = 1, /*i2c2*/ .addr = 0x52, .port_type = TYPEC_PORT_UFP, .max_snk_mv = 9000, .max_snk_ma = 3000, .max_snk_mw = 40000, .op_snk_mv = 9000, .switch_setup_func = &pd_switch_snk_enable, }; static int setup_typec(void) { int ret; debug("tcpc_init port 2\n"); ret = tcpc_init(&port2, port2_config, NULL); if (ret) { printf("%s: tcpc port2 init failed, err=%d\n", __func__, ret); } else if (tcpc_pd_sink_check_charging(&port2)) { /* Disable PD for USB1, since USB2 has priority */ port1_config.disable_pd = true; printf("Power supply on USB2\n"); } debug("tcpc_init port 1\n"); ret = tcpc_init(&port1, port1_config, NULL); if (ret) { printf("%s: tcpc port1 init failed, err=%d\n", __func__, ret); } else { if (!port1_config.disable_pd) printf("Power supply on USB1\n"); return ret; } return ret; } #endif #ifdef CONFIG_USB_EHCI_HCD int board_usb_init(int index, enum usb_init_type init) { int ret = 0; #ifdef CONFIG_USB_TCPC struct tcpc_port *port_ptr; #endif debug("board_usb_init %d, type %d\n", index, init); imx8m_usb_power(index, true); #ifdef CONFIG_USB_TCPC if (index == 0) port_ptr = &port1; else port_ptr = &port2; if (init == USB_INIT_HOST) tcpc_setup_dfp_mode(port_ptr); else tcpc_setup_ufp_mode(port_ptr); #endif return ret; } int board_usb_cleanup(int index, enum usb_init_type init) { int ret = 0; debug("board_usb_cleanup %d, type %d\n", index, init); #ifdef CONFIG_USB_TCPC if (init == USB_INIT_HOST) { if (index == 0) ret = tcpc_disable_src_vbus(&port1); else ret = tcpc_disable_src_vbus(&port2); } #endif imx8m_usb_power(index, false); return ret; } #ifdef CONFIG_USB_TCPC int board_ehci_usb_phy_mode(struct udevice *dev) { int ret = 0; enum typec_cc_polarity pol; enum typec_cc_state state; struct tcpc_port *port_ptr; if (dev_seq(dev) == 0) port_ptr = &port1; else port_ptr = &port2; tcpc_setup_ufp_mode(port_ptr); ret = tcpc_get_cc_status(port_ptr, &pol, &state); if (!ret) { if (state == TYPEC_STATE_SRC_RD_RA || state == TYPEC_STATE_SRC_RD) return USB_INIT_HOST; } return USB_INIT_DEVICE; } #endif #endif int board_init(void) { #ifdef CONFIG_USB_TCPC setup_typec(); #endif #ifdef CONFIG_MXC_SPI setup_spi(); #endif if (IS_ENABLED(CONFIG_FEC_MXC)) setup_fec(); return 0; } int board_late_init(void) { #ifdef CONFIG_ENV_IS_IN_MMC board_late_mmc_env_init(); #endif #ifdef CONFIG_ENV_VARS_UBOOT_RUNTIME_CONFIG env_set("board_name", "VAL"); env_set("board_rev", "iMX8MM"); #endif return 0; }