/* * board.c * * Board functions for Netmodule HW 25, based on AM335x EVB * * Copyright (C) 2018-2020 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 "../common/bdparser.h" #include "../common/board_descriptor.h" #include "../common/da9063.h" #include "board.h" #include "fileaccess.h" /* TODO: place in proper header file */ extern void serial_set_console_index(int index); extern int console_init_f(void); DECLARE_GLOBAL_DATA_PTR; /* * CPU GPIOs * * (J18) GPIO0_16: RST_PHY~ * (U10) GPIO0_22: SEL_RS232/RS485~ * (T10) GPIO0_23: EN_RS485_TERM~ * (T11) GPIO0_26: IO_OUT1 * (U12) GPIO0_27: IO_OUT2 * * (T12) GPIO1_12: IO_IN0 * (T13) GPIO1_13: IO_IN1 * (T14) GPIO1_14: IO_IN2 * (T15) GPIO1_15: IO_IN3 * * (T13) GPIO2_0: RST_SDCARD~ * (L17) GPIO2_18: GSM_PWR_EN * (L16) GPIO2_19: RST_GSM * * (K18) GPIO3_9: WLAN_IRQ * (L18) GPIO3_10: WLAN_EN * (C12) GPIO3_17: SIM_SEL */ #define GPIO_TO_PIN(bank, gpio) (32 * (bank) + (gpio)) #define GPIO_RST_ETH_N GPIO_TO_PIN(0, 16) #define GPIO_RST_GSM GPIO_TO_PIN(2, 19) #define GPIO_PWR_GSM GPIO_TO_PIN(2, 18) #define GPIO_WLAN_EN GPIO_TO_PIN(3, 10) #define GPIO_SIM_SEL GPIO_TO_PIN(3, 17) #define GPIO_RST_SDCARD_N GPIO_TO_PIN(2, 0) #define GPIO_SERIAL_SEL GPIO_TO_PIN(0, 22) #define GPIO_RS485_TERM_EN GPIO_TO_PIN(0, 23) #define GPIO_OUT1 GPIO_TO_PIN(0, 26) #define GPIO_OUT2 GPIO_TO_PIN(0, 27) #define GPIO_IN0 GPIO_TO_PIN(1, 12) #define GPIO_IN1 GPIO_TO_PIN(1, 13) #define GPIO_IN2 GPIO_TO_PIN(1, 14) #define GPIO_IN3 GPIO_TO_PIN(1, 15) /* * PMIC GPIOs * * GPIO_7: EN_SUPPLY_GSM * GPIO_10: LED.LWR * GPIO_11: LED.UPR */ // TODO: Can we use more meaningful names instead of upper, lower? // TODO: What are the functions? #define PMIC_GSM_SUPPLY_EN_IO 7 #define PMIC_LED0 10 /* Lower */ #define PMIC_LED1 11 /* Upper */ #define DDR3_CLOCK_FREQUENCY (400) #if !defined(CONFIG_SPL_BUILD) /* Hardware version information of mainboard, loaded by get_hw_version() */ static int hw_ver = -1; static int hw_rev = -1; static int hw_patch = -1; static int hw_type = -1; static char hw_variant_name[64]; #else static int hw_type = -1; #endif #if !defined(CONFIG_SPL_BUILD) static struct ctrl_dev *cdev = (struct ctrl_dev *)CTRL_DEVICE_BASE; #endif #define I2C_BD_EEPROM_BUS (2) #define BD_EEPROM_ADDR (0x50) /* CPU BD EEPROM (8kByte) is at 50 (A0) */ #define BD_ADDRESS (0x0000) /* Board descriptor at beginning of EEPROM */ #define PD_ADDRESS (0x0200) /* Product descriptor */ #define PARTITION_ADDRESS (0x0600) /* Partition Table */ static BD_Context bdctx[3]; /* The descriptor contexts */ #if !defined(CONFIG_SPL_BUILD) static void request_and_set_gpio(int gpio, const char *name, int value) { int ret; ret = gpio_request(gpio, name); if (ret < 0) { printf("%s: Unable to request %s\n", __func__, name); return; } ret = gpio_direction_output(gpio, value); if (ret < 0) { printf("%s: Unable to set %s as output\n", __func__, name); goto err_free_gpio; } return; err_free_gpio: gpio_free(gpio); } #define REQUEST_AND_SET_GPIO(N) request_and_set_gpio(N, #N, 1); #define REQUEST_AND_CLEAR_GPIO(N) request_and_set_gpio(N, #N, 0); #endif static void init_leds(void) { /* No init code required */ } // TODO: Double check how LEDs shall be used // TODO: Netmodule use of status/indicator might not be what customer expects // TODO: Can we check with Marcel from Timeserver project? static void set_status_led(int red, int green) { int bus; /* * Note: Only green color LED is available in hw25 * Enable LED when either red or green is desired. */ bus = da9063_claim_i2c_bus(); da9063_set_gpio(PMIC_LED1, red | green); da9063_release_i2c_bus(bus); } static void set_indicator_led(int red, int green) { int bus; /* See above */ bus = da9063_claim_i2c_bus(); da9063_set_gpio(PMIC_LED0, red | green); da9063_release_i2c_bus(bus); } static void init_i2c(void) { i2c_set_bus_num(0); i2c_init(CONFIG_SYS_I2C_SPEED, CONFIG_SYS_I2C_SLAVE); i2c_set_bus_num(2); 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; } if (bd_get_context(&bdctx[2], BD_EEPROM_ADDR, PARTITION_ADDRESS) != 0) { printf("%s() no valid partition table found\n", __func__); return -1; } 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(); } #ifndef CONFIG_SKIP_LOWLEVEL_INIT // TODO: Double check training values. See /* \\netmodule.intranet\nm\projects\NM-Router\9100098_NRHW_24_NB800_Facelift\06_sw_engineering\DDR3_Testing_Calibration */ static const struct ddr_data ddr3_data = { /* Ratios were optimized by DDR3 training software from TI */ .datardsratio0 = 0x39, /* 0x39 */ .datawdsratio0 = 0x3f, /* 0x40 */ /* 3f */ .datafwsratio0 = 0x98, /* 0x96 */ /* 98 */ .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 }; // TODO: Since there is no ignition logic (with edge generator) on hw25 // TODO: the following is not required #if 0 static void pmic_ignition_gate_on(void) { uint8_t val; /* 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_get_reg(PMIC_REG_CONTROL_D, &val); /* No blinking, state selected by GPIOxx_MODE */ val &= ~0xF8; (void)da9063_set_reg(PMIC_REG_CONTROL_D, val); (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); } #endif static void init_pmic_spl(void) { int bus; /* PMIC basic configuration */ da9063_init(CONFIG_PMIC_I2C_BUS); bus = da9063_claim_i2c_bus(); // TODO: Since there is no ignition logic (with edge generator) on hw25 // TODO: the following is not required // pmic_ignition_gate_on(); /* Enable charging of RTC backup capacitor (1mA, 3.1V) */ (void)da9063_set_reg(PMIC_REG_BBAT_CONT, 0xAF); da9063_release_i2c_bus(bus); } struct reset_registers { uint32_t value; uint32_t value_crc; }; #ifdef CONFIG_NRSW_BUILD /* TODO: Move ethernet crc to dedicated file */ static uint32_t ether_crc(size_t len, uint8_t const *p) { uint32_t crc; unsigned i; crc = ~0; while (len--) { crc ^= *p++; for (i = 0; i < 8; i++) crc = (crc >> 1) ^ ((crc & 1) ? 0xedb88320 : 0); } /* an reverse the bits, cuz of way they arrive -- last-first */ crc = (crc >> 16) | (crc << 16); crc = (crc >> 8 & 0x00ff00ff) | (crc << 8 & 0xff00ff00); crc = (crc >> 4 & 0x0f0f0f0f) | (crc << 4 & 0xf0f0f0f0); crc = (crc >> 2 & 0x33333333) | (crc << 2 & 0xcccccccc); crc = (crc >> 1 & 0x55555555) | (crc << 1 & 0xaaaaaaaa); return crc; } void check_pmic_reset_reason(unsigned int reset_reason_shm_location) { volatile struct reset_registers* reset_regs = (struct reset_registers*)reset_reason_shm_location; uint8_t state = 0x00; int bus; int ret; bus = da9063_claim_i2c_bus(); ret = da9063_get_reg(PMIC_REG_FAULT_LOG, &state); if ((ret == 0) && (state != 0)) { if (state & PMIC_FAULT_TWD_ERROR_MASK) { reset_regs->value = EXTERNAL_WATCHDOG_PATTERN; reset_regs->value_crc = ether_crc(sizeof(reset_regs->value), (const uint8_t*)&(reset_regs->value)); } /* clear pmic fault log by writing back all bits currently set */ da9063_set_reg(PMIC_REG_FAULT_LOG, state); } da9063_release_i2c_bus(bus); } #endif static void init_bd_spl(void) { hw_type = 25; /* Assume hw25, unless BD tells different */ if (read_eeprom() >= 0) { int hw_type_from_bd = -1; /* 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(); /* Setup PMIC */ init_pmic_spl(); init_leds(); #ifndef CONFIG_NRSW_BUILD set_status_led(1, 0); /* Red */ 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); #ifdef CONFIG_NRSW_BUILD check_pmic_reset_reason(RESET_REASON_SHM_LOCATION); #endif /* 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(); } 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 = 100us (SMSC8720) */ mdelay(1); gpio_set_value(GPIO_RST_ETH_N, 1); /* Give clocks time to stabilize */ mdelay(1); } static void init_sim_mux(void) { /* * Switch pluggable micro SIM to onboard modem (mux = 0) */ REQUEST_AND_CLEAR_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 } #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); /* Let user know we're starting */ // TODO: Check LED behaviour init_leds(); set_status_led(1, 1); /* Orange */ set_indicator_led(0, 0); /* Off */ printf("OSC: %lu MHz\n", get_osclk()/1000000); return 0; } #if !defined(CONFIG_SPL_BUILD) /* * Set Linux console based on * - Selection in /root/boot/consoledev * - Available tty interfaces * - ttyS0: standard console (default, internal only) * - ttyS5: RS232/RS485 * - ttyNull0: Dummy device if no real UART is available */ void set_console(void) { const char *defaultconsole = getenv("defaultconsole"); /* Set default console to ttyS0 if not yet defined in env */ if (defaultconsole == 0) { setenv("defaultconsole", "ttyS0"); } serial_set_console_index(1); #if defined(CONFIG_PRE_CONSOLE_BUFFER) serial_init(); /* serial communications setup */ console_init_f(); /* stage 1 init of console */ #endif } 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-hw25-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); } static void get_variant_name(void) { bd_get_variantname(hw_variant_name, sizeof(hw_variant_name)); printf("SYS: %s\n", hw_variant_name); } static void get_hw_version(void) { #ifdef CONFIG_NRSW_BUILD char hw_versions[16]; char new_env[256]; /* current bootargs = 84 bytes */ #endif 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 HW25 if tag is not present */ hw_type = 25; } printf("HW%02d: V%d.%d\n", hw_type, hw_ver, hw_rev); #ifdef CONFIG_NRSW_BUILD /* 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); #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); 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 */ /* Assumes status led on, indicator off */ set_status_led(0, 0); while (pulses) { udelay(pulse_width); set_status_led(1, 1); set_indicator_led(1, 1); udelay(pulse_width); set_status_led(0, 0); set_indicator_led(0, 0); pulses--; } udelay(pulse_width); set_status_led(1, 1); /* Orange */ } // TODO: Double check against specification, TC Router static void check_reset_button(void) { int counter = 0; /* Check how long button is pressed */ do { if (!get_button_state()) break; udelay(100*1000); /* 100ms */ counter += 100; if (counter == 2000) { /* Indicate factory reset threshold */ blink_led(1); } else if (counter == 12000) { /* Indicate recovery boot threshold */ blink_led(2); } } while (counter < 12000); if (counter < 2000) { /* Don't do anything for duration < 2s */ } else if (counter < 12000) { /* Do factory reset for duration between 2s and 12s */ char new_bootargs[512]; char *bootargs = getenv("bootargs"); if (bootargs == 0) bootargs = ""; puts("Do factory reset during boot...\n"); strncpy(new_bootargs, bootargs, sizeof(new_bootargs)); strncat(new_bootargs, " factory-reset", sizeof(new_bootargs)); setenv("bootargs", new_bootargs); } else { /* Boot into recovery for duration > 12s */ puts("Booting recovery image...\n"); /* TODO: ... internal .. port on HW25 */ /* Set consoledev to external port */ setenv("defaultconsole", "ttyS1"); /* Set bootcmd to run recovery */ setenv("bootcmd", "run recovery"); } } #endif /* !defined(CONFIG_SPL_BUILD) */ int board_late_init(void) { #if !defined(CONFIG_SPL_BUILD) if (read_eeprom() < 0) { puts("Could not get board ID.\n"); } get_variant_name(); get_hw_version(); get_pmic_version(); set_root_partition(); set_devicetree_name(); /* Initialize pins */ REQUEST_AND_CLEAR_GPIO(GPIO_WLAN_EN); init_ethernet(); init_sim_mux(); init_gsm(); /* * Check if a user action is requested * - Short press: factory reset * - Long press: recovery boot */ check_reset_button(); set_console(); 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_addr = 1 }, { .slave_reg_ofs = 0x308, .sliver_reg_ofs = 0xdc0, .phy_addr = 0, }, }; 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"); } } /* 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 rv, n = 0; uint8_t mac_addr0[6] = {02,00,00,00,00,01}; uint8_t mac_addr1[6] = {02,00,00,00,00,02}; __maybe_unused struct ti_am_eeprom *header; #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); bd_get_mac(1, mac_addr1, sizeof(mac_addr1)); set_mac_address(1, mac_addr1); writel(RMII_MODE_ENABLE | RMII_CHIPCKL_ENABLE, &cdev->miisel); cpsw_slaves[0].phy_if = PHY_INTERFACE_MODE_RMII; cpsw_slaves[1].phy_if = PHY_INTERFACE_MODE_RMII; cpsw_slaves[0].phy_addr = 1; // TODO: Check why this override is required cpsw_slaves[1].phy_addr = 0; 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); } { rv = usb_eth_initialize(bis); if (rv < 0) { printf("Error %d registering USB_ETHER\n", rv); } else { n += rv; } } #endif 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) #if 0 static void ft_enable_node(void* blob, const char* name) { int node_ofs = -1; node_ofs = fdt_path_offset(blob, name); 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 == -1) { 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; i 120) { temp_in_degs = 120; } printf("WARNING: Overriding CPU thermal alert to %d°C, critical to 125°C\n", temp_in_degs); node_ofs = fdt_path_offset(blob, "/thermal-zones/cpu-thermal/trips/cpu-alert0"); if (node_ofs >= 0) { fdt_setprop_inplace_u32(blob, node_ofs, "temperature", temp_in_degs*1000); } node_ofs = fdt_path_offset(blob, "/thermal-zones/cpu-thermal/trips/cpu-crit"); if (node_ofs >= 0) { fdt_setprop_inplace_u32(blob, node_ofs, "temperature", 125*1000); } } } #endif int ft_board_setup(void *blob, bd_t *bd) { ft_bootloader_version(blob); ft_hw_info(blob); /* ft_override_thermal(blob); */ return 0; } #endif /* defined(CONFIG_OF_BOARD_SETUP) && !defined(CONFIG_SPL_BUILD) */