1*f29d1e0cSSheetal Tigadoli /*
2*f29d1e0cSSheetal Tigadoli * Copyright (c) 2017-2020, Broadcom
3*f29d1e0cSSheetal Tigadoli *
4*f29d1e0cSSheetal Tigadoli * SPDX-License-Identifier: BSD-3-Clause
5*f29d1e0cSSheetal Tigadoli */
6*f29d1e0cSSheetal Tigadoli
7*f29d1e0cSSheetal Tigadoli #include <string.h>
8*f29d1e0cSSheetal Tigadoli
9*f29d1e0cSSheetal Tigadoli #include <arch_helpers.h>
10*f29d1e0cSSheetal Tigadoli #include <common/bl_common.h>
11*f29d1e0cSSheetal Tigadoli #include <common/debug.h>
12*f29d1e0cSSheetal Tigadoli #include <drivers/delay_timer.h>
13*f29d1e0cSSheetal Tigadoli
14*f29d1e0cSSheetal Tigadoli #include <bcm_elog_ddr.h>
15*f29d1e0cSSheetal Tigadoli #include <brcm_mhu.h>
16*f29d1e0cSSheetal Tigadoli #include <brcm_scpi.h>
17*f29d1e0cSSheetal Tigadoli #include <chimp.h>
18*f29d1e0cSSheetal Tigadoli #include <cmn_plat_util.h>
19*f29d1e0cSSheetal Tigadoli #include <ddr_init.h>
20*f29d1e0cSSheetal Tigadoli #include <scp.h>
21*f29d1e0cSSheetal Tigadoli #include <scp_cmd.h>
22*f29d1e0cSSheetal Tigadoli #include <scp_utils.h>
23*f29d1e0cSSheetal Tigadoli
24*f29d1e0cSSheetal Tigadoli #include "m0_cfg.h"
25*f29d1e0cSSheetal Tigadoli #include "m0_ipc.h"
26*f29d1e0cSSheetal Tigadoli
27*f29d1e0cSSheetal Tigadoli #ifdef BCM_ELOG
prepare_elog(void)28*f29d1e0cSSheetal Tigadoli static void prepare_elog(void)
29*f29d1e0cSSheetal Tigadoli {
30*f29d1e0cSSheetal Tigadoli #if (CLEAN_DDR && !defined(MMU_DISABLED))
31*f29d1e0cSSheetal Tigadoli /*
32*f29d1e0cSSheetal Tigadoli * Now DDR has been initialized. We want to copy all the logs in SRAM
33*f29d1e0cSSheetal Tigadoli * into DDR so we will have much more space to store the logs in the
34*f29d1e0cSSheetal Tigadoli * next boot stage
35*f29d1e0cSSheetal Tigadoli */
36*f29d1e0cSSheetal Tigadoli bcm_elog_copy_log((void *)BCM_ELOG_BL31_BASE,
37*f29d1e0cSSheetal Tigadoli MIN(BCM_ELOG_BL2_SIZE, BCM_ELOG_BL31_SIZE)
38*f29d1e0cSSheetal Tigadoli );
39*f29d1e0cSSheetal Tigadoli
40*f29d1e0cSSheetal Tigadoli /*
41*f29d1e0cSSheetal Tigadoli * We are almost at the end of BL2, and we can stop log here so we do
42*f29d1e0cSSheetal Tigadoli * not need to add 'bcm_elog_exit' to the standard BL2 code. The
43*f29d1e0cSSheetal Tigadoli * benefit of capturing BL2 logs after this is very minimal in a
44*f29d1e0cSSheetal Tigadoli * production system.
45*f29d1e0cSSheetal Tigadoli */
46*f29d1e0cSSheetal Tigadoli bcm_elog_exit();
47*f29d1e0cSSheetal Tigadoli #endif
48*f29d1e0cSSheetal Tigadoli
49*f29d1e0cSSheetal Tigadoli /*
50*f29d1e0cSSheetal Tigadoli * Notify CRMU that now it should pull logs from DDR instead of from
51*f29d1e0cSSheetal Tigadoli * FS4 SRAM.
52*f29d1e0cSSheetal Tigadoli */
53*f29d1e0cSSheetal Tigadoli SCP_WRITE_CFG(flash_log.can_use_ddr, 1);
54*f29d1e0cSSheetal Tigadoli }
55*f29d1e0cSSheetal Tigadoli #endif
56*f29d1e0cSSheetal Tigadoli
is_crmu_alive(void)57*f29d1e0cSSheetal Tigadoli bool is_crmu_alive(void)
58*f29d1e0cSSheetal Tigadoli {
59*f29d1e0cSSheetal Tigadoli return (scp_send_cmd(MCU_IPC_MCU_CMD_NOP, 0, SCP_CMD_DEFAULT_TIMEOUT_US)
60*f29d1e0cSSheetal Tigadoli == 0);
61*f29d1e0cSSheetal Tigadoli }
62*f29d1e0cSSheetal Tigadoli
bcm_scp_issue_sys_reset(void)63*f29d1e0cSSheetal Tigadoli bool bcm_scp_issue_sys_reset(void)
64*f29d1e0cSSheetal Tigadoli {
65*f29d1e0cSSheetal Tigadoli return (scp_send_cmd(MCU_IPC_MCU_CMD_L1_RESET, 0,
66*f29d1e0cSSheetal Tigadoli SCP_CMD_DEFAULT_TIMEOUT_US));
67*f29d1e0cSSheetal Tigadoli }
68*f29d1e0cSSheetal Tigadoli
69*f29d1e0cSSheetal Tigadoli /*
70*f29d1e0cSSheetal Tigadoli * Note that this is just a temporary implementation until
71*f29d1e0cSSheetal Tigadoli * channels are introduced
72*f29d1e0cSSheetal Tigadoli */
73*f29d1e0cSSheetal Tigadoli
plat_bcm_bl2_plat_handle_scp_bl2(image_info_t * scp_bl2_image_info)74*f29d1e0cSSheetal Tigadoli int plat_bcm_bl2_plat_handle_scp_bl2(image_info_t *scp_bl2_image_info)
75*f29d1e0cSSheetal Tigadoli {
76*f29d1e0cSSheetal Tigadoli int scp_patch_activated, scp_patch_version;
77*f29d1e0cSSheetal Tigadoli #ifndef EMULATION_SETUP
78*f29d1e0cSSheetal Tigadoli uint8_t active_ch_bitmap, i;
79*f29d1e0cSSheetal Tigadoli #endif
80*f29d1e0cSSheetal Tigadoli uint32_t reset_state = 0;
81*f29d1e0cSSheetal Tigadoli uint32_t mcu_ap_init_param = 0;
82*f29d1e0cSSheetal Tigadoli
83*f29d1e0cSSheetal Tigadoli /*
84*f29d1e0cSSheetal Tigadoli * First check if SCP patch has already been loaded
85*f29d1e0cSSheetal Tigadoli * Send NOP command and see if there is a valid response
86*f29d1e0cSSheetal Tigadoli */
87*f29d1e0cSSheetal Tigadoli scp_patch_activated =
88*f29d1e0cSSheetal Tigadoli (scp_send_cmd(MCU_IPC_MCU_CMD_NOP, 0,
89*f29d1e0cSSheetal Tigadoli SCP_CMD_DEFAULT_TIMEOUT_US) == 0);
90*f29d1e0cSSheetal Tigadoli if (scp_patch_activated) {
91*f29d1e0cSSheetal Tigadoli INFO("SCP Patch is already active.\n");
92*f29d1e0cSSheetal Tigadoli
93*f29d1e0cSSheetal Tigadoli reset_state = SCP_READ_CFG(board_cfg.reset_state);
94*f29d1e0cSSheetal Tigadoli mcu_ap_init_param = SCP_READ_CFG(board_cfg.mcu_init_param);
95*f29d1e0cSSheetal Tigadoli
96*f29d1e0cSSheetal Tigadoli /* Clear reset state, it's been already read */
97*f29d1e0cSSheetal Tigadoli SCP_WRITE_CFG(board_cfg.reset_state, 0);
98*f29d1e0cSSheetal Tigadoli
99*f29d1e0cSSheetal Tigadoli if (mcu_ap_init_param & MCU_PATCH_LOADED_BY_NITRO) {
100*f29d1e0cSSheetal Tigadoli /*
101*f29d1e0cSSheetal Tigadoli * Reset "MCU_PATCH_LOADED_BY_NITRO" flag, but
102*f29d1e0cSSheetal Tigadoli * Preserve any other flags we don't deal with here
103*f29d1e0cSSheetal Tigadoli */
104*f29d1e0cSSheetal Tigadoli INFO("AP booted by Nitro\n");
105*f29d1e0cSSheetal Tigadoli SCP_WRITE_CFG(
106*f29d1e0cSSheetal Tigadoli board_cfg.mcu_init_param,
107*f29d1e0cSSheetal Tigadoli mcu_ap_init_param &
108*f29d1e0cSSheetal Tigadoli ~MCU_PATCH_LOADED_BY_NITRO
109*f29d1e0cSSheetal Tigadoli );
110*f29d1e0cSSheetal Tigadoli }
111*f29d1e0cSSheetal Tigadoli } else {
112*f29d1e0cSSheetal Tigadoli /*
113*f29d1e0cSSheetal Tigadoli * MCU Patch not loaded, so load it.
114*f29d1e0cSSheetal Tigadoli * MCU patch stamps critical points in REG9 (debug test-point)
115*f29d1e0cSSheetal Tigadoli * Display its last content here. This helps to locate
116*f29d1e0cSSheetal Tigadoli * where crash occurred if a CRMU watchdog kicked in.
117*f29d1e0cSSheetal Tigadoli */
118*f29d1e0cSSheetal Tigadoli int ret;
119*f29d1e0cSSheetal Tigadoli
120*f29d1e0cSSheetal Tigadoli INFO("MCU Patch Point: 0x%x\n",
121*f29d1e0cSSheetal Tigadoli mmio_read_32(CRMU_IHOST_SW_PERSISTENT_REG9));
122*f29d1e0cSSheetal Tigadoli
123*f29d1e0cSSheetal Tigadoli ret = download_scp_patch((void *)scp_bl2_image_info->image_base,
124*f29d1e0cSSheetal Tigadoli scp_bl2_image_info->image_size);
125*f29d1e0cSSheetal Tigadoli if (ret != 0)
126*f29d1e0cSSheetal Tigadoli return ret;
127*f29d1e0cSSheetal Tigadoli
128*f29d1e0cSSheetal Tigadoli VERBOSE("SCP Patch loaded OK.\n");
129*f29d1e0cSSheetal Tigadoli
130*f29d1e0cSSheetal Tigadoli ret = scp_send_cmd(MCU_IPC_MCU_CMD_INIT,
131*f29d1e0cSSheetal Tigadoli MCU_PATCH_LOADED_BY_AP,
132*f29d1e0cSSheetal Tigadoli SCP_CMD_SCP_BOOT_TIMEOUT_US);
133*f29d1e0cSSheetal Tigadoli if (ret) {
134*f29d1e0cSSheetal Tigadoli ERROR("SCP Patch could not initialize; error %d\n",
135*f29d1e0cSSheetal Tigadoli ret);
136*f29d1e0cSSheetal Tigadoli return ret;
137*f29d1e0cSSheetal Tigadoli }
138*f29d1e0cSSheetal Tigadoli
139*f29d1e0cSSheetal Tigadoli INFO("SCP Patch successfully initialized.\n");
140*f29d1e0cSSheetal Tigadoli }
141*f29d1e0cSSheetal Tigadoli
142*f29d1e0cSSheetal Tigadoli scp_patch_version = scp_send_cmd(MCU_IPC_MCU_CMD_GET_FW_VERSION, 0,
143*f29d1e0cSSheetal Tigadoli SCP_CMD_DEFAULT_TIMEOUT_US);
144*f29d1e0cSSheetal Tigadoli INFO("SCP Patch version :0x%x\n", scp_patch_version);
145*f29d1e0cSSheetal Tigadoli
146*f29d1e0cSSheetal Tigadoli /* Next block just reports current AVS voltages (if applicable) */
147*f29d1e0cSSheetal Tigadoli {
148*f29d1e0cSSheetal Tigadoli uint16_t vcore_mv, ihost03_mv, ihost12_mv;
149*f29d1e0cSSheetal Tigadoli
150*f29d1e0cSSheetal Tigadoli vcore_mv = SCP_READ_CFG16(vcore.millivolts) +
151*f29d1e0cSSheetal Tigadoli SCP_READ_CFG8(vcore.avs_cfg.additive_margin);
152*f29d1e0cSSheetal Tigadoli ihost03_mv = SCP_READ_CFG16(ihost03.millivolts) +
153*f29d1e0cSSheetal Tigadoli SCP_READ_CFG8(ihost03.avs_cfg.additive_margin);
154*f29d1e0cSSheetal Tigadoli ihost12_mv = SCP_READ_CFG16(ihost12.millivolts) +
155*f29d1e0cSSheetal Tigadoli SCP_READ_CFG8(ihost12.avs_cfg.additive_margin);
156*f29d1e0cSSheetal Tigadoli
157*f29d1e0cSSheetal Tigadoli if (vcore_mv || ihost03_mv || ihost12_mv) {
158*f29d1e0cSSheetal Tigadoli INFO("AVS voltages from cfg (including margin)\n");
159*f29d1e0cSSheetal Tigadoli if (vcore_mv > 0)
160*f29d1e0cSSheetal Tigadoli INFO("%s\tVCORE: %dmv\n",
161*f29d1e0cSSheetal Tigadoli SCP_READ_CFG8(vcore.avs_cfg.avs_set) ?
162*f29d1e0cSSheetal Tigadoli "*" : "n/a", vcore_mv);
163*f29d1e0cSSheetal Tigadoli if (ihost03_mv > 0)
164*f29d1e0cSSheetal Tigadoli INFO("%s\tIHOST03: %dmv\n",
165*f29d1e0cSSheetal Tigadoli SCP_READ_CFG8(ihost03.avs_cfg.avs_set) ?
166*f29d1e0cSSheetal Tigadoli "*" : "n/a", ihost03_mv);
167*f29d1e0cSSheetal Tigadoli if (ihost12_mv > 0)
168*f29d1e0cSSheetal Tigadoli INFO("%s\tIHOST12: %dmv\n",
169*f29d1e0cSSheetal Tigadoli SCP_READ_CFG8(ihost12.avs_cfg.avs_set) ?
170*f29d1e0cSSheetal Tigadoli "*" : "n/a", ihost12_mv);
171*f29d1e0cSSheetal Tigadoli } else {
172*f29d1e0cSSheetal Tigadoli INFO("AVS settings not applicable\n");
173*f29d1e0cSSheetal Tigadoli }
174*f29d1e0cSSheetal Tigadoli }
175*f29d1e0cSSheetal Tigadoli
176*f29d1e0cSSheetal Tigadoli #if (CLEAN_DDR && !defined(MMU_DISABLED) && !defined(EMULATION_SETUP))
177*f29d1e0cSSheetal Tigadoli /* This will clean the DDR and enable ECC if set */
178*f29d1e0cSSheetal Tigadoli check_ddr_clean();
179*f29d1e0cSSheetal Tigadoli #endif
180*f29d1e0cSSheetal Tigadoli
181*f29d1e0cSSheetal Tigadoli #if (WARMBOOT_DDR_S3_SUPPORT && ELOG_STORE_MEDIA_DDR)
182*f29d1e0cSSheetal Tigadoli elog_init_ddr_log();
183*f29d1e0cSSheetal Tigadoli #endif
184*f29d1e0cSSheetal Tigadoli
185*f29d1e0cSSheetal Tigadoli #ifdef BCM_ELOG
186*f29d1e0cSSheetal Tigadoli /* Prepare ELOG to use DDR */
187*f29d1e0cSSheetal Tigadoli prepare_elog();
188*f29d1e0cSSheetal Tigadoli #endif
189*f29d1e0cSSheetal Tigadoli
190*f29d1e0cSSheetal Tigadoli #ifndef EMULATION_SETUP
191*f29d1e0cSSheetal Tigadoli /* Ask ddr_init to save obtained DDR information into DDR */
192*f29d1e0cSSheetal Tigadoli ddr_info_save();
193*f29d1e0cSSheetal Tigadoli #endif
194*f29d1e0cSSheetal Tigadoli
195*f29d1e0cSSheetal Tigadoli /*
196*f29d1e0cSSheetal Tigadoli * Configure TMON DDR address.
197*f29d1e0cSSheetal Tigadoli * This cfg is common for all cases
198*f29d1e0cSSheetal Tigadoli */
199*f29d1e0cSSheetal Tigadoli SCP_WRITE_CFG(tmon_cfg.ddr_desc, TMON_SHARED_DDR_ADDRESS);
200*f29d1e0cSSheetal Tigadoli
201*f29d1e0cSSheetal Tigadoli if (reset_state == SOFT_RESET_L3 && !mcu_ap_init_param) {
202*f29d1e0cSSheetal Tigadoli INFO("SCP configuration after L3 RESET done.\n");
203*f29d1e0cSSheetal Tigadoli return 0;
204*f29d1e0cSSheetal Tigadoli }
205*f29d1e0cSSheetal Tigadoli
206*f29d1e0cSSheetal Tigadoli if (bcm_chimp_is_nic_mode())
207*f29d1e0cSSheetal Tigadoli /* Configure AP WDT to not reset the NIC interface */
208*f29d1e0cSSheetal Tigadoli SCP_WRITE_CFG(board_cfg.apwdt_reset_type, SOFT_RESET_L3);
209*f29d1e0cSSheetal Tigadoli
210*f29d1e0cSSheetal Tigadoli #if (WARMBOOT_DDR_S3_SUPPORT && ELOG_STORE_MEDIA_DDR)
211*f29d1e0cSSheetal Tigadoli /* When AP WDog triggers perform L3 reset if DDR err logging enabled */
212*f29d1e0cSSheetal Tigadoli SCP_WRITE_CFG(board_cfg.apwdt_reset_type, SOFT_RESET_L3);
213*f29d1e0cSSheetal Tigadoli #endif
214*f29d1e0cSSheetal Tigadoli
215*f29d1e0cSSheetal Tigadoli #ifndef EMULATION_SETUP
216*f29d1e0cSSheetal Tigadoli
217*f29d1e0cSSheetal Tigadoli #ifdef DDR_SCRUB_ENA
218*f29d1e0cSSheetal Tigadoli ddr_scrub_enable();
219*f29d1e0cSSheetal Tigadoli #endif
220*f29d1e0cSSheetal Tigadoli /* Fill the Active channel information */
221*f29d1e0cSSheetal Tigadoli active_ch_bitmap = get_active_ddr_channel();
222*f29d1e0cSSheetal Tigadoli for (i = 0; i < MAX_NR_DDR_CH; i++)
223*f29d1e0cSSheetal Tigadoli SCP_WRITE_CFG(ddr_cfg.ddr_cfg[i],
224*f29d1e0cSSheetal Tigadoli (active_ch_bitmap & BIT(i)) ? 1 : 0);
225*f29d1e0cSSheetal Tigadoli #endif
226*f29d1e0cSSheetal Tigadoli return 0;
227*f29d1e0cSSheetal Tigadoli }
228