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
elog_init_ddr_log(void)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