hw21, 26: suppress power on with ignition off

power down system in SPL when ignition is not active on a
power-on start.
This commit is contained in:
Rene Straub 2020-11-18 16:49:50 +01:00
parent f82ac7239a
commit f5b16d4cf7
2 changed files with 132 additions and 25 deletions

View File

@ -16,17 +16,21 @@
#define CONFIG_PMIC_I2C_ADDR 0x58 /* Pages 0 and 1, Pages 2 and 3 -> 0x59 */ #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 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_REG_FAULT_LOG 0x05 /* PMIC fault log register, holding reset reason */
#define PMIC_FAULT_TWD_ERROR_MASK 0x01 /* Watchdog timeout detected */ #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_FAULT_POR_MASK 0x02 /* Startup from No-Power/RTC/Delivery mode */
#define PMIC_REG_EVENT_A 0x06 #define PMIC_REG_EVENT_A 0x06
#define PMIC_REG_EVENT_RTC_ALARM_MASK 0x02 #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_EVENTS_B_MASK 0x20
#define PMIC_REG_EVENT_B 0x07 #define PMIC_REG_EVENT_B 0x07
#define PMIC_REG_EVENT_COMP1V2_MASK 0x04 #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_CONTROL_D 0x11 /* Control register for blink/watchdog */
#define PMIC_REG_GPIO14_15 0x1C /* Configuration of GPIO14/15 (mode, wake) */ #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_MODE0_7 0x1D /* Control register for GPIOs 0..7 */

View File

@ -153,8 +153,10 @@ static int hw_type = -1;
static char hw_variant_name[64]; static char hw_variant_name[64];
#else #else
static int hw_type = -1; static int hw_type = -1;
static uint32_t sys_start_event = 0x0;
#endif #endif
#if !defined(CONFIG_SPL_BUILD) #if !defined(CONFIG_SPL_BUILD)
static struct ctrl_dev *cdev = (struct ctrl_dev *)CTRL_DEVICE_BASE; static struct ctrl_dev *cdev = (struct ctrl_dev *)CTRL_DEVICE_BASE;
#endif #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) static void init_pmic_spl(void)
{ {
int bus; int bus;
@ -462,8 +443,6 @@ static void init_pmic_spl(void)
(void)da9063_set_reg(PMIC_REG_LDO11_CONT, PMIC_LDOx_EN_MASK); (void)da9063_set_reg(PMIC_REG_LDO11_CONT, PMIC_LDOx_EN_MASK);
mdelay(2); mdelay(2);
pmic_ignition_gate_on();
if (hw_type == 21) { if (hw_type == 21) {
/* hw21: trim RTC to compensate +18ppm crystal deviation */ /* hw21: trim RTC to compensate +18ppm crystal deviation */
(void)da9063_set_reg(PMIC_REG_TRIM_CLDR, (-18*10)/19); (void)da9063_set_reg(PMIC_REG_TRIM_CLDR, (-18*10)/19);
@ -499,17 +478,18 @@ struct reset_registers {
#define SE_WATCHDOG 0x00000010 #define SE_WATCHDOG 0x00000010
#define SE_IGNITION 0x00000100 #define SE_IGNITION 0x00000100
#define SE_RTC_ALARM 0x00000200 #define SE_RTC_ALARM 0x00000200
#define SE_RTC_TICK 0x00000400
static void print_start_reason(uint32_t events) static void print_start_reason(uint32_t events)
{ {
puts("Start Events: "); puts("\nStart Events: ");
if (events == 0) { if (events == 0) {
puts("-\n"); puts("-\n");
} }
else { else {
static char buffer[10+11+11+6+1]; static char buffer[10+11+11+6+6+1];
buffer[0] = 0; buffer[0] = 0;
if (events & SE_POR) if (events & SE_POR)
@ -520,6 +500,8 @@ static void print_start_reason(uint32_t events)
strncat(buffer, "Ignition, ", sizeof(buffer)); strncat(buffer, "Ignition, ", sizeof(buffer));
if (events & SE_RTC_ALARM) if (events & SE_RTC_ALARM)
strncat(buffer, "RTC, ", sizeof(buffer)); 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 */ /* Trim last comma, no 0 len check required, at least one entry is present */
buffer[strlen(buffer)-2] = 0; 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 Register A
* - Event B Activity * - Event B Activity
* - RTC Alarm * - RTC Alarm
* - RTC Tick
*/ */
ret = da9063_get_reg(PMIC_REG_EVENT_A, &state); ret = da9063_get_reg(PMIC_REG_EVENT_A, &state);
if ((ret == 0) && (state != 0)) { 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; 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) { if (state & PMIC_REG_EVENT_EVENTS_B_MASK) {
/* /*
* Event Register B * 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 */ /* Store start events in shared memory region for OS */
reset_regs->se_magic = SE_MAGIC; reset_regs->se_magic = SE_MAGIC;
reset_regs->se_events = start_event; 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); 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) static void init_bd_spl(void)
{ {
hw_type = 21; /* Assume hw21, unless BD tells different */ hw_type = 21; /* Assume hw21, unless BD tells different */
@ -648,6 +740,17 @@ void am33xx_spl_board_init(void)
/* Detect reset/Wakeup reason */ /* Detect reset/Wakeup reason */
check_pmic_reset_reason(RESET_REASON_SHM_LOCATION); 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 */ /* Setup PMIC */
init_pmic_spl(); init_pmic_spl();