soc/qc/x1p42100: Add APIs to read PON reason from PMIC
Add the Power-On (PON) history log parsing and status API to the SOC layer (soc/qualcomm/x1p42100/pmic.c). This code is specific to the Qualcomm PMIC architecture (reading registers for PON events and reasons), making it an SOC-specific utility rather than a board-level policy. Moving it here improves modularization and allows other X1p42100-based boards to reuse this critical power management logic. Key APIs introduced: - pm_pon_read_pon_hist(): Reads the raw circular PON event log from the PMIC, reverses the buffer to put the latest entry first. - is_pon_on_ac(): Interprets the log to detect if the power-on reason was due to AC/Cable Power (PON_CBLPWR_RSN). Key changes: - Create src/soc/qualcomm/x1p42100/include/soc/pmic.h with PON definitions and API prototypes. - Create src/soc/qualcomm/x1p42100/pmic.c containing the PON log reading and parsing logic. - Add pmic.c to the SOC's romstage build via Makefile.mk. BUG=b:439819922 TEST=Verify off-mode charging behavior on Google/Quenbi. Change-Id: I8cd1478b9f8d53519f603e8f5168d0a51fa54971 Signed-off-by: Kapil Porwal <kapilporwal@google.com> Reviewed-on: https://review.coreboot.org/c/coreboot/+/90192 Reviewed-by: Subrata Banik <subratabanik@google.com> Tested-by: build bot (Jenkins) <no-reply@coreboot.org>
This commit is contained in:
parent
293f3a7f5c
commit
201ebd48ee
3 changed files with 229 additions and 0 deletions
|
|
@ -37,6 +37,7 @@ romstage-y += mmu.c
|
|||
romstage-y += ../common/aop_load_reset.c
|
||||
romstage-$(CONFIG_DRIVERS_UART) += ../common/qupv3_uart.c
|
||||
romstage-y += ../common/spmi.c
|
||||
romstage-y += pmic.c
|
||||
|
||||
################################################################################
|
||||
ramstage-y += soc.c
|
||||
|
|
|
|||
53
src/soc/qualcomm/x1p42100/include/soc/pmic.h
Normal file
53
src/soc/qualcomm/x1p42100/include/soc/pmic.h
Normal file
|
|
@ -0,0 +1,53 @@
|
|||
/* SPDX-License-Identifier: GPL-2.0-only */
|
||||
|
||||
#ifndef _SOC_QUALCOMM_X1P42100_PMIC_H__
|
||||
#define _SOC_QUALCOMM_X1P42100_PMIC_H__
|
||||
|
||||
#include <types.h>
|
||||
|
||||
#define PMIC_SLAVE_ID 0x00
|
||||
#define SDAM05_BASE_ADDR 0x7400
|
||||
#define MEM_OFFSET_START 0x40
|
||||
#define PON_EVENT_LOG_AREA_SIZE (127 - 11 + 1)
|
||||
#define PON_EVENT_TOTAL_LOG_AREA_SIZE (PON_EVENT_LOG_AREA_SIZE * 2)
|
||||
|
||||
#define PM_PON_SDAM_COUNT_ADDR (SDAM05_BASE_ADDR + MEM_OFFSET_START + 5)
|
||||
#define PM_PON_ENQUEUE_ADDR (SDAM05_BASE_ADDR + MEM_OFFSET_START + 6)
|
||||
#define PM_PON_ENQUEUE_SDAM_NUM (SDAM05_BASE_ADDR + MEM_OFFSET_START + 7)
|
||||
#define PM_PON_LOGGING_AREA_START (SDAM05_BASE_ADDR + MEM_OFFSET_START + 11)
|
||||
#define PM_PON_LOGGING_AREA_END (SDAM05_BASE_ADDR + MEM_OFFSET_START + 127)
|
||||
#define PM_PON_PUSH_PTR_INDEX(x) (x - (MEM_OFFSET_START + 11))
|
||||
|
||||
#define PM_PON_EVENT_PON_TRIGGER 0x1
|
||||
#define PM_PON_EVENT_RESET_TYPE 0x7
|
||||
#define PM_PON_EVENT_FUNDAMENTAL_RESET 0xC
|
||||
#define PM_PON_EVENT_RESET_TRIGGER 0x6
|
||||
#define BEGIN_PON 0XD
|
||||
#define PON_EVENT_PARSE_LIMIT 2
|
||||
|
||||
#define PON_KEYPD_PWR_N_S2_RSN 0x0080
|
||||
#define PON_RESIN_N_S2_RSN 0x0081
|
||||
#define PON_KPDPWR_AND_RESIN_RSN 0x0082
|
||||
#define PON_PMIC_WD_RSN 0x0083
|
||||
#define PON_PS_HOLD_RSN 0x0084
|
||||
#define PON_SW_RST_RSN 0x0085
|
||||
#define PON_RESIN_N_DEB_RSN 0x0086
|
||||
#define PON_KEYPD_PWR_N_RSN 0x0087
|
||||
#define PON_SMPL_RSN 0x0640
|
||||
#define PON_PON1_RSN 0x18C1
|
||||
#define PON_CBLPWR_RSN 0x18C0
|
||||
#define PON_SYS_OK_RSN 0x71C2
|
||||
#define PON_RTC_ALARM_RSN 0x0621
|
||||
|
||||
#define PON_RAW_XVDD_RB_MASK 0x8000
|
||||
#define PON_RAW_DVDD_RB_MASK 0x4000
|
||||
#define PON_S3_RESET_MASK 0xF0
|
||||
|
||||
#define PON_HARDRESET 0x7
|
||||
#define PON_SHUTDOWN 0x4
|
||||
#define PON_WARMRESET 0x1
|
||||
|
||||
int pm_pon_read_pon_hist(uint8_t *pon_hist_raw);
|
||||
bool is_pon_on_ac(void);
|
||||
|
||||
#endif // _SOC_QUALCOMM_X1P42100_PMIC_H__
|
||||
175
src/soc/qualcomm/x1p42100/pmic.c
Normal file
175
src/soc/qualcomm/x1p42100/pmic.c
Normal file
|
|
@ -0,0 +1,175 @@
|
|||
/* SPDX-License-Identifier: GPL-2.0-only */
|
||||
|
||||
#include <console/console.h>
|
||||
#include <soc/pmic.h>
|
||||
#include <soc/qcom_spmi.h>
|
||||
#include <types.h>
|
||||
|
||||
/*
|
||||
* pm_pon_get_pon_event - Search for a specific event type in the PON log.
|
||||
* @event: The event type to search for.
|
||||
* @pon_hist_log: Pointer to the PON history log buffer.
|
||||
* @pon_hist_raw_size: Total size of the raw log buffer.
|
||||
* @return_data: Pointer to store the associated event data.
|
||||
*
|
||||
* This helper function iterates through the PON log buffer and searches for an
|
||||
* entry matching the specified event type (e.g., PM_PON_EVENT_PON_TRIGGER).
|
||||
* If found, it extracts the associated 16-bit data field (which usually contains
|
||||
* the power-on reason or status) and returns it via return_data.
|
||||
*
|
||||
* @return 0 on success, -1 on error.
|
||||
*/
|
||||
static int pm_pon_get_pon_event(uint8_t event, uint8_t *pon_hist_log, uint32_t pon_hist_raw_size, uint16_t *return_data)
|
||||
{
|
||||
bool event_found = false;
|
||||
uint8_t data0;
|
||||
uint8_t data1;
|
||||
uint32_t i;
|
||||
|
||||
if (!pon_hist_log || !return_data)
|
||||
return -1;
|
||||
|
||||
for (i = 0; i < pon_hist_raw_size; i += 4) {
|
||||
if (event == *(pon_hist_log + 2)) {
|
||||
data0 = *pon_hist_log;
|
||||
data1 = *(pon_hist_log + 1);
|
||||
event_found = true;
|
||||
break;
|
||||
}
|
||||
pon_hist_log += 4;
|
||||
}
|
||||
|
||||
if (event_found == false)
|
||||
*return_data = 0;
|
||||
else
|
||||
*return_data = ((uint16_t) data1 << 8) | data0;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* pm_pon_read_pon_hist - Read, reorder, and prepare the PMIC Power-On history log.
|
||||
* @pon_hist_raw: Buffer to store the resulting PON history log. The buffer size
|
||||
* must be at least PON_EVENT_TOTAL_LOG_AREA_SIZE bytes.
|
||||
*
|
||||
* This function handles the low-level logic to read the PON event data from
|
||||
* the PMIC's SDAM registers (which function as a circular buffer) and reorders
|
||||
* the data in the output buffer (pon_hist_raw) so that the most recent event
|
||||
* entry is placed at the beginning (index 0).
|
||||
*
|
||||
* @return 0 on success, -1 on failure (e.g., if pon_hist_raw is NULL or SPMI read fails).
|
||||
*/
|
||||
int pm_pon_read_pon_hist(uint8_t *pon_hist_raw)
|
||||
{
|
||||
int status;
|
||||
uint8_t sdam_count;
|
||||
uint8_t enqueue_sdam_num;
|
||||
uint32_t i;
|
||||
uint32_t read_size;
|
||||
uint32_t push_ptr;
|
||||
uint8_t enqueue_addr;
|
||||
uint8_t temp;
|
||||
|
||||
if (!pon_hist_raw)
|
||||
return -1;
|
||||
|
||||
enqueue_addr = spmi_read8(SPMI_ADDR(PMIC_SLAVE_ID, PM_PON_ENQUEUE_ADDR));
|
||||
sdam_count = spmi_read8(SPMI_ADDR(PMIC_SLAVE_ID, PM_PON_SDAM_COUNT_ADDR));
|
||||
enqueue_sdam_num = spmi_read8(SPMI_ADDR(PMIC_SLAVE_ID, PM_PON_ENQUEUE_SDAM_NUM));
|
||||
|
||||
/* if sdam_count == 1, each SDAM contains half of the total size
|
||||
* otherwise, the SDAM stores the whole size
|
||||
*/
|
||||
status = spmi_read_bytes(SPMI_ADDR(PMIC_SLAVE_ID, PM_PON_LOGGING_AREA_START), pon_hist_raw, PON_EVENT_LOG_AREA_SIZE);
|
||||
|
||||
if (sdam_count != 0) {
|
||||
/* 0: Only used 1 SDAM
|
||||
* 1: Used 2 SDAM
|
||||
* Currently only extend to 2 continuous SDAM.
|
||||
*/
|
||||
status |= spmi_read_bytes(SPMI_ADDR(PMIC_SLAVE_ID, (PM_PON_LOGGING_AREA_START + 0x100)), pon_hist_raw + PON_EVENT_LOG_AREA_SIZE, PON_EVENT_LOG_AREA_SIZE);
|
||||
}
|
||||
|
||||
push_ptr = enqueue_addr;
|
||||
push_ptr = PM_PON_PUSH_PTR_INDEX(push_ptr) + (enqueue_sdam_num * PON_EVENT_LOG_AREA_SIZE);
|
||||
|
||||
if (status != 0 || push_ptr >= PON_EVENT_TOTAL_LOG_AREA_SIZE)
|
||||
return -1;
|
||||
|
||||
read_size = push_ptr/2;
|
||||
|
||||
/* Reverse the Buffer to start from latest event */
|
||||
for (i = 0; i < read_size; i++) {
|
||||
temp = pon_hist_raw[push_ptr - i - 1];
|
||||
pon_hist_raw[push_ptr - i - 1] = pon_hist_raw[i];
|
||||
pon_hist_raw[i] = temp;
|
||||
}
|
||||
|
||||
read_size = (PON_EVENT_TOTAL_LOG_AREA_SIZE - push_ptr) / 2;
|
||||
|
||||
for (i = 0; i < read_size; i++) {
|
||||
temp = pon_hist_raw[PON_EVENT_TOTAL_LOG_AREA_SIZE - i - 1];
|
||||
if (push_ptr + i < PON_EVENT_TOTAL_LOG_AREA_SIZE) {
|
||||
pon_hist_raw[PON_EVENT_TOTAL_LOG_AREA_SIZE - i - 1] = pon_hist_raw[push_ptr + i];
|
||||
pon_hist_raw[push_ptr + i] = temp;
|
||||
}
|
||||
}
|
||||
|
||||
return status;
|
||||
}
|
||||
|
||||
/*
|
||||
* is_pon_on_ac - Checks if the system was powered on by an AC/cable insertion event.
|
||||
*
|
||||
* This function reads and parses the PMIC Power-On (PON) history log to determine
|
||||
* the specific cause of the system power-up. It specifically looks for the
|
||||
* PON_CBLPWR_RSN trigger, which indicates that external power (AC/charging cable)
|
||||
* was the reason for the boot sequence initiation.
|
||||
*
|
||||
* @return true if AC/Cable Power was the PON reason, false otherwise.
|
||||
*/
|
||||
bool is_pon_on_ac(void)
|
||||
{
|
||||
uint16_t data, data2;
|
||||
uint32_t i;
|
||||
int8_t current_index = -1;
|
||||
uint8_t *pon_hist_curr_addr;
|
||||
uint8_t pon_hist_raw[PON_EVENT_TOTAL_LOG_AREA_SIZE] = {0};
|
||||
|
||||
printk(BIOS_INFO, "PON: Show power on reason -\n");
|
||||
if (pm_pon_read_pon_hist(pon_hist_raw))
|
||||
return false;
|
||||
|
||||
pon_hist_curr_addr = pon_hist_raw;
|
||||
|
||||
for (i = 0; i < PON_EVENT_LOG_AREA_SIZE - 2; i += 4) {
|
||||
if (current_index >= PON_EVENT_PARSE_LIMIT) {
|
||||
pon_hist_curr_addr += 4;
|
||||
continue;
|
||||
}
|
||||
data = ((uint16_t)(*(pon_hist_curr_addr + 1)) << 8) | *pon_hist_curr_addr;
|
||||
|
||||
if (BEGIN_PON == *(pon_hist_curr_addr + 2)) {
|
||||
pm_pon_get_pon_event(BEGIN_PON, pon_hist_curr_addr, (PON_EVENT_LOG_AREA_SIZE - 2) - (uint8_t)(pon_hist_curr_addr - pon_hist_raw), &data2);
|
||||
current_index += 1;
|
||||
} else if (PM_PON_EVENT_PON_TRIGGER == *(pon_hist_curr_addr + 2)) {
|
||||
switch (data) { /* SID<<12|PID<<4|IRQ */
|
||||
case PON_CBLPWR_RSN:
|
||||
printk(BIOS_INFO, " PON Reason : cblpwr\n");
|
||||
return true;
|
||||
default:
|
||||
printk(BIOS_INFO, " PON Reason : %d\n", data);
|
||||
return false;
|
||||
}
|
||||
} else if (PM_PON_EVENT_RESET_TYPE == *(pon_hist_curr_addr + 2)) {
|
||||
printk(BIOS_INFO, " Reset Reason : %d\n", data & 0xFF);
|
||||
return false;
|
||||
} else if (PM_PON_EVENT_FUNDAMENTAL_RESET == *(pon_hist_curr_addr + 2)) {
|
||||
printk(BIOS_INFO, " POFF Reason : %d\n", data & PON_RAW_XVDD_RB_MASK);
|
||||
return false;
|
||||
}
|
||||
pon_hist_curr_addr += 4;
|
||||
}
|
||||
printk(BIOS_INFO, " Unable to detect PON reason.\n");
|
||||
return false;
|
||||
}
|
||||
Loading…
Add table
Add a link
Reference in a new issue