/* * board.c * * Board functions for Netmodule nmhw21 board, based on AM335x EVB * * Copyright (C) 2018-2019 NetModule AG - http://www.netmodule.com/ * Copyright (C) 2011, Texas Instruments, Incorporated - http://www.ti.com/ * * SPDX-License-Identifier: GPL-2.0+ */ #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include "../common/bdparser.h" #include "../common/board_descriptor.h" #include "../common/da9063.h" #include "board.h" #include "reset_reason.h" #include "sja1105.h" #include "ui.h" #include "um.h" DECLARE_GLOBAL_DATA_PTR; /* * CPU GPIOs * * (C15) GPIO0_6: MB_LED_PWM * (J18) GPIO0_16: ETH_SW_RST~ (V2.0) * (K15) GPIO0_17: CTRL.INT~ * (T10) GPIO0_23: CAN_TERM1~ (V1.0) * (T17) GPIO0_30: LED0.GN (= 0x0302; return res; } static void init_leds(void) { REQUEST_AND_SET_GPIO(GPIO_LED0_RED); if (is_v32_or_newer()) { REQUEST_AND_SET_GPIO(GPIO_LED_PWM_V32); REQUEST_AND_SET_GPIO(GPIO_LED0_GREEN_V32); } else { REQUEST_AND_SET_GPIO(GPIO_LED0_GREEN); } REQUEST_AND_SET_GPIO(GPIO_LED1_RED); REQUEST_AND_SET_GPIO(GPIO_LED1_GREEN); } static void set_status_led(int red, int green) { gpio_set_value(GPIO_LED0_RED, red); if (is_v32_or_newer()) { gpio_set_value(GPIO_LED0_GREEN_V32, green); } else { gpio_set_value(GPIO_LED0_GREEN, green); } } static void set_indicator_led(int red, int green) { gpio_set_value(GPIO_LED1_RED, red); gpio_set_value(GPIO_LED1_GREEN, green); } #ifndef CONFIG_NRSW_BUILD static void ui_set_status_led(int red, int green) { ui_set_top_led(red, green); } static void ui_set_indicator_led(int red, int green) { ui_set_bottom_led(red, green); } #endif static void init_i2c(void) { i2c_set_bus_num(0); i2c_init(CONFIG_SYS_I2C_SPEED, CONFIG_SYS_I2C_SLAVE); i2c_set_bus_num(1); i2c_init(CONFIG_SYS_I2C_SPEED, CONFIG_SYS_I2C_SLAVE); i2c_set_bus_num(0); } static int _bd_init(void) { int old_bus; old_bus = i2c_get_bus_num(); i2c_set_bus_num(I2C_BD_EEPROM_BUS); if (bd_get_context(&bdctx[0], BD_EEPROM_ADDR, BD_ADDRESS) != 0) { printf("%s() no valid bd found\n", __func__); return -1; } if (bd_get_context(&bdctx[1], BD_EEPROM_ADDR, PD_ADDRESS) != 0) { printf("%s() no valid pd found\n", __func__); return -1; } #ifdef CONFIG_NRSW_BUILD /* TODO: Check if we can get rid of this descriptor and use eMMC partition table */ if (bd_get_context(&bdctx[2], BD_EEPROM_ADDR, PARTITION_ADDRESS) != 0) { printf("%s() no valid partition table found\n", __func__); return -1; } #endif bd_register_context_list(bdctx, ARRAY_SIZE(bdctx)); i2c_set_bus_num(old_bus); return 0; } static bool is_jtag_boot(uint32_t address) { char* jtag_token = (char*)address; if (strcmp(jtag_token, "JTAGBOOT") == 0) { strcpy(jtag_token, "jtagboot"); return true; } else { return false; } } /* * Read header information from EEPROM into global structure. */ static inline int __maybe_unused read_eeprom(void) { return _bd_init(); } /* * Selects console for SPL. * U-Boot console is defined by CONFIG_CONS_INDEX (via menuconfig) */ struct serial_device *default_serial_console(void) { enable_uart2_pin_mux(); /* Provide UART on UART2 regardless of boot mode */ return &eserial3_device; } #ifndef CONFIG_SKIP_LOWLEVEL_INIT static const struct ddr_data ddr3_data = { /* Ratios were optimized by DDR3 training software from TI */ /* TODO: Evaluate new values and update */ .datardsratio0 = 0x39, /* 0x39 */ .datawdsratio0 = 0x3f, /* 0x40 */ .datafwsratio0 = 0x98, /* 0x96 */ .datawrsratio0 = 0x7d, /* 0x7d */ }; static const struct cmd_control ddr3_cmd_ctrl_data = { .cmd0csratio = MT41K256M16HA125E_RATIO, .cmd0iclkout = MT41K256M16HA125E_INVERT_CLKOUT, .cmd1csratio = MT41K256M16HA125E_RATIO, .cmd1iclkout = MT41K256M16HA125E_INVERT_CLKOUT, .cmd2csratio = MT41K256M16HA125E_RATIO, .cmd2iclkout = MT41K256M16HA125E_INVERT_CLKOUT, }; static struct emif_regs ddr3_emif_reg_data = { .sdram_config = MT41K256M16HA125E_EMIF_SDCFG, .ref_ctrl = 0x61A, /* 32ms > 85°C */ .sdram_tim1 = 0x0AAAE51B, .sdram_tim2 = 0x246B7FDA, .sdram_tim3 = 0x50FFE67F, .zq_config = MT41K256M16HA125E_ZQ_CFG, .emif_ddr_phy_ctlr_1 = MT41K256M16HA125E_EMIF_READ_LATENCY, }; #define OSC (V_OSCK/1000000) struct dpll_params dpll_ddr = { DDR3_CLOCK_FREQUENCY, OSC-1, 1, -1, -1, -1, -1 }; static void pmic_fix_config(void) { int rc; uint8_t val; /* Workaround for pre v1.3 config (reports ID 0x3e -> 3.14) */ rc = da9063_get_reg(PMIC_REG_CONFIG_ID, &val); if (!rc && ((val == 0x3E) || (val == 0x12))) { printf("Detected pre v1.3 PMIC config. Fixing registers\n"); /* Include +3V3_SENSORS (LDO3) in sequencing and enable manually */ (void)da9063_set_reg(PMIC_REG_ID_4_3, 0x07 /* Slot 7 */); (void)da9063_set_reg(PMIC_REG_LDO3_CONT, PMIC_LDOx_EN_MASK); /* * Set AUTO Bit for sequencer controlled supplies, so that they get * enabled when leaving power down state */ (void)da9063_set_reg(PMIC_REG_CONFIG_E, 0x3B); (void)da9063_set_reg(PMIC_REG_CONFIG_G, 0x44); /* * Clear sequencer target state bit (xxx_CONT::xxx_CONF bit), so that * regulators are disabled when entering power down state. * Keep EN bit enabled in order not to disable supply. */ (void)da9063_set_reg(PMIC_REG_LDO3_CONT, PMIC_LDOx_EN_MASK); (void)da9063_set_reg(PMIC_REG_LDO7_CONT, PMIC_LDOx_EN_MASK); (void)da9063_set_reg(PMIC_REG_BCORE1_CONT, PMIC_LDOx_EN_MASK); (void)da9063_set_reg(PMIC_REG_BCORE2_CONT, PMIC_LDOx_EN_MASK); (void)da9063_set_reg(PMIC_REG_BPERI_CONT, PMIC_LDOx_EN_MASK); (void)da9063_set_reg(PMIC_REG_BIO_CONT, PMIC_LDOx_EN_MASK); (void)da9063_set_reg(PMIC_REG_BMEM_CONT, PMIC_LDOx_EN_MASK); } } static void pmic_disable_auto_mode(void) { /* * In some rare cases the automatic mode switching between synchronous and sleep * mode can lead to PMIC issues. In this case the rail output is disabled. * The following code fixes the operation mode to synchronous operation. */ uint8_t val = 0; /* Check whether config has automatic mode defined */ (void)da9063_get_reg(PMIC_REG_BCORE1_CONF, &val); if ((val & PMIC_CONF_MODE_MASK) == PMIC_CONF_MODE_AUTO) { (void)da9063_set_reg(PMIC_REG_BCORE1_CONF, PMIC_CONF_MODE_SYNC | 0x01); (void)da9063_set_reg(PMIC_REG_BCORE2_CONF, PMIC_CONF_MODE_SYNC | 0x01); (void)da9063_set_reg(PMIC_REG_BPERI_CONF, PMIC_CONF_MODE_SYNC | 0x01); (void)da9063_set_reg(PMIC_REG_BIO_CONF, PMIC_CONF_MODE_SYNC | 0x01); (void)da9063_set_reg(PMIC_REG_BMEM_CONF, PMIC_CONF_MODE_SYNC | 0x01); } } static void init_pmic_spl(void) { int bus; /* PMIC basic configuration */ da9063_init(CONFIG_PMIC_I2C_BUS); bus = da9063_claim_i2c_bus(); /* Fix old configs (mainly prototype boards) */ if (hw_type == 21) { pmic_fix_config(); /* Disable automatic mode switching */ pmic_disable_auto_mode(); } /* Enable +3V3_GNSS (LDO6) */ (void)da9063_set_reg(PMIC_REG_LDO6_CONT, PMIC_LDOx_EN_MASK); mdelay(2); /* Enable +5V_CAN (LDO11 Switch) */ (void)da9063_set_reg(PMIC_REG_LDO11_CONT, PMIC_LDOx_EN_MASK); mdelay(2); if (hw_type == 21) { /* hw21: trim RTC to compensate +18ppm crystal deviation */ (void)da9063_set_reg(PMIC_REG_TRIM_CLDR, (-18*10)/19); } else { /* hw26 does not need trimming */ (void)da9063_set_reg(PMIC_REG_TRIM_CLDR, 0); } /* Mask unwanted IRQs to avoid accidental wakeup */ const uint8_t mask_a = PMIC_REG_EVENT_ONKEY_MASK | PMIC_REG_EVENT_RTC_ALARM_MASK | PMIC_REG_EVENT_RTC_TICK_MASK; (void)da9063_set_reg(PMIC_REG_IRQ_MASK_A, ~(mask_a) & 0x1F); (void)da9063_set_reg(PMIC_REG_IRQ_MASK_B, ~PMIC_REG_EVENT_COMP1V2_MASK); (void)da9063_set_reg(PMIC_REG_IRQ_MASK_C, ~0x00); (void)da9063_set_reg(PMIC_REG_IRQ_MASK_D, ~0x00); da9063_release_i2c_bus(bus); } static void check_reset_reason(unsigned int reset_reason_shm_location) { volatile struct reset_registers* reset_regs = (struct reset_registers*)reset_reason_shm_location; uint32_t start_reason = 0; uint32_t reset_reason = 0; uint32_t cpu_reset_reason = 0; uint8_t state = 0x00; int bus; int ret; char strbuf[256]; bus = da9063_claim_i2c_bus(); /* * Check/write boot marker to PMIC register GP_ID_1 * If this marker is not present, we have a power on reset */ ret = da9063_get_reg(PMIC_GP_ID_1, &state); if ((ret == 0) && (state != 0xC5)) { (void)da9063_set_reg(PMIC_GP_ID_1, 0xC5); start_reason |= SR_POR; } /* * Check Fault Log register for * - Power On Reset: No Power, RTC Delivery -> requires removal of RTC battery * - Watchdog */ ret = da9063_get_reg(PMIC_REG_FAULT_LOG, &state); if ((ret == 0) && (state != 0)) { /* clear pmic fault log by writing back all bits currently set */ (void)da9063_set_reg(PMIC_REG_FAULT_LOG, state); /* PMIC Power On Reset (only when RTC battery is removed) */ if (state & PMIC_FAULT_POR_MASK) { start_reason |= SR_POR; } /* PMIC Watchdog */ if (state & PMIC_FAULT_TWD_ERROR_MASK) { start_reason |= SR_WATCHDOG; } } /* * Check CPU reset reason register as the device can be reset * by a CPU watchdog */ cpu_reset_reason = readl(PRM_RSTST); if (cpu_reset_reason & CPU_WDT1_RESET) { start_reason |= SR_WATCHDOG; } /* clear the CPU reset reason register */ writel((CPU_WDT1_RESET | CPU_GLOBAL_COLD_RST | CPU_GLOBAL_WARM_SW_RST), PRM_RSTST); /* * Check Wakeup Events * Event Register A holds: * - Event B, C Activity * - nONKEY: Button * - RTC Alarm * - RTC Tick * Event Register B * - COMP 1V2: Ignition */ ret = da9063_get_reg(PMIC_REG_EVENT_A, &state); if ((ret == 0) && (state != 0)) { (void)da9063_set_reg(PMIC_REG_EVENT_A, state); if (state & PMIC_REG_EVENT_ONKEY_MASK) { start_reason |= (SR_WAKEUP | SR_EVT_BUTTON); } if (state & PMIC_REG_EVENT_RTC_ALARM_MASK) { start_reason |= (SR_WAKEUP | SR_EVT_RTC_ALARM); } if (state & PMIC_REG_EVENT_RTC_TICK_MASK) { start_reason |= (SR_WAKEUP | SR_EVT_RTC_TICK); } if (state & PMIC_REG_EVENT_EVENTS_B_MASK) { uint8_t state_b; ret = da9063_get_reg(PMIC_REG_EVENT_B, &state_b); if ((ret == 0) && (state_b != 0)) { (void)da9063_set_reg(PMIC_REG_EVENT_B, state_b); if (state_b & PMIC_REG_EVENT_COMP1V2_MASK) { start_reason |= (SR_WAKEUP | SR_EVT_IGNITION); } } } } /* * Check for software reboot indicated by OS via shared memory * - checksum valid? * - Reason == 'REBO' or 'OOPS' */ if (rr_is_reset_reason_valid(reset_regs)) { if (reset_regs->rr_value == RR_REBOOT_PATTERN) { start_reason |= SR_REBOOT; } else if (reset_regs->rr_value == RR_OOPS_PATTERN) { /* Treat kernel oops as reboot */ start_reason |= SR_REBOOT; } else if (reset_regs->rr_value == RR_WAKE_PATTERN) { start_reason |= SR_WAKEUP; } else { /* Unknown reset reason */ } } /* * Priority decoder for start and reset reason */ if (start_reason & SR_WATCHDOG) { /* Watchdog has highest priority as it also sets POR and other events */ start_reason = SR_WATCHDOG; reset_reason = RR_EXTERNAL_WATCHDOG_PATTERN; } else if (start_reason & SR_POR) { start_reason = SR_POR; reset_reason = RR_POWEROFF_PATTERN; } else if (start_reason & SR_WAKEUP) { /* Include start events when wakeup is detected */ start_reason = SR_WAKEUP | (start_reason & SR_EVT_WAKE_MASK); reset_reason = RR_WAKE_PATTERN; } else if (start_reason & SR_REBOOT) { start_reason = SR_REBOOT; reset_reason = reset_regs->rr_value; } else { /* Unknown start reason, assume reboot */ start_reason = SR_REBOOT; reset_reason = reset_regs->rr_value; } sys_start_event = start_reason; rr_set_reset_reason(reset_regs, reset_reason); rr_set_start_reason(reset_regs, start_reason); da9063_release_i2c_bus(bus); rr_start_reason_to_str(reset_regs->sr_events, strbuf, sizeof(strbuf)); printf("\nStart Events: %s\n", strbuf); } static void pmic_ignition_gate_on(void) { int bus; uint8_t val; bus = da9063_claim_i2c_bus(); /* Configure GPIO15 to permanent high, so that ignition sense signal is readable */ (void)da9063_set_reg(PMIC_REG_GPIO14_15, 0xCC); /* GPIO14/15 = Outputs open drain */ (void)da9063_get_reg(PMIC_REG_CONFIG_L, &val); /* Enable pull ups on GPIO14/15 */ val |= 0xC0; (void)da9063_set_reg(PMIC_REG_CONFIG_L, val); (void)da9063_set_reg(PMIC_REG_CONTROL_D, 0x00); /* No blinking, state selected by GPIOxx_MODE */ (void)da9063_get_reg(PMIC_REG_GPIO_MODE8_15, &val); /* Set to GPIO14,15 to high */ val |= 0xC0; (void)da9063_set_reg(PMIC_REG_GPIO_MODE8_15, val); /* * Comparator input is debounced (10ms), see DA9063 datasheet 5.13.5 * Give enough time to stabilize input reading. */ mdelay(10+10); da9063_release_i2c_bus(bus); } static void powerdown(void) { int bus; bus = da9063_claim_i2c_bus(); /* Final call, will not return */ (void)da9063_set_reg(PMIC_REG_CONTROL_A, 0x00); da9063_release_i2c_bus(bus); puts("ERROR: PMIC power down failed\n"); for (;;) {} } static void reset(void) { /* Code copied from arm v7 lib */ udelay (50000); disable_interrupts(); reset_misc(); reset_cpu(0); puts("ERROR: Reset failed\n"); for (;;) {} } static void stop_if_ignition_is_off(void) { uint8_t state = 0x00; int bus; int ret; bus = da9063_claim_i2c_bus(); ret = da9063_get_reg(PMIC_REG_STATUS_A, &state); if (ret == 0) { if ((state & PMIC_REG_STATUS_A_COMP1V2_MASK) == PMIC_REG_STATUS_A_COMP1V2_MASK) { puts("Ignition : On\n"); } else { puts("Ignition : Off\n"); /* * Ignition is off, if this is a power-on start, power down * as this is considered an unwanted system start. */ /* * There is a chance for a race condition, when ignition is enabled * between the check above and here. In this case we should just reset * not power down. * Although the risk is minimal here due to the very short time interval * we do the check. The same logic will have to be added in other * components. */ ret = da9063_get_reg(PMIC_REG_EVENT_B, &state); if ((ret == 0) && ((state & PMIC_REG_EVENT_COMP1V2_MASK) == 0)) { powerdown(); } else { reset(); } } } da9063_release_i2c_bus(bus); } static void init_bd_spl(void) { hw_type = 21; /* Assume hw21, unless BD tells different */ if (read_eeprom() >= 0) { int hw_type_from_bd = -1; bd_get_hw_version(&hw_ver, &hw_rev); /* If entry is found returns value, otherwise 0 */ bd_get_hw_type(&hw_type_from_bd); if (hw_type_from_bd != 0) { hw_type = hw_type_from_bd; } } else { puts("Could not get board ID.\n"); } } void am33xx_spl_board_init(void) { /* Set CPU speed to 600 MHz (fix) */ dpll_mpu_opp100.m = MPUPLL_M_600; /* Set CORE Frequencies to OPP100 (600MHz) */ do_setup_dpll(&dpll_core_regs, &dpll_core_opp100); /* Configure both I2C buses used */ init_i2c(); /* Get board descriptor */ init_bd_spl(); /* Detect reset/Wakeup reason */ check_reset_reason(RESET_REASON_SHM_LOCATION); /* Switch on ignition gate so we can read state later */ pmic_ignition_gate_on(); /* Setup PMIC */ init_pmic_spl(); /* * If this is a power-on start, see if ignition is active. * If not, power down as this is considered an unwanted system start. */ if (sys_start_event & SR_POR) { stop_if_ignition_is_off(); } if (is_v32_or_newer()) { enable_led_mux_v32(); enable_uart4_pin_mux(); } else { enable_led_mux(); } init_leds(); set_status_led(1, 0); /* Red */ set_indicator_led(1, 0); /* Red */ #ifndef CONFIG_NRSW_BUILD /* UI detection */ REQUEST_AND_SET_GPIO(GPIO_RST_UI_N); ui_init(CONFIG_UI_I2C_BUS); ui_set_status_led(1, 0); /* Red */ ui_set_indicator_led(1, 0); /* Red */ #endif /* Set MPU Frequency to what we detected now that voltages are set */ do_setup_dpll(&dpll_mpu_regs, &dpll_mpu_opp100); /* Debugger can place marker at end of SRAM to stop boot here */ if (is_jtag_boot(CONFIG_JTAG_MARKER_SPL)) { puts("Detected JTAG boot, executing bkpt #0\n"); __asm__ __volatile__ ("bkpt #0"); } } const struct dpll_params *get_dpll_ddr_params(void) { dpll_ddr.n = (get_osclk() / 1000000) - 1; return &dpll_ddr; } void set_uart_mux_conf(void) { enable_uart0_pin_mux(); enable_uart2_pin_mux(); } void set_mux_conf_regs(void) { enable_board_pin_mux(); } const struct ctrl_ioregs ioregs = { .cm0ioctl = MT41K256M16HA125E_IOCTRL_VALUE, .cm1ioctl = MT41K256M16HA125E_IOCTRL_VALUE, .cm2ioctl = MT41K256M16HA125E_IOCTRL_VALUE, .dt0ioctl = MT41K256M16HA125E_IOCTRL_VALUE, .dt1ioctl = MT41K256M16HA125E_IOCTRL_VALUE }; void sdram_init(void) { config_ddr(DDR3_CLOCK_FREQUENCY, &ioregs, &ddr3_data, &ddr3_cmd_ctrl_data, &ddr3_emif_reg_data, 0); } #endif /* CONFIG_SKIP_LOWLEVEL_INIT */ #if !defined(CONFIG_SPL_BUILD) /* * Override for Ethernet link timeout definition, * with option to specify via environment variable linktimeout */ int eth_phy_timeout(void) { const char* timeout_env = NULL; int timeout; timeout = PHY_ANEG_DEFAULT_TIMEOUT; /* * Check if timeout has been defined by environment. * Valid range: 1000..10000 milliseconds */ timeout_env = getenv("linktimeout"); if (timeout_env != NULL) { timeout = simple_strtoul(timeout_env, NULL, 10); if (timeout == 0) { timeout = PHY_ANEG_DEFAULT_TIMEOUT; } else if (timeout < 1000) { timeout = 1000; } else if (timeout > 10000) { timeout = 10000; } } return timeout; } #endif /* !defined(CONFIG_SPL_BUILD) */ #if !defined(CONFIG_SPL_BUILD) static void init_ethernet(void) { REQUEST_AND_CLEAR_GPIO(GPIO_RST_ETH_N); /* Minimum Reset Pulse = 5us (switch), 20us (TJA1100), 100us (SMSC8720) */ mdelay(1); gpio_set_value(GPIO_RST_ETH_N, 1); } static void init_ethernet_v2(void) { /* Put switch and PHYs in reset */ REQUEST_AND_CLEAR_GPIO(GPIO_RST_ETH_N); REQUEST_AND_CLEAR_GPIO(GPIO_RST_ETH_SW_N); /* Take switch out of reset. Minimum Reset Pulse = 5us */ mdelay(1); gpio_set_value(GPIO_RST_ETH_SW_N, 1); /* Give clocks time to stabilize */ mdelay(1); } static void init_ethernet_phys_v2(void) { /* Take Ethernet PHYs out of reset */ /* Minimum Reset Pulse = 20us (TJA1102), 100us (SMSC8720) */ mdelay(1); gpio_set_value(GPIO_RST_ETH_N, 1); } static void configure_ethernet_switch(void) { static struct spi_slave *spi = 0; if (spi == 0) { configure_module_pin_mux(spi1_pin_mux); spi_init(); /* Maximum bitrate supported by switch is 17.8 MHz */ spi = spi_setup_slave(CONFIG_SJA1105_SPI_BUS, CONFIG_SJA1105_SPI_CS, 15000000 /* Frequency 15 MHz */, SPI_MODE_1); sja1105_init(spi); } spi_claim_bus(spi); /* 1ms delay after init before first SPI acces */ mdelay(1); sja1105_configure_firmware(); /* Configure clocks */ sja1105_configure_mode_and_clocks(); /* Configure IO pads */ sja1105_configure_io(); spi_release_bus(spi); } static void configure_broadr_phys(void) { unsigned char phy_start; unsigned char phy; const char *devname; int err = 0; if (hw_ver == 1) { phy_start = 6; /* HW v1.0 has PHYs on 6 and 7, by accident */ } else { phy_start = 2; /* From HW v2.0 addresses are correct at 2 and 3 */ } /* Get current device */ devname = miiphy_get_current_dev(); /* Configure TJA1100 BroadR PHY ports as slave and restart FSM */ for (phy = phy_start; phy <= phy_start+1 && err == 0; phy++) { /* Extended control register : bit 15 -> Link control disabled */ if (0 != miiphy_write (devname, phy, 0x11, 0x0004)) { err++; } /* Configuration register 1 : bit 15 -> PHY configured as Slave */ if (0 != miiphy_write (devname, phy, 0x12, 0x0910)) { err++; } /* Extended control register : link control enable and training restart */ if (0 != miiphy_write (devname, phy, 0x11, 0x9A04)) { err++; } } if (err != 0) { puts("BroadR not ready, "); } else { puts("BroadR ready, "); } } static void init_usb_hub(void) { REQUEST_AND_CLEAR_GPIO(GPIO_RST_USB_HUB_N); /* Minimum Reset Pulse = 1us */ mdelay(2); gpio_set_value(GPIO_RST_USB_HUB_N, 1); } #ifndef CONFIG_NRSW_BUILD static void init_user_module(void) { int bus; bus = da9063_claim_i2c_bus(); puts("UM: "); REQUEST_AND_CLEAR_GPIO(GPIO_RST_UM_N); /* Assert reset (active low) */ REQUEST_AND_CLEAR_GPIO(GPIO_CTRL_WDIS_N) /* TODO: CHECK */ /* TODO: Should this be done at first power up as well? */ da9063_set_gpio(PMIC_UM_SUPPLY_EN_IO, 0); /* Switch Supply off */ mdelay(30); /* Give time to discharge output */ da9063_set_gpio(PMIC_UM_SUPPLY_VSEL_IO, 0); /* Set voltage to 3.3V */ mdelay(1); da9063_set_gpio(PMIC_UM_SUPPLY_EN_IO, 1); /* Enable Supply */ mdelay(10); gpio_direction_input(GPIO_RST_UM_N); /* Release reset (open drain) */ mdelay(10); da9063_release_i2c_bus(bus); mdelay(200); /* Give module some time to boot */ um_init(CONFIG_UM_I2C_BUS); /* Try to detect user module */ if (um_present()) { const char* type = um_type_as_str(); uint8_t ver = 0; uint8_t rev = 0; um_version(&ver, &rev); printf("%s V%d.%d\n", type, ver, rev); } else { puts("N/A\n"); } } #endif static void init_sim_mux(void) { /* * Switch pluggable micro SIM to onboard modem (mux = 1) */ REQUEST_AND_SET_GPIO(GPIO_SIM_SEL); } static void init_gsm(void) { /* * Perform power up sequence for TOBY-L2 modem. * * TOBY-L2 series can be switched on in one of the following ways: * - Rising edge on the VCC pin to a valid voltage for module supply, * i.e. applying module supply * - Low level on the PWR_ON pin, which is normally set high by an * internal pull-up, for a valid time period when the applied VCC * voltage is within the valid operating range (see section 4.2.8). * - Low level on the RESET_N pin, which is normally set high by an * internal pull-up, for a valid time period when the applied VCC * voltage is within the valid operating range (see section 4.2.9). * * PWR_ON low time: 5 ms - Low time to switch-on the module * RESET_N low time: 18..800 ms - Low time to switch-on the module * 2.1..15 s - Low time to reset the module * 16 s - Low time to switch-off the module * * References: * - uBlox TOBY-L2 Datasheet UBX-13004573 - R24 * 2.3.1 Module power-on * 4.2.8 PWR_ON pin * 4.2.9 RESET_N pin * * Functionality Yocto: * - Leave GSM power enable as is (default at power up = off) * - Set reset line inactive (note: inverter logic in HW present) * - Leave button unpressed (note: inverter logic in HW present) * - Modem shall be enabled by Linux system by enabling GSM power * supply */ #ifdef CONFIG_NRSW_BUILD int bus; puts("GSM: "); bus = da9063_claim_i2c_bus(); /* TODO: Keep Power-On and use GSM Modem Reset Signal to restart */ REQUEST_AND_SET_GPIO(GPIO_RST_GSM); /* Assert reset (active high) */ REQUEST_AND_CLEAR_GPIO(GPIO_PWR_GSM); /* Keep power switch inactive (released) */ da9063_set_gpio(PMIC_GSM_SUPPLY_EN_IO, 0); /* Switch GSM Supply off */ mdelay(30+100); /* Give time to discharge supply */ /* Keep of for 100ms, #3.3.2 */ da9063_set_gpio(PMIC_GSM_SUPPLY_EN_IO, 1); /* Enable GSM supply */ mdelay(10); gpio_set_value(GPIO_RST_GSM, 0); /* Take modem out of reset */ mdelay(300); /* Wait for power to stabilizy, #3.4.2 */ gpio_set_value(GPIO_PWR_GSM, 1); /* Generate power on event, #3.4.2 */ mdelay(1200); gpio_set_value(GPIO_PWR_GSM, 0); da9063_release_i2c_bus(bus); puts("ready\n"); #else puts("GSM: "); REQUEST_AND_CLEAR_GPIO(GPIO_RST_GSM); /* Set reset inactive (active high) */ REQUEST_AND_CLEAR_GPIO(GPIO_PWR_GSM); /* Set power switch inactive/released (active high) */ puts("init\n"); #endif } static void init_gnss(void) { /* * Release GNSS reset line, so that module starts up early */ REQUEST_AND_SET_GPIO(GPIO_RST_GNSS); } static void init_timepulse(void) { /* * Configure timepulse as input. * * Note: * Was output on HW21, function SIM_PRES_N, never worked. * Therefore reused as timepulse input on hw26. */ /* * Action: None, just leave pin at reset default = input */ } #endif /* !defined(CONFIG_SPL_BUILD) */ /* * Basic board specific setup. Pinmux has been handled already. * Not called in SPL build. */ int board_init(void) { #if defined(CONFIG_HW_WATCHDOG) hw_watchdog_init(); #endif gd->bd->bi_boot_params = CONFIG_SYS_SDRAM_BASE + 0x100; /* Configure both I2C buses used */ init_i2c(); da9063_init(CONFIG_PMIC_I2C_BUS); #ifndef CONFIG_NRSW_BUILD /* UI detection */ REQUEST_AND_SET_GPIO(GPIO_RST_UI_N); ui_init(CONFIG_UI_I2C_BUS); #endif printf("OSC: %lu MHz\n", get_osclk()/1000000); return 0; } #if !defined(CONFIG_SPL_BUILD) void set_console(void) { const char *defaultconsole = getenv("defaultconsole"); if (defaultconsole == 0) { /* Use the default console */ setenv("defaultconsole", "ttyS2"); } } #ifdef CONFIG_NRSW_BUILD static void set_devicetree_name(void) { char devicetreename[64]; /* add hardware versions to environment */ if (bd_get_devicetree(devicetreename, sizeof(devicetreename)) != 0) { printf("Devicetree name not found, using default name\n"); strcpy(devicetreename, "am335x-nmhw21-prod1.dtb"); } setenv("fdt_image", devicetreename); } static void set_root_partition(void) { int boot_partition; /* add active root partition to environment */ boot_partition = bd_get_boot_partition(); if (boot_partition > 1) { boot_partition = 0; } /* mmcblk1p1 => root0, mmcblk1p2 => root1 so +1 */ setenv_ulong("root_part", boot_partition + 1); } #endif static void get_variant_name(void) { bd_get_variantname(hw_variant_name, sizeof(hw_variant_name)); printf("SYS: %s\n", hw_variant_name); } #ifdef CONFIG_NRSW_BUILD static void get_hw_version(void) { char hw_versions[16]; char new_env[256]; /* current bootargs = 84 bytes */ bd_get_hw_version(&hw_ver, &hw_rev); bd_get_hw_patch(&hw_patch); bd_get_hw_type(&hw_type); if (hw_type == 0) { /* Fallback to HW21 if tag is not present */ hw_type = 21; } printf("HW%02d: V%d.%d\n", hw_type, hw_ver, hw_rev); /* add hardware versions to environment */ snprintf(hw_versions, sizeof(hw_versions), "CP=%d.%d", hw_ver, hw_rev); snprintf(new_env, sizeof(new_env), "setenv bootargs $bootargs %s", hw_versions); setenv("add_version_bootargs", new_env); } #else static void get_hw_version(void) { bd_get_hw_version(&hw_ver, &hw_rev); bd_get_hw_patch(&hw_patch); bd_get_hw_type(&hw_type); if (hw_type == 0) { /* Fallback to HW21 if tag is not present */ hw_type = 21; } printf("MB: V%d.%d (HW%2d)\n", hw_ver, hw_rev, hw_type); } #endif static void get_pmic_version(void) { uint8_t val = 0x00; uint8_t ver, rev; int bus; int rc; bus = da9063_claim_i2c_bus(); rc = da9063_get_reg(PMIC_REG_CONFIG_ID, &val); if (!rc) { ver = (val >> 4) & 0xF; rev = (val >> 0) & 0xF; } else { ver = 0; rev = 0; } da9063_release_i2c_bus(bus); /* Quirk: * If reported version is 3.14, this is one of the 5 prototypes which have * been programmed multiple times --> Treat these as 1.0 */ if ((ver == 3) && (rev == 14)) { ver = 1; rev = 0; } printf("PMIC: V%d.%d\n", ver, rev); } static void check_jtag_boot(void) { if (is_jtag_boot(CONFIG_JTAG_MARKER_UBOOT)) { char *bootcmd = getenv("bootcmd"); setenv ("bootcmd", ""); /* Save original bootcmd in "bootcmd_orig" to allow manual boot */ setenv ("bootcmd_orig", bootcmd); puts("Detected JTAG boot. Waiting on command line\n"); } } static void check_fct(void) { /* * Check whether an I2C device (EEPROM) is present at address 0xA2/0x51 * In this case we are connected to the factory test station. * Clear the bootcmd, so that test system can easily connect. */ int old_bus; old_bus = i2c_get_bus_num(); i2c_set_bus_num(I2C_BD_EEPROM_BUS); /* If probe fails we are sure no eeprom is connected */ if (i2c_probe(0x51) == 0) { setenv ("bootcmd", ""); puts("Detected factory test system. Waiting on command line\n"); } i2c_set_bus_num(old_bus); } static bool get_button_state(void) { uint8_t state = 0x00; bool pressed = false; int bus; int rc; bus = da9063_claim_i2c_bus(); rc = da9063_get_reg(PMIC_REG_STATUS_A, &state); da9063_release_i2c_bus(bus); if (!rc) { pressed = (state & 0x01) == 0x01; } return pressed; } static void blink_led(int pulses) { const int pulse_width = 400*1000; /* 400ms */ #ifdef CONFIG_NRSW_BUILD /* Assumes status LED is orange */ set_status_led(0, 0); ui_set_top_led(0, 0); #endif while (pulses) { udelay(pulse_width); set_status_led(1, 1); #ifndef CONFIG_NRSW_BUILD ui_set_status_led(1, 1); #endif udelay(pulse_width); set_status_led(0, 0); #ifndef CONFIG_NRSW_BUILD ui_set_status_led(0, 0); #endif pulses--; } udelay(pulse_width); set_status_led(1, 1); /* Orange */ #ifndef CONFIG_NRSW_BUILD ui_set_status_led(1, 1); #endif } #define RESET_CHECK_PERIOD (100) /* 100 ms */ typedef enum _action_t { NONE = 0, WAIT, FACTORY_RESET, RECOVERY_BOOT } action_t; static void uart2_rx_gpio_pin_mux(void) { /* Configure UART2 rxd pin as GPIO */ static struct module_pin_mux uart2_gpio_pin_mux[] = { {OFFSET(spi0_sclk), (MODE(7) | PULLUDEN | PULLUP_EN | RXACTIVE)}, /* (A17) uart2_rxd = gpio0_2 */ {-1} }; configure_module_pin_mux(uart2_gpio_pin_mux); } static void uart2_rx_rx_pin_mux(void) { /* Configure UART2 rxd pin as rxd function */ static struct module_pin_mux uart2_pin_mux[] = { {OFFSET(spi0_sclk), (MODE(1) | PULLUDEN | PULLUP_EN | RXACTIVE)}, /* (A17) uart2_rxd */ {-1} }; configure_module_pin_mux(uart2_pin_mux); } static bool get_rxd_state(void) { uart2_rx_gpio_pin_mux(); (void)gpio_request(GPIO_UART2_RX, ""); int val = gpio_get_value(GPIO_UART2_RX); gpio_free(GPIO_UART2_RX); uart2_rx_rx_pin_mux(); return (val == 0); } static int check_button(int time, bool button) { /* * Hardware button logic * * input: * button: current button press state (true = pressed) * logic: * - if button is not pressed initially, return action NONE for all * invocations (state NO_ACTION) * - if button pressed initially, return action WAIT and measure duration * of press (state PRESSED). * - while button is pressed, measure time, indicate actions with LED, * - when button is released, check time and decide on factory reset * or recovery boot. */ typedef enum _state_t { INIT = 0, PRESSED, DONE } state_t; static state_t state = INIT; /* Current state */ static action_t act = NONE; /* Action to report to user, returned at function end */ static int duration = 0; if (time == 0) { state = INIT; } switch (state) { case INIT: if (button) { /* Pressed, start to measure time until released */ duration = 0; act = WAIT; state = PRESSED; } else { /* If not pressed, no further action is possible */ act = NONE; state = DONE; } break; case PRESSED: if (button) { duration += RESET_CHECK_PERIOD; if (duration == DURATION_FACTORY_RESET) { /* Indicate factory reset threshold */ blink_led(1); } else if (duration == DURATION_RECOVERY_BOOT) { /* Indicate recovery boot threshold and leave state */ blink_led(2); act = RECOVERY_BOOT; state = DONE; } } else { /* Check how long button was pressed */ if (duration >= DURATION_RECOVERY_BOOT) { act = RECOVERY_BOOT; state = DONE; } else if (duration >= DURATION_FACTORY_RESET) { act = FACTORY_RESET; state = DONE; } else { /* too short, nothing to do */ act = NONE; state = DONE; } } break; case DONE: /* Final state when an action has been chosen */ break; default: break; } return act; } static int check_break_length(int time, bool rx_line) { /* * RS232 RxD Reset input logic * * Treats RxD line as reset input. Line is considered active when * break condition applies (RS232 line > 3.0 V) * * input: * rx_line: true if rxd input is '0' (break condition) * logic: * see explanation in check_button() * additional logic is added to debounce input */ #define BREAK_DEB_TIME 500 typedef enum _state_t { WAIT_BREAK = 0, HAVE_BREAK, DONE } state_t; static state_t state = WAIT_BREAK; /* Current state */ static action_t act = NONE; /* Action to report to user, returned at function end */ static int duration = 0; static int wait_time = 0; if (time == 0) { state = WAIT_BREAK; wait_time = BREAK_DEB_TIME; } switch (state) { case WAIT_BREAK: if (rx_line) { /* Break detected, start to measure time */ duration = 0; wait_time = BREAK_DEB_TIME; act = WAIT; state = HAVE_BREAK; } if (wait_time > 0) { wait_time -= RESET_CHECK_PERIOD; act = WAIT; } else { /* If no break seen, stop here */ act = NONE; state = DONE; } break; case HAVE_BREAK: if (rx_line) { wait_time = BREAK_DEB_TIME; duration += RESET_CHECK_PERIOD; if (duration == DURATION_FACTORY_RESET) { /* Indicate factory reset threshold */ blink_led(1); } else if (duration == DURATION_RECOVERY_BOOT) { /* Indicate recovery boot threshold and leave state */ blink_led(2); act = RECOVERY_BOOT; /* TODO: maybe remain in state until break removed */ state = DONE; } } if (wait_time > 0) { wait_time -= RESET_CHECK_PERIOD; } else { /* puts("break condition released\n"); */ /* Check how long button was pressed */ if (duration >= DURATION_RECOVERY_BOOT) { act = RECOVERY_BOOT; state = DONE; } else if (duration >= DURATION_FACTORY_RESET) { act = FACTORY_RESET; state = DONE; } else { /* too short, nothing to do */ act = NONE; state = DONE; } } break; case DONE: /* Final state when an action has been chosen */ break; default: break; } return act; } static int check_break_command(int time, int has_input, int c) { /* * Break command logic * * Tries to receive the break button (system magic key) and a command to execute. * * input: * has_input: true if a character is available * c: character code (can be 0x00 for break condition, system magic key) * logic: * - waits up to 500 ms to receive a break character. if character is not seen, * stops here, action = NONE. if character is detected goes to next state * - waits up to 500 ms to receive command character. if character is not seen, * stops here, action = NONE. if character is detected define action accordingly * 'f': factory reset * 'r': recovery boot */ #define BREAK_WAIT_TIME 1000 /* Initial wait time for break character */ #define CHARACTER_WAIT_TIME 1500 /* Subsequent wait time for command */ typedef enum _state_t { WAIT_BREAK = 1, WAIT_COMMAND, DONE } state_t; static state_t state = WAIT_BREAK; /* Current state */ static action_t act = NONE; /* Action to report to user, returned at function end */ static int wait_time; if (time == 0) { state = WAIT_BREAK; wait_time = BREAK_WAIT_TIME; } switch (state) { case WAIT_BREAK: /* Wait for break indication */ act = WAIT; if (has_input) { if (c == 0x00) { /* puts("break detected\n"); */ wait_time = CHARACTER_WAIT_TIME; state = WAIT_COMMAND; } } if (wait_time > 0) { wait_time -= RESET_CHECK_PERIOD; } else { /* No break received, nothing to do from our side */ act = NONE; state = DONE; } break; case WAIT_COMMAND: if (has_input) { wait_time = CHARACTER_WAIT_TIME; if (c == 0x00) { /* puts("break detected\n"); */ act = WAIT; } else if (c == 'f') { blink_led(1); act = FACTORY_RESET; state = DONE; } else if (c == 'r') { blink_led(2); act = RECOVERY_BOOT; state = DONE; } else { /* Unknown command */ act = NONE; state = DONE; } } if (wait_time > 0) { wait_time -= RESET_CHECK_PERIOD; } else { /* puts("character timeout\n"); */ act = NONE; state = DONE; } break; case DONE: /* Final state when an action has been chosen */ break; default: break; } return act; } static void check_reset_button(void) { /* * Runs state machines of all reset sources to find out if one detects * an action. * * SMs return * - WAIT if they are still trying to get a result. * - NONE if they know there is no action required. * - FACTORY_RESET, RECOVERY_BOOT if detected. */ action_t action = NONE; int counter = 0; do { action_t a_[3]; bool button; bool rx_line; int has_input; int c = -1; /* Get state machine inputs */ button = get_button_state(); rx_line = get_rxd_state(); has_input = tstc(); if (has_input) { c = getc(); } /* run processing state machines */ a_[0] = check_button(counter, button); if (hw_type == 26) { /* break function are only present on hw26 */ a_[1] = check_break_length(counter, rx_line); a_[2] = check_break_command(counter, has_input, c); } else { a_[1] = NONE; a_[2] = NONE; } /* if all SMs are sure there is not action, stop here */ if ((a_[0] == NONE) && (a_[1] == NONE) && (a_[2] == NONE)) { action = NONE; break; } /* if one of the SMs has an action, stop here */ for (int i=0; i<3; i++) { if ((a_[i] == FACTORY_RESET) || (a_[i] == RECOVERY_BOOT)) { action = a_[i]; break; } } mdelay(RESET_CHECK_PERIOD); counter += RESET_CHECK_PERIOD; } while ((action != FACTORY_RESET) && (action != RECOVERY_BOOT)); switch (action) { case FACTORY_RESET: { char new_bootargs[512]; char *bootargs = getenv("bootargs"); puts("Do factory reset during boot...\n"); if (bootargs == 0) bootargs = ""; strncpy(new_bootargs, bootargs, sizeof(new_bootargs)); strncat(new_bootargs, " factory-reset", sizeof(new_bootargs)); setenv("bootargs", new_bootargs); break; } case RECOVERY_BOOT: puts("Booting recovery image...\n"); setenv("bootcmd", "run recovery"); break; default: set_indicator_led(0, 0); break; } } #endif /* !defined(CONFIG_SPL_BUILD) */ int board_late_init(void) { #if !defined(CONFIG_SPL_BUILD) #ifndef CONFIG_NRSW_BUILD int ui_ver = -1; #endif if (read_eeprom() < 0) { puts("Could not get board ID.\n"); } get_variant_name(); get_hw_version(); get_pmic_version(); /* Let user know we're starting */ init_leds(); set_status_led(1, 1); /* Orange */ set_indicator_led(0, 0); /* Off */ #ifndef CONFIG_NRSW_BUILD ui_set_status_led(1, 1); /* Orange */ ui_set_indicator_led(0, 0); /* Off */ #endif #ifdef CONFIG_NRSW_BUILD set_root_partition(); set_devicetree_name(); #endif /* Initialize pins */ REQUEST_AND_CLEAR_GPIO(GPIO_WLAN_EN); REQUEST_AND_CLEAR_GPIO(GPIO_BT_EN); REQUEST_AND_SET_GPIO(CAN0_TERM_N); /* Unused on V2.0 */ REQUEST_AND_SET_GPIO(CAN1_TERM_N); #ifndef CONFIG_NRSW_BUILD ui_ver = ui_version(); switch (ui_ver) { case 1: puts("UI: V1.0\n"); break; case 2: puts("UI: V2.0\n"); break; default: puts("UI: N/A\n"); break; } #endif if (hw_ver == 1) { /* On HW v1.0 switch and PHYs share the same reset line. * Clocks for the PHYs are only present once switch is configured * Thus the switch needs to be configured once to allow to bootstrap * the PHYs. This requires the assertion of reset again, which also * reset the switch (a 2nd time). It therefore has to be configured * a 2nd time. */ init_ethernet(); configure_ethernet_switch(); /* Reset ETH system again to pin strap PHYs */ mdelay(10); gpio_set_value(GPIO_RST_ETH_N, 0); mdelay(10); gpio_set_value(GPIO_RST_ETH_N, 1); /* Configure switch again, after 2nd reset */ configure_ethernet_switch(); } else { init_ethernet_v2(); configure_ethernet_switch(); /* * Now that Ethernet switch is running, PHY clocks are present. * Take PHYs out of reset. */ init_ethernet_phys_v2(); } init_usb_hub(); #ifndef CONFIG_NRSW_BUILD init_user_module(); #endif init_sim_mux(); init_gsm(); init_gnss(); init_timepulse(); /* * Check if a user action is requested * - Short press: factory reset * - Long press: recovery boot */ check_reset_button(); set_status_led(1, 1); /* Orange */ set_indicator_led(0, 0); /* Off */ #ifndef CONFIG_NRSW_BUILD set_status_led(1, 1); /* Orange */ set_indicator_led(0, 0); /* Off */ #endif check_fct(); check_jtag_boot(); #endif return 0; } #ifndef CONFIG_DM_ETH #if (defined(CONFIG_DRIVER_TI_CPSW) && !defined(CONFIG_SPL_BUILD)) || \ (defined(CONFIG_SPL_ETH_SUPPORT) && defined(CONFIG_SPL_BUILD)) static void cpsw_control(int enabled) { /* VTP can be added here */ return; } static struct cpsw_slave_data cpsw_slaves[] = { { .slave_reg_ofs = 0x208, .sliver_reg_ofs = 0xd80, .phy_if = PHY_INTERFACE_MODE_RMII, .phy_addr = 1 } }; static struct cpsw_platform_data cpsw_data = { .mdio_base = CPSW_MDIO_BASE, .cpsw_base = CPSW_BASE, .mdio_div = 0xff, .channels = 8, .cpdma_reg_ofs = 0x800, .slaves = 1, .slave_data = cpsw_slaves, .ale_reg_ofs = 0xd00, .ale_entries = 1024, .host_port_reg_ofs = 0x108, .hw_stats_reg_ofs = 0x900, .bd_ram_ofs = 0x2000, .mac_control = (1 << 5), .control = cpsw_control, .host_port_num = 0, .version = CPSW_CTRL_VERSION_2, }; #endif #if ((defined(CONFIG_SPL_ETH_SUPPORT) || defined(CONFIG_SPL_USBETH_SUPPORT)) &&\ defined(CONFIG_SPL_BUILD)) || \ ((defined(CONFIG_DRIVER_TI_CPSW) || \ defined(CONFIG_USB_ETHER) && defined(CONFIG_MUSB_GADGET)) && \ !defined(CONFIG_SPL_BUILD)) static void set_mac_address(int index, uchar mac[6]) { /* Then take mac from bd */ if (is_valid_ethaddr(mac)) { eth_setenv_enetaddr_by_index("eth", index, mac); } else { printf("Trying to set invalid MAC address"); } } static int read_tja1102(struct mii_dev *bus, int phy_id, int dev_addr, int phy_reg) { /* Remove TJA1102 mirror(s) at address 0 from bus */ if (phy_id == 0) { return -1; } /* * Also report ID registers 2&3 for 2nd PHY in TJA1102 * Take values from 1st PHY (ID 2) */ if (phy_id == 3 && (phy_reg == 2 || phy_reg == 3)) { phy_id = 2; } return olddev.read(bus, phy_id, dev_addr, phy_reg); } static void register_phy_hook(void) { struct mii_dev* dev; dev = miiphy_get_dev_by_name("cpsw"); if (dev != NULL) { /* Remember original structure (read pointer) */ memcpy(&olddev, dev, sizeof(olddev)); /* Override read method with SJA1002 wrapper */ dev->read = read_tja1102; } } /* TODO: Update doc */ /* * This function will: * Read the eFuse for MAC addresses, and set ethaddr/eth1addr/usbnet_devaddr * in the environment * Perform fixups to the PHY present on certain boards. We only need this * function in: * - SPL with either CPSW or USB ethernet support * - Full U-Boot, with either CPSW or USB ethernet * Build in only these cases to avoid warnings about unused variables * when we build an SPL that has neither option but full U-Boot will. */ int board_eth_init(bd_t *bis) { int n = 0; __maybe_unused uint8_t mac_addr0[6] = {02,00,00,00,00,01}; #if !defined(CONFIG_SPL_BUILD) #ifdef CONFIG_DRIVER_TI_CPSW cpsw_data.mdio_div = 0x3E; bd_get_mac(0, mac_addr0, sizeof(mac_addr0)); set_mac_address(0, mac_addr0); writel(RMII_MODE_ENABLE | RMII_CHIPCKL_ENABLE, &cdev->miisel); { int rv = cpsw_register(&cpsw_data); if (rv < 0) { printf("Error %d registering CPSW switch\n", rv); } else { n += rv; } } #endif #endif #if defined(CONFIG_USB_ETHER) && \ (!defined(CONFIG_SPL_BUILD) || defined(CONFIG_SPL_USBETH_SUPPORT)) if (is_valid_ethaddr(mac_addr0)) { eth_setenv_enetaddr("usbnet_devaddr", mac_addr0); } { int rv = usb_eth_initialize(bis); if (rv < 0) { printf("Error %d registering USB_ETHER\n", rv); } else { n += rv; } } #endif register_phy_hook(); /* Enable BroadR PHYs, set to slave mode */ configure_broadr_phys(); return n; } #endif #endif /* CONFIG_DM_ETH */ #ifdef CONFIG_SPL_LOAD_FIT int board_fit_config_name_match(const char *name) { return 0; } #endif #if defined(CONFIG_OF_BOARD_SETUP) && !defined(CONFIG_SPL_BUILD) static void ft_enable_node(void* blob, const char* name) { int node_ofs = -1; node_ofs = fdt_path_offset(blob, name); printf("ft_enable_node %s -> %d\n", name, node_ofs); if (node_ofs >= 0) { fdt_setprop_string(blob, node_ofs, "status", "okay"); } } /* * Modify the name of a gpio in a gpio-line-names string list. */ static void ft_set_gpio_name(void *blob, const char* gpio, int pin, const char* name) { int node_ofs = fdt_path_offset(blob, gpio); int gpios = -1; const char* text; int pos = 0; int i; char buffer[512]; if (node_ofs < 0) { printf("Can't find node %s\n", gpio); goto end; } /* get number of IOs in node */ gpios = fdt_getprop_u32_default_node(blob, node_ofs, 0, "ngpios", -1); if (gpios == -1 || gpios > 64) { printf("Illegal number of gpios %d\n", gpios); goto end; } /* get string array with names */ const struct fdt_property* prop = fdt_get_property(blob, node_ofs, "gpio-line-names", NULL); if (prop == NULL) { goto end; } /* modify given name */ for (i=0; isr_events); } } } #endif static void ft_eth(void *blob) { /* * PHY ID Assignment * * broadr0 broadr1 * HW V1.0: 6 7 * HW V2.0: 3 2 * * DTB defines V2.0 settings. When running on v1.0 hardware, we change the PHY Ids as required. */ if (hw_ver == 1) { int node_offset; node_offset = fdt_path_offset(blob, "broadr1"); if (node_offset != -1) { fdt_setprop_u32(blob, node_offset, "", 7); fdt_setprop_u32(blob, node_offset, "reg", 7); } node_offset = fdt_path_offset(blob, "broadr0"); if (node_offset != -1) { fdt_setprop_u32(blob, node_offset, "", 6); fdt_setprop_u32(blob, node_offset, "reg", 6); } } } static void ft_uart4(void *blob) { /* * V3.2 HW can feature uart4 as RS232/485 interface. * TODO: Check product descriptor to see if interface is assembled? */ if (is_v32_or_newer()) { ft_enable_node(blob, "serial4"); } else { /* If interface is not present, remove SEL_RS232_RS485n name from gpio0_8 */ ft_set_gpio_name(blob, "gpio0", 8, ""); } } static void ft_led(void *blob) { /* * V3.2 HW has LED0 Green at GPIO1_23 instead of 0_30 * Link from SysState-LED Driver also needs to be adapted */ if (is_v32_or_newer()) { ft_enable_node(blob, "status_led_v32"); ft_enable_node(blob, "/sysstate-led-v32"); } else { ft_enable_node(blob, "status_led"); ft_enable_node(blob, "/sysstate-led"); } } int ft_board_setup(void *blob, bd_t *bd) { ft_bootloader_version(blob); ft_hw_info(blob); #ifndef CONFIG_NRSW_BUILD ft_user_interface(blob); ft_user_module(blob); #endif ft_eth(blob); ft_uart4(blob); ft_led(blob); ft_start_event(blob, RESET_REASON_SHM_LOCATION); return 0; } #endif /* defined(CONFIG_OF_BOARD_SETUP) && !defined(CONFIG_SPL_BUILD) */