From f82ac7239a97479708cf84e282cda7f2a32ca2d7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ren=C3=A9=20Straub?= Date: Mon, 9 Nov 2020 10:13:45 +0100 Subject: [PATCH] hw21,26: add start/wakeup reason detection logic (#58) Move detection logic before PMIC rails init Add detection logic in hw21/26 Detect start events from pmic Co-authored-by: Rene Straub Reviewed-on: https://git.netmodule.intranet/nmrouter/u-boot/pulls/58 --- board/nm/common/da9063.h | 14 +++- board/nm/common/ether_crc.c | 36 ++++++++ board/nm/common/ether_crc.h | 18 ++++ board/nm/nmhw21/Makefile | 2 +- board/nm/nmhw21/board.c | 144 +++++++++++++++++++++++++------- include/configs/am335x_nmhw21.h | 5 +- 6 files changed, 181 insertions(+), 38 deletions(-) create mode 100644 board/nm/common/ether_crc.c create mode 100644 board/nm/common/ether_crc.h diff --git a/board/nm/common/da9063.h b/board/nm/common/da9063.h index 78706e0a7d..2db561459f 100644 --- a/board/nm/common/da9063.h +++ b/board/nm/common/da9063.h @@ -18,9 +18,17 @@ #define PMIC_REG_STATUS_A 0x01 /* Status of ON_KEY, WAKE, COMP1V2, DVC */ #define PMIC_REG_FAULT_LOG 0x05 /* PMIC fault log register, holding reset reason */ #define PMIC_FAULT_TWD_ERROR_MASK 0x01 /* Watchdog timeout detected */ +#define PMIC_FAULT_POR_MASK 0x02 /* Startup from No-Power/RTC/Delivery mode */ -#define PMIC_REG_CONTROL_D 0x11 /* Control register for blink/watchdog */ -#define PMIC_REG_GPIO14_15 0x1C /* Configuration of GPIO14/15 (mode, wake) */ +#define PMIC_REG_EVENT_A 0x06 +#define PMIC_REG_EVENT_RTC_ALARM_MASK 0x02 +#define PMIC_REG_EVENT_EVENTS_B_MASK 0x20 + +#define PMIC_REG_EVENT_B 0x07 +#define PMIC_REG_EVENT_COMP1V2_MASK 0x04 + +#define PMIC_REG_CONTROL_D 0x11 /* Control register for blink/watchdog */ +#define PMIC_REG_GPIO14_15 0x1C /* Configuration of GPIO14/15 (mode, wake) */ #define PMIC_REG_GPIO_MODE0_7 0x1D /* Control register for GPIOs 0..7 */ #define PMIC_REG_GPIO_MODE8_15 0x1E /* Control register for GPIOs 8..15 */ @@ -64,6 +72,8 @@ #define PMIC_REG_TRIM_CLDR 0x120 /* Calendar Trim register, 2's complement, 1.9ppm per bit */ +#define PMIC_GP_ID_0 0x121 /* General purpose ID 0 (R/W) */ + #define PMIC_REG_CONFIG_ID 0x184 /* OTP Config ID */ diff --git a/board/nm/common/ether_crc.c b/board/nm/common/ether_crc.c new file mode 100644 index 0000000000..b94f6169b2 --- /dev/null +++ b/board/nm/common/ether_crc.c @@ -0,0 +1,36 @@ +/* + * ether_crc.c + * + * Ethernet CRC computation + * + * Copyright (C) 2018-2020 NetModule AG - http://www.netmodule.com/ + * + * SPDX-License-Identifier: GPL-2.0+ + */ + +#include + +#include "ether_crc.h" + + +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; +} diff --git a/board/nm/common/ether_crc.h b/board/nm/common/ether_crc.h new file mode 100644 index 0000000000..f8947a3a62 --- /dev/null +++ b/board/nm/common/ether_crc.h @@ -0,0 +1,18 @@ +/* + * ether_crc.h + * + * Ethernet CRC computation + * + * Copyright (C) 2018-2020 NetModule AG - http://www.netmodule.com/ + * + * SPDX-License-Identifier: GPL-2.0+ + */ + +#ifndef ETHER_CRC_H +#define ETHER_CRC_H + + +extern uint32_t ether_crc(size_t len, uint8_t const *p); + + +#endif /* ETHER_CRC_H */ diff --git a/board/nm/nmhw21/Makefile b/board/nm/nmhw21/Makefile index 98c6bf7e80..3d736b1aee 100644 --- a/board/nm/nmhw21/Makefile +++ b/board/nm/nmhw21/Makefile @@ -10,4 +10,4 @@ ifeq ($(CONFIG_SKIP_LOWLEVEL_INIT),) obj-y := mux.o endif -obj-y += board.o ../common/bdparser.o ../common/board_descriptor.o ../common/da9063.o fileaccess.o sja1105.o ui.o um.o +obj-y += board.o ../common/bdparser.o ../common/board_descriptor.o ../common/da9063.o ../common/ether_crc.o fileaccess.o sja1105.o ui.o um.o diff --git a/board/nm/nmhw21/board.c b/board/nm/nmhw21/board.c index e5897680b5..757c3d4779 100644 --- a/board/nm/nmhw21/board.c +++ b/board/nm/nmhw21/board.c @@ -37,6 +37,7 @@ #include "../common/bdparser.h" #include "../common/board_descriptor.h" #include "../common/da9063.h" +#include "../common/ether_crc.h" #include "board.h" #include "sja1105.h" #include "ui.h" @@ -475,60 +476,142 @@ static void init_pmic_spl(void) da9063_release_i2c_bus(bus); } + struct reset_registers { - uint32_t value; - uint32_t value_crc; + /* Reboot Reasons, set by OS, expect watchdog set by bootloader */ + uint32_t rr_value; + uint32_t rr_value_crc; + + /* Start Events */ + uint32_t se_magic; /* Token to check presence of following fields */ + uint32_t se_events; /* Events bitmask, see SE_... defines */ + uint32_t se_checksum; /* Checksum over se_events */ }; -#ifdef CONFIG_NRSW_BUILD +/* Watchdog reboot reason event */ +#define RR_EXTERNAL_WATCHDOG_PATTERN 0x781f9ce2 -static uint32_t ether_crc(size_t len, uint8_t const *p) +/* Start event token 'SRTE' */ +#define SE_MAGIC 0x53525445 + +/* Possible start events (see se_events) */ +#define SE_POR 0x00000001 +#define SE_WATCHDOG 0x00000010 +#define SE_IGNITION 0x00000100 +#define SE_RTC_ALARM 0x00000200 + + +static void print_start_reason(uint32_t events) { - uint32_t crc; - unsigned i; + puts("Start Events: "); - crc = ~0; - while (len--) { - crc ^= *p++; - for (i = 0; i < 8; i++) - crc = (crc >> 1) ^ ((crc & 1) ? 0xedb88320 : 0); + if (events == 0) { + puts("-\n"); } + else { + static char buffer[10+11+11+6+1]; + + buffer[0] = 0; + if (events & SE_POR) + strncat(buffer, "PowerOn, ", sizeof(buffer)); + if (events & SE_WATCHDOG) + strncat(buffer, "Watchdog, ", sizeof(buffer)); + if (events & SE_IGNITION) + strncat(buffer, "Ignition, ", sizeof(buffer)); + if (events & SE_RTC_ALARM) + strncat(buffer, "RTC, ", sizeof(buffer)); - /* 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; + /* Trim last comma, no 0 len check required, at least one entry is present */ + buffer[strlen(buffer)-2] = 0; + printf("%s\n", buffer); + } } -void check_pmic_reset_reason(unsigned int reset_reason_shm_location) +static void check_pmic_reset_reason(unsigned int reset_reason_shm_location) { volatile struct reset_registers* reset_regs = (struct reset_registers*)reset_reason_shm_location; + uint32_t start_event = 0; uint8_t state = 0x00; int bus; int ret; bus = da9063_claim_i2c_bus(); + /* + * Check/write boot marker to GP_ID_0 + * If this marker is not present, we have a power on reset + */ + ret = da9063_get_reg(PMIC_GP_ID_0, &state); + if ((ret == 0) && (state != 0xC5)) { + start_event |= SE_POR; + (void)da9063_set_reg(PMIC_GP_ID_0, 0xC5); + } + + /* + * Check Fault Log register for + * - Power On Reset: No Power, RTC Delivery -> requires removal of RTC battery + * - Watchdog + */ ret = da9063_get_reg(PMIC_REG_FAULT_LOG, &state); if ((ret == 0) && (state != 0)) { + // PMIC Watchdog 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)); + start_event |= SE_WATCHDOG; + + reset_regs->rr_value = RR_EXTERNAL_WATCHDOG_PATTERN; + reset_regs->rr_value_crc = ether_crc(sizeof(reset_regs->rr_value), + (const uint8_t*)&(reset_regs->rr_value)); + } + + // PMIC Power On Reset (only when RTC battery is removed) + if (state & PMIC_FAULT_POR_MASK) { + start_event |= SE_POR; } /* clear pmic fault log by writing back all bits currently set */ - da9063_set_reg(PMIC_REG_FAULT_LOG, state); + (void)da9063_set_reg(PMIC_REG_FAULT_LOG, state); } - da9063_release_i2c_bus(bus); -} + /* + * Event Register A + * - Event B Activity + * - RTC Alarm + */ + ret = da9063_get_reg(PMIC_REG_EVENT_A, &state); + if ((ret == 0) && (state != 0)) { + (void)da9063_set_reg(PMIC_REG_EVENT_A, state); -#endif + if (state & PMIC_REG_EVENT_RTC_ALARM_MASK) { + start_event |= SE_RTC_ALARM; + } + + if (state & PMIC_REG_EVENT_EVENTS_B_MASK) { + /* + * Event Register B + * - COMP 1V2: Ignition + */ + ret = da9063_get_reg(PMIC_REG_EVENT_B, &state); + if ((ret == 0) && (state != 0)) { + (void)da9063_set_reg(PMIC_REG_EVENT_B, state); + + if (state & PMIC_REG_EVENT_COMP1V2_MASK) { + start_event |= SE_IGNITION; + } + } + } + } + + /* Store start events in shared memory region for OS */ + reset_regs->se_magic = SE_MAGIC; + reset_regs->se_events = start_event; + reset_regs->se_checksum = 0; + reset_regs->se_checksum = ether_crc(sizeof(reset_regs->se_events), + (const uint8_t*)&(reset_regs->se_events)); + + da9063_release_i2c_bus(bus); + + print_start_reason(reset_regs->se_events); +} static void init_bd_spl(void) { @@ -562,6 +645,9 @@ void am33xx_spl_board_init(void) /* Get board descriptor */ init_bd_spl(); + /* Detect reset/Wakeup reason */ + check_pmic_reset_reason(RESET_REASON_SHM_LOCATION); + /* Setup PMIC */ init_pmic_spl(); @@ -583,10 +669,6 @@ void am33xx_spl_board_init(void) /* 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)) { diff --git a/include/configs/am335x_nmhw21.h b/include/configs/am335x_nmhw21.h index 4f23825947..3d6a531bd7 100644 --- a/include/configs/am335x_nmhw21.h +++ b/include/configs/am335x_nmhw21.h @@ -298,11 +298,8 @@ int eth_phy_timeout(void); #define CONFIG_JTAG_MARKER_SPL 0x402FFF00 #define CONFIG_JTAG_MARKER_UBOOT 0x807FFF00 -/* NRSW PMIC Reset Reason */ -#ifdef CONFIG_NRSW_BUILD +/* Reset and Start Reason */ #define RESET_REASON_SHM_LOCATION 0x8e000000 -#define EXTERNAL_WATCHDOG_PATTERN 0x781f9ce2 -#endif /* SPL command is not needed */