From ada1d837e648fe1fb8194109ed0f3e5c51c4d776 Mon Sep 17 00:00:00 2001 From: Huibin Hong Date: Wed, 2 Dec 2020 15:36:25 +0800 Subject: [PATCH] soc: rockchip: debug: support pmu pcsr for rk356x RK356x doesn't support EDPCSR, but support pmupcsr of pmu Signed-off-by: Huibin Hong Change-Id: If588f4cc11909a57ded61937e4266ab7fd3fab17 --- drivers/soc/rockchip/rockchip_debug.c | 229 +++++++++++++++++++++++--- 1 file changed, 206 insertions(+), 23 deletions(-) diff --git a/drivers/soc/rockchip/rockchip_debug.c b/drivers/soc/rockchip/rockchip_debug.c index bc0b89209e09..67c46c15b6b4 100644 --- a/drivers/soc/rockchip/rockchip_debug.c +++ b/drivers/soc/rockchip/rockchip_debug.c @@ -65,16 +65,22 @@ #define EDPRSR 0x314 #define EDPRSR_PU 0x1 +#define EDDEVID 0xFC8 + +#define PMPCSR_LO 0x200 +#define PMPCSR_HI 0x204 #define NUM_CPU_SAMPLES 100 #define NUM_SAMPLES_TO_PRINT 32 static void __iomem *rockchip_cpu_debug[16]; +static void __iomem *rockchip_cs_pmu[16]; +static bool edpcsr_present; #if IS_ENABLED(CONFIG_FIQ_DEBUGGER) -int rockchip_debug_dump_pcsr(struct fiq_debugger_output *output) +static int rockchip_debug_dump_edpcsr(struct fiq_debugger_output *output) { - unsigned long dbgpcsr; + unsigned long edpcsr; int i = 0, j = 0; void *pc = NULL; void *prev_pc = NULL; @@ -100,14 +106,14 @@ int rockchip_debug_dump_pcsr(struct fiq_debugger_output *output) /* Try to read a bunch of times if CPU is actually running */ for (j = 0; j < NUM_CPU_SAMPLES && printed < NUM_SAMPLES_TO_PRINT; j++) { - if (sizeof(dbgpcsr) == 8) - dbgpcsr = ((u64)readl(base + EDPCSR_LO)) | + if (sizeof(edpcsr) == 8) + edpcsr = ((u64)readl(base + EDPCSR_LO)) | ((u64)readl(base + EDPCSR_HI) << 32); else - dbgpcsr = (u32)readl(base + EDPCSR_LO); + edpcsr = (u32)readl(base + EDPCSR_LO); /* NOTE: no offset on ARMv8; see DBGDEVID1.PCSROffset */ - pc = (void *)(dbgpcsr & ~1); + pc = (void *)(edpcsr & ~1); if (pc != prev_pc) { output->printf(output, @@ -124,13 +130,80 @@ int rockchip_debug_dump_pcsr(struct fiq_debugger_output *output) } return NOTIFY_OK; } + +#ifdef CONFIG_ARM64 +static int rockchip_debug_dump_pmpcsr(struct fiq_debugger_output *output) +{ + u64 pmpcsr; + int i = 0, j = 0, el, ns; + void *pc = NULL; + void *prev_pc = NULL; + int printed = 0; + void __iomem *base; + + while (rockchip_cs_pmu[i]) { + base = rockchip_cs_pmu[i]; + + output->printf(output, + "CPU%d online:%d\n", i, cpu_online(i)); + + /* Try to read a bunch of times if CPU is actually running */ + for (j = 0; j < NUM_CPU_SAMPLES && + printed < NUM_SAMPLES_TO_PRINT; j++) { + pmpcsr = ((u64)readl(base + PMPCSR_LO)) | + ((u64)readl(base + PMPCSR_HI) << 32); + + el = (pmpcsr >> 61) & 0x3; + if (pmpcsr & 0x8000000000000000) + ns = 1; + else + ns = 0; + + if (el == 2) + pmpcsr |= 0xff00000000000000; + else + pmpcsr &= 0x0fffffffffffffff; + /* NOTE: no offset on ARMv8; see DBGDEVID1.PCSROffset */ + pc = (void *)(pmpcsr & ~1); + + if (pc != prev_pc) { + output->printf(output, "\tEL%d(%s) PC: <0x%px> %pS\n", + el, ns?"NS":"S", pc, pc); + printed++; + } + prev_pc = pc; + } + + output->printf(output, "\n"); + i++; + prev_pc = NULL; + printed = 0; + } + return NOTIFY_OK; +} +#else +static int rockchip_debug_dump_pmpcsr(struct fiq_debugger_output *output) +{ + return 0; +} +#endif + + +int rockchip_debug_dump_pcsr(struct fiq_debugger_output *output) +{ + if (edpcsr_present) + rockchip_debug_dump_edpcsr(output); + else + rockchip_debug_dump_pmpcsr(output); + return 0; +} EXPORT_SYMBOL_GPL(rockchip_debug_dump_pcsr); #endif -static int rockchip_panic_notify(struct notifier_block *nb, unsigned long event, - void *p) +static int rockchip_panic_notify_edpcsr(struct notifier_block *nb, + unsigned long event, void *p) { - unsigned long dbgpcsr; + unsigned long edpcsr; int i = 0, j; void *pc = NULL; void *prev_pc = NULL; @@ -162,14 +235,14 @@ static int rockchip_panic_notify(struct notifier_block *nb, unsigned long event, /* Try to read a bunch of times if CPU is actually running */ for (j = 0; j < NUM_CPU_SAMPLES && printed < NUM_SAMPLES_TO_PRINT; j++) { - if (sizeof(dbgpcsr) == 8) - dbgpcsr = ((u64)readl(base + EDPCSR_LO)) | + if (sizeof(edpcsr) == 8) + edpcsr = ((u64)readl(base + EDPCSR_LO)) | ((u64)readl(base + EDPCSR_HI) << 32); else - dbgpcsr = (u32)readl(base + EDPCSR_LO); + edpcsr = (u32)readl(base + EDPCSR_LO); /* NOTE: no offset on ARMv8; see DBGDEVID1.PCSROffset */ - pc = (void *)(dbgpcsr & ~1); + pc = (void *)(edpcsr & ~1); if (pc != prev_pc) { pr_err("\tPC: <0x%px> %pS\n", pc, pc); @@ -186,38 +259,144 @@ static int rockchip_panic_notify(struct notifier_block *nb, unsigned long event, return NOTIFY_OK; } +#ifdef CONFIG_ARM64 +static int rockchip_panic_notify_pmpcsr(struct notifier_block *nb, + unsigned long event, void *p) +{ + u64 pmpcsr; + int i = 0, j, el, ns; + void *pc = NULL; + void *prev_pc = NULL; + int printed = 0; + void __iomem *base; + + /* + * The panic handler will try to shut down the other CPUs. + * If any of them are still online at this point, this loop attempts + * to determine the program counter value. If there are no wedged + * CPUs, this loop will do nothing. + */ + + while (rockchip_cs_pmu[i]) { + base = rockchip_cs_pmu[i]; + + pr_err("CPU%d online:%d\n", i, cpu_online(i)); + + /* Try to read a bunch of times if CPU is actually running */ + for (j = 0; j < NUM_CPU_SAMPLES && + printed < NUM_SAMPLES_TO_PRINT; j++) { + pmpcsr = ((u64)readl(base + PMPCSR_LO)) | + ((u64)readl(base + PMPCSR_HI) << 32); + + el = (pmpcsr >> 61) & 0x3; + if (pmpcsr & 0x8000000000000000) + ns = 1; + else + ns = 0; + + if (el == 2) + pmpcsr |= 0xff00000000000000; + else + pmpcsr &= 0x0fffffffffffffff; + /* NOTE: no offset on ARMv8; see DBGDEVID1.PCSROffset */ + pc = (void *)(pmpcsr & ~1); + + if (pc != prev_pc) { + pr_err("\tEL%d(%s) PC: <0x%px> %pS\n", + el, ns?"NS":"S", pc, pc); + printed++; + } + prev_pc = pc; + } + + pr_err("\n"); + i++; + prev_pc = NULL; + printed = 0; + } + return NOTIFY_OK; +} +#else +static int rockchip_panic_notify_pmpcsr(struct notifier_block *nb, + unsigned long event, void *p) +{ + return NOTIFY_OK; +} +#endif + +static int rockchip_panic_notify(struct notifier_block *nb, unsigned long event, + void *p) +{ + if (edpcsr_present) + rockchip_panic_notify_edpcsr(nb, event, p); + else + rockchip_panic_notify_pmpcsr(nb, event, p); + return NOTIFY_OK; +} static struct notifier_block rockchip_panic_nb = { .notifier_call = rockchip_panic_notify, }; static const struct of_device_id rockchip_debug_dt_match[] __initconst = { + /* external debug */ { .compatible = "rockchip,debug", }, { /* sentinel */ }, }; +static const struct of_device_id rockchip_cspmu_dt_match[] __initconst = { + /* coresight pmu */ + { + .compatible = "rockchip,cspmu", + }, + { /* sentinel */ }, +}; + + static int __init rockchip_debug_init(void) { int i; - struct device_node *np = NULL; + u32 pcs; + struct device_node *debug_np = NULL, *cspmu_np = NULL; - np = of_find_matching_node_and_match(NULL, + debug_np = of_find_matching_node_and_match(NULL, rockchip_debug_dt_match, NULL); - if (!np) + if (debug_np) { + i = -1; + do { + i++; + rockchip_cpu_debug[i] = of_iomap(debug_np, i); + } while (rockchip_cpu_debug[i]); + of_node_put(debug_np); + } + + cspmu_np = of_find_matching_node_and_match(NULL, + rockchip_cspmu_dt_match, NULL); + + if (cspmu_np) { + i = -1; + do { + i++; + rockchip_cs_pmu[i] = of_iomap(cspmu_np, i); + } while (rockchip_cs_pmu[i]); + of_node_put(cspmu_np); + } + + if (!debug_np) return -ENODEV; - i = -1; - do { - i++; - rockchip_cpu_debug[i] = of_iomap(np, i); - } while (rockchip_cpu_debug[i]); + pcs = readl(rockchip_cpu_debug[0] + EDDEVID) & 0xf; + /* 0x3 EDPCSR, EDCIDSR, and EDVIDSR are implemented */ + if (pcs == 0x3) + edpcsr_present = true; - of_node_put(np); + if (!edpcsr_present && !cspmu_np) + return -ENODEV; atomic_notifier_chain_register(&panic_notifier_list, - &rockchip_panic_nb); + &rockchip_panic_nb); return 0; } arch_initcall(rockchip_debug_init); @@ -231,6 +410,10 @@ static void __exit rockchip_debug_exit(void) while (rockchip_cpu_debug[i]) iounmap(rockchip_cpu_debug[i++]); + + i = 0; + while (rockchip_cs_pmu[i]) + iounmap(rockchip_cs_pmu[i++]); } module_exit(rockchip_debug_exit);