10ae76531SDavid Feng /*
20ae76531SDavid Feng * (C) Copyright 2013
30ae76531SDavid Feng * David Feng <fenghua@phytium.com.cn>
40ae76531SDavid Feng *
50ae76531SDavid Feng * SPDX-License-Identifier: GPL-2.0+
60ae76531SDavid Feng */
70ae76531SDavid Feng
80ae76531SDavid Feng #include <common.h>
90ae76531SDavid Feng #include <linux/compiler.h>
1064982915SAlexander Graf #include <efi_loader.h>
1158d85a14SJoseph Chen #include <iomem.h>
12d554a7b2SJoseph Chen #include <stacktrace.h>
13*4905c834SHuibin Hong #ifdef CONFIG_ROCKCHIP_MINIDUMP
14*4905c834SHuibin Hong #include <rk_mini_dump.h>
15*4905c834SHuibin Hong #endif
160ae76531SDavid Feng
175e076729SPeng Fan DECLARE_GLOBAL_DATA_PTR;
183fe16d46SJoseph Chen
197cef7918SJoseph Chen #if !CONFIG_IS_ENABLED(IRQ)
interrupt_init(void)200ae76531SDavid Feng int interrupt_init(void)
210ae76531SDavid Feng {
220ae76531SDavid Feng return 0;
230ae76531SDavid Feng }
240ae76531SDavid Feng
enable_interrupts(void)250ae76531SDavid Feng void enable_interrupts(void)
260ae76531SDavid Feng {
270ae76531SDavid Feng return;
280ae76531SDavid Feng }
290ae76531SDavid Feng
disable_interrupts(void)300ae76531SDavid Feng int disable_interrupts(void)
310ae76531SDavid Feng {
320ae76531SDavid Feng return 0;
330ae76531SDavid Feng }
34fa40f8a0SJoseph Chen #endif
350ae76531SDavid Feng
36faa7eb0fSJoseph Chen #define REG_BITS(val, shift, mask) (((val) >> (shift)) & (mask))
37faa7eb0fSJoseph Chen
387cef7918SJoseph Chen #ifndef CONFIG_SPL_BUILD
show_regs(struct pt_regs * regs)39faa7eb0fSJoseph Chen void show_regs(struct pt_regs *regs)
40faa7eb0fSJoseph Chen {
41faa7eb0fSJoseph Chen int el = current_el();
4274ab8aa2SJoseph Chen int i;
4374ab8aa2SJoseph Chen
44faa7eb0fSJoseph Chen const char *esr_bits_ec[] = {
4574ab8aa2SJoseph Chen [0] = "an unknown reason",
4674ab8aa2SJoseph Chen [1] = "a WFI or WFE instruction",
4774ab8aa2SJoseph Chen [3] = "an MCR or MRC access",
4874ab8aa2SJoseph Chen [4] = "an MCRR or MRRC access",
4974ab8aa2SJoseph Chen [5] = "an MCR or MRC access",
5074ab8aa2SJoseph Chen [6] = "an LDC or STC access to CP14",
5174ab8aa2SJoseph Chen [7] = "an access to an Advanced SIMD or floating-point register, resulting from CPACR_EL1.FPEN or CPTR_ELx.TFP",
5274ab8aa2SJoseph Chen [8] = "an MCR or MRC access",
5374ab8aa2SJoseph Chen [12] = "an MCRR or MRRC access",
5474ab8aa2SJoseph Chen [14] = "an Illegal execution state, or a PC or SP alignment fault",
5574ab8aa2SJoseph Chen [10] = "HVC or SVC instruction execution",
5674ab8aa2SJoseph Chen [18] = "HVC or SVC instruction execution",
5774ab8aa2SJoseph Chen [19] = "SMC instruction execution in AArch32 state",
5874ab8aa2SJoseph Chen [21] = "HVC or SVC instruction execution",
5974ab8aa2SJoseph Chen [22] = "HVC or SVC instruction execution",
6074ab8aa2SJoseph Chen [23] = "SMC instruction execution in AArch64 state",
6174ab8aa2SJoseph Chen [24] = "MSR, MRS, or System instruction execution in AArch64 state",
6274ab8aa2SJoseph Chen [31] = "IMPLEMENTATION DEFINED exception to EL3",
6374ab8aa2SJoseph Chen [32] = "an Instruction abort",
6474ab8aa2SJoseph Chen [33] = "an Instruction abort",
6574ab8aa2SJoseph Chen [34] = "an Illegal execution state, or a PC or SP alignment fault",
6674ab8aa2SJoseph Chen [36] = "a Data abort, from lower exception level",
6774ab8aa2SJoseph Chen [37] = "a Data abort, from current exception level",
6874ab8aa2SJoseph Chen [38] = "an Illegal execution state, or a PC or SP alignment fault",
6974ab8aa2SJoseph Chen [40] = "a trapped Floating-point exception",
7074ab8aa2SJoseph Chen [44] = "a trapped Floating-point exception",
7174ab8aa2SJoseph Chen [47] = "SError interrupt",
7274ab8aa2SJoseph Chen [48] = "a Breakpoint or Vector Catch debug event",
7374ab8aa2SJoseph Chen [49] = "a Breakpoint or Vector Catch debug event",
7474ab8aa2SJoseph Chen [50] = "a Software Step debug event",
7574ab8aa2SJoseph Chen [51] = "a Software Step debug event",
7674ab8aa2SJoseph Chen [52] = "a Watchpoint debug event",
7774ab8aa2SJoseph Chen [53] = "a Watchpoint debug event",
7874ab8aa2SJoseph Chen [56] = "execution of a Software Breakpoint instructio",
79faa7eb0fSJoseph Chen };
80faa7eb0fSJoseph Chen
8174ab8aa2SJoseph Chen printf("\n");
82faa7eb0fSJoseph Chen
8374ab8aa2SJoseph Chen /* PC/LR/SP ... */
8474ab8aa2SJoseph Chen printf("* Reason: Exception from %s\n", esr_bits_ec[REG_BITS(regs->esr, 26, 0x3f)]);
85faa7eb0fSJoseph Chen if (gd->flags & GD_FLG_RELOC) {
8674ab8aa2SJoseph Chen printf("* PC = %016lx\n", regs->elr - gd->reloc_off);
87faa7eb0fSJoseph Chen printf("* LR = %016lx\n", regs->regs[30] - gd->reloc_off);
88faa7eb0fSJoseph Chen } else {
89faa7eb0fSJoseph Chen printf("* ELR(PC) = %016lx\n", regs->elr);
90faa7eb0fSJoseph Chen printf("* LR = %016lx\n", regs->regs[30]);
91faa7eb0fSJoseph Chen }
92faa7eb0fSJoseph Chen printf("* SP = %016lx\n", regs->sp);
93faa7eb0fSJoseph Chen printf("* ESR_EL%d = %016lx\n", el, regs->esr);
9474ab8aa2SJoseph Chen printf("* Reloc Off = %016lx\n\n", gd->reloc_off);
95faa7eb0fSJoseph Chen
9674ab8aa2SJoseph Chen /* CPU */
97faa7eb0fSJoseph Chen for (i = 0; i < 29; i += 2)
98faa7eb0fSJoseph Chen printf("x%-2d: %016lx x%-2d: %016lx\n",
99faa7eb0fSJoseph Chen i, regs->regs[i], i+1, regs->regs[i+1]);
100faa7eb0fSJoseph Chen printf("\n");
10124cd8f36SJoseph Chen
10274ab8aa2SJoseph Chen /* SoC */
10324cd8f36SJoseph Chen #ifdef CONFIG_ROCKCHIP_CRASH_DUMP
10424cd8f36SJoseph Chen iomem_show_by_compatible("-cru", 0, 0x400);
10524cd8f36SJoseph Chen iomem_show_by_compatible("-pmucru", 0, 0x400);
10624cd8f36SJoseph Chen iomem_show_by_compatible("-grf", 0, 0x400);
10724cd8f36SJoseph Chen iomem_show_by_compatible("-pmugrf", 0, 0x400);
10824cd8f36SJoseph Chen #endif
10974ab8aa2SJoseph Chen /* Call trace */
110d554a7b2SJoseph Chen dump_core_stack(regs);
111faa7eb0fSJoseph Chen }
112faa7eb0fSJoseph Chen
113faa7eb0fSJoseph Chen #else
show_regs(struct pt_regs * regs)1140ae76531SDavid Feng void show_regs(struct pt_regs *regs)
1150ae76531SDavid Feng {
1160ae76531SDavid Feng int i;
1170ae76531SDavid Feng
1185e076729SPeng Fan if (gd->flags & GD_FLG_RELOC) {
1195e076729SPeng Fan printf("ELR: %lx\n", regs->elr - gd->reloc_off);
1205e076729SPeng Fan printf("LR: %lx\n", regs->regs[30] - gd->reloc_off);
1215e076729SPeng Fan } else {
1220ae76531SDavid Feng printf("ELR: %lx\n", regs->elr);
1230ae76531SDavid Feng printf("LR: %lx\n", regs->regs[30]);
1245e076729SPeng Fan }
1253fe16d46SJoseph Chen
1263fe16d46SJoseph Chen printf("ESR: %lx (ec=%ld)\n", regs->esr, REG_BITS(regs->esr, 26, 0x3f));
1273fe16d46SJoseph Chen
1280ae76531SDavid Feng for (i = 0; i < 29; i += 2)
1290ae76531SDavid Feng printf("x%-2d: %016lx x%-2d: %016lx\n",
1300ae76531SDavid Feng i, regs->regs[i], i+1, regs->regs[i+1]);
1310ae76531SDavid Feng printf("\n");
132d554a7b2SJoseph Chen
133d554a7b2SJoseph Chen dump_core_stack(regs);
1340ae76531SDavid Feng }
135faa7eb0fSJoseph Chen #endif
1360ae76531SDavid Feng
1370ae76531SDavid Feng /*
1380ae76531SDavid Feng * do_bad_sync handles the impossible case in the Synchronous Abort vector.
1390ae76531SDavid Feng */
do_bad_sync(struct pt_regs * pt_regs,unsigned int esr)1400ae76531SDavid Feng void do_bad_sync(struct pt_regs *pt_regs, unsigned int esr)
1410ae76531SDavid Feng {
14264982915SAlexander Graf efi_restore_gd();
1430ae76531SDavid Feng printf("Bad mode in \"Synchronous Abort\" handler, esr 0x%08x\n", esr);
1440ae76531SDavid Feng show_regs(pt_regs);
1450ae76531SDavid Feng panic("Resetting CPU ...\n");
1460ae76531SDavid Feng }
1470ae76531SDavid Feng
1480ae76531SDavid Feng /*
1490ae76531SDavid Feng * do_bad_irq handles the impossible case in the Irq vector.
1500ae76531SDavid Feng */
do_bad_irq(struct pt_regs * pt_regs,unsigned int esr)1510ae76531SDavid Feng void do_bad_irq(struct pt_regs *pt_regs, unsigned int esr)
1520ae76531SDavid Feng {
15364982915SAlexander Graf efi_restore_gd();
1540ae76531SDavid Feng printf("Bad mode in \"Irq\" handler, esr 0x%08x\n", esr);
1550ae76531SDavid Feng show_regs(pt_regs);
1560ae76531SDavid Feng panic("Resetting CPU ...\n");
1570ae76531SDavid Feng }
1580ae76531SDavid Feng
1590ae76531SDavid Feng /*
1600ae76531SDavid Feng * do_bad_fiq handles the impossible case in the Fiq vector.
1610ae76531SDavid Feng */
do_bad_fiq(struct pt_regs * pt_regs,unsigned int esr)1620ae76531SDavid Feng void do_bad_fiq(struct pt_regs *pt_regs, unsigned int esr)
1630ae76531SDavid Feng {
16464982915SAlexander Graf efi_restore_gd();
1650ae76531SDavid Feng printf("Bad mode in \"Fiq\" handler, esr 0x%08x\n", esr);
1660ae76531SDavid Feng show_regs(pt_regs);
1670ae76531SDavid Feng panic("Resetting CPU ...\n");
1680ae76531SDavid Feng }
1690ae76531SDavid Feng
1700ae76531SDavid Feng /*
1710ae76531SDavid Feng * do_bad_error handles the impossible case in the Error vector.
1720ae76531SDavid Feng */
do_bad_error(struct pt_regs * pt_regs,unsigned int esr)1730ae76531SDavid Feng void do_bad_error(struct pt_regs *pt_regs, unsigned int esr)
1740ae76531SDavid Feng {
17564982915SAlexander Graf efi_restore_gd();
1760ae76531SDavid Feng printf("Bad mode in \"Error\" handler, esr 0x%08x\n", esr);
1770ae76531SDavid Feng show_regs(pt_regs);
1780ae76531SDavid Feng panic("Resetting CPU ...\n");
1790ae76531SDavid Feng }
1800ae76531SDavid Feng
1810ae76531SDavid Feng /*
1820ae76531SDavid Feng * do_sync handles the Synchronous Abort exception.
1830ae76531SDavid Feng */
do_sync(struct pt_regs * pt_regs,unsigned int esr)1840ae76531SDavid Feng void do_sync(struct pt_regs *pt_regs, unsigned int esr)
1850ae76531SDavid Feng {
18664982915SAlexander Graf efi_restore_gd();
187*4905c834SHuibin Hong #ifdef CONFIG_ROCKCHIP_MINIDUMP
188*4905c834SHuibin Hong if (md_no_fault_handler(pt_regs, esr)) {
189*4905c834SHuibin Hong /* Return to next instruction */
190*4905c834SHuibin Hong pt_regs->elr += 4;
191*4905c834SHuibin Hong return;
192*4905c834SHuibin Hong }
193*4905c834SHuibin Hong #endif
1940ae76531SDavid Feng printf("\"Synchronous Abort\" handler, esr 0x%08x\n", esr);
1950ae76531SDavid Feng show_regs(pt_regs);
1960ae76531SDavid Feng panic("Resetting CPU ...\n");
1970ae76531SDavid Feng }
1980ae76531SDavid Feng
1997cef7918SJoseph Chen #if !CONFIG_IS_ENABLED(IRQ)
2000ae76531SDavid Feng /*
2010ae76531SDavid Feng * do_irq handles the Irq exception.
2020ae76531SDavid Feng */
do_irq(struct pt_regs * pt_regs,unsigned int esr)2030ae76531SDavid Feng void do_irq(struct pt_regs *pt_regs, unsigned int esr)
2040ae76531SDavid Feng {
20564982915SAlexander Graf efi_restore_gd();
2060ae76531SDavid Feng printf("\"Irq\" handler, esr 0x%08x\n", esr);
2070ae76531SDavid Feng show_regs(pt_regs);
2080ae76531SDavid Feng panic("Resetting CPU ...\n");
2090ae76531SDavid Feng }
210fa40f8a0SJoseph Chen #endif
2110ae76531SDavid Feng
2120ae76531SDavid Feng /*
2130ae76531SDavid Feng * do_fiq handles the Fiq exception.
2140ae76531SDavid Feng */
do_fiq(struct pt_regs * pt_regs,unsigned int esr)2150ae76531SDavid Feng void do_fiq(struct pt_regs *pt_regs, unsigned int esr)
2160ae76531SDavid Feng {
21764982915SAlexander Graf efi_restore_gd();
2180ae76531SDavid Feng printf("\"Fiq\" handler, esr 0x%08x\n", esr);
2190ae76531SDavid Feng show_regs(pt_regs);
2200ae76531SDavid Feng panic("Resetting CPU ...\n");
2210ae76531SDavid Feng }
2220ae76531SDavid Feng
2230ae76531SDavid Feng /*
2240ae76531SDavid Feng * do_error handles the Error exception.
2250ae76531SDavid Feng * Errors are more likely to be processor specific,
2260ae76531SDavid Feng * it is defined with weak attribute and can be redefined
2270ae76531SDavid Feng * in processor specific code.
2280ae76531SDavid Feng */
do_error(struct pt_regs * pt_regs,unsigned int esr)2290ae76531SDavid Feng void __weak do_error(struct pt_regs *pt_regs, unsigned int esr)
2300ae76531SDavid Feng {
23164982915SAlexander Graf efi_restore_gd();
232*4905c834SHuibin Hong #ifdef CONFIG_ROCKCHIP_MINIDUMP
233*4905c834SHuibin Hong if (md_no_fault_handler(pt_regs, esr)) {
234*4905c834SHuibin Hong /* Return to next instruction */
235*4905c834SHuibin Hong pt_regs->elr += 4;
236*4905c834SHuibin Hong return;
237*4905c834SHuibin Hong }
238*4905c834SHuibin Hong #endif
2390ae76531SDavid Feng printf("\"Error\" handler, esr 0x%08x\n", esr);
2400ae76531SDavid Feng show_regs(pt_regs);
2410ae76531SDavid Feng panic("Resetting CPU ...\n");
2420ae76531SDavid Feng }
243