diff --git a/arch/arm/Kconfig b/arch/arm/Kconfig index a99e7c6a81..aa3d37afb1 100644 --- a/arch/arm/Kconfig +++ b/arch/arm/Kconfig @@ -414,6 +414,14 @@ config TARGET_AM335X_NRHW24 select DM_SERIAL select DM_GPIO +config TARGET_AM335X_HW25 + bool "Support am335x_hw25" + select CPU_V7 + select SUPPORT_SPL + select DM + select DM_SERIAL + select DM_GPIO + config TARGET_AM335X_SL50 bool "Support am335x_sl50" select CPU_V7 @@ -915,6 +923,7 @@ source "board/nm/nrhw20/Kconfig" source "board/nm/nmhw21/Kconfig" source "board/nm/nrhw22/Kconfig" source "board/nm/nrhw24/Kconfig" +source "board/nm/hw25/Kconfig" source "board/olimex/mx23_olinuxino/Kconfig" source "board/phytec/pcm051/Kconfig" source "board/phytec/pcm052/Kconfig" diff --git a/board/nm/hw25/Kconfig b/board/nm/hw25/Kconfig new file mode 100644 index 0000000000..b4faa24e28 --- /dev/null +++ b/board/nm/hw25/Kconfig @@ -0,0 +1,26 @@ +if TARGET_AM335X_HW25 + +config SYS_BOARD + default "hw25" + +config SYS_VENDOR + default "nm" + +config SYS_SOC + default "am33xx" + +config SYS_CONFIG_NAME + default "am335x_hw25" + +config CONS_INDEX + int "UART used for console" + range 1 6 + default 1 + help + The AM335x SoC has a total of 6 UARTs (UART0 to UART5 as referenced + in documentation, etc) available to it. Depending on your specific + board you may want something other than UART0 as for example the IDK + uses UART3 so enter 4 here. + +endif + diff --git a/board/nm/hw25/Makefile b/board/nm/hw25/Makefile new file mode 100644 index 0000000000..813f0b8103 --- /dev/null +++ b/board/nm/hw25/Makefile @@ -0,0 +1,13 @@ +# +# Makefile +# +# Copyright (C) 2011 Texas Instruments Incorporated - http://www.ti.com/ +# +# SPDX-License-Identifier: GPL-2.0+ +# + +ifeq ($(CONFIG_SKIP_LOWLEVEL_INIT),) +obj-y := mux.o +endif + +obj-y += board.o ../common/bdparser.o ../common/board_descriptor.o ../common/da9063.o shield.o shield_can.o shield_comio.o fileaccess.o diff --git a/board/nm/hw25/board.c b/board/nm/hw25/board.c new file mode 100644 index 0000000000..96008be985 --- /dev/null +++ b/board/nm/hw25/board.c @@ -0,0 +1,1350 @@ +/* + * board.c + * + * Board functions for Netmodule NRHW 24, 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 "shield.h" +#include "shield_can.h" +#include "shield_comio.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 + * + * (A17) GPIO0_2: RST_GNSS~ + * (A16) GPIO0_5: EXTINT_GNSS + * (C15) GPIO0_6: TIMEPULSE_GNSS + * + * (J18) GPIO0_16: RST_PHY~ + * (U12) GPIO0_27: RST_SHIELD~ + * + * (R14) GPIO1_20: BT_EN + * (V15) GPIO1_21: GSM_PWR_EN + * (U16) GPIO1_25: RST_GSM + * (T16) GPIO1_26: WLAN_EN + * (V17) GPIO1_27: WLAN_IRQ + * + * (C12) GPIO3_17: SIM_SEL + */ + +#define GPIO_TO_PIN(bank, gpio) (32 * (bank) + (gpio)) + +#define GPIO_RST_GSM GPIO_TO_PIN(1, 25) +#define GPIO_PWR_GSM GPIO_TO_PIN(1, 21) + +#define GPIO_WLAN_EN GPIO_TO_PIN(1, 26) +#define GPIO_BT_EN GPIO_TO_PIN(1, 20) +#define GPIO_RST_GNSS GPIO_TO_PIN(0, 2) + +#define GPIO_RST_ETH_N GPIO_TO_PIN(0, 16) + +#define GPIO_SIM_SEL GPIO_TO_PIN(3, 17) + +/* + * PMIC GPIOs + * + * GPIO_7: EN_SUPPLY_GSM + * GPIO_8: EN_SUPPLY_WIFI + * GPIO_10: LED.LWR + * GPIO_11: LED.UPR + */ + +#define PMIC_GSM_SUPPLY_EN_IO 7 +#define PMIC_WIFI_SUPPLY_EN_IO 8 +#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 char hw_variant_name[64]; +#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 */ +} + +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(); +} + +/* + * Selects console for SPL. + * U-Boot console is selected in set_console() + */ +struct serial_device *default_serial_console(void) +{ + /* + * Mux pins for selected UART properly. + * Note: UART indexes start at 0 while eserial indexes start at 1. + * + * Provide console on internal UART1 regardless of boot mode. + * This only has a side effect when using X-Modem boot + */ + if (spl_boot_device() == BOOT_DEVICE_UART) { + /* Continue booting from UART in case of serial (xmodem) boot */ + enable_uart0_pin_mux(); + return &eserial1_device; + } else { + /* Regular and JTAG boot use internal UART1 */ + enable_uart1_pin_mux(); + return &eserial2_device; + } +} + +#ifndef CONFIG_SKIP_LOWLEVEL_INIT + +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 +}; + +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); +} + +static void init_pmic_spl(void) +{ + int bus; + + /* PMIC basic configuration */ + da9063_init(CONFIG_PMIC_I2C_BUS); + + bus = da9063_claim_i2c_bus(); + + /* Enable +3V3_GNSS (LDO6) */ + (void)da9063_set_reg(PMIC_REG_LDO6_CONT, PMIC_LDOx_EN_MASK); + mdelay(2); + + 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 + +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(); + + /* 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(); + enable_uart1_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 +} + +static void init_gnss(void) +{ + /* + * Release GNSS reset line, so that module starts up early + */ + REQUEST_AND_SET_GPIO(GPIO_RST_GNSS); +} + +/* TODO: Double Check - WiFi is enabled by sequencer already */ +static void init_wifi(void) +{ + int bus; + + /* Enable WiFi power supply */ + bus = da9063_claim_i2c_bus(); + da9063_set_gpio(PMIC_WIFI_SUPPLY_EN_IO, 1); + da9063_release_i2c_bus(bus); +} + +#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 */ + 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 + * - ttyS1: standard console (default, internal only) + * - ttyS0: COM/IO shield (or used as console by kernel, + * when no other console available) + * - ttyNull0: Dummy device if no real UART is available + */ +void set_console(void) +{ + const char *defaultconsole = getenv("defaultconsole"); + int shield_id = bd_get_shield(0); + + /* Set default console to ttyS1 if not yet defined in env */ + if (defaultconsole == 0) { + setenv("defaultconsole", "ttyS1"); + } + + /* + * Always use internal console for u-boot + * as COM/IO shield is not ready at that time. + * (Needs to be initialized first using the + * shieldcmd that is run by bootcmd.) + */ + 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 + + if (shield_id == SHIELD_COM_IO) { + char buf[20]; + + /* + * With COM/IO shield the defaultconsole for the kernel should + * be ttyS0 (external port). + * If consoledev file is present, take the tty defined in it as console + */ + setenv("defaultconsole", "ttyS0"); + + if (read_file("/root/boot/consoledev", buf, sizeof(buf)) > 3) { + if (strstr(buf, "tty") == buf) { + int i; + /* TODO: What is this code doing? */ + /* Truncating after whitespace? */ + /* are there broken consoledev files around ? */ + buf[sizeof(buf)-1] = 0; + for (i=0; i 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); + + printf("HW25: V%d.%d\n", 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); +} + + +struct shield_command { + int shield_id; + const char *name; + const char *default_shieldcmd; + void (*init)(void); +}; + +static struct shield_command known_shield_commands[] = { + { + SHIELD_COM_IO, + "comio", + "shield comio mode rs232", + comio_shield_init + }, + { + SHIELD_DUALCAN, + "dualcan", + "shield dualcan termination off off", + can_shield_init + }, + { + SHIELD_DUALCAN_PASSIVE, + "dualcan-passive", + "shield dualcan-passive", + can_shield_passive_init + } +}; + +static const struct shield_command* get_shield_command(int shield_id) +{ + int i; + + for (i = 0; i < ARRAY_SIZE(known_shield_commands); i++) { + if (known_shield_commands[i].shield_id == shield_id) { + return &known_shield_commands[i]; + } + } + + return NULL; +} + +static void shield_config(void) +{ +#define MAX_SHIELD_CMD_LEN 128 + + char shieldcmd_linux[MAX_SHIELD_CMD_LEN]; + const char *shieldcmd = ";"; /* default shield command is empty */ + const struct shield_command *cmd; + int len; + + int shield_id = bd_get_shield(0); + if (shield_id < 0) { + debug("No shield found in bd\n"); + goto end; + } + + cmd = get_shield_command(shield_id); + if (cmd == NULL) { + printf ("Unknown shield id %d\n", shield_id); + goto end; + } + + printf("Shield:%s\n", cmd->name); + + cmd->init(); + shieldcmd = cmd->default_shieldcmd; + + /* If a shield configuration is set by Linux, take it without bd check. + * We asume that Linux knows what to do. + */ + len = read_file("/root/boot/shieldcmd", shieldcmd_linux, MAX_SHIELD_CMD_LEN); + if (len > 0) { + debug("Shield command found in file, using it\n"); + shieldcmd = shieldcmd_linux; + } + +end: + setenv("shieldcmd", shieldcmd); +} + +static void shield_init(void) +{ + shield_config(); +} + +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 */ +} + +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); + REQUEST_AND_CLEAR_GPIO(GPIO_BT_EN); + + init_ethernet(); + init_sim_mux(); + init_gsm(); + init_gnss(); + init_wifi(); + + /* + * Check if a user action is requested + * - Short press: factory reset + * - Long press: recovery boot + */ + check_reset_button(); + + set_console(); + shield_init(); + + 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 = 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 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 + + 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); + 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); + } + } +} + +int ft_board_setup(void *blob, bd_t *bd) +{ + ft_bootloader_version(blob); + ft_hw_info(blob); + + ft_shields(blob); + + + ft_override_thermal(blob); + + return 0; +} + +#endif /* defined(CONFIG_OF_BOARD_SETUP) && !defined(CONFIG_SPL_BUILD) */ diff --git a/board/nm/hw25/board.h b/board/nm/hw25/board.h new file mode 100644 index 0000000000..ba3a2feca3 --- /dev/null +++ b/board/nm/hw25/board.h @@ -0,0 +1,28 @@ +/* + * board.h + * + * TI AM335x boards information header + * + * Copyright (C) 2011, Texas Instruments, Incorporated - http://www.ti.com/ + * + * SPDX-License-Identifier: GPL-2.0+ + */ + +#ifndef _BOARD_H_ +#define _BOARD_H_ + +/* + * We have three pin mux functions that must exist. We must be able to enable + * uart0, for initial output and i2c2 to read the main EEPROM. We then have a + * main pinmux function that can be overridden to enable all other pinmux that + * is required on the board. + */ +void enable_uart0_pin_mux(void); +void disable_uart0_pin_mux(void); +void enable_uart1_pin_mux(void); + +void enable_board_pin_mux(void); + +#define GPIO_TO_PIN(bank, gpio) (32 * (bank) + (gpio)) + +#endif diff --git a/board/nm/hw25/fileaccess.c b/board/nm/hw25/fileaccess.c new file mode 100644 index 0000000000..f296704637 --- /dev/null +++ b/board/nm/hw25/fileaccess.c @@ -0,0 +1,40 @@ +#include +#include + +#define BLOCK_DEVICE "mmc" +#define OVERLAY_PART "1:3" + +int read_file(const char* filename, char *buf, int size) +{ + loff_t filesize = 0; + loff_t len; + int ret; + + if (fs_set_blk_dev(BLOCK_DEVICE, OVERLAY_PART, FS_TYPE_EXT) != 0) { + puts("Error, can not set blk device\n"); + return -1; + } + + /* Read at most file size bytes */ + if (fs_size(filename, &filesize)) { + return -1; + } + + if (filesize < size) + size = filesize; + + /* For very unclear reasons the block device needs to be set again after the call to fs_size() */ + if (fs_set_blk_dev(BLOCK_DEVICE, OVERLAY_PART, FS_TYPE_EXT) != 0) { + puts("Error, can not set blk device\n"); + return -1; + } + + if ((ret = fs_read(filename, (ulong)buf, 0, size, &len))) { + printf("Can't read file %s (size %d, len %lld, ret %d)\n", filename, size, len, ret); + return -1; + } + + buf[len] = 0; + + return len; +} diff --git a/board/nm/hw25/fileaccess.h b/board/nm/hw25/fileaccess.h new file mode 100644 index 0000000000..00bbaaea04 --- /dev/null +++ b/board/nm/hw25/fileaccess.h @@ -0,0 +1,14 @@ +/**@file /home/eichenberger/projects/nbhw16/u-boot/board/nm/netbird_v2/fileaccess.h + * @author eichenberger + * @version 704 + * @date + * Created: Tue 06 Jun 2017 02:02:33 PM CEST \n + * Last Update: Tue 06 Jun 2017 02:02:33 PM CEST + */ +#ifndef FILEACCESS_H +#define FILEACCESS_H + +void fs_set_console(void); +int read_file(const char* filename, char *buf, int size); + +#endif // FILEACCESS_H diff --git a/board/nm/hw25/mux.c b/board/nm/hw25/mux.c new file mode 100644 index 0000000000..ef1bb6760d --- /dev/null +++ b/board/nm/hw25/mux.c @@ -0,0 +1,233 @@ +/* + * mux.c + * + * Copyright (C) 2018-2019 NetModule AG - http://www.netmodule.com/ + * Copyright (C) 2011 Texas Instruments Incorporated - http://www.ti.com/ + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation version 2. + * + * This program is distributed "as is" WITHOUT ANY WARRANTY of any + * kind, whether express or implied; without even the implied warranty + * of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + */ + +#include +#include +#include +#include +#include +#include "board.h" + +static struct module_pin_mux gpio_pin_mux[] = { + /* + * CPU GPIOs + * + * (A17) GPIO0_2: RST_GNSS~ + * (A16) GPIO0_5: EXTINT_GNSS + * (C15) GPIO0_6: TIMEPULSE + * (C18) GPIO0_7: PWM / SHIELD LATCH + * (J18) GPIO0_16: RST_PHY~ + * (U12) GPIO0_27: RST_SHIELD~ + * + * (R14) GPIO1_20: BT_EN + * (V15) GPIO1_21: GSM_PWR_EN + * (U16) GPIO1_25: RST_GSM + * (T16) GPIO1_26: WLAN_EN + * (V17) GPIO1_27: WLAN_IRQ + * + * (C12) GPIO3_17: SIM_SEL + */ + + /* Bank 0 */ + {OFFSET(spi0_sclk), (MODE(7) | PULLUDDIS)}, /* (A17) gpio0[2] */ /* RST_GNSS */ + {OFFSET(spi0_cs0), (MODE(7) | PULLUDEN | PULLDOWN_EN)}, /* (A16) gpio0[5] */ /* EXTINT_GNSS */ + {OFFSET(spi0_cs1), (MODE(7) | PULLUDEN | PULLUP_EN | RXACTIVE)}, /* (C15) gpio0[6] */ /* TIMEPULSE */ + {OFFSET(ecap0_in_pwm0_out), (MODE(7) | PULLUDEN | PULLUP_EN)}, /* (C18) gpio0[7] */ /* IO_SHIELD */ + {OFFSET(mii1_txd3), (MODE(7) | PULLUDDIS)}, /* (J18) gpio0[16] */ /* RST_PHY~ */ + {OFFSET(gpmc_ad11), (MODE(7) | PULLUDDIS)}, /* (U12) gpio0[27] */ /* RST_SHIELD~ */ + + /* Bank 1 */ + {OFFSET(gpmc_a4), (MODE(7) | PULLUDDIS)}, /* (R14) gpio1[20] */ /* BT_EN */ + {OFFSET(gpmc_a5), (MODE(7) | PULLUDDIS)}, /* (V15) gpio1[21] */ /* GSM_PWR_EN */ + {OFFSET(gpmc_a9), (MODE(7) | PULLUDDIS)}, /* (U16) gpio1[25] */ /* RST_GSM */ + {OFFSET(gpmc_a10), (MODE(7) | PULLUDDIS)}, /* (T16) gpio1[26] */ /* WLAN_EN */ + {OFFSET(gpmc_a11), (MODE(7) | PULLUDDIS | RXACTIVE)}, /* (V17) gpio1[27] */ /* WLAN_IRQ */ + + /* TODO: What about all the unused GPMC pins ? */ + + /* Bank 2 */ +#if 0 + /* TODO: What is this meant for? */ + {OFFSET(lcd_data3), (MODE(7) | PULLUDEN | PULLUP_EN)}, /* (R4) gpio2[9] */ /* SYSBOOT_3 */ + {OFFSET(lcd_data4), (MODE(7) | PULLUDEN | PULLUP_EN)}, /* (T1) gpio2[10] */ /* SYSBOOT_4 */ + + /* TODO: Check other unued pins from sysboot block */ + /* Ensure PU/PD does not work against external signal */ + /* + * SYSBOOT 0,1,5,12,13 = Low + * SYSBOOT 2 = High + */ +#endif + + /* Bank 3 */ + {OFFSET(mcasp0_ahclkr), (MODE(7) | PULLUDEN | PULLDOWN_EN)}, /* (C12) gpio3[17] */ /* SIM_SEL */ + {-1} +}; + +/* I2C0 PMIC */ +static struct module_pin_mux i2c0_pin_mux[] = { + {OFFSET(i2c0_sda), (MODE(0) | RXACTIVE | PULLUDEN | PULLUP_EN | SLEWCTRL)}, /* (C17) I2C0_SDA */ + {OFFSET(i2c0_scl), (MODE(0) | RXACTIVE | PULLUDEN | PULLUP_EN | SLEWCTRL)}, /* (C16) I2C0_SCL */ + {-1} +}; + +/* I2C2 System */ +static struct module_pin_mux i2c2_pin_mux[] = { + {OFFSET(uart1_rtsn), (MODE(3) | RXACTIVE | PULLUDEN | PULLUP_EN | SLEWCTRL)}, /* (D17) I2C2_SCL */ + {OFFSET(uart1_ctsn), (MODE(3) | RXACTIVE | PULLUDEN | PULLUP_EN | SLEWCTRL)}, /* (D18) I2C2_SDA */ + {-1}, +}; + +/* RMII1: Ethernet */ +static struct module_pin_mux rmii1_pin_mux[] = { + /* RMII */ + {OFFSET(mii1_crs), MODE(1) | PULLUDDIS | RXACTIVE}, /* (H17) rmii1_crs */ + {OFFSET(mii1_rxerr), MODE(7) | PULLUDEN | PULLDOWN_EN | RXACTIVE}, /* (J15) gpio */ + {OFFSET(mii1_rxd0), MODE(1) | PULLUDDIS | RXACTIVE}, /* (M16) rmii1_rxd0 */ + {OFFSET(mii1_rxd1), MODE(1) | PULLUDDIS | RXACTIVE}, /* (L15) rmii1_rxd1 */ + {OFFSET(mii1_txen), MODE(1) | PULLUDDIS}, /* (J16) rmii1_txen */ + {OFFSET(mii1_txd0), MODE(1) | PULLUDDIS}, /* (K17) rmii1_txd0 */ + {OFFSET(mii1_txd1), MODE(1) | PULLUDDIS}, /* (K16) rmii1_txd1 */ + {OFFSET(rmii1_refclk), MODE(0) | PULLUDDIS | RXACTIVE}, /* (H18) rmii1_refclk */ + + /* SMI */ + {OFFSET(mdio_clk), MODE(0) | PULLUDDIS}, /* (M18) mdio_clk */ + {OFFSET(mdio_data), MODE(0) | PULLUDEN | PULLUP_EN | RXACTIVE}, /* (M17) mdio_data */ + + /* 25MHz Clock Output */ + {OFFSET(xdma_event_intr0), MODE(3)}, /* (A15) clkout1 (25 MHz clk for PHY) */ + {-1} +}; + +/* MMC0: WiFi */ +static struct module_pin_mux mmc0_sdio_pin_mux[] = { + {OFFSET(mmc0_clk), (MODE(0) | PULLUDEN | PULLUP_EN | RXACTIVE)}, /* (G17) MMC0_CLK */ + {OFFSET(mmc0_cmd), (MODE(0) | PULLUDEN | PULLUP_EN | RXACTIVE)}, /* (G18) MMC0_CMD */ + {OFFSET(mmc0_dat0), (MODE(0) | PULLUDEN | PULLUP_EN | RXACTIVE)}, /* (G16) MMC0_DAT0 */ + {OFFSET(mmc0_dat1), (MODE(0) | PULLUDEN | PULLUP_EN | RXACTIVE)}, /* (G15) MMC0_DAT1 */ + {OFFSET(mmc0_dat2), (MODE(0) | PULLUDEN | PULLUP_EN | RXACTIVE)}, /* (F18) MMC0_DAT2 */ + {OFFSET(mmc0_dat3), (MODE(0) | PULLUDEN | PULLUP_EN | RXACTIVE)}, /* (F17) MMC0_DAT3 */ + {-1} +}; + +/* MMC1: eMMC */ +static struct module_pin_mux mmc1_emmc_pin_mux[] = { + {OFFSET(gpmc_csn1), (MODE(2) | PULLUDEN | PULLUP_EN | RXACTIVE)}, /* (U9) MMC1_CLK */ + {OFFSET(gpmc_csn2), (MODE(2) | PULLUDEN | PULLUP_EN | RXACTIVE)}, /* (V9) MMC1_CMD */ + {OFFSET(gpmc_ad0), (MODE(1) | PULLUDEN | PULLUP_EN | RXACTIVE)}, /* (U7) MMC1_DAT0 */ + {OFFSET(gpmc_ad1), (MODE(1) | PULLUDEN | PULLUP_EN | RXACTIVE)}, /* (V7) MMC1_DAT1 */ + {OFFSET(gpmc_ad2), (MODE(1) | PULLUDEN | PULLUP_EN | RXACTIVE)}, /* (R8) MMC1_DAT2 */ + {OFFSET(gpmc_ad3), (MODE(1) | PULLUDEN | PULLUP_EN | RXACTIVE)}, /* (T8) MMC1_DAT3 */ + {OFFSET(gpmc_ad4), (MODE(1) | PULLUDEN | PULLUP_EN | RXACTIVE)}, /* (U8) MMC1_DAT4 */ + {OFFSET(gpmc_ad5), (MODE(1) | PULLUDEN | PULLUP_EN | RXACTIVE)}, /* (V8) MMC1_DAT5 */ + {OFFSET(gpmc_ad6), (MODE(1) | PULLUDEN | PULLUP_EN | RXACTIVE)}, /* (R9) MMC1_DAT6 */ + {OFFSET(gpmc_ad7), (MODE(1) | PULLUDEN | PULLUP_EN | RXACTIVE)}, /* (T9) MMC1_DAT7 */ + {-1} +}; + +/* USB_DRVBUS not used -> configure as GPIO */ +static struct module_pin_mux usb_pin_mux[] = { + {OFFSET(usb0_drvvbus), (MODE(7) | PULLUDDIS)}, /* (F16) USB0_DRVVBUS */ + {OFFSET(usb1_drvvbus), (MODE(7) | PULLUDDIS)}, /* (F15) USB1_DRVVBUS */ + {-1} +}; + +/* UART0: RS232/RS485 shield mode */ +static struct module_pin_mux uart0_pin_mux[] = { + {OFFSET(uart0_rxd), (MODE(0) | PULLUDEN | PULLUP_EN | RXACTIVE)}, /* (E15) UART0_RXD */ + {OFFSET(uart0_txd), (MODE(0) | PULLUDEN | PULLUP_EN | SLEWCTRL)}, /* (E16) UART0_TXD */ + {-1}, +}; + +/* UART0: Shield I/F (UART, CAN) */ +/* Leave UART0 unconfigured because we want to configure it as needed by Linux (can/spi/uart/etc) */ +/* Mode 7 = GPIO */ +static struct module_pin_mux uart0_disabled_pin_mux[] = { + {OFFSET(uart0_rxd), (MODE(7) | PULLUDDIS | RXACTIVE)}, /* (E15) GPIO1_10 */ + {OFFSET(uart0_txd), (MODE(7) | PULLUDDIS | RXACTIVE)}, /* (E16) GPIO1_11 */ + {OFFSET(uart0_ctsn), (MODE(7) | PULLUDDIS | RXACTIVE)}, /* (E18) GPIO1_8 */ + {OFFSET(uart0_rtsn), (MODE(7) | PULLUDEN | PULLUP_EN)}, /* (E17) GPIO1_9 */ + {-1}, +}; + +/* UART1: User (Debug/Console) */ +static struct module_pin_mux uart1_pin_mux[] = { + {OFFSET(uart1_rxd), (MODE(0) | PULLUDEN | PULLUP_EN | RXACTIVE)}, /* (D16) uart1_rxd */ + {OFFSET(uart1_txd), (MODE(0) | PULLUDEN | PULLUP_EN | SLEWCTRL)}, /* (D15) uart1_txd */ + {-1}, +}; + +/* UART3: GNSS */ +static struct module_pin_mux uart3_pin_mux[] = { + {OFFSET(mii1_rxd3), (MODE(1) | PULLUDEN | PULLUP_EN | RXACTIVE)}, /* (L17) UART3_RXD */ + {OFFSET(mii1_rxd2), (MODE(1) | PULLUDEN | PULLUP_EN | SLEWCTRL)}, /* (L16) UART3_TXD */ + {-1} +}; + +/* UART5: Highspeed UART for Bluetooth (no SLEWCTRL) */ +static struct module_pin_mux uart5_pin_mux[] = { + {OFFSET(lcd_data9), (MODE(4) | PULLUDEN | PULLUP_EN | RXACTIVE)}, /* (U2) UART5_RXD */ + {OFFSET(lcd_data8), (MODE(4) | PULLUDEN | PULLUP_EN)}, /* (U1) UART5_TXD */ + {OFFSET(lcd_data14), (MODE(6) | PULLUDEN | PULLUP_EN | RXACTIVE)}, /* (V4) uart5_ctsn */ + {OFFSET(lcd_data15), (MODE(6) | PULLUDEN | PULLUP_EN)}, /* (T5) uart5_rtsn */ + {-1} +}; + +static struct module_pin_mux unused_pin_mux[] = { + /* SYSBOOT6, 7, 10, 11: Not used pulldown active, receiver disabled */ + {OFFSET(lcd_data6), (MODE(7) | PULLUDEN | PULLDOWN_EN)}, + {OFFSET(lcd_data7), (MODE(7) | PULLUDEN | PULLDOWN_EN)}, + {OFFSET(lcd_data10), (MODE(7) | PULLUDEN | PULLDOWN_EN)}, + {OFFSET(lcd_data11), (MODE(7) | PULLUDEN | PULLDOWN_EN)}, + + /* TODO: GPMCA1..3, A6..8 */ + + {-1} +}; + + +void enable_board_pin_mux(void) +{ + configure_module_pin_mux(gpio_pin_mux); + + configure_module_pin_mux(rmii1_pin_mux); + configure_module_pin_mux(mmc0_sdio_pin_mux); + configure_module_pin_mux(mmc1_emmc_pin_mux); + configure_module_pin_mux(usb_pin_mux); + + configure_module_pin_mux(i2c0_pin_mux); + configure_module_pin_mux(i2c2_pin_mux); + + configure_module_pin_mux(uart3_pin_mux); + configure_module_pin_mux(uart5_pin_mux); + + configure_module_pin_mux(unused_pin_mux); +} + +void enable_uart0_pin_mux(void) +{ + configure_module_pin_mux(uart0_pin_mux); +} + +void disable_uart0_pin_mux(void) +{ + configure_module_pin_mux(uart0_disabled_pin_mux); +} + +void enable_uart1_pin_mux(void) +{ + configure_module_pin_mux(uart1_pin_mux); +} diff --git a/board/nm/hw25/shield.c b/board/nm/hw25/shield.c new file mode 100644 index 0000000000..e25e905381 --- /dev/null +++ b/board/nm/hw25/shield.c @@ -0,0 +1,74 @@ +#undef DEBUG + +#include +#include +#include + +#include "shield.h" +#include "board.h" + +#define MAX_SHIELDS 16 + +static struct shield_t *shields[MAX_SHIELDS]; +static int shield_count = 0; + +/* Perhaps this function shouldn't leave in shields.c? */ +int shield_gpio_request_as_input(unsigned int gpio, const char *label) +{ + int ret; + + ret = gpio_request(gpio, label); + if ((ret < 0)) { + printf("Could not request shield slot %s gpio\n", label); + return -1; + } + + ret = gpio_direction_input(gpio); + if ((ret < 0)) { + printf("Could not configure shield slot %s gpio as input\n", label); + return -1; + } + + return 0; +} + +void shield_register(struct shield_t *shield) +{ + if (shield_count >= MAX_SHIELDS) { + printf("Max shield count reached (%d), please increment MAX_SHIELDS\n", MAX_SHIELDS); + return; + } + shields[shield_count++] = shield; +} + +int shield_set_mode(const char* shield_type, int argc, char * const argv[]) +{ + int i; + + for (i = 0; i < shield_count; i++) { + if (strcmp(shield_type, shields[i]->name) == 0) { + return shields[i]->setmode(argv, argc); + } + } + printf("## Error: No %s shield installed\n", shield_type); + /* Do not return error, to not show usage (request by rs) */ + return 0; +} + +static int do_shieldmode(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[]) +{ + if (argc < 2) { + return -1; + } + + return shield_set_mode(argv[1], argc - 2, &argv[2]); +} + +U_BOOT_CMD( + shield, 6, 1, do_shieldmode, + "Set the shield mode", + "dualcan termination [on|off] [on|off]\n" + "shield dualcan-passive\n" + "shield comio mode [rs232|rs485] termination [on|off]\n" +); + diff --git a/board/nm/hw25/shield.h b/board/nm/hw25/shield.h new file mode 100644 index 0000000000..bd748eedde --- /dev/null +++ b/board/nm/hw25/shield.h @@ -0,0 +1,26 @@ +/**@file /home/eichenberger/projects/nbhw16/u-boot/board/nm/netbird_v2/shield.h + * @author eichenberger + * @version 704 + * @date + * Created: Wed 31 May 2017 02:56:16 PM CEST \n + * Last Update: Wed 31 May 2017 02:56:16 PM CEST + */ +#ifndef SHIELD_H +#define SHIELD_H + +#define SHIELD_COM_IO 0 +#define SHIELD_DUALCAN 1 +#define SHIELD_CAN_GNSS 2 +#define SHIELD_DUALCAN_PASSIVE 3 + +struct shield_t{ + char name[64]; + int (*setmode)(char * const argv[], int argc); +}; + +int shield_setmode(int mode); +void shield_register(struct shield_t *shield); + +int shield_gpio_request_as_input(unsigned int gpio, const char *label); + +#endif // SHIELD_H diff --git a/board/nm/hw25/shield_can.c b/board/nm/hw25/shield_can.c new file mode 100644 index 0000000000..a1252fff7f --- /dev/null +++ b/board/nm/hw25/shield_can.c @@ -0,0 +1,214 @@ +#undef DEBUG + +#include +#include +#include + +#include "shield.h" +#include "board.h" + +#define CAN_PORTS 2 + +#define NETBIRD_GPIO_RST_SHIELD_N GPIO_TO_PIN(0, 27) +#define NETBIRD_GPIO_LATCH GPIO_TO_PIN(0, 7) +#define NETBIRD_GPIO_MODE_0 GPIO_TO_PIN(1, 10) +#define NETBIRD_GPIO_MODE_1 GPIO_TO_PIN(1, 8) + + +static int shield_slot_initialized = 0; + + +static struct module_pin_mux can_shield_netbird_pin_mux_config[] = { + /* Leave UART0 unconfigured because we want to configure it as needed by linux (can/spi/uart/etc) */ + {OFFSET(uart0_ctsn), (MODE(7) | PULLUDEN | PULLUP_EN)}, /* (E18) gpio1_8 */ /* Mode 0 */ + {OFFSET(uart0_rxd), (MODE(7) | PULLUDEN | PULLUP_EN)}, /* (E15) gpio1_10 */ /* Mode 1 */ + {OFFSET(ecap0_in_pwm0_out), (MODE(7) | PULLUDEN | PULLUP_EN)}, /* (C18) eCAP0_in_PWM0_out.gpio0[7] */ /* Latch EN */ + {-1}, +}; + +static struct module_pin_mux can_shield_netbird_pin_mux_final[] = { + {OFFSET(uart0_txd), (MODE(2) | PULLUDDIS | RXACTIVE)}, /* (E16) dcan0_rx */ + {OFFSET(uart0_rxd), (MODE(2) | PULLUDEN | PULLUP_EN)}, /* (E15) dcan0_tx */ + {OFFSET(uart0_rtsn), (MODE(2) | PULLUDDIS | RXACTIVE)}, /* (E17) dcan1_rx */ + {OFFSET(uart0_ctsn), (MODE(2) | PULLUDEN | PULLUP_EN)}, /* (E18) dcan1_tx */ + {-1}, +}; + + +static int request_gpios(void) +{ + int ret; + + debug("Shield configure gpios\n"); + ret = shield_gpio_request_as_input(NETBIRD_GPIO_RST_SHIELD_N, "shield-rst"); + if ((ret < 0)) + return -1; + ret = shield_gpio_request_as_input(NETBIRD_GPIO_LATCH, "shield-load"); + if ((ret < 0)) + return -1; + ret = shield_gpio_request_as_input(NETBIRD_GPIO_MODE_0, "shield-mode0"); + if ((ret < 0)) + return -1; + ret = shield_gpio_request_as_input(NETBIRD_GPIO_MODE_1, "shield-mode1"); + if ((ret < 0)) + return -1; + + shield_slot_initialized = 1; + return 0; +} + +static int configure_shieldmode(int mode) +{ + int ret; + + if (mode < 0 || mode > 3) { + debug("Invalid shield mode %d\n", mode); + return -1; + } + + debug("Shield type dualcan\n"); + debug ("Set shield mode to %d\n", mode); + + if (!shield_slot_initialized) { + if (request_gpios()) { + puts("Failed to request gpios\n"); + return -1; + } + } + + debug("Configure shield pin muxing for configuration\n"); + configure_module_pin_mux(can_shield_netbird_pin_mux_config); + + debug("Make sure shield module is in reset\n"); + ret = gpio_direction_output(NETBIRD_GPIO_RST_SHIELD_N, 0); + if (ret < 0) { + puts("Can not set shield-rst as output\n"); + return -1; + } + udelay(10); + + debug("Set latch to high\n"); + ret = gpio_direction_output(NETBIRD_GPIO_LATCH, 1); + if (ret < 0) { + puts("Can not set shield-load as output\n"); + return -1; + } + udelay(10); + + debug("Write mode to GPIOs\n"); + ret = gpio_direction_output(NETBIRD_GPIO_MODE_0, mode & 0x01); + if (ret < 0) { + puts("Can not set shield-mode0 as output\n"); + return -1; + } + ret = gpio_direction_output(NETBIRD_GPIO_MODE_1, mode & 0x02); + if (ret < 0) { + puts("Can not set shield-mode1 as output\n"); + return -1; + } + udelay(10); + + debug("Set latch to low\n"); + gpio_set_value(NETBIRD_GPIO_LATCH, 0); + udelay(10); + + debug("Set mode0 and mode1 to highz again\n"); + ret = gpio_direction_input(NETBIRD_GPIO_MODE_0); + if ((ret < 0)) { + puts("Could not configure shield slot mode0 gpio as input\n"); + return -1; + } + + ret = gpio_direction_input(NETBIRD_GPIO_MODE_1); + if ((ret < 0)) { + puts("Could not configure shield slot mode1 gpio as input\n"); + return -1; + } + udelay(10); + + debug("Take shield out of reset\n"); + gpio_set_value(NETBIRD_GPIO_RST_SHIELD_N, 1); + udelay(10); + + debug("Set final can shield muxing\n"); + configure_module_pin_mux(can_shield_netbird_pin_mux_final); + + return 0; + +} + +static int get_termination(const char* termination) +{ + if (strcmp("on", termination) == 0) { + return 1; + } + else if (strcmp("off", termination) == 0) { + return 0; + } + + debug ("Invalid termination mode %s (falling back to off)", termination); + return -1; +} + +static int get_mode_from_args(char * const argv[], int argc) +{ + int terminations[CAN_PORTS]; + int i; + + assert(argc == (CAN_PORTS + 1)); + + if (strcmp ("termination", argv[0])) { + debug("The only option for dualcan is terminations\n"); + return -1; + } + + for (i = 0; i < CAN_PORTS; i ++) { + terminations[i] = get_termination(argv[i + 1]); + if (terminations[i] < 0) { + return -1; + } + } + + /* Termination is inverse */ + /* TODO: Double check */ + return (!terminations[0] << 0) | (!terminations[1] << 1); +} + +static int set_shieldmode(char * const argv[], int argc) +{ + if (argc != 3) { + debug("Too few arguments for dualcan\n"); + return -1; + } + + return configure_shieldmode(get_mode_from_args(argv, argc)); +} + +static int no_options(char * const argv[], int argc) +{ + if (argc != 0) { + debug("Too many arguments\n"); + return -1; + } + + return 0; +} + + +static struct shield_t can_shield = { + "dualcan", set_shieldmode +}; + +void can_shield_init(void) +{ + shield_register(&can_shield); +} + +static struct shield_t can_shield_passive = { + "dualcan-passive", no_options +}; + +void can_shield_passive_init(void) +{ + shield_register(&can_shield_passive); +} diff --git a/board/nm/hw25/shield_can.h b/board/nm/hw25/shield_can.h new file mode 100644 index 0000000000..56d8251e36 --- /dev/null +++ b/board/nm/hw25/shield_can.h @@ -0,0 +1,10 @@ +#ifndef SHIELD_CAN_H +#define SHIELD_CAN_H + +int shield_can_init(void); +int shield_can_setmode(int mode); + +void can_shield_init(void); +void can_shield_passive_init(void); + +#endif // SHIELD_CAN_H diff --git a/board/nm/hw25/shield_comio.c b/board/nm/hw25/shield_comio.c new file mode 100644 index 0000000000..f43e992349 --- /dev/null +++ b/board/nm/hw25/shield_comio.c @@ -0,0 +1,252 @@ +#undef DEBUG + +#include +#include +#include + +#include "shield.h" +#include "board.h" + +/* TODO: Double Check */ +#define NETBIRD_GPIO_RST_SHIELD_N GPIO_TO_PIN(0, 27) +#define NETBIRD_GPIO_LOAD GPIO_TO_PIN(1, 9) +/* TODO: Who configures UART0_RTSn, GPIO1_9 ? */ +#define NETBIRD_GPIO_MODE_0 GPIO_TO_PIN(1, 11) +#define NETBIRD_GPIO_MODE_1 GPIO_TO_PIN(1, 10) + +static int shield_slot_initialized = 0; + + +/* TODO: Naming -> config, final */ +static struct module_pin_mux shield_gpio_netbird_pin_mux[] = { + {OFFSET(uart0_rxd), (MODE(7) | PULLUDDIS)}, /* (E15) gpio1_10 */ /* Mode 0 */ + {OFFSET(uart0_txd), (MODE(7) | PULLUDEN | PULLUP_EN)}, /* (E16) gpio1_11 */ /* Mode 1 */ + {-1}, +}; + +static struct module_pin_mux shield_gpio_safe_netbird_pin_mux[] = { + /* Leave UART0 unconfigured (GPIO) because we want to configure it as needed by linux (can/spi/uart/etc) */ + {OFFSET(uart0_rxd), (MODE(7) | PULLUDDIS | RXACTIVE)}, /* (E15) gpio1_10 */ /* Mode 0 */ + {OFFSET(uart0_txd), (MODE(7) | PULLUDDIS | RXACTIVE)}, /* (E16) gpio1_11 */ /* Mode 1 */ + {-1}, +}; + + +static int request_gpios(void) +{ + int ret; + + debug("Extension slot init\n"); + ret = shield_gpio_request_as_input(NETBIRD_GPIO_RST_SHIELD_N, "shield-rst"); + if ((ret < 0)) + return -1; + ret = shield_gpio_request_as_input(NETBIRD_GPIO_LOAD, "shield-load"); + if ((ret < 0)) + return -1; + ret = shield_gpio_request_as_input(NETBIRD_GPIO_MODE_0, "shield-mode0"); + if ((ret < 0)) + return -1; + ret = shield_gpio_request_as_input(NETBIRD_GPIO_MODE_1, "shield-mode1"); + if ((ret < 0)) + return -1; + + shield_slot_initialized = 1; + return 0; +} + +static int configure_shieldmode(int mode) +{ + int ret; + + if (mode < 0 || mode > 3) { + debug ("Invalid shield mode %d\n", mode); + return -1; + } + + debug("Shield type comio\n"); + debug ("Set shield mode to %d\n", mode); + + if (!shield_slot_initialized) { + if (request_gpios()) { + puts("Failed to request gpios\n"); + return -1; + } + } + + debug("Make sure shield module is in reset\n"); + ret = gpio_direction_output(NETBIRD_GPIO_RST_SHIELD_N, 0); + if (ret < 0) { + puts("Can not set shield-rst as output\n"); + return -1; + } + udelay(10); + + debug("Enable gpio pull-ups\n"); + configure_module_pin_mux(shield_gpio_netbird_pin_mux); + + debug("Set load to low\n"); + ret = gpio_direction_output(NETBIRD_GPIO_LOAD, 0); + if (ret < 0) { + puts("Can not set shield-load as output\n"); + return -1; + } + udelay(10); + + debug("Write mode to GPIOs\n"); + ret = gpio_direction_output(NETBIRD_GPIO_MODE_0, mode & 0x01); + if (ret < 0) { + puts("Can not set shield-mode0 as output\n"); + return -1; + } + ret = gpio_direction_output(NETBIRD_GPIO_MODE_1, mode & 0x02); + if (ret < 0) { + puts("Can not set shield-mode1 as output\n"); + return -1; + } + udelay(10); + + debug("Set load to high\n"); + gpio_set_value(NETBIRD_GPIO_LOAD, 1); + udelay(10); + + debug("Set mode0 and mode1 to highz again\n"); + ret = gpio_direction_input(NETBIRD_GPIO_MODE_0); + if ((ret < 0)) { + puts("Could not configure shield slot mode0 gpio as input\n"); + return -1; + } + + ret = gpio_direction_input(NETBIRD_GPIO_MODE_1); + if ((ret < 0)) { + puts("Could not configure shield slot mode1 gpio as input\n"); + return -1; + } + udelay(10); + + debug("Disable pullups on shield gpios\n"); + configure_module_pin_mux(shield_gpio_safe_netbird_pin_mux); + udelay(10); + + debug("Take shield out of reset\n"); + gpio_set_value(NETBIRD_GPIO_RST_SHIELD_N, 1); + udelay(10); + + debug("Set gpio load as input again\n"); + ret = gpio_direction_input(NETBIRD_GPIO_LOAD); + if (ret < 0) { + puts("Can not configure shield slot load as input"); + return -1; + } + + return 0; +} + +enum mode_nr { + RS232, + RS485, + UNKNOWN +}; + +struct mode { + enum mode_nr nr; + const char* name; + int argc; +}; + +struct mode modes[] = { + { RS232, "rs232", 0 }, + { RS485, "rs485", 2 } +}; + +static const struct mode *get_mode(const char *mode) +{ + int i; + for (i = 0; i < ARRAY_SIZE(modes); i++) { + if (strcmp(modes[i].name, mode) == 0) { + return &modes[i]; + } + } + return NULL; +} + +static int get_termination(const char* termination) +{ + if (strcmp("on", termination) == 0) { + return 1; + } + else if (strcmp("off", termination) == 0) { + return 0; + } + + debug ("Invalid termination mode %s (falling back to off)", termination); + return -1; +} + +static int get_mode_from_args(char * const argv[], int argc) +{ + int termination = 0; + int rs232 = 0; + const struct mode *selected_mode; + + assert(argc >= 2); + + if (strcmp ("mode", argv[0])) { + debug("Invalid arguments (see help)\n"); + return -1; + } + + selected_mode = get_mode(argv[1]); + if (selected_mode == NULL) { + debug("Mode %s not supported\n", argv[1]); + return -1; + } + + debug ("Mode %s, index %d, argc %d\n", selected_mode->name, + selected_mode->nr, selected_mode->argc); + + if (selected_mode->argc != argc - 2) { + debug("Invalid argument count for mode %s (should %d is %d)\n", + argv[1], selected_mode->argc, argc - 2); + return -1; + } + + if (selected_mode->nr == RS485) { + if (strcmp("termination", argv[2])) { + debug("Invalid arguments, do not configure termination\n"); + return -1; + } + + termination = get_termination(argv[3]); + if (termination < 0) { + debug("Invalid termination %s\n", argv[3]); + return -1; + } + } + else { + rs232 = 1; + } + + /* Termination is inverse */ + return (rs232 << 0) | ((!termination) << 1); +} + +int set_shieldmode(char * const argv[], int argc) +{ + if (argc < 2) { + debug("Too few arguments for comio\n"); + return -1; + } + + /* -1 will make configure_shieldmode to faile and is okay therefore */ + return configure_shieldmode(get_mode_from_args(argv, argc)); +} + +/* TODO: Static ? */ +struct shield_t comio_shield = { + "comio", set_shieldmode +}; + +void comio_shield_init(void) +{ + shield_register(&comio_shield); +} diff --git a/board/nm/hw25/shield_comio.h b/board/nm/hw25/shield_comio.h new file mode 100644 index 0000000000..2b2602e917 --- /dev/null +++ b/board/nm/hw25/shield_comio.h @@ -0,0 +1,6 @@ +#ifndef SHIELD_COMIO_H +#define SHIELD_COMIO_H + +void comio_shield_init(void); + +#endif // SHIELD_COMIO_H diff --git a/board/nm/hw25/u-boot.lds b/board/nm/hw25/u-boot.lds new file mode 100644 index 0000000000..517b31021e --- /dev/null +++ b/board/nm/hw25/u-boot.lds @@ -0,0 +1,158 @@ +/* + * Copyright (c) 2004-2008 Texas Instruments + * + * (C) Copyright 2002 + * Gary Jennejohn, DENX Software Engineering, + * + * See file CREDITS for list of people who contributed to this + * project. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 of + * the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, + * MA 02111-1307 USA + */ + +OUTPUT_FORMAT("elf32-littlearm", "elf32-littlearm", "elf32-littlearm") +OUTPUT_ARCH(arm) +ENTRY(_start) +SECTIONS +{ + . = 0x00000000; + + . = ALIGN(4); + .text : + { + *(.__image_copy_start) + *(.vectors) + CPUDIR/start.o (.text*) + board/nm/hw25/built-in.o (.text*) + *(.text*) + } + + . = ALIGN(4); + .rodata : { *(SORT_BY_ALIGNMENT(SORT_BY_NAME(.rodata*))) } + + . = ALIGN(4); + .data : { + *(.data*) + } + + . = ALIGN(4); + + . = .; + + . = ALIGN(4); + .u_boot_list : { + KEEP(*(SORT(.u_boot_list*))); + } + + . = ALIGN(4); + + .__efi_runtime_start : { + *(.__efi_runtime_start) + } + + .efi_runtime : { + *(efi_runtime_text) + *(efi_runtime_data) + } + + .__efi_runtime_stop : { + *(.__efi_runtime_stop) + } + + .efi_runtime_rel_start : + { + *(.__efi_runtime_rel_start) + } + + .efi_runtime_rel : { + *(.relefi_runtime_text) + *(.relefi_runtime_data) + } + + .efi_runtime_rel_stop : + { + *(.__efi_runtime_rel_stop) + } + + . = ALIGN(4); + + .image_copy_end : + { + *(.__image_copy_end) + } + + .rel_dyn_start : + { + *(.__rel_dyn_start) + } + + .rel.dyn : { + *(.rel*) + } + + .rel_dyn_end : + { + *(.__rel_dyn_end) + } + + .hash : { *(.hash*) } + + .end : + { + *(.__end) + } + + _image_binary_end = .; + + /* + * Deprecated: this MMU section is used by pxa at present but + * should not be used by new boards/CPUs. + */ + . = ALIGN(4096); + .mmutable : { + *(.mmutable) + } + +/* + * Compiler-generated __bss_start and __bss_end, see arch/arm/lib/bss.c + * __bss_base and __bss_limit are for linker only (overlay ordering) + */ + + .bss_start __rel_dyn_start (OVERLAY) : { + KEEP(*(.__bss_start)); + __bss_base = .; + } + + .bss __bss_base (OVERLAY) : { + *(.bss*) + . = ALIGN(4); + __bss_limit = .; + } + + .bss_end __bss_limit (OVERLAY) : { + KEEP(*(.__bss_end)); + } + + .dynsym _image_binary_end : { *(.dynsym) } + .dynbss : { *(.dynbss) } + .dynstr : { *(.dynstr*) } + .dynamic : { *(.dynamic*) } + .gnu.hash : { *(.gnu.hash) } + .plt : { *(.plt*) } + .interp : { *(.interp*) } + .gnu : { *(.gnu*) } + .ARM.exidx : { *(.ARM.exidx*) } +} diff --git a/configs/am335x_hw25_defconfig b/configs/am335x_hw25_defconfig new file mode 100644 index 0000000000..bc1facd176 --- /dev/null +++ b/configs/am335x_hw25_defconfig @@ -0,0 +1,49 @@ +CONFIG_ARM=y +CONFIG_TARGET_AM335X_HW25=y +CONFIG_SPL_STACK_R_ADDR=0x82000000 +CONFIG_SPL=y +CONFIG_SPL_STACK_R=y +CONFIG_FIT=y +CONFIG_SYS_EXTRA_OPTIONS="EMMC_BOOT" +CONFIG_HUSH_PARSER=y +CONFIG_AUTOBOOT_KEYED=y +CONFIG_AUTOBOOT_PROMPT="Press s to abort autoboot in %d seconds\n" +CONFIG_AUTOBOOT_STOP_STR="s" +CONFIG_CMD_BOOTZ=y +# CONFIG_CMD_IMLS is not set +CONFIG_CMD_ASKENV=y +# CONFIG_CMD_FLASH is not set +CONFIG_CMD_MMC=y +CONFIG_CMD_I2C=y +CONFIG_CMD_USB=y +# CONFIG_CMD_SETEXPR is not set +CONFIG_CMD_DHCP=y +CONFIG_CMD_MII=y +CONFIG_CMD_PING=y +CONFIG_CMD_EXT2=y +CONFIG_CMD_EXT4=y +CONFIG_CMD_EXT4_WRITE=y +CONFIG_CMD_FAT=y +CONFIG_CMD_FS_GENERIC=y +CONFIG_DFU_TFTP=y +CONFIG_SYS_NS16550=y +CONFIG_USB=y +CONFIG_USB_MUSB_HOST=y +CONFIG_USB_MUSB_GADGET=y +CONFIG_USB_GADGET=y +CONFIG_USB_GADGET_DOWNLOAD=y +CONFIG_G_DNL_MANUFACTURER="Texas Instruments" +CONFIG_G_DNL_VENDOR_NUM=0x0451 +CONFIG_G_DNL_PRODUCT_NUM=0xd022 +CONFIG_OF_LIBFDT=y +# CONFIG_BOOTP_PXE_CLIENTARCH is not set +# CONFIG_CMD_PXE is not set +# CONFIG_CMD_BOOTEFI is not set +# CONFIG_CMD_XIMG is not set +# CONFIG_CMD_ELF is not set +# CONFIG_FPGA is not set +# CONFIG_CMD_FPGA is not set +# CONFIG_CMD_PMIC is not set +# CONFIG_EFI_LOADER is not set +# CONFIG_CMD_LOADB is not set +# CONFIG_CMD_LOADS is not set diff --git a/include/configs/am335x_hw25.h b/include/configs/am335x_hw25.h new file mode 100644 index 0000000000..15ca461a12 --- /dev/null +++ b/include/configs/am335x_hw25.h @@ -0,0 +1,313 @@ +/* + * am335x_hw25.h + * + * Copyright (C) 2018-2019 NetModule AG - http://www.netmodule.com/ + * Copyright (C) 2011 Texas Instruments Incorporated - http://www.ti.com/ + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation version 2. + * + * This program is distributed "as is" WITHOUT ANY WARRANTY of any + * kind, whether express or implied; without even the implied warranty + * of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + */ + +#ifndef __CONFIG_AM335X_HW25_H +#define __CONFIG_AM335X_HW25_H + +#include + +/* Disable U-Boot load from filesystems, to save around 10 kB SPL image size */ +#ifdef CONFIG_SYS_MMCSD_FS_BOOT_PARTITION +# undef CONFIG_SYS_MMCSD_FS_BOOT_PARTITION +#endif + +#undef CONFIG_SPL_AM33XX_ENABLE_RTC32K_OSC + +#undef CONFIG_HW_WATCHDOG +#undef CONFIG_OMPAP_WATCHDOG +#undef CONFIG_SPL_WATCHDOG_SUPPORT + +#ifndef CONFIG_SPL_BUILD +# define CONFIG_TIMESTAMP +# define CONFIG_LZO +#endif + +#define CONFIG_SYS_BOOTM_LEN (16 << 20) + +#define MACH_TYPE_TIAM335EVM 3589 /* Until the next sync */ +#define CONFIG_MACH_TYPE MACH_TYPE_TIAM335EVM +#define CONFIG_BOARD_LATE_INIT + +/* TODO: It could be preconsole buffer is not properly working in SPL + * Observed lock ups when printing too much text. +#define CONFIG_PRE_CONSOLE_BUFFER +#define CONFIG_PRE_CON_BUF_ADDR 0x80000000 +#define CONFIG_PRE_CON_BUF_SZ 64*1024 +*/ + +/* Clock Defines */ +#define V_OSCK 0 /* 0 means detect from sysboot1 config */ +#define V_SCLK (V_OSCK) + +#include + +/* Dynamic override for PHY_ANEG_TIMEOUT value */ +#ifndef CONFIG_SPL_BUILD +# ifndef __ASSEMBLER__ +int eth_phy_timeout(void); +# endif +#endif +#define PHY_ANEG_TIMEOUT eth_phy_timeout() +#define PHY_ANEG_DEFAULT_TIMEOUT 5000 + +#define CONFIG_ARP_TIMEOUT 200 +#undef CONFIG_NET_RETRY_COUNT +#define CONFIG_NET_RETRY_COUNT 5 +#define CONFIG_BOOTP_MAY_FAIL + +#ifndef CONFIG_SPL_BUILD + +/* + * Memory map for booting Linux + * + * 0x80000000 32MB KERNEL_ADDR (kernel_addr), kernel execution address + * 0x82000000 190MB KERNEL_ADDR_R (kernel_addr_r), FIT image/kernel loading address + * kernel will be relocated kernel_addr + * for FIT images, ramdisc and dtb will be relocated to + * top of bootmemory (0x8e000000 downwards) + * 0x8BE00000 1MB FDT_ADDR_R (fdt_addr_r), device tree if separate from kernel/FIT + * 0x8BF00000 1MB PXE_ADDR (pxefile_addr_r), pxe configuration file (pxe get command) + * 0x8C000000 32MB LOAD_ADDR (load_addr), loading address for generic files + * + * 0x8E000000 4B NRSW reset reason + * 32MB <>, Free space + * 0x90000000 256MB <>, Free space, 512MB systems + * 0xA0000000 512MB <>, Free space, 1GB systems only + * 0xC0000000 End of RAM + */ + +#define KERNEL_ADDR "0x80000000" +#define KERNEL_ADDR_R "0x82000000" +#define FDT_ADDR_R "0x8BE00000" +#define PXE_ADDR "0x8BF00000" +#define LOAD_ADDR "0x8C000000" + +/* + * Limit boot memory to 256 MBytes to comply with kernel initial memory layout + * This is the official way to restrict image load addresses. + * Don't use xx_high_addr variables. + */ +#define BOOTM_SIZE "0x0E000000" + +/* Set boot command depending of software environment */ +#ifndef CONFIG_NRSW_BUILD +/* Yocto/OSTree boot command */ +#define MAIN_BOOTCMD "run boot_ostree" +#else +/* NRSW boot command */ +#define MAIN_BOOTCMD "run sdboot" +#endif + +#define CONFIG_EXTRA_ENV_SETTINGS \ + /* Memory Adresses */ \ + "fdt_addr_r=" FDT_ADDR_R "\0" \ + "kernel_addr=" KERNEL_ADDR "\0" /* NRSW only */ \ + "kernel_addr_r=" KERNEL_ADDR_R "\0" \ + "load_addr=" LOAD_ADDR "\0" \ + "pxefile_addr_r=" PXE_ADDR "\0" \ + "bootm_size=" BOOTM_SIZE "\0" \ + \ + /* Misc */ \ + "defaultconsole=ttyS1\0" \ + "fdt_skip_update=yes\0" \ + "bootdelay=0\0" \ + \ + /* Networking */ \ + "ethprime=cpsw\0" \ + "ethopts=ti_cpsw.rx_packet_max=1526\0" \ + "ipaddr=192.168.1.1\0" \ + "serverip=192.168.1.254\0" \ + "tftptimeout=2000\0" \ + "tftptimeoutcountmax=5\0" \ + "bootpretryperiod=10000\0" /* 2000 */ \ + "autoload=false\0" \ + \ + /* OSTree boot */ \ + "bootcmd_otenv=ext4load mmc 1:1 $load_addr /boot/loader/uEnv.txt; " \ + "setenv bootargs_prev $bootargs; " \ + "env import -t $load_addr $filesize; setenv bootargs $bootargs_prev $bootargs root=/dev/ram0 console=$defaultconsole,115200 " \ + "$ethopts rw ostree_root=/dev/mmcblk1p1\0" \ + "bootcmd_rd_in_mmc=ext4load mmc 1:1 $kernel_addr_r /boot$kernel_image; " \ + "bootm $kernel_addr_r\0" \ + "boot_ostree=run shieldcmd; run bootcmd_otenv; run bootcmd_rd_in_mmc\0" \ + \ + /* NRSW boot */ \ + "root_part=1\0" /* from NRSW, required here? set from board.c */ \ + "kernel_image=kernel.bin\0" \ + "fdt_image=am335x-hw25-prod1.dtb\0" \ + "add_sd_bootargs=setenv bootargs $bootargs root=/dev/${mmc_dev}p$root_part rootfstype=ext4 " \ + "console=$defaultconsole,115200 rootwait loglevel=4 ti_cpsw.rx_packet_max=1526\0" \ + "add_version_bootargs=setenv bootargs $bootargs\0" \ + "sdbringup=echo Try bringup boot && ext4load mmc 1:$root_part $kernel_addr /boot/zImage && " \ + "ext4load mmc 1:$root_part $fdt_addr /boot/$fdt_image && setenv bootargs $bootargs rw;\0" \ + "sdprod=ext4load mmc 1:$root_part $kernel_addr /boot/$kernel_image && " \ + "ext4load mmc 1:$root_part $fdt_addr /boot/$fdt_image && setenv bootargs $bootargs ro;\0" \ + "sdboot=env set fdt_addr " FDT_ADDR_R "; "\ + "if mmc dev 1; then echo Copying Linux from SD to RAM...; "\ + "if test -e mmc 1:$root_part /boot/$kernel_image; then run sdprod; " \ + "else run sdbringup; fi; " \ + /* For v4.19 kernel $mmc_dev should be "mmcblk1" (read from DT), for v3.18 kernel: "mmcblk0" */ \ + "fdt addr $fdt_addr;if fdt get value mmc_dev /nm_env nm,mmc-dev;then;else setenv mmc_dev mmcblk0;fi;" \ + "run add_sd_bootargs; run add_version_bootargs; run shieldcmd; " \ + "bootz $kernel_addr - $fdt_addr; fi\0" \ + \ + /* Boot command */ \ + "bootcmd=" MAIN_BOOTCMD "\0" \ + \ + /* Recovery boot (same for OSTree and NRSW) */ \ + "recovery=run pxe_recovery || setenv ipaddr $ipaddr; setenv serverip $serverip; run tftp_recovery\0" \ + /* setenv ipaddr and serverip is necessary, because dhclient destroys the IPs internally */ \ + "pxe_recovery=mdio up $ethprime && dhcp && pxe get && pxe boot\0" \ + "tftp_recovery=tftpboot $kernel_addr_r recovery-image; tftpboot $fdt_addr_r recovery-dtb; " \ + "setenv bootargs rdinit=/etc/preinit console=$defaultconsole,115200 " \ + "debug $ethopts; " \ + "run shieldcmd; " \ + "bootz $kernel_addr_r - $fdt_addr_r\0" /* kernel_addr_r */ + +#endif + + +/* TODO: Check if ok for NRSW? */ +#define CONFIG_ZERO_BOOTDELAY_CHECK + +/* UART Configuration */ +#define CONFIG_SYS_NS16550_COM1 0x44e09000 /* UART0: XModem Boot, Shield */ +#define CONFIG_SYS_NS16550_COM2 0x48022000 /* UART1: Debug UART (Internal) */ + +#define CONFIG_I2C +#define CONFIG_I2C_MULTI_BUS + +#define CONFIG_CMD_EEPROM +#define CONFIG_SYS_I2C_EEPROM_ADDR 0x50 /* Main EEPROM */ +#define CONFIG_SYS_I2C_EEPROM_ADDR_LEN 2 +#define CONFIG_SYS_I2C_SPEED 100000 +#define CONFIG_SYS_EEPROM_PAGE_WRITE_BITS 4 +#define CONFIG_SYS_EEPROM_PAGE_WRITE_DELAY_MS 50 /* TODO: Can this be reduced to 20ms */ + +/* Put Environment in eMMC */ +#define CONFIG_ENV_OFFSET (512 * 128) /* @ 512*256 SPL starts */ +#define CONFIG_ENV_SIZE (4 * 1024) +#define CONFIG_ENV_IS_IN_MMC +#define CONFIG_SYS_MMC_ENV_DEV 1 + +#undef CONFIG_SPL_ENV_SUPPORT +#undef CONFIG_SPL_NAND_SUPPORT +#undef CONFIG_SPL_ONENAND_SUPPORT + +/* We need to disable SPI to not confuse the eeprom env driver */ +#undef CONFIG_SPI +#undef CONFIG_SPI_BOOT +#undef CONFIG_SPL_OS_BOOT + +#define CONFIG_SPL_YMODEM_SUPPORT + +#define CONFIG_SPL_LDSCRIPT "$(CPUDIR)/am33xx/u-boot-spl.lds" + +#define CONFIG_SUPPORT_EMMC_BOOT + +/* + * USB configuration. We enable MUSB support, both for host and for + * gadget. We set USB0 as peripheral and USB1 as host, based on the + * board schematic and physical port wired to each. Then for host we + * add mass storage support and for gadget we add both RNDIS ethernet + * and DFU. + */ +#define CONFIG_USB_MUSB_DSPS +#define CONFIG_ARCH_MISC_INIT +#define CONFIG_USB_MUSB_PIO_ONLY +#define CONFIG_USB_MUSB_DISABLE_BULK_COMBINE_SPLIT +#define CONFIG_AM335X_USB0 +#define CONFIG_AM335X_USB0_MODE MUSB_HOST + +/* To support eMMC booting */ +#define CONFIG_STORAGE_EMMC +#define CONFIG_FASTBOOT_FLASH_MMC_DEV 1 + +#ifdef CONFIG_USB_MUSB_HOST +#define CONFIG_USB_STORAGE +#endif + +#ifdef CONFIG_USB_MUSB_GADGET +/* Removing USB gadget and can be enabled adter adding support usb DM */ +#ifndef CONFIG_DM_ETH +#define CONFIG_USB_ETHER +#define CONFIG_USB_ETH_RNDIS +#define CONFIG_USBNET_HOST_ADDR "de:ad:be:af:00:00" +#endif /* CONFIG_DM_ETH */ +#endif /* CONFIG_USB_MUSB_GADGET */ + + +/* + * Disable MMC DM for SPL build and can be re-enabled after adding + * DM support in SPL + */ +#ifdef CONFIG_SPL_BUILD +#undef CONFIG_DM_MMC +#undef CONFIG_TIMER +#endif + +#if defined(CONFIG_SPL_BUILD) +/* Remove other SPL modes. */ +#undef CONFIG_SPL_NAND_SUPPORT +#define CONFIG_ENV_IS_NOWHERE +#undef CONFIG_PARTITION_UUIDS +#undef CONFIG_EFI_PARTITION +#endif + +/* Network. */ +#define CONFIG_IP_DEFRAG /* so we can use large tftp blocks */ +#define CONFIG_TFTP_TSIZE /* tftp transfer size, progress bar */ + +#define CONFIG_PHYLIB +#define CONFIG_PHY_SMSC + +#define CONFIG_CMD_MEMTEST +#define CONFIG_SYS_MEMTEST_START 0x84000000 +#define CONFIG_SYS_MEMTEST_END 0x87900000 + + +#ifdef CONFIG_NRSW_BUILD +/* support for NM packed bootloader */ +#define CONFIG_NM_BOOTLOADER_FORMAT + +/* password protected login */ +#define CONFIG_CRYPT +#define CONFIG_NM_LOGIN +#define CONFIG_NM_LOGIN_PART "1:3" /* TODO: Define location of file for OSTree/Yocto */ +#define CONFIG_NM_LOGIN_PASSWD "/root/boot/bootpass" +#endif + +#define CONFIG_CMD_PXE + +#define CONFIG_OF_BOARD_SETUP + +#define CONFIG_JTAG_MARKER_SPL 0x402FFF00 +#define CONFIG_JTAG_MARKER_UBOOT 0x807FFF00 + +/* NRSW PMIC Reset Reason */ +#ifdef CONFIG_NRSW_BUILD +#define RESET_REASON_SHM_LOCATION 0x8e000000 +#define EXTERNAL_WATCHDOG_PATTERN 0x781f9ce2 +#endif + + +/* SPL command is not needed */ +#undef CONFIG_CMD_SPL + +/* Never enable ISO it is broken and can lead to a crash */ +#undef CONFIG_ISO_PARTITION + +#endif /* ! __CONFIG_AM335X_HW25_H */