diff options
Diffstat (limited to 'board/toradex/verdin-imx8mm/verdin-imx8mm.c')
-rw-r--r-- | board/toradex/verdin-imx8mm/verdin-imx8mm.c | 494 |
1 files changed, 494 insertions, 0 deletions
diff --git a/board/toradex/verdin-imx8mm/verdin-imx8mm.c b/board/toradex/verdin-imx8mm/verdin-imx8mm.c new file mode 100644 index 0000000000..e3c5774410 --- /dev/null +++ b/board/toradex/verdin-imx8mm/verdin-imx8mm.c @@ -0,0 +1,494 @@ +// SPDX-License-Identifier: GPL-2.0+ +/* + * Copyright 2019 Toradex + */ + +#include <common.h> +#include <asm/io.h> +#include <asm/arch/clock.h> +#include <asm/arch/imx8mm_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 <asm/mach-imx/video.h> +#include <dm.h> +#include <errno.h> +#include <fsl_esdhc.h> +#include <imx_mipi_dsi_bridge.h> +#include <malloc.h> +#include <miiphy.h> +#include <mipi_dsi_panel.h> +#include <mmc.h> +#include <netdev.h> +#include <power/pmic.h> +#include <power/bd71837.h> +#include <sec_mipi_dsim.h> +#include <spl.h> +#include <usb.h> + +#include "../common/tdx-cfg-block.h" + +DECLARE_GLOBAL_DATA_PTR; + +#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; +} + +#ifdef CONFIG_BOARD_POSTCLK_INIT +int board_postclk_init(void) +{ + /* TODO */ + return 0; +} +#endif + +int dram_init(void) +{ + /* rom_pointer[1] contains the size of TEE occupies */ + if (rom_pointer[1]) + gd->ram_size = PHYS_SDRAM_SIZE - rom_pointer[1]; + else + gd->ram_size = PHYS_SDRAM_SIZE; + + return 0; +} + +#ifdef CONFIG_OF_BOARD_SETUP +int ft_board_setup(void *blob, bd_t *bd) +{ + return ft_common_board_setup(blob, bd); +} +#endif + +#ifdef CONFIG_FEC_MXC +static int setup_fec(void) +{ + struct iomuxc_gpr_base_regs *const iomuxc_gpr_regs + = (struct iomuxc_gpr_base_regs *) IOMUXC_GPR_BASE_ADDR; + + /* Use 125M anatop REF_CLK1 for ENET1, not from external */ + clrsetbits_le32(&iomuxc_gpr_regs->gpr[1], + IOMUXC_GPR_GPR1_GPR_ENET1_TX_CLK_SEL_SHIFT, 0); + return set_clk_enet(ENET_125MHZ); +} + +int board_phy_config(struct phy_device *phydev) +{ + /* TODO: check settings for KSZ9030/31 */ + + /* 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 + +#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 = 5000, + .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 /* CONFIG_USB_TCPC */ + +#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_SPL_BUILD +int board_usb_phy_mode(struct udevice *dev) +#else +int board_ehci_usb_phy_mode(struct udevice *dev) +#endif +{ +#ifdef CONFIG_USB_TCPC + int ret = 0; + enum typec_cc_polarity pol; + enum typec_cc_state state; + struct tcpc_port *port_ptr; + + if (dev->seq == 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; + } +#endif /* CONFIG_USB_TCPC */ + + return USB_INIT_DEVICE; +} +#endif + +int board_init(void) +{ +#ifdef CONFIG_USB_TCPC + setup_typec(); +#endif + +#ifdef CONFIG_FEC_MXC + setup_fec(); +#endif + + return 0; +} + +#ifdef CONFIG_VIDEO_MXS + +/* TODO: video integration */ +#define ADV7535_MAIN 0x3d +#define ADV7535_DSI_CEC 0x3c + +static const struct sec_mipi_dsim_plat_data imx8mm_mipi_dsim_plat_data = { + .version = 0x1060200, + .max_data_lanes = 4, + .max_data_rate = 1500000000ULL, + .reg_base = MIPI_DSI_BASE_ADDR, + .gpr_base = CSI_BASE_ADDR + 0x8000, +}; + +#define DISPLAY_MIX_SFT_RSTN_CSR 0x00 +#define DISPLAY_MIX_CLK_EN_CSR 0x04 + + /* 'DISP_MIX_SFT_RSTN_CSR' bit fields */ +#define BUS_RSTN_BLK_SYNC_SFT_EN BIT(6) + + /* 'DISP_MIX_CLK_EN_CSR' bit fields */ +#define LCDIF_PIXEL_CLK_SFT_EN BIT(7) +#define LCDIF_APB_CLK_SFT_EN BIT(6) + +void disp_mix_bus_rstn_reset(ulong gpr_base, bool reset) +{ + if (!reset) + /* release reset */ + setbits_le32(gpr_base + DISPLAY_MIX_SFT_RSTN_CSR, BUS_RSTN_BLK_SYNC_SFT_EN); + else + /* hold reset */ + clrbits_le32(gpr_base + DISPLAY_MIX_SFT_RSTN_CSR, BUS_RSTN_BLK_SYNC_SFT_EN); +} + +void disp_mix_lcdif_clks_enable(ulong gpr_base, bool enable) +{ + if (enable) + /* enable lcdif clks */ + setbits_le32(gpr_base + DISPLAY_MIX_CLK_EN_CSR, LCDIF_PIXEL_CLK_SFT_EN | LCDIF_APB_CLK_SFT_EN); + else + /* disable lcdif clks */ + clrbits_le32(gpr_base + DISPLAY_MIX_CLK_EN_CSR, LCDIF_PIXEL_CLK_SFT_EN | LCDIF_APB_CLK_SFT_EN); +} + +struct mipi_dsi_client_dev adv7535_dev = { + .channel = 0, + .lanes = 4, + .format = MIPI_DSI_FMT_RGB888, + .mode_flags = MIPI_DSI_MODE_VIDEO | MIPI_DSI_MODE_VIDEO_SYNC_PULSE | + MIPI_DSI_MODE_EOT_PACKET | MIPI_DSI_MODE_VIDEO_HSE, + .name = "ADV7535", +}; + +struct mipi_dsi_client_dev rm67191_dev = { + .channel = 0, + .lanes = 4, + .format = MIPI_DSI_FMT_RGB888, + .mode_flags = MIPI_DSI_MODE_VIDEO | MIPI_DSI_MODE_VIDEO_SYNC_PULSE | + MIPI_DSI_MODE_EOT_PACKET | MIPI_DSI_MODE_VIDEO_HSE, +}; + +#define FSL_SIP_GPC 0xC2000000 +#define FSL_SIP_CONFIG_GPC_PM_DOMAIN 0x3 +#define DISPMIX 9 +#define MIPI 10 + +void do_enable_mipi2hdmi(struct display_info_t const *dev) +{ + gpio_request(IMX_GPIO_NR(1, 8), "DSI EN"); + gpio_direction_output(IMX_GPIO_NR(1, 8), 1); + + /* ADV7353 initialization */ +/* TODO: disable for now + adv7535_init(); */ + + /* enable the dispmix & mipi phy power domain */ + call_imx_sip(FSL_SIP_GPC, FSL_SIP_CONFIG_GPC_PM_DOMAIN, DISPMIX, true, 0); + call_imx_sip(FSL_SIP_GPC, FSL_SIP_CONFIG_GPC_PM_DOMAIN, MIPI, true, 0); + + /* Put lcdif out of reset */ + disp_mix_bus_rstn_reset(imx8mm_mipi_dsim_plat_data.gpr_base, false); + disp_mix_lcdif_clks_enable(imx8mm_mipi_dsim_plat_data.gpr_base, true); + + /* Setup mipi dsim */ + sec_mipi_dsim_setup(&imx8mm_mipi_dsim_plat_data); + imx_mipi_dsi_bridge_attach(&adv7535_dev); /* attach adv7535 device */ +} + +void do_enable_mipi_led(struct display_info_t const *dev) +{ + gpio_request(IMX_GPIO_NR(1, 8), "DSI EN"); + gpio_direction_output(IMX_GPIO_NR(1, 8), 0); + mdelay(100); + gpio_direction_output(IMX_GPIO_NR(1, 8), 1); + + /* enable the dispmix & mipi phy power domain */ + call_imx_sip(FSL_SIP_GPC, FSL_SIP_CONFIG_GPC_PM_DOMAIN, DISPMIX, true, 0); + call_imx_sip(FSL_SIP_GPC, FSL_SIP_CONFIG_GPC_PM_DOMAIN, MIPI, true, 0); + + /* Put lcdif out of reset */ + disp_mix_bus_rstn_reset(imx8mm_mipi_dsim_plat_data.gpr_base, false); + disp_mix_lcdif_clks_enable(imx8mm_mipi_dsim_plat_data.gpr_base, true); + + /* Setup mipi dsim */ + sec_mipi_dsim_setup(&imx8mm_mipi_dsim_plat_data); + + rm67191_init(); + rm67191_dev.name = displays[1].mode.name; + imx_mipi_dsi_bridge_attach(&rm67191_dev); /* attach rm67191 device */ +} + +void board_quiesce_devices(void) +{ + gpio_request(IMX_GPIO_NR(1, 8), "DSI EN"); + gpio_direction_output(IMX_GPIO_NR(1, 8), 0); +} + +struct display_info_t const displays[] = {{ + .bus = LCDIF_BASE_ADDR, + .addr = 0, + .pixfmt = 24, + .detect = NULL, + .enable = do_enable_mipi2hdmi, + .mode = { + .name = "MIPI2HDMI", + .refresh = 60, + .xres = 1920, + .yres = 1080, + .pixclock = 6734, /* 148500000 */ + .left_margin = 148, + .right_margin = 88, + .upper_margin = 36, + .lower_margin = 4, + .hsync_len = 44, + .vsync_len = 5, + .sync = FB_SYNC_EXT, + .vmode = FB_VMODE_NONINTERLACED + +} }, { + .bus = LCDIF_BASE_ADDR, + .addr = 0, + .pixfmt = 24, + .detect = NULL, + .enable = do_enable_mipi_led, + .mode = { + .name = "RM67191_OLED", + .refresh = 60, + .xres = 1080, + .yres = 1920, + .pixclock = 7575, /* 132000000 */ + .left_margin = 34, + .right_margin = 20, + .upper_margin = 4, + .lower_margin = 10, + .hsync_len = 2, + .vsync_len = 2, + .sync = FB_SYNC_EXT, + .vmode = FB_VMODE_NONINTERLACED + +} } }; +size_t display_count = ARRAY_SIZE(displays); +#endif /* CONFIG_VIDEO_MXS */ + +int board_late_init(void) +{ + 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*/ |