// SPDX-License-Identifier: GPL-2.0+ /* * Copyright 2017-2019 NXP * * Copyright 2019 Siemens AG * */ #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #ifndef CONFIG_SPL #include #endif #include "../common/factoryset.h" #define GPIO_PAD_CTRL \ ((SC_PAD_CONFIG_NORMAL << PADRING_CONFIG_SHIFT) | \ (SC_PAD_ISO_OFF << PADRING_LPCONFIG_SHIFT) | \ (SC_PAD_28FDSOI_DSE_DV_HIGH << PADRING_DSE_SHIFT) | \ (SC_PAD_28FDSOI_PS_PU << PADRING_PULL_SHIFT)) #define ENET_NORMAL_PAD_CTRL \ ((SC_PAD_CONFIG_NORMAL << PADRING_CONFIG_SHIFT) | \ (SC_PAD_ISO_OFF << PADRING_LPCONFIG_SHIFT) | \ (SC_PAD_28FDSOI_DSE_18V_10MA << PADRING_DSE_SHIFT) | \ (SC_PAD_28FDSOI_PS_PU << PADRING_PULL_SHIFT)) #define UART_PAD_CTRL \ ((SC_PAD_CONFIG_OUT_IN << PADRING_CONFIG_SHIFT) | \ (SC_PAD_ISO_OFF << PADRING_LPCONFIG_SHIFT) | \ (SC_PAD_28FDSOI_DSE_DV_HIGH << PADRING_DSE_SHIFT) | \ (SC_PAD_28FDSOI_PS_PU << PADRING_PULL_SHIFT)) static iomux_cfg_t uart2_pads[] = { SC_P_UART2_RX | MUX_PAD_CTRL(UART_PAD_CTRL), SC_P_UART2_TX | MUX_PAD_CTRL(UART_PAD_CTRL), }; static void setup_iomux_uart(void) { imx8_iomux_setup_multiple_pads(uart2_pads, ARRAY_SIZE(uart2_pads)); } int board_early_init_f(void) { /* Set UART clock root to 80 MHz */ sc_pm_clock_rate_t rate = SC_80MHZ; int ret; ret = sc_pm_setup_uart(SC_R_UART_0, rate); ret |= sc_pm_setup_uart(SC_R_UART_2, rate); if (ret) return ret; setup_iomux_uart(); return 0; } #define ENET_PHY_RESET IMX_GPIO_NR(0, 3) #define ENET_TEST_1 IMX_GPIO_NR(0, 8) #define ENET_TEST_2 IMX_GPIO_NR(0, 9) /*#define ETH_IO_TEST*/ static iomux_cfg_t enet_reset[] = { SC_P_ESAI0_SCKT | MUX_MODE_ALT(4) | MUX_PAD_CTRL(GPIO_PAD_CTRL), #ifdef ETH_IO_TEST /* GPIO0.IO08 MODE3: TXD0 */ SC_P_ESAI0_TX4_RX1 | MUX_MODE_ALT(4) | MUX_PAD_CTRL(ENET_NORMAL_PAD_CTRL), /* GPIO0.IO09 MODE3: TXD1 */ SC_P_ESAI0_TX5_RX0 | MUX_MODE_ALT(4) | MUX_PAD_CTRL(ENET_NORMAL_PAD_CTRL), #endif }; static void enet_device_phy_reset(void) { int ret = 0; imx8_iomux_setup_multiple_pads(enet_reset, ARRAY_SIZE(enet_reset)); ret = gpio_request(ENET_PHY_RESET, "enet_phy_reset"); if (!ret) { gpio_direction_output(ENET_PHY_RESET, 1); gpio_set_value(ENET_PHY_RESET, 0); /* SMSC9303 TRM chapter 14.5.2 */ udelay(200); gpio_set_value(ENET_PHY_RESET, 1); } else { printf("ENET RESET failed!\n"); } #ifdef ETH_IO_TEST ret = gpio_request(ENET_TEST_1, "enet_test1"); if (!ret) { int i; printf("ENET TEST 1!\n"); for (i = 0; i < 20; i++) { gpio_direction_output(ENET_TEST_1, 1); gpio_set_value(ENET_TEST_1, 0); udelay(50); gpio_set_value(ENET_TEST_1, 1); udelay(50); } gpio_free(ENET_TEST_1); } else { printf("GPIO for ENET TEST 1 failed!\n"); } ret = gpio_request(ENET_TEST_2, "enet_test2"); if (!ret) { int i; printf("ENET TEST 2!\n"); for (i = 0; i < 20; i++) { gpio_direction_output(ENET_TEST_2, 1); gpio_set_value(ENET_TEST_2, 0); udelay(50); gpio_set_value(ENET_TEST_2, 1); udelay(50); } gpio_free(ENET_TEST_2); } else { printf("GPIO for ENET TEST 2 failed!\n"); } #endif } int setup_gpr_fec(void) { sc_ipc_t ipc_handle = -1; sc_err_t err = 0; unsigned int test; /* * TX_CLK_SEL: it controls a mux between clock coming from the pad 50M * input pin and clock generated internally to connectivity subsystem * 0: internal clock * 1: external clock ---> your choice for RMII * * CLKDIV_SEL: it controls a div by 2 on the internal clock path à * it should be don’t care when using external clock * 0: non-divided clock * 1: clock divided by 2 * 50_DISABLE or 125_DISABLE: * it’s used to disable the clock tree going outside the chip * when reference clock is generated internally. * It should be don’t care when reference clock is provided * externally. * 0: clock is enabled * 1: clock is disabled * * SC_C_TXCLK = 24, * SC_C_CLKDIV = 25, * SC_C_DISABLE_50 = 26, * SC_C_DISABLE_125 = 27, */ err = sc_misc_set_control(ipc_handle, SC_R_ENET_1, SC_C_TXCLK, 1); if (err != SC_ERR_NONE) printf("Error in setting up SC_C %d\n\r", SC_C_TXCLK); sc_misc_get_control(ipc_handle, SC_R_ENET_1, SC_C_TXCLK, &test); debug("TEST SC_C %d-->%d\n\r", SC_C_TXCLK, test); err = sc_misc_set_control(ipc_handle, SC_R_ENET_1, SC_C_CLKDIV, 0); if (err != SC_ERR_NONE) printf("Error in setting up SC_C %d\n\r", SC_C_CLKDIV); sc_misc_get_control(ipc_handle, SC_R_ENET_1, SC_C_CLKDIV, &test); debug("TEST SC_C %d-->%d\n\r", SC_C_CLKDIV, test); err = sc_misc_set_control(ipc_handle, SC_R_ENET_1, SC_C_DISABLE_50, 0); if (err != SC_ERR_NONE) printf("Error in setting up SC_C %d\n\r", SC_C_DISABLE_50); sc_misc_get_control(ipc_handle, SC_R_ENET_1, SC_C_TXCLK, &test); debug("TEST SC_C %d-->%d\n\r", SC_C_DISABLE_50, test); err = sc_misc_set_control(ipc_handle, SC_R_ENET_1, SC_C_DISABLE_125, 1); if (err != SC_ERR_NONE) printf("Error in setting up SC_C %d\n\r", SC_C_DISABLE_125); sc_misc_get_control(ipc_handle, SC_R_ENET_1, SC_C_TXCLK, &test); debug("TEST SC_C %d-->%d\n\r", SC_C_DISABLE_125, test); err = sc_misc_set_control(ipc_handle, SC_R_ENET_1, SC_C_SEL_125, 1); if (err != SC_ERR_NONE) printf("Error in setting up SC_C %d\n\r", SC_C_SEL_125); sc_misc_get_control(ipc_handle, SC_R_ENET_1, SC_C_SEL_125, &test); debug("TEST SC_C %d-->%d\n\r", SC_C_SEL_125, test); return 0; } #if IS_ENABLED(CONFIG_FEC_MXC) #include int board_phy_config(struct phy_device *phydev) { if (phydev->drv->config) phydev->drv->config(phydev); return 0; } #endif static int setup_fec(void) { setup_gpr_fec(); /* Reset ENET PHY */ enet_device_phy_reset(); return 0; } void reset_cpu(ulong addr) { } #ifndef CONFIG_SPL_BUILD /* LED's */ static int board_led_init(void) { struct udevice *bus, *dev; u8 pca_led[2] = { 0x00, 0x00 }; int ret; /* init all GPIO LED's */ if (IS_ENABLED(CONFIG_LED)) led_default_state(); /* enable all leds on PCA9552 */ ret = uclass_get_device_by_seq(UCLASS_I2C, PCA9552_1_I2C_BUS, &bus); if (ret) { printf("ERROR: I2C get %d\n", ret); return ret; } ret = dm_i2c_probe(bus, PCA9552_1_I2C_ADDR, 0, &dev); if (ret) { printf("ERROR: PCA9552 probe failed\n"); return ret; } ret = dm_i2c_write(dev, 0x16, pca_led, sizeof(pca_led)); if (ret) { printf("ERROR: PCA9552 write failed\n"); return ret; } mdelay(1); return ret; } #endif /* !CONFIG_SPL_BUILD */ int checkboard(void) { puts("Board: Capricorn\n"); /* * Running build_info() doesn't work with current SCFW blob. * Uncomment below call when new blob is available. */ /*build_info();*/ print_bootinfo(); return 0; } int board_init(void) { setup_fec(); return 0; } #ifdef CONFIG_OF_BOARD_SETUP int ft_board_setup(void *blob, bd_t *bd) { return 0; } #endif int board_mmc_get_env_dev(int devno) { return devno; } static int check_mmc_autodetect(void) { char *autodetect_str = env_get("mmcautodetect"); if (autodetect_str && (strcmp(autodetect_str, "yes") == 0)) return 1; return 0; } /* This should be defined for each board */ __weak int mmc_map_to_kernel_blk(int dev_no) { return dev_no; } void board_late_mmc_env_init(void) { char cmd[32]; char mmcblk[32]; u32 dev_no = mmc_get_env_dev(); if (!check_mmc_autodetect()) return; env_set_ulong("mmcdev", dev_no); /* Set mmcblk env */ sprintf(mmcblk, "/dev/mmcblk%dp2 rootwait rw", mmc_map_to_kernel_blk(dev_no)); env_set("mmcroot", mmcblk); sprintf(cmd, "mmc dev %d", dev_no); run_command(cmd, 0); } #ifndef CONFIG_SPL_BUILD int factoryset_read_eeprom(int i2c_addr); static int load_parameters_from_factoryset(void) { int ret; ret = factoryset_read_eeprom(EEPROM_I2C_ADDR); if (ret) return ret; return factoryset_env_set(); } int board_late_init(void) { env_set("sec_boot", "no"); #ifdef CONFIG_AHAB_BOOT env_set("sec_boot", "yes"); #endif #ifdef CONFIG_ENV_IS_IN_MMC board_late_mmc_env_init(); #endif /* Init LEDs */ if (board_led_init()) printf("I2C LED init failed\n"); /* Set environment from factoryset */ if (load_parameters_from_factoryset()) printf("Loading factoryset parameters failed!\n"); return 0; } /* Service button */ #define MAX_PIN_NUMBER 128 #define BOARD_DEFAULT_BUTTON_GPIO IMX_GPIO_NR(1, 31) unsigned char get_button_state(char * const envname, unsigned char def) { int button = 0; int gpio; char *ptr_env; /* If button is not found we take default */ ptr_env = env_get(envname); if (!ptr_env) { printf("Using default: %u\n", def); gpio = def; } else { gpio = (unsigned char)simple_strtoul(ptr_env, NULL, 0); if (gpio > MAX_PIN_NUMBER) gpio = def; } gpio_request(gpio, ""); gpio_direction_input(gpio); if (gpio_get_value(gpio)) button = 1; else button = 0; gpio_free(gpio); return button; } /* * This command returns the status of the user button on * Input - none * Returns - 1 if button is held down * 0 if button is not held down */ static int do_userbutton(struct cmd_tbl *cmdtp, int flag, int argc, char *const argv[]) { int button = 0; button = get_button_state("button_usr1", BOARD_DEFAULT_BUTTON_GPIO); if (argc > 1) printf("Button state: %u\n", button); return button; } U_BOOT_CMD( usrbutton, CONFIG_SYS_MAXARGS, 2, do_userbutton, "Return the status of user button", "[print]" ); #define ERST IMX_GPIO_NR(0, 3) static int do_eth_reset(struct cmd_tbl *cmdtp, int flag, int argc, char *const argv[]) { gpio_request(ERST, "ERST"); gpio_direction_output(ERST, 0); udelay(200); gpio_set_value(ERST, 1); return 0; } U_BOOT_CMD( switch_rst, CONFIG_SYS_MAXARGS, 2, do_eth_reset, "Reset eth phy", "[print]" ); #endif /* ! CONFIG_SPL_BUILD */