// SPDX-License-Identifier: GPL-2.0+ /* * U-Boot board functions for CompuLab CL-SOM-iMX7 module * * (C) Copyright 2017 CompuLab, Ltd. http://www.compulab.com * * Author: Uri Mashiach */ #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include "../common/eeprom.h" #include "common.h" DECLARE_GLOBAL_DATA_PTR; #ifdef CONFIG_SYS_I2C_MXC #define I2C_PAD_CTRL (PAD_CTL_DSE_3P3V_32OHM | PAD_CTL_SRE_SLOW | \ PAD_CTL_HYS) #define CL_SOM_IMX7_GPIO_I2C2_SCL IMX_GPIO_NR(1, 6) #define CL_SOM_IMX7_GPIO_I2C2_SDA IMX_GPIO_NR(1, 7) static struct i2c_pads_info cl_som_imx7_i2c_pad_info2 = { .scl = { .i2c_mode = MX7D_PAD_GPIO1_IO06__I2C2_SCL | MUX_PAD_CTRL(I2C_PAD_CTRL), .gpio_mode = MX7D_PAD_GPIO1_IO06__GPIO1_IO6 | MUX_PAD_CTRL(I2C_PAD_CTRL), .gp = CL_SOM_IMX7_GPIO_I2C2_SCL, }, .sda = { .i2c_mode = MX7D_PAD_GPIO1_IO07__I2C2_SDA | MUX_PAD_CTRL(I2C_PAD_CTRL), .gpio_mode = MX7D_PAD_GPIO1_IO07__GPIO1_IO7 | MUX_PAD_CTRL(I2C_PAD_CTRL), .gp = CL_SOM_IMX7_GPIO_I2C2_SDA, }, }; /* * cl_som_imx7_setup_i2c() - I2C pinmux configuration. */ static void cl_som_imx7_setup_i2c(void) { setup_i2c(0, CONFIG_SYS_I2C_SPEED, 0x7f, &cl_som_imx7_i2c_pad_info2); } #else /* !CONFIG_SYS_I2C_MXC */ static void cl_som_imx7_setup_i2c(void) {} #endif /* CONFIG_SYS_I2C_MXC */ int dram_init(void) { gd->ram_size = imx_ddr_size(); return 0; } #ifdef CONFIG_FSL_ESDHC_IMX #define CL_SOM_IMX7_GPIO_USDHC3_PWR IMX_GPIO_NR(6, 11) static struct fsl_esdhc_cfg cl_som_imx7_usdhc_cfg[3] = { {USDHC1_BASE_ADDR, 0, 4}, {USDHC3_BASE_ADDR}, }; int board_mmc_init(struct bd_info *bis) { int i, ret; /* * According to the board_mmc_init() the following map is done: * (U-Boot device node) (Physical Port) * mmc0 USDHC1 * mmc2 USDHC3 (eMMC) */ for (i = 0; i < CFG_SYS_FSL_USDHC_NUM; i++) { switch (i) { case 0: cl_som_imx7_usdhc1_pads_set(); gpio_request(CL_SOM_IMX7_GPIO_USDHC1_CD, "usdhc1_cd"); cl_som_imx7_usdhc_cfg[0].sdhc_clk = mxc_get_clock(MXC_ESDHC_CLK); break; case 1: cl_som_imx7_usdhc3_emmc_pads_set(); gpio_request(CL_SOM_IMX7_GPIO_USDHC3_PWR, "usdhc3_pwr"); gpio_direction_output(CL_SOM_IMX7_GPIO_USDHC3_PWR, 0); udelay(500); gpio_direction_output(CL_SOM_IMX7_GPIO_USDHC3_PWR, 1); cl_som_imx7_usdhc_cfg[1].sdhc_clk = mxc_get_clock(MXC_ESDHC3_CLK); 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, &cl_som_imx7_usdhc_cfg[i]); if (ret) return ret; } return 0; } #endif /* CONFIG_FSL_ESDHC_IMX */ #ifdef CONFIG_FEC_MXC #define CL_SOM_IMX7_ETH1_PHY_NRST IMX_GPIO_NR(1, 4) /* * cl_som_imx7_rgmii_rework() - Ethernet PHY configuration. */ static void cl_som_imx7_rgmii_rework(struct phy_device *phydev) { unsigned short val; /* Ar8031 phy SmartEEE feature cause link status generates glitch, * which cause ethernet link down/up issue, so disable SmartEEE */ phy_write(phydev, MDIO_DEVAD_NONE, 0xd, 0x3); phy_write(phydev, MDIO_DEVAD_NONE, 0xe, 0x805d); phy_write(phydev, MDIO_DEVAD_NONE, 0xd, 0x4003); val = phy_read(phydev, MDIO_DEVAD_NONE, 0xe); val &= ~(0x1 << 8); phy_write(phydev, MDIO_DEVAD_NONE, 0xe, val); /* To enable AR8031 ouput a 125MHz clk from CLK_25M */ phy_write(phydev, MDIO_DEVAD_NONE, 0xd, 0x7); phy_write(phydev, MDIO_DEVAD_NONE, 0xe, 0x8016); phy_write(phydev, MDIO_DEVAD_NONE, 0xd, 0x4007); val = phy_read(phydev, MDIO_DEVAD_NONE, 0xe); val &= 0xffe3; val |= 0x18; phy_write(phydev, MDIO_DEVAD_NONE, 0xe, val); /* introduce tx clock delay */ phy_write(phydev, MDIO_DEVAD_NONE, 0x1d, 0x5); val = phy_read(phydev, MDIO_DEVAD_NONE, 0x1e); val |= 0x0100; phy_write(phydev, MDIO_DEVAD_NONE, 0x1e, val); } int board_phy_config(struct phy_device *phydev) { cl_som_imx7_rgmii_rework(phydev); if (phydev->drv->config) phydev->drv->config(phydev); return 0; } /* * cl_som_imx7_handle_mac_address() - set Ethernet MAC address environment. * * @env_var: MAC address environment variable * @eeprom_bus: I2C bus of the environment EEPROM * * @return: 0 on success, < 0 on failure */ static int cl_som_imx7_handle_mac_address(char *env_var, uint eeprom_bus) { int ret; unsigned char enetaddr[6]; ret = eth_env_get_enetaddr(env_var, enetaddr); if (ret) return 0; ret = cl_eeprom_read_mac_addr(enetaddr, eeprom_bus); if (ret) return ret; ret = is_valid_ethaddr(enetaddr); if (!ret) return -1; return eth_env_set_enetaddr(env_var, enetaddr); } #define CL_SOM_IMX7_FEC_DEV_ID_PRI 0 int board_eth_init(struct bd_info *bis) { /* set Ethernet MAC address environment */ cl_som_imx7_handle_mac_address("ethaddr", CONFIG_SYS_I2C_EEPROM_BUS); /* Ethernet interface pinmux configuration */ cl_som_imx7_phy1_rst_pads_set(); cl_som_imx7_fec1_pads_set(); /* PHY reset */ gpio_request(CL_SOM_IMX7_ETH1_PHY_NRST, "eth1_phy_nrst"); gpio_direction_output(CL_SOM_IMX7_ETH1_PHY_NRST, 0); mdelay(10); gpio_set_value(CL_SOM_IMX7_ETH1_PHY_NRST, 1); /* MAC initialization */ return fecmxc_initialize_multi(bis, CL_SOM_IMX7_FEC_DEV_ID_PRI, CFG_FEC_MXC_PHYADDR, IMX_FEC_BASE); } /* * cl_som_imx7_setup_fec() - Ethernet MAC 1 clock configuration. * - ENET1 reference clock mode select. * - ENET1_TX_CLK output driver is disabled when configured for ALT1. */ static void cl_som_imx7_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, clear gpr1[13], gpr1[17]*/ clrsetbits_le32(&iomuxc_gpr_regs->gpr[1], (IOMUXC_GPR_GPR1_GPR_ENET1_TX_CLK_SEL_MASK | IOMUXC_GPR_GPR1_GPR_ENET1_CLK_DIR_MASK), 0); set_clk_enet(ENET_125MHZ); } #else /* !CONFIG_FEC_MXC */ static void cl_som_imx7_setup_fec(void) {} #endif /* CONFIG_FEC_MXC */ #ifdef CONFIG_SPI static void cl_som_imx7_spi_init(void) { cl_som_imx7_espi1_pads_set(); } #else /* !CONFIG_SPI */ static void cl_som_imx7_spi_init(void) {} #endif /* CONFIG_SPI */ int board_early_init_f(void) { cl_som_imx7_uart1_pads_set(); cl_som_imx7_usb_otg1_pads_set(); return 0; } int board_init(void) { /* address of boot parameters */ gd->bd->bi_boot_params = PHYS_SDRAM + 0x100; cl_som_imx7_setup_i2c(); cl_som_imx7_setup_fec(); cl_som_imx7_spi_init(); return 0; } #if CONFIG_IS_ENABLED(POWER_LEGACY) #define I2C_PMIC 0 int power_init_board(void) { struct pmic *p; int ret; unsigned int reg, rev_id; ret = power_pfuze3000_init(I2C_PMIC); if (ret) return ret; p = pmic_get("PFUZE3000"); ret = pmic_probe(p); if (ret) return ret; pmic_reg_read(p, PFUZE3000_DEVICEID, ®); pmic_reg_read(p, PFUZE3000_REVID, &rev_id); printf("PMIC: PFUZE3000 DEV_ID=0x%x REV_ID=0x%x\n", reg, rev_id); /* disable Low Power Mode during standby mode */ pmic_reg_write(p, PFUZE3000_LDOGCTL, 0x1); return 0; } #endif /* CONFIG_IS_ENABLED(POWER_LEGACY) */ /* * cl_som_imx7_setup_wdog() - watchdog configuration. * - Output WDOG_B signal to reset external pmic. * - Suspend the watchdog timer during low-power modes. */ void cl_som_imx7_setup_wdog(void) { struct wdog_regs *wdog = (struct wdog_regs *)WDOG1_BASE_ADDR; cl_som_imx7_wdog_pads_set(); set_wdog_reset(wdog); /* * Do not assert internal WDOG_RESET_B_DEB(controlled by bit 4), * since we use PMIC_PWRON to reset the board. */ clrsetbits_le16(&wdog->wcr, 0, 0x10); } int board_late_init(void) { env_set("board_name", "CL-SOM-iMX7"); cl_som_imx7_setup_wdog(); return 0; } int checkboard(void) { char *mode; if (IS_ENABLED(CONFIG_ARMV7_BOOT_SEC_DEFAULT)) mode = "secure"; else mode = "non-secure"; printf("Board: CL-SOM-iMX7 in %s mode\n", mode); return 0; }