322 lines
9.4 KiB
C
322 lines
9.4 KiB
C
|
|
// SPDX-License-Identifier: GPL-2.0
|
||
|
|
/*
|
||
|
|
* Copyright (c) 2019 MediaTek Inc.
|
||
|
|
*/
|
||
|
|
|
||
|
|
|
||
|
|
#include <linux/kernel.h>
|
||
|
|
#include <linux/errno.h>
|
||
|
|
#include <linux/of.h>
|
||
|
|
#include <linux/of_address.h>
|
||
|
|
#include <linux/io.h>
|
||
|
|
|
||
|
|
#include <aee.h>
|
||
|
|
#include <mtk_lpm.h>
|
||
|
|
|
||
|
|
#include <mt6779_spm_comm.h>
|
||
|
|
#include <mt6779_spm_reg.h>
|
||
|
|
#include <mt6779_pwr_ctrl.h>
|
||
|
|
#include <mt6779_pcm_def.h>
|
||
|
|
#include <mtk_dbg_common_v1.h>
|
||
|
|
|
||
|
|
#define BYPASS_LOG
|
||
|
|
|
||
|
|
#ifndef BYPASS_LOG
|
||
|
|
static struct mt6779_spm_wake_status mt6779_wake;
|
||
|
|
#endif
|
||
|
|
void __iomem *mt6779_spm_base;
|
||
|
|
|
||
|
|
const char *mt6779_wakesrc_str[32] = {
|
||
|
|
[0] = " R12_PCM_TIMER_EVENT",
|
||
|
|
[1] = " R12_SPM_TWAM_IRQ_B",
|
||
|
|
[2] = " R12_KP_IRQ_B",
|
||
|
|
[3] = " R12_APWDT_EVENT_B",
|
||
|
|
[4] = " R12_APXGPT1_EVENT_B",
|
||
|
|
[5] = " R12_CONN2AP_SPM_WAKEUP_B",
|
||
|
|
[6] = " R12_EINT_EVENT_B",
|
||
|
|
[7] = " R12_CONN_WDT_IRQ_B",
|
||
|
|
[8] = " R12_CCIF0_EVENT_B",
|
||
|
|
[9] = " R12_LOWBATTERY_IRQ_B",
|
||
|
|
[10] = " R12_SC_SSPM2SPM_WAKEUP",
|
||
|
|
[11] = " R12_SC_SCP2SPM_WAKEUP",
|
||
|
|
[12] = " R12_SC_ADSP2SPM_WAKEUP",
|
||
|
|
[13] = " R12_PCM_WDT_EVENT_B",
|
||
|
|
[14] = " R12_USBX_CDSC_B",
|
||
|
|
[15] = " R12_USBX_POWERDWN_B",
|
||
|
|
[16] = " R12_SYS_TIMER_EVENT_B",
|
||
|
|
[17] = " R12_EINT_EVENT_SECURE_B",
|
||
|
|
[18] = " R12_CCIF1_EVENT_B",
|
||
|
|
[19] = " R12_UART0_IRQ_B",
|
||
|
|
[20] = " R12_AFE_IRQ_MCU_B",
|
||
|
|
[21] = " R12_THERMAL_CTRL_EVENT_B",
|
||
|
|
[22] = " R12_SYS_CIRQ_IRQ_B",
|
||
|
|
[23] = " R12_MD2AP_PEER_WAKEUP_EVENT",
|
||
|
|
[24] = " R12_CSYSPWREQ_B",
|
||
|
|
[25] = " R12_MD1_WDT_B",
|
||
|
|
[26] = " R12_AP2AP_PEER_WAKEUP_EVENT",
|
||
|
|
[27] = " R12_SEJ_EVENT_B",
|
||
|
|
[28] = " R12_SPM_CPU_WAKEUP_EVENT",
|
||
|
|
[29] = " R12_CPU_IRQOUT",
|
||
|
|
[30] = " R12_CPU_WFI",
|
||
|
|
[31] = " R12_MCUSYS_IDLE_TO_EMI_ALL",
|
||
|
|
};
|
||
|
|
|
||
|
|
|
||
|
|
#define plat_mmio_read(offset) __raw_readl(mt6779_spm_base + offset)
|
||
|
|
int mt6779_get_wakeup_status(struct mt6779_spm_wake_status *wakesta)
|
||
|
|
{
|
||
|
|
if (!wakesta || !mt6779_spm_base)
|
||
|
|
return -EINVAL;
|
||
|
|
|
||
|
|
wakesta->r12 = plat_mmio_read(SPM_SW_RSV_0);
|
||
|
|
wakesta->r12_ext = plat_mmio_read(SPM_WAKEUP_STA);
|
||
|
|
wakesta->raw_sta = plat_mmio_read(SPM_WAKEUP_STA);
|
||
|
|
wakesta->raw_ext_sta = plat_mmio_read(SPM_WAKEUP_EXT_STA);
|
||
|
|
wakesta->md32pcm_wakeup_sta = plat_mmio_read(MD32PCM_WAKEUP_STA);
|
||
|
|
wakesta->md32pcm_event_sta = plat_mmio_read(MD32PCM_EVENT_STA);
|
||
|
|
|
||
|
|
wakesta->src_req = plat_mmio_read(SPM_SRC_REQ);
|
||
|
|
|
||
|
|
/* backup of SPM_WAKEUP_MISC */
|
||
|
|
wakesta->wake_misc = plat_mmio_read(SPM_SW_RSV_5);
|
||
|
|
|
||
|
|
/* get sleep time */
|
||
|
|
/* backup of PCM_TIMER_OUT */
|
||
|
|
wakesta->timer_out = plat_mmio_read(SPM_SW_RSV_6);
|
||
|
|
|
||
|
|
/* get other SYS and co-clock status */
|
||
|
|
wakesta->r13 = plat_mmio_read(PCM_REG13_DATA);
|
||
|
|
wakesta->idle_sta = plat_mmio_read(SUBSYS_IDLE_STA);
|
||
|
|
wakesta->req_sta0 = plat_mmio_read(SRC_REQ_STA_0);
|
||
|
|
wakesta->req_sta1 = plat_mmio_read(SRC_REQ_STA_1);
|
||
|
|
wakesta->req_sta2 = plat_mmio_read(SRC_REQ_STA_2);
|
||
|
|
wakesta->req_sta3 = plat_mmio_read(SRC_REQ_STA_3);
|
||
|
|
wakesta->req_sta4 = plat_mmio_read(SRC_REQ_STA_4);
|
||
|
|
|
||
|
|
/* get debug flag for PCM execution check */
|
||
|
|
wakesta->debug_flag = plat_mmio_read(PCM_WDT_LATCH_SPARE_0);
|
||
|
|
wakesta->debug_flag1 = plat_mmio_read(PCM_WDT_LATCH_SPARE_1);
|
||
|
|
|
||
|
|
/* get backup SW flag status */
|
||
|
|
wakesta->b_sw_flag0 = plat_mmio_read(SPM_SW_RSV_7);
|
||
|
|
wakesta->b_sw_flag1 = plat_mmio_read(SPM_SW_RSV_8);
|
||
|
|
|
||
|
|
/* get ISR status */
|
||
|
|
wakesta->isr = plat_mmio_read(SPM_IRQ_STA);
|
||
|
|
|
||
|
|
/* get SW flag status */
|
||
|
|
wakesta->sw_flag0 = plat_mmio_read(SPM_SW_FLAG_0);
|
||
|
|
wakesta->sw_flag1 = plat_mmio_read(SPM_SW_FLAG_1);
|
||
|
|
|
||
|
|
/* get CLK SETTLE */
|
||
|
|
wakesta->clk_settle = plat_mmio_read(SPM_CLK_SETTLE);
|
||
|
|
/* check abort */
|
||
|
|
wakesta->is_abort = wakesta->debug_flag & DEBUG_ABORT_MASK;
|
||
|
|
wakesta->is_abort |= wakesta->debug_flag1 & DEBUG_ABORT_MASK_1;
|
||
|
|
|
||
|
|
return 0;
|
||
|
|
}
|
||
|
|
|
||
|
|
#ifdef BYPASS_LOG
|
||
|
|
|
||
|
|
int mt6779_show_log_message(int type, const char *prefix, void *data)
|
||
|
|
{
|
||
|
|
return 0;
|
||
|
|
}
|
||
|
|
|
||
|
|
#else
|
||
|
|
|
||
|
|
int mt6779_show_log_message(int type, const char *prefix, void *data)
|
||
|
|
{
|
||
|
|
#define LOG_BUF_SIZE 256
|
||
|
|
#define LOG_BUF_OUT_SZ 768
|
||
|
|
int i;
|
||
|
|
char buf[LOG_BUF_SIZE] = { 0 };
|
||
|
|
char log_buf[LOG_BUF_OUT_SZ] = { 0 };
|
||
|
|
char *local_ptr;
|
||
|
|
int log_size = 0;
|
||
|
|
unsigned int wr = WR_UNKNOWN;
|
||
|
|
const char *scenario = prefix ?: "UNKNOWN";
|
||
|
|
|
||
|
|
mt6779_get_wakeup_status(&mt6779_wake);
|
||
|
|
|
||
|
|
/* Disable rcu lock checking */
|
||
|
|
rcu_irq_enter_irqson();
|
||
|
|
|
||
|
|
if (mt6779_wake.is_abort != 0) {
|
||
|
|
/* add size check for vcoredvfs */
|
||
|
|
aee_sram_printk("SPM ABORT (%s), r13 = 0x%x, ",
|
||
|
|
scenario, mt6779_wake.r13);
|
||
|
|
log_size += scnprintf(log_buf + log_size,
|
||
|
|
LOG_BUF_OUT_SZ - log_size,
|
||
|
|
"[SPM] ABORT (%s), r13 = 0x%x, ",
|
||
|
|
scenario, mt6779_wake.r13);
|
||
|
|
|
||
|
|
aee_sram_printk(" debug_flag = 0x%x 0x%x\n",
|
||
|
|
mt6779_wake.debug_flag, mt6779_wake.debug_flag1);
|
||
|
|
log_size += scnprintf(log_buf + log_size,
|
||
|
|
LOG_BUF_OUT_SZ - log_size,
|
||
|
|
" debug_flag = 0x%x 0x%x\n",
|
||
|
|
mt6779_wake.debug_flag, mt6779_wake.debug_flag1);
|
||
|
|
|
||
|
|
aee_sram_printk(" sw_flag = 0x%x 0x%x\n",
|
||
|
|
mt6779_wake.sw_flag0, mt6779_wake.sw_flag1);
|
||
|
|
log_size += scnprintf(log_buf + log_size,
|
||
|
|
LOG_BUF_OUT_SZ - log_size,
|
||
|
|
" sw_flag = 0x%x 0x%x\n",
|
||
|
|
mt6779_wake.sw_flag0, mt6779_wake.sw_flag1);
|
||
|
|
|
||
|
|
aee_sram_printk(" b_sw_flag = 0x%x 0x%x\n",
|
||
|
|
mt6779_wake.b_sw_flag0, mt6779_wake.b_sw_flag1);
|
||
|
|
log_size += scnprintf(log_buf + log_size,
|
||
|
|
LOG_BUF_OUT_SZ - log_size,
|
||
|
|
" b_sw_flag = 0x%x 0x%x\n",
|
||
|
|
mt6779_wake.b_sw_flag0, mt6779_wake.b_sw_flag1);
|
||
|
|
|
||
|
|
wr = WR_ABORT;
|
||
|
|
}
|
||
|
|
|
||
|
|
if (mt6779_wake.r12 & R12_PCM_TIMER_EVENT) {
|
||
|
|
if (mt6779_wake.wake_misc & WAKE_MISC_PCM_TIMER_EVENT) {
|
||
|
|
local_ptr = " PCM_TIMER";
|
||
|
|
if ((strlen(buf) + strlen(local_ptr)) < LOG_BUF_SIZE)
|
||
|
|
strncat(buf, local_ptr, strlen(local_ptr));
|
||
|
|
wr = WR_PCM_TIMER;
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
if (mt6779_wake.r12 & R12_SPM_TWAM_IRQ_B) {
|
||
|
|
if (mt6779_wake.wake_misc & WAKE_MISC_DVFSRC_IRQ) {
|
||
|
|
local_ptr = " DVFSRC";
|
||
|
|
if ((strlen(buf) + strlen(local_ptr)) < LOG_BUF_SIZE)
|
||
|
|
strncat(buf, local_ptr, strlen(local_ptr));
|
||
|
|
wr = WR_DVFSRC;
|
||
|
|
}
|
||
|
|
if (mt6779_wake.wake_misc & WAKE_MISC_TWAM_IRQ_B) {
|
||
|
|
local_ptr = " TWAM";
|
||
|
|
if ((strlen(buf) + strlen(local_ptr)) < LOG_BUF_SIZE)
|
||
|
|
strncat(buf, local_ptr, strlen(local_ptr));
|
||
|
|
wr = WR_TWAM;
|
||
|
|
}
|
||
|
|
if (mt6779_wake.wake_misc & WAKE_MISC_PMSR_IRQ_B_SET0) {
|
||
|
|
local_ptr = " PMSR";
|
||
|
|
if ((strlen(buf) + strlen(local_ptr)) < LOG_BUF_SIZE)
|
||
|
|
strncat(buf, local_ptr, strlen(local_ptr));
|
||
|
|
wr = WR_PMSR;
|
||
|
|
}
|
||
|
|
if (mt6779_wake.wake_misc & WAKE_MISC_PMSR_IRQ_B_SET1) {
|
||
|
|
local_ptr = " PMSR";
|
||
|
|
if ((strlen(buf) + strlen(local_ptr)) < LOG_BUF_SIZE)
|
||
|
|
strncat(buf, local_ptr, strlen(local_ptr));
|
||
|
|
wr = WR_PMSR;
|
||
|
|
}
|
||
|
|
if (mt6779_wake.wake_misc & WAKE_MISC_SPM_ACK_CHK_WAKEUP_0) {
|
||
|
|
local_ptr = " SPM_ACK_CHK";
|
||
|
|
if ((strlen(buf) + strlen(local_ptr)) < LOG_BUF_SIZE)
|
||
|
|
strncat(buf, local_ptr, strlen(local_ptr));
|
||
|
|
wr = WR_SPM_ACK_CHK;
|
||
|
|
}
|
||
|
|
if (mt6779_wake.wake_misc & WAKE_MISC_SPM_ACK_CHK_WAKEUP_1) {
|
||
|
|
local_ptr = " SPM_ACK_CHK";
|
||
|
|
if ((strlen(buf) + strlen(local_ptr)) < LOG_BUF_SIZE)
|
||
|
|
strncat(buf, local_ptr, strlen(local_ptr));
|
||
|
|
wr = WR_SPM_ACK_CHK;
|
||
|
|
}
|
||
|
|
if (mt6779_wake.wake_misc & WAKE_MISC_SPM_ACK_CHK_WAKEUP_2) {
|
||
|
|
local_ptr = " SPM_ACK_CHK";
|
||
|
|
if ((strlen(buf) + strlen(local_ptr)) < LOG_BUF_SIZE)
|
||
|
|
strncat(buf, local_ptr, strlen(local_ptr));
|
||
|
|
wr = WR_SPM_ACK_CHK;
|
||
|
|
}
|
||
|
|
if (mt6779_wake.wake_misc & WAKE_MISC_SPM_ACK_CHK_WAKEUP_3) {
|
||
|
|
local_ptr = " SPM_ACK_CHK";
|
||
|
|
if ((strlen(buf) + strlen(local_ptr)) < LOG_BUF_SIZE)
|
||
|
|
strncat(buf, local_ptr, strlen(local_ptr));
|
||
|
|
wr = WR_SPM_ACK_CHK;
|
||
|
|
}
|
||
|
|
if (mt6779_wake.wake_misc & WAKE_MISC_SPM_ACK_CHK_WAKEUP_ALL) {
|
||
|
|
local_ptr = " SPM_ACK_CHK";
|
||
|
|
if ((strlen(buf) + strlen(local_ptr)) < LOG_BUF_SIZE)
|
||
|
|
strncat(buf, local_ptr, strlen(local_ptr));
|
||
|
|
wr = WR_SPM_ACK_CHK;
|
||
|
|
}
|
||
|
|
}
|
||
|
|
for (i = 1; i < 32; i++) {
|
||
|
|
if (mt6779_wake.r12 & (1U << i)) {
|
||
|
|
if ((strlen(buf) + strlen(mt6779_wakesrc_str[i])) <
|
||
|
|
LOG_BUF_SIZE)
|
||
|
|
strncat(buf, mt6779_wakesrc_str[i],
|
||
|
|
strlen(mt6779_wakesrc_str[i]));
|
||
|
|
|
||
|
|
wr = WR_WAKE_SRC;
|
||
|
|
}
|
||
|
|
}
|
||
|
|
WARN_ON(strlen(buf) >= LOG_BUF_SIZE);
|
||
|
|
|
||
|
|
log_size += scnprintf(log_buf + log_size, LOG_BUF_OUT_SZ - log_size,
|
||
|
|
"%s wake up by %s, timer_out = %u, r13 = 0x%x, debug_flag = 0x%x 0x%x, ",
|
||
|
|
scenario, buf, mt6779_wake.timer_out, mt6779_wake.r13,
|
||
|
|
mt6779_wake.debug_flag, mt6779_wake.debug_flag1);
|
||
|
|
|
||
|
|
log_size += scnprintf(log_buf + log_size, LOG_BUF_OUT_SZ - log_size,
|
||
|
|
"r12 = 0x%x, r12_ext = 0x%x, raw_sta = 0x%x 0x%x 0x%x, idle_sta = 0x%x, ",
|
||
|
|
mt6779_wake.r12, mt6779_wake.r12_ext, mt6779_wake.raw_sta,
|
||
|
|
mt6779_wake.md32pcm_wakeup_sta, mt6779_wake.md32pcm_event_sta,
|
||
|
|
mt6779_wake.idle_sta);
|
||
|
|
|
||
|
|
log_size += scnprintf(log_buf + log_size, LOG_BUF_OUT_SZ - log_size,
|
||
|
|
" req_sta = 0x%x 0x%x 0x%x 0x%x 0x%x, isr = 0x%x, ",
|
||
|
|
mt6779_wake.req_sta0, mt6779_wake.req_sta1,
|
||
|
|
mt6779_wake.req_sta2, mt6779_wake.req_sta3,
|
||
|
|
mt6779_wake.req_sta4, mt6779_wake.isr);
|
||
|
|
|
||
|
|
log_size += scnprintf(log_buf + log_size,
|
||
|
|
LOG_BUF_OUT_SZ - log_size,
|
||
|
|
"raw_ext_sta = 0x%x, wake_misc = 0x%x, pcm_flag = 0x%x 0x%x 0x%x 0x%x, req = 0x%x, ",
|
||
|
|
mt6779_wake.raw_ext_sta,
|
||
|
|
mt6779_wake.wake_misc,
|
||
|
|
mt6779_wake.sw_flag0,
|
||
|
|
mt6779_wake.sw_flag1, mt6779_wake.b_sw_flag0,
|
||
|
|
mt6779_wake.b_sw_flag0,
|
||
|
|
mt6779_wake.src_req);
|
||
|
|
|
||
|
|
log_size += scnprintf(log_buf + log_size,
|
||
|
|
LOG_BUF_OUT_SZ - log_size,
|
||
|
|
" clk_settle = 0x%x, ", mt6779_wake.clk_settle);
|
||
|
|
|
||
|
|
WARN_ON(log_size >= LOG_BUF_OUT_SZ);
|
||
|
|
|
||
|
|
pr_info("[name:spm&][SPM] %s", log_buf);
|
||
|
|
|
||
|
|
/* Eable rcu lock checking */
|
||
|
|
rcu_irq_exit_irqson();
|
||
|
|
|
||
|
|
return wr;
|
||
|
|
}
|
||
|
|
#endif
|
||
|
|
|
||
|
|
struct mtk_lpm_issuer mt6779_issuer = {
|
||
|
|
.log = mt6779_show_log_message,
|
||
|
|
};
|
||
|
|
|
||
|
|
int mt6779_logger_init(void)
|
||
|
|
{
|
||
|
|
struct device_node *node = NULL;
|
||
|
|
|
||
|
|
node = of_find_compatible_node(NULL, NULL, "mediatek,spm");
|
||
|
|
|
||
|
|
if (node) {
|
||
|
|
mt6779_spm_base = of_iomap(node, 0);
|
||
|
|
of_node_put(node);
|
||
|
|
}
|
||
|
|
|
||
|
|
if (mt6779_spm_base)
|
||
|
|
mtk_lp_issuer_register(&mt6779_issuer);
|
||
|
|
else
|
||
|
|
pr_info("[name:mtk_lpm][P] - Don't register the issue by error! (%s:%d)\n",
|
||
|
|
__func__, __LINE__);
|
||
|
|
return 0;
|
||
|
|
}
|
||
|
|
EXPORT_SYMBOL(mt6779_logger_init);
|
||
|
|
|