1*91f16700Schasinglulu /* 2*91f16700Schasinglulu * Copyright 2019-2020 Broadcom. 3*91f16700Schasinglulu * 4*91f16700Schasinglulu * SPDX-License-Identifier: BSD-3-Clause 5*91f16700Schasinglulu */ 6*91f16700Schasinglulu 7*91f16700Schasinglulu #include <arch_helpers.h> 8*91f16700Schasinglulu #include <common/debug.h> 9*91f16700Schasinglulu 10*91f16700Schasinglulu #include <ddr_init.h> 11*91f16700Schasinglulu #include <scp_cmd.h> 12*91f16700Schasinglulu #include <scp_utils.h> 13*91f16700Schasinglulu #include <platform_def.h> 14*91f16700Schasinglulu 15*91f16700Schasinglulu #include "bcm_elog_ddr.h" 16*91f16700Schasinglulu #include "m0_cfg.h" 17*91f16700Schasinglulu #include "m0_ipc.h" 18*91f16700Schasinglulu 19*91f16700Schasinglulu void elog_init_ddr_log(void) 20*91f16700Schasinglulu { 21*91f16700Schasinglulu struct elog_setup setup = {0}; 22*91f16700Schasinglulu struct elog_global_header global; 23*91f16700Schasinglulu struct elog_meta_record rec; 24*91f16700Schasinglulu unsigned int rec_idx = 0; 25*91f16700Schasinglulu uint32_t log_offset; 26*91f16700Schasinglulu uintptr_t metadata; 27*91f16700Schasinglulu char *rec_desc[ELOG_SUPPORTED_REC_CNT] = {"SYSRESET", "THERMAL", 28*91f16700Schasinglulu "DDR_ECC", "APBOOTLG", 29*91f16700Schasinglulu "IDM"}; 30*91f16700Schasinglulu 31*91f16700Schasinglulu /* 32*91f16700Schasinglulu * If this is warm boot, return immediately. 33*91f16700Schasinglulu * We expect metadata to be initialized already 34*91f16700Schasinglulu */ 35*91f16700Schasinglulu if (is_warmboot()) { 36*91f16700Schasinglulu WARN("Warmboot detected, skip ELOG metadata initialization\n"); 37*91f16700Schasinglulu return; 38*91f16700Schasinglulu } 39*91f16700Schasinglulu 40*91f16700Schasinglulu memset(&global, 0, sizeof(global)); 41*91f16700Schasinglulu 42*91f16700Schasinglulu global.sector_size = ELOG_SECTOR_SIZE; 43*91f16700Schasinglulu global.signature = ELOG_GLOBAL_META_HDR_SIG; 44*91f16700Schasinglulu global.rec_count = ELOG_SUPPORTED_REC_CNT; 45*91f16700Schasinglulu 46*91f16700Schasinglulu /* Start of logging area in DDR memory */ 47*91f16700Schasinglulu log_offset = ELOG_STORE_OFFSET; 48*91f16700Schasinglulu 49*91f16700Schasinglulu /* Shift to the first RECORD header */ 50*91f16700Schasinglulu log_offset += 2 * global.sector_size; 51*91f16700Schasinglulu 52*91f16700Schasinglulu /* Temporary place to hold metadata */ 53*91f16700Schasinglulu metadata = TMP_ELOG_METADATA_BASE; 54*91f16700Schasinglulu 55*91f16700Schasinglulu memcpy((void *)metadata, &global, sizeof(global)); 56*91f16700Schasinglulu metadata += sizeof(global); 57*91f16700Schasinglulu 58*91f16700Schasinglulu while (rec_idx < global.rec_count) { 59*91f16700Schasinglulu memset(&rec, 0, sizeof(rec)); 60*91f16700Schasinglulu 61*91f16700Schasinglulu rec.type = rec_idx; 62*91f16700Schasinglulu if (rec_idx == ELOG_REC_UART_LOG) { 63*91f16700Schasinglulu rec.format = ELOG_REC_FMT_ASCII; 64*91f16700Schasinglulu rec.src_mem_type = ELOG_SRC_MEM_TYPE_DDR; 65*91f16700Schasinglulu rec.alt_src_mem_type = ELOG_SRC_MEM_TYPE_FS4_SCRATCH; 66*91f16700Schasinglulu rec.src_mem_addr = BCM_ELOG_BL31_BASE; 67*91f16700Schasinglulu rec.alt_src_mem_addr = BCM_ELOG_BL2_BASE; 68*91f16700Schasinglulu rec.rec_size = ELOG_APBOOTLG_REC_SIZE; 69*91f16700Schasinglulu } else if (rec_idx == ELOG_REC_IDM_LOG) { 70*91f16700Schasinglulu rec.type = IDM_ELOG_REC_TYPE; 71*91f16700Schasinglulu rec.format = ELOG_REC_FMT_CUSTOM; 72*91f16700Schasinglulu rec.src_mem_type = ELOG_SRC_MEM_TYPE_DDR; 73*91f16700Schasinglulu rec.alt_src_mem_type = ELOG_SRC_MEM_TYPE_CRMU_SCRATCH; 74*91f16700Schasinglulu rec.src_mem_addr = ELOG_IDM_SRC_MEM_ADDR; 75*91f16700Schasinglulu rec.alt_src_mem_addr = 0x0; 76*91f16700Schasinglulu rec.rec_size = ELOG_DEFAULT_REC_SIZE; 77*91f16700Schasinglulu } else { 78*91f16700Schasinglulu rec.format = ELOG_REC_FMT_CUSTOM; 79*91f16700Schasinglulu rec.src_mem_type = ELOG_SRC_MEM_TYPE_CRMU_SCRATCH; 80*91f16700Schasinglulu rec.alt_src_mem_type = ELOG_SRC_MEM_TYPE_CRMU_SCRATCH; 81*91f16700Schasinglulu rec.src_mem_addr = ELOG_USE_DEFAULT_MEM_ADDR; 82*91f16700Schasinglulu rec.alt_src_mem_addr = ELOG_USE_DEFAULT_MEM_ADDR; 83*91f16700Schasinglulu rec.rec_size = ELOG_DEFAULT_REC_SIZE; 84*91f16700Schasinglulu } 85*91f16700Schasinglulu 86*91f16700Schasinglulu rec.nvm_type = LOG_MEDIA_DDR; 87*91f16700Schasinglulu rec.sector_size = ELOG_SECTOR_SIZE; 88*91f16700Schasinglulu 89*91f16700Schasinglulu rec.rec_addr = (uint64_t)log_offset; 90*91f16700Schasinglulu log_offset += rec.rec_size; 91*91f16700Schasinglulu 92*91f16700Schasinglulu /* Sanity checks */ 93*91f16700Schasinglulu if (rec.type > ELOG_MAX_REC_COUNT || 94*91f16700Schasinglulu rec.format > ELOG_MAX_REC_FORMAT || 95*91f16700Schasinglulu (rec.nvm_type > ELOG_MAX_NVM_TYPE && 96*91f16700Schasinglulu rec.nvm_type != ELOG_NVM_DEFAULT) || 97*91f16700Schasinglulu !rec.rec_size || 98*91f16700Schasinglulu !rec.sector_size || 99*91f16700Schasinglulu rec_idx >= ELOG_SUPPORTED_REC_CNT) { 100*91f16700Schasinglulu ERROR("Invalid ELOG record(%u) detected\n", rec_idx); 101*91f16700Schasinglulu return; 102*91f16700Schasinglulu } 103*91f16700Schasinglulu 104*91f16700Schasinglulu memset(rec.rec_desc, ' ', sizeof(rec.rec_desc)); 105*91f16700Schasinglulu 106*91f16700Schasinglulu memcpy(rec.rec_desc, rec_desc[rec_idx], 107*91f16700Schasinglulu strlen(rec_desc[rec_idx])); 108*91f16700Schasinglulu 109*91f16700Schasinglulu memcpy((void *)metadata, &rec, sizeof(rec)); 110*91f16700Schasinglulu metadata += sizeof(rec); 111*91f16700Schasinglulu 112*91f16700Schasinglulu rec_idx++; 113*91f16700Schasinglulu } 114*91f16700Schasinglulu 115*91f16700Schasinglulu setup.params[0] = TMP_ELOG_METADATA_BASE; 116*91f16700Schasinglulu setup.params[1] = (sizeof(global) + global.rec_count * sizeof(rec)); 117*91f16700Schasinglulu setup.cmd = ELOG_SETUP_CMD_WRITE_META; 118*91f16700Schasinglulu 119*91f16700Schasinglulu flush_dcache_range((uintptr_t)&setup, sizeof(struct elog_setup)); 120*91f16700Schasinglulu flush_dcache_range((uintptr_t)setup.params[0], setup.params[1]); 121*91f16700Schasinglulu 122*91f16700Schasinglulu /* initialize DDR Logging METADATA if this is NOT warmboot */ 123*91f16700Schasinglulu if (!is_warmboot()) { 124*91f16700Schasinglulu if (scp_send_cmd(MCU_IPC_MCU_CMD_ELOG_SETUP, 125*91f16700Schasinglulu (uint32_t)(uintptr_t)(&setup), 126*91f16700Schasinglulu SCP_CMD_DEFAULT_TIMEOUT_US)) { 127*91f16700Schasinglulu ERROR("scp_send_cmd: timeout/error for elog setup\n"); 128*91f16700Schasinglulu return; 129*91f16700Schasinglulu } 130*91f16700Schasinglulu } 131*91f16700Schasinglulu 132*91f16700Schasinglulu NOTICE("MCU Error logging initialized\n"); 133*91f16700Schasinglulu } 134