summaryrefslogtreecommitdiff
path: root/board/toradex/verdin-imx8mm
diff options
context:
space:
mode:
Diffstat (limited to 'board/toradex/verdin-imx8mm')
-rw-r--r--board/toradex/verdin-imx8mm/Kconfig30
-rw-r--r--board/toradex/verdin-imx8mm/MAINTAINERS8
-rw-r--r--board/toradex/verdin-imx8mm/Makefile12
-rw-r--r--board/toradex/verdin-imx8mm/spl.c231
-rw-r--r--board/toradex/verdin-imx8mm/verdin-imx8mm.c494
5 files changed, 775 insertions, 0 deletions
diff --git a/board/toradex/verdin-imx8mm/Kconfig b/board/toradex/verdin-imx8mm/Kconfig
new file mode 100644
index 0000000000..8a2fe98682
--- /dev/null
+++ b/board/toradex/verdin-imx8mm/Kconfig
@@ -0,0 +1,30 @@
+if TARGET_VERDIN_IMX8MM
+
+config SYS_BOARD
+ default "verdin-imx8mm"
+
+config SYS_VENDOR
+ default "toradex"
+
+config SYS_CONFIG_NAME
+ default "verdin-imx8mm"
+
+config TDX_CFG_BLOCK
+ default y
+
+config TDX_HAVE_MMC
+ default y
+
+config TDX_CFG_BLOCK_DEV
+ default "0"
+
+config TDX_CFG_BLOCK_PART
+ default "1"
+
+# Toradex config block in eMMC, at the end of 1st "boot sector"
+config TDX_CFG_BLOCK_OFFSET
+ default "-512"
+
+source "board/toradex/common/Kconfig"
+
+endif
diff --git a/board/toradex/verdin-imx8mm/MAINTAINERS b/board/toradex/verdin-imx8mm/MAINTAINERS
new file mode 100644
index 0000000000..339266d72e
--- /dev/null
+++ b/board/toradex/verdin-imx8mm/MAINTAINERS
@@ -0,0 +1,8 @@
+Verdin iMX8MM
+M: Igor Opaniuk <igor.opaniuk@toradex.com>
+W: http://developer.toradex.com/software/linux/linux-software
+S: Maintained
+F: arch/arm/dts/fsl-imx8mm-verdin.dts
+F: board/toradex/verdin-imx8mm/
+F: configs/verdin-imx8mm_defconfig
+F: include/configs/verdin-imx8mm.h
diff --git a/board/toradex/verdin-imx8mm/Makefile b/board/toradex/verdin-imx8mm/Makefile
new file mode 100644
index 0000000000..7161b19d0f
--- /dev/null
+++ b/board/toradex/verdin-imx8mm/Makefile
@@ -0,0 +1,12 @@
+# SPDX-License-Identifier: GPL-2.0+
+#
+# Copyright 2018-2019 Toradex
+#
+
+obj-y += verdin-imx8mm.o
+
+ifdef CONFIG_SPL_BUILD
+obj-y += spl.o
+obj-$(CONFIG_IMX8M_LPDDR4) += lpddr4_timing.o
+obj-$(CONFIG_IMX8M_DDR4) += ddr4_timing.o
+endif
diff --git a/board/toradex/verdin-imx8mm/spl.c b/board/toradex/verdin-imx8mm/spl.c
new file mode 100644
index 0000000000..5f1bfbbc17
--- /dev/null
+++ b/board/toradex/verdin-imx8mm/spl.c
@@ -0,0 +1,231 @@
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * Copyright 2019 Toradex
+ */
+
+#include <common.h>
+#include <spl.h>
+#include <asm/io.h>
+#include <asm/arch/clock.h>
+#include <asm/arch/imx8m_ddr.h>
+#include <asm/arch/imx8mm_pins.h>
+#include <asm/arch/sys_proto.h>
+#include <asm/mach-imx/gpio.h>
+#include <asm/mach-imx/iomux-v3.h>
+#include <asm/mach-imx/mxc_i2c.h>
+#include <errno.h>
+#include <fsl_esdhc.h>
+#include <mmc.h>
+#include <power/pmic.h>
+#include <power/bd71837.h>
+
+DECLARE_GLOBAL_DATA_PTR;
+
+void spl_dram_init(void)
+{
+ ddr_init(&dram_timing);
+}
+
+#define I2C_PAD_CTRL (PAD_CTL_DSE6 | PAD_CTL_HYS | PAD_CTL_PUE | PAD_CTL_PE)
+#define PC MUX_PAD_CTRL(I2C_PAD_CTRL)
+struct i2c_pads_info i2c_pad_info1 = {
+ .scl = {
+ .i2c_mode = IMX8MM_PAD_I2C1_SCL_I2C1_SCL | PC,
+ .gpio_mode = IMX8MM_PAD_I2C1_SCL_GPIO5_IO14 | PC,
+ .gp = IMX_GPIO_NR(5, 14),
+ },
+ .sda = {
+ .i2c_mode = IMX8MM_PAD_I2C1_SDA_I2C1_SDA | PC,
+ .gpio_mode = IMX8MM_PAD_I2C1_SDA_GPIO5_IO15 | PC,
+ .gp = IMX_GPIO_NR(5, 15),
+ },
+};
+
+#define USDHC2_CD_GPIO IMX_GPIO_NR(2, 12)
+#define USDHC2_PWR_GPIO IMX_GPIO_NR(3, 5)
+
+#define USDHC_PAD_CTRL (PAD_CTL_DSE6 | PAD_CTL_HYS | PAD_CTL_PUE | PAD_CTL_PE | \
+ PAD_CTL_FSEL2)
+#define USDHC_GPIO_PAD_CTRL (PAD_CTL_HYS | PAD_CTL_DSE1)
+
+static iomux_v3_cfg_t const usdhc1_pads[] = {
+ IMX8MM_PAD_SD1_CLK_USDHC1_CLK | MUX_PAD_CTRL(USDHC_PAD_CTRL),
+ IMX8MM_PAD_SD1_CMD_USDHC1_CMD | MUX_PAD_CTRL(USDHC_PAD_CTRL),
+ IMX8MM_PAD_SD1_DATA0_USDHC1_DATA0 | MUX_PAD_CTRL(USDHC_PAD_CTRL),
+ IMX8MM_PAD_SD1_DATA1_USDHC1_DATA1 | MUX_PAD_CTRL(USDHC_PAD_CTRL),
+ IMX8MM_PAD_SD1_DATA2_USDHC1_DATA2 | MUX_PAD_CTRL(USDHC_PAD_CTRL),
+ IMX8MM_PAD_SD1_DATA3_USDHC1_DATA3 | MUX_PAD_CTRL(USDHC_PAD_CTRL),
+ IMX8MM_PAD_SD1_DATA4_USDHC1_DATA4 | MUX_PAD_CTRL(USDHC_PAD_CTRL),
+ IMX8MM_PAD_SD1_DATA5_USDHC1_DATA5 | MUX_PAD_CTRL(USDHC_PAD_CTRL),
+ IMX8MM_PAD_SD1_DATA6_USDHC1_DATA6 | MUX_PAD_CTRL(USDHC_PAD_CTRL),
+ IMX8MM_PAD_SD1_DATA7_USDHC1_DATA7 | MUX_PAD_CTRL(USDHC_PAD_CTRL),
+ IMX8MM_PAD_SD1_STROBE_USDHC1_STROBE | MUX_PAD_CTRL(USDHC_PAD_CTRL),
+};
+
+static iomux_v3_cfg_t const usdhc2_pads[] = {
+ IMX8MM_PAD_SD2_CLK_USDHC2_CLK | MUX_PAD_CTRL(USDHC_PAD_CTRL),
+ IMX8MM_PAD_SD2_CMD_USDHC2_CMD | MUX_PAD_CTRL(USDHC_PAD_CTRL),
+ IMX8MM_PAD_SD2_DATA0_USDHC2_DATA0 | MUX_PAD_CTRL(USDHC_PAD_CTRL),
+ IMX8MM_PAD_SD2_DATA1_USDHC2_DATA1 | MUX_PAD_CTRL(USDHC_PAD_CTRL),
+ IMX8MM_PAD_SD2_DATA2_USDHC2_DATA2 | MUX_PAD_CTRL(USDHC_PAD_CTRL),
+ IMX8MM_PAD_SD2_DATA3_USDHC2_DATA3 | MUX_PAD_CTRL(USDHC_PAD_CTRL),
+ IMX8MM_PAD_SD2_RESET_B_GPIO2_IO19 | MUX_PAD_CTRL(USDHC_GPIO_PAD_CTRL),
+ IMX8MM_PAD_SD2_CD_B_GPIO2_IO12 | MUX_PAD_CTRL(USDHC_GPIO_PAD_CTRL),
+ IMX8MM_PAD_NAND_CLE_GPIO3_IO5 | MUX_PAD_CTRL(USDHC_GPIO_PAD_CTRL),
+};
+
+static struct fsl_esdhc_cfg usdhc_cfg[2] = {
+ /* esdhc_base, sdhc_clk, max_bus_width */
+ {USDHC1_BASE_ADDR, 0, 8},
+ {USDHC2_BASE_ADDR, 0, 4},
+};
+
+int board_mmc_init(bd_t *bis)
+{
+ int i, ret;
+ /*
+ * According to the board_mmc_init() the following map is done:
+ * (U-Boot device node) (Physical Port)
+ * mmc0 USDHC1 (eMMC)
+ * mmc1 USDHC2 (SD card)
+ */
+ for (i = 0; i < CONFIG_SYS_FSL_USDHC_NUM; i++) {
+ switch (i) {
+ case 0:
+ usdhc_cfg[i].sdhc_clk = mxc_get_clock(MXC_ESDHC_CLK);
+ imx_iomux_v3_setup_multiple_pads(
+ usdhc1_pads, ARRAY_SIZE(usdhc1_pads));
+ break;
+ case 1:
+ usdhc_cfg[i].sdhc_clk = mxc_get_clock(MXC_ESDHC2_CLK);
+ imx_iomux_v3_setup_multiple_pads(
+ usdhc2_pads, ARRAY_SIZE(usdhc2_pads));
+ gpio_request(USDHC2_PWR_GPIO, "SD_1_PWR_EN");
+ gpio_direction_output(USDHC2_PWR_GPIO, 1);
+ break;
+ default:
+ printf("Warning: you configured more USDHC controllers"
+ "(%d) than supported by the board\n", i + 1);
+ return -EINVAL;
+ }
+
+ ret = fsl_esdhc_initialize(bis, &usdhc_cfg[i]);
+ if (ret)
+ return ret;
+ }
+
+ return 0;
+}
+
+int board_mmc_getcd(struct mmc *mmc)
+{
+ struct fsl_esdhc_cfg *cfg = (struct fsl_esdhc_cfg *)mmc->priv;
+ int ret = 0;
+
+ switch (cfg->esdhc_base) {
+ case USDHC1_BASE_ADDR:
+ ret = 1; /* eMMC */
+ break;
+ case USDHC2_BASE_ADDR:
+ gpio_request(USDHC2_CD_GPIO, "SD_1_CD#");
+ gpio_direction_input(USDHC2_CD_GPIO);
+ ret = !gpio_get_value(USDHC2_CD_GPIO);
+ return ret;
+ }
+
+ return 1;
+}
+
+#ifdef CONFIG_POWER
+#define I2C_PMIC 0
+int power_init_board(void)
+{
+ struct pmic *p;
+ int ret;
+
+ ret = power_bd71837_init(I2C_PMIC);
+ if (ret)
+ printf("power init failed");
+
+ p = pmic_get("BD71837");
+ pmic_probe(p);
+
+ /* decrease RESET key long push time from the default 10s to 10ms */
+ pmic_reg_write(p, BD71837_PWRONCONFIG1, 0x0);
+
+ /* unlock the PMIC regs */
+ pmic_reg_write(p, BD71837_REGLOCK, 0x1);
+
+ /* increase VDD_DRAM to 0.9v for 3Ghz DDR */
+ pmic_reg_write(p, BD71837_BUCK5_VOLT, 0x2);
+
+#ifndef CONFIG_IMX8M_LPDDR4
+ /* increase NVCC_DRAM_1V2 to 1.2v for DDR4 */
+ pmic_reg_write(p, BD71837_BUCK8_VOLT, 0x28);
+#endif
+
+ /* lock the PMIC regs */
+ pmic_reg_write(p, BD71837_REGLOCK, 0x11);
+
+ return 0;
+}
+#endif
+
+void spl_board_init(void)
+{
+#ifndef CONFIG_SPL_USB_SDP_SUPPORT
+ /* Serial download mode */
+ if (is_usb_boot()) {
+ puts("Back to ROM, SDP\n");
+ restore_boot_params();
+ }
+#endif
+ puts("Normal Boot\n");
+}
+
+#ifdef CONFIG_SPL_LOAD_FIT
+int board_fit_config_name_match(const char *name)
+{
+ /* Just empty function now - can't decide what to choose */
+ debug("%s: %s\n", __func__, name);
+
+ return 0;
+}
+#endif
+
+void board_init_f(ulong dummy)
+{
+ int ret;
+
+ /* Clear global data */
+ memset((void *)gd, 0, sizeof(gd_t));
+
+ arch_cpu_init();
+
+ board_early_init_f();
+
+ timer_init();
+
+ preloader_console_init();
+
+ /* Clear the BSS. */
+ memset(__bss_start, 0, __bss_end - __bss_start);
+
+ ret = spl_init();
+ if (ret) {
+ debug("spl_init() failed: %d\n", ret);
+ hang();
+ }
+
+ enable_tzc380();
+
+ /* Adjust pmic voltage to 1.0V for 800M */
+ setup_i2c(0, CONFIG_SYS_I2C_SPEED, 0x7f, &i2c_pad_info1);
+
+ power_init_board();
+
+ /* DDR initialization */
+ spl_dram_init();
+
+ board_init_r(NULL, 0);
+}
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*/