diff --git a/board/nm/common/da9063.h b/board/nm/common/da9063.h index 2db561459f..344d6ce518 100644 --- a/board/nm/common/da9063.h +++ b/board/nm/common/da9063.h @@ -16,17 +16,21 @@ #define CONFIG_PMIC_I2C_ADDR 0x58 /* Pages 0 and 1, Pages 2 and 3 -> 0x59 */ #define PMIC_REG_STATUS_A 0x01 /* Status of ON_KEY, WAKE, COMP1V2, DVC */ +#define PMIC_REG_STATUS_A_COMP1V2_MASK 0x08 + #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_EVENT_A 0x06 #define PMIC_REG_EVENT_RTC_ALARM_MASK 0x02 +#define PMIC_REG_EVENT_RTC_TICK_MASK 0x04 #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_A 0x0E /* Control register for power states */ #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 */ diff --git a/board/nm/nmhw21/board.c b/board/nm/nmhw21/board.c index 757c3d4779..42adfe17f3 100644 --- a/board/nm/nmhw21/board.c +++ b/board/nm/nmhw21/board.c @@ -153,8 +153,10 @@ static int hw_type = -1; static char hw_variant_name[64]; #else static int hw_type = -1; +static uint32_t sys_start_event = 0x0; #endif + #if !defined(CONFIG_SPL_BUILD) static struct ctrl_dev *cdev = (struct ctrl_dev *)CTRL_DEVICE_BASE; #endif @@ -416,27 +418,6 @@ static void pmic_disable_auto_mode(void) } } -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; @@ -462,8 +443,6 @@ static void init_pmic_spl(void) (void)da9063_set_reg(PMIC_REG_LDO11_CONT, PMIC_LDOx_EN_MASK); mdelay(2); - pmic_ignition_gate_on(); - if (hw_type == 21) { /* hw21: trim RTC to compensate +18ppm crystal deviation */ (void)da9063_set_reg(PMIC_REG_TRIM_CLDR, (-18*10)/19); @@ -499,17 +478,18 @@ struct reset_registers { #define SE_WATCHDOG 0x00000010 #define SE_IGNITION 0x00000100 #define SE_RTC_ALARM 0x00000200 +#define SE_RTC_TICK 0x00000400 static void print_start_reason(uint32_t events) { - puts("Start Events: "); + puts("\nStart Events: "); if (events == 0) { puts("-\n"); } else { - static char buffer[10+11+11+6+1]; + static char buffer[10+11+11+6+6+1]; buffer[0] = 0; if (events & SE_POR) @@ -520,6 +500,8 @@ static void print_start_reason(uint32_t events) strncat(buffer, "Ignition, ", sizeof(buffer)); if (events & SE_RTC_ALARM) strncat(buffer, "RTC, ", sizeof(buffer)); + if (events & SE_RTC_TICK) + strncat(buffer, "Tick, ", sizeof(buffer)); /* Trim last comma, no 0 len check required, at least one entry is present */ buffer[strlen(buffer)-2] = 0; @@ -576,6 +558,7 @@ static void check_pmic_reset_reason(unsigned int reset_reason_shm_location) * Event Register A * - Event B Activity * - RTC Alarm + * - RTC Tick */ ret = da9063_get_reg(PMIC_REG_EVENT_A, &state); if ((ret == 0) && (state != 0)) { @@ -585,6 +568,10 @@ static void check_pmic_reset_reason(unsigned int reset_reason_shm_location) start_event |= SE_RTC_ALARM; } + if (state & PMIC_REG_EVENT_RTC_TICK_MASK) { + start_event |= SE_RTC_TICK; + } + if (state & PMIC_REG_EVENT_EVENTS_B_MASK) { /* * Event Register B @@ -599,8 +586,12 @@ static void check_pmic_reset_reason(unsigned int reset_reason_shm_location) } } } + + /* TODO: Should we clear events here or leave them for Linux driver? */ } + sys_start_event = start_event; + /* Store start events in shared memory region for OS */ reset_regs->se_magic = SE_MAGIC; reset_regs->se_events = start_event; @@ -613,6 +604,107 @@ static void check_pmic_reset_reason(unsigned int reset_reason_shm_location) print_start_reason(reset_regs->se_events); } +static void pmic_ignition_gate_on(void) +{ + int bus; + uint8_t val; + + bus = da9063_claim_i2c_bus(); + + /* Configure GPIO15 to permanent high, so that ignition sense signal is readable */ + + (void)da9063_set_reg(PMIC_REG_GPIO14_15, 0xCC); /* GPIO14/15 = Outputs open drain */ + + (void)da9063_get_reg(PMIC_REG_CONFIG_L, &val); /* Enable pull ups on GPIO14/15 */ + val |= 0xC0; + (void)da9063_set_reg(PMIC_REG_CONFIG_L, val); + + (void)da9063_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); + + /* + * Comparator input is debounced (10ms), see DA9063 datasheet 5.13.5 + * Give enough time to stabilize input reading. + */ + mdelay(10+10); + + da9063_release_i2c_bus(bus); +} + +static void powerdown(void) +{ + int bus; + + bus = da9063_claim_i2c_bus(); + + /* Final call, will not return */ + da9063_set_reg(PMIC_REG_CONTROL_A, 0x00); + + da9063_release_i2c_bus(bus); + + puts("ERROR: PMIC power down failed\n"); + for (;;) {} +} + +static void reset(void) +{ + /* Code copied from arm v7 lib */ + udelay (50000); + + disable_interrupts(); + reset_misc(); + reset_cpu(0); + + puts("ERROR: Reset failed\n"); + for (;;) {} +} + +static void stop_if_ignition_is_off(void) +{ + uint8_t state = 0x00; + int bus; + int ret; + + bus = da9063_claim_i2c_bus(); + + ret = da9063_get_reg(PMIC_REG_STATUS_A, &state); + if (ret == 0) { + if ((state & PMIC_REG_STATUS_A_COMP1V2_MASK) == PMIC_REG_STATUS_A_COMP1V2_MASK) { + puts("Ignition : On\n"); + } + else { + puts("Ignition : Off\n"); + /* + * Ignition is off, if this is a power-on start, power down + * as this is considered an unwanted system start. + */ + + /* + * There is a chance for a race condition, when ignition is enabled + * between the check above and here. In this case we should just reset + * not power down. + * Although the risk is minimal here due to the very short time interval + * we do the check. The same logic will have to be added in other + * components. + */ + ret = da9063_get_reg(PMIC_REG_EVENT_B, &state); + if ((ret == 0) && ((state & PMIC_REG_EVENT_COMP1V2_MASK) == 0)) { + powerdown(); + } + else { + reset(); + } + } + } + + da9063_release_i2c_bus(bus); +} + static void init_bd_spl(void) { hw_type = 21; /* Assume hw21, unless BD tells different */ @@ -648,6 +740,17 @@ void am33xx_spl_board_init(void) /* Detect reset/Wakeup reason */ check_pmic_reset_reason(RESET_REASON_SHM_LOCATION); + /* Switch on ignition gate so we can read state later */ + pmic_ignition_gate_on(); + + /* + * If this is a power-on start, see if ignition is active. + * If not, power down as this is considered an unwanted system start. + */ + if (sys_start_event & SE_POR) { + stop_if_ignition_is_off(); + } + /* Setup PMIC */ init_pmic_spl();