| /* |
| * Copyright (c) 2018 MediaTek Inc. |
| * |
| * Permission is hereby granted, free of charge, to any person obtaining |
| * a copy of this software and associated documentation files |
| * (the "Software"), to deal in the Software without restriction, |
| * including without limitation the rights to use, copy, modify, merge, |
| * publish, distribute, sublicense, and/or sell copies of the Software, |
| * and to permit persons to whom the Software is furnished to do so, |
| * subject to the following conditions: |
| * |
| * The above copyright notice and this permission notice shall be |
| * included in all copies or substantial portions of the Software. |
| * |
| * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, |
| * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF |
| * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. |
| * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY |
| * CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, |
| * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE |
| * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. |
| */ |
| |
| #include <arch/ops.h> |
| #include <boot_args.h> |
| #include <env.h> |
| #include <lib/kcmdline.h> |
| #include <libfdt.h> |
| #include <malloc.h> |
| #include <mrdump.h> |
| #include <platform.h> |
| #include <platform/mtk_wdt.h> |
| #include <platform/platform_blx.h> |
| #include <printf.h> |
| #include <ram_console.h> |
| #include <stdarg.h> |
| #include <stdint.h> |
| #include <stdlib.h> |
| #include <string.h> |
| #include "aee.h" |
| #include "kdump.h" |
| |
| extern BOOT_ARGUMENT *g_boot_arg; |
| extern int kedump_restore_mem(void); |
| |
| #define MRDUMP_RSV_MEM "mrdump_rsvmem=0x%x,0x%x,0x%x,0x%x,0x%x,0x%x,0x%x,0x%x,0x%x,0x%x" |
| #define MRDUMP_CB_RSV_MEM "mrdump_cb=0x%x,0x%x" |
| #define RAM_CONSOLE_RSV_MEM "ram_console_rsvmem=0x%x,0x%x" |
| #define MINIDUMP_RSV_MEM "minirdump_rsvmem=0x%x,0x%x" |
| #define PSTORE_RSV_MEM "pstore_rsvmem=0x%x,0x%x,0x%x,0x%x" |
| |
| unsigned int get_reboot_reason(unsigned int boot_reason) |
| { |
| unsigned int rc_wdt_status; |
| unsigned int rc_exp_type; |
| unsigned int ret = 0; |
| if (boot_reason == BR_WDT_BY_PASS_PWK) { |
| if (ram_console_get_wdt_status(&rc_wdt_status) && ram_console_get_exp_type(&rc_exp_type)){ |
| dprintf(CRITICAL, "rc_wdt_status = %d, rc_exp_type = %d\n", rc_wdt_status, rc_exp_type); |
| switch (rc_exp_type) { |
| case 0: |
| if (rc_wdt_status == 5) |
| ret = REBOOT_REASON_WATCHDOG; |
| break; |
| case AEE_EXP_TYPE_HWT: |
| ret = REBOOT_REASON_WATCHDOG; |
| break; |
| case AEE_EXP_TYPE_DM_VERITY_CORRUPTION: |
| ret = REBOOT_REASON_DM_VERITY_CORRUPTION; |
| break; |
| case AEE_EXP_TYPE_KE: |
| case AEE_EXP_TYPE_NESTED_PANIC: |
| ret = REBOOT_REASON_KERNEL_PANIC; |
| break; |
| default: |
| break; |
| } |
| } |
| } |
| else if (boot_reason == BR_2SEC_REBOOT) { |
| ret = REBOOT_REASON_2S_REBOOT; |
| } else { |
| ret = REBOOT_REASON_REBOOT; |
| } |
| return ret; |
| } |
| |
| static void mrdump_ddr_reserved_mode_control(void) |
| { |
| if (g_boot_arg->ddr_reserve_ready != AEE_MRDUMP_DDR_RSV_READY) { |
| kcmdline_append("mrdump_ddrsv=no"); |
| dprintf(CRITICAL, "MT-RAMDUMP: DDR reserve mode not ready, skipped (0x%x)\n", |
| g_boot_arg->ddr_reserve_ready); |
| } else |
| kcmdline_append("mrdump_ddrsv=yes"); |
| } |
| |
| void mrdump_setup_boot_reason(void) |
| { |
| unsigned int boot_reason = 0; |
| unsigned int reboot_reason = 0; |
| char tmpbuf[128]; |
| unsigned int len_bootreason=0; |
| const char aee_reboot_reason[][20] = {"reboot", "watchdog", "kernel_panic", "oemerr_2sec_reboot","dmveri_corruption"}; |
| |
| boot_reason = platform_boot_status(); |
| reboot_reason=get_reboot_reason(boot_reason); |
| len_bootreason = strlen(" androidboot.bootreason=") + strlen(aee_reboot_reason[reboot_reason]); |
| snprintf(tmpbuf,len_bootreason,"%s%s", "androidboot.bootreason=",aee_reboot_reason[reboot_reason]); |
| dprintf(CRITICAL, "tmpbuf %s\n", tmpbuf); |
| kcmdline_append(tmpbuf); |
| } |
| |
| void mrdump_append_cmdline(void) |
| { |
| mrdump_ddr_reserved_mode_control(); |
| /* mrdump control block reserve memory*/ |
| #ifdef MTK_MRDUMP_SRAM_CB |
| aee_reserve_memory(MRDUMP_CB_RSV_MEM, MRDUMP_CB_ADDR, MRDUMP_CB_SIZE); |
| #endif |
| |
| /* mrdump reserve memory*/ |
| aee_reserve_memory(MRDUMP_RSV_MEM, MEMBASE, AEE_MRDUMP_LK_RSV_SIZE, |
| DRAM_BOOTARG_BASE, DRAM_BOOTARG_SIZE, DRAM_ARENA_BASE, |
| DRAM_ARENA_SIZE, kvaddr_to_paddr((void *)UNCACHED_MEMPOOL_ADDR), |
| UNCACHED_MEMPOOL_SIZE, kvaddr_to_paddr((void *)CACHED_MEMPOOL_ADDR), |
| CACHED_MEMPOOL_SIZE); |
| |
| /* ram_console reserve memory*/ |
| #if RAM_CONSOLE_DRAM_ADDR |
| aee_reserve_memory(RAM_CONSOLE_RSV_MEM, RAM_CONSOLE_DEF_ADDR, |
| RAM_CONSOLE_DEF_SIZE); |
| #endif |
| |
| /* minidump reserve memory*/ |
| #if MINIRDUMP_MEM_ADDR |
| aee_reserve_memory(MINIDUMP_RSV_MEM, MINIRDUMP_MEM_ADDR, |
| MINIRDUMP_MEM_SIZE); |
| #endif |
| |
| /* pstore reserve memory*/ |
| #if PSTORE_RESERVE_ADDR |
| aee_reserve_memory(PSTORE_RSV_MEM, PSTORE_RESERVE_ADDR, PSTORE_RESERVE_SIZE, |
| PSTORE_CONSOEL_SIZE, PSTORE_PMSG_SIZE); |
| #endif |
| mrdump_setup_version(); |
| mrdump_setup_boot_reason(); |
| } |
| |
| static int kedump_get_bootreason(unsigned int wdt_status) |
| { |
| unsigned int g_rgu_status = 0; |
| |
| if (wdt_status & MTK_WDT_STATUS_HWWDT_RST) { |
| /* For E1 bug, that SW reset value is 0xC000, we using "==" to check */ |
| /* Time out reboot always by pass power key */ |
| g_rgu_status = RE_BOOT_BY_WDT_HW; |
| } else if (wdt_status & MTK_WDT_STATUS_SWWDT_RST) { |
| g_rgu_status = RE_BOOT_BY_WDT_SW; |
| } else { |
| g_rgu_status = RE_BOOT_REASON_UNKNOW; |
| } |
| |
| if (wdt_status & MTK_WDT_STATUS_IRQWDT_RST) { |
| g_rgu_status |= RE_BOOT_WITH_INTTERUPT; |
| } |
| #ifdef MTK_THERMAL_RESET_SUPPORT |
| if (wdt_status & MTK_WDT_STATUS_SPM_THERMAL_RST) { |
| g_rgu_status |= RE_BOOT_BY_SPM_THERMAL; |
| } |
| #endif |
| if (wdt_status & MTK_WDT_STATUS_SPMWDT_RST) { |
| g_rgu_status |= RE_BOOT_BY_SPM; |
| } |
| if (wdt_status & MTK_WDT_STATUS_THERMAL_CTL_RST) { |
| g_rgu_status |= RE_BOOT_BY_THERMAL_DIRECT; |
| } |
| if (wdt_status & MTK_WDT_STATUS_DEBUGWDT_RST) { |
| g_rgu_status |= RE_BOOT_BY_DEBUG; |
| } |
| if (wdt_status & MTK_WDT_STATUS_SECURITY_RST) { |
| g_rgu_status |= RE_BOOT_BY_SECURITY; |
| } |
| |
| #ifdef MTK_PMIC_FULL_RESET |
| if (mtk_wdt_is_pmic_full_reset()) |
| g_rgu_status |= RE_BOOT_BY_PMIC_FULL_RST; |
| #endif |
| return g_rgu_status; |
| } |
| |
| int kedump_init(void) |
| { |
| static int kedump_dumped = 0; |
| unsigned int boot_reason = kedump_get_bootreason(g_boot_arg->boot_reason); |
| |
| pl_ram_console_init(); |
| ram_console_reboot_reason_save(boot_reason); |
| |
| ram_console_init(); |
| |
| /* this flow should be executed once only */ |
| if (kedump_dumped == 0) { |
| kedump_dumped = 1; |
| if (ram_console_is_abnormal_boot()) |
| return -1; |
| } |
| |
| // for power lost or reboot before KE DB collected scenario |
| kedump_restore_mem(); |
| return 0; |
| } |