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