summaryrefslogtreecommitdiffstats
path: root/plat/brcm/board/stingray/src/scp_utils.c
blob: 1d82ceff1e1a63844f768fadf76336b6b75a003a (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
/*
 * Copyright (c) 2017-2020, Broadcom
 *
 * SPDX-License-Identifier: BSD-3-Clause
 */

#include <string.h>

#include <arch_helpers.h>
#include <common/bl_common.h>
#include <common/debug.h>
#include <drivers/delay_timer.h>

#include <bcm_elog_ddr.h>
#include <brcm_mhu.h>
#include <brcm_scpi.h>
#include <chimp.h>
#include <cmn_plat_util.h>
#include <ddr_init.h>
#include <scp.h>
#include <scp_cmd.h>
#include <scp_utils.h>

#include "m0_cfg.h"
#include "m0_ipc.h"

#ifdef BCM_ELOG
static void prepare_elog(void)
{
#if (CLEAN_DDR && !defined(MMU_DISABLED))
	/*
	 * Now DDR has been initialized. We want to copy all the logs in SRAM
	 * into DDR so we will have much more space to store the logs in the
	 * next boot stage
	 */
	bcm_elog_copy_log((void *)BCM_ELOG_BL31_BASE,
			   MIN(BCM_ELOG_BL2_SIZE, BCM_ELOG_BL31_SIZE)
			 );

	/*
	 * We are almost at the end of BL2, and we can stop log here so we do
	 * not need to add 'bcm_elog_exit' to the standard BL2 code. The
	 * benefit of capturing BL2 logs after this is very minimal in a
	 * production system.
	 */
	bcm_elog_exit();
#endif

	/*
	 * Notify CRMU that now it should pull logs from DDR instead of from
	 * FS4 SRAM.
	 */
	SCP_WRITE_CFG(flash_log.can_use_ddr, 1);
}
#endif

bool is_crmu_alive(void)
{
	return (scp_send_cmd(MCU_IPC_MCU_CMD_NOP, 0, SCP_CMD_DEFAULT_TIMEOUT_US)
		== 0);
}

bool bcm_scp_issue_sys_reset(void)
{
	return (scp_send_cmd(MCU_IPC_MCU_CMD_L1_RESET, 0,
			     SCP_CMD_DEFAULT_TIMEOUT_US));
}

/*
 * Note that this is just a temporary implementation until
 * channels are introduced
 */

int plat_bcm_bl2_plat_handle_scp_bl2(image_info_t *scp_bl2_image_info)
{
	int scp_patch_activated, scp_patch_version;
#ifndef EMULATION_SETUP
	uint8_t active_ch_bitmap, i;
#endif
	uint32_t reset_state = 0;
	uint32_t mcu_ap_init_param = 0;

	/*
	 * First check if SCP patch has already been loaded
	 * Send NOP command and see if there is a valid response
	 */
	scp_patch_activated =
		(scp_send_cmd(MCU_IPC_MCU_CMD_NOP, 0,
		SCP_CMD_DEFAULT_TIMEOUT_US) == 0);
	if (scp_patch_activated) {
		INFO("SCP Patch is already active.\n");

		reset_state =  SCP_READ_CFG(board_cfg.reset_state);
		mcu_ap_init_param = SCP_READ_CFG(board_cfg.mcu_init_param);

		/* Clear reset state, it's been already read */
		SCP_WRITE_CFG(board_cfg.reset_state, 0);

		if (mcu_ap_init_param & MCU_PATCH_LOADED_BY_NITRO) {
			/*
			 * Reset "MCU_PATCH_LOADED_BY_NITRO" flag, but
			 * Preserve any other flags we don't deal with here
			 */
			INFO("AP booted by Nitro\n");
			SCP_WRITE_CFG(
					board_cfg.mcu_init_param,
					mcu_ap_init_param &
						~MCU_PATCH_LOADED_BY_NITRO
				      );
		}
	} else {
		/*
		 * MCU Patch not loaded, so load it.
		 * MCU patch stamps critical points in REG9 (debug test-point)
		 * Display its last content here. This helps to locate
		 * where crash occurred if a CRMU watchdog kicked in.
		 */
		int ret;

		INFO("MCU Patch Point: 0x%x\n",
			mmio_read_32(CRMU_IHOST_SW_PERSISTENT_REG9));

		ret = download_scp_patch((void *)scp_bl2_image_info->image_base,
				scp_bl2_image_info->image_size);
		if (ret != 0)
			return ret;

		VERBOSE("SCP Patch loaded OK.\n");

		ret = scp_send_cmd(MCU_IPC_MCU_CMD_INIT,
				MCU_PATCH_LOADED_BY_AP,
				SCP_CMD_SCP_BOOT_TIMEOUT_US);
		if (ret) {
			ERROR("SCP Patch could not initialize; error %d\n",
				ret);
			return ret;
		}

		INFO("SCP Patch successfully initialized.\n");
	}

	scp_patch_version = scp_send_cmd(MCU_IPC_MCU_CMD_GET_FW_VERSION, 0,
				SCP_CMD_DEFAULT_TIMEOUT_US);
	INFO("SCP Patch version :0x%x\n", scp_patch_version);

	/* Next block just reports current AVS voltages (if applicable) */
	{
		uint16_t vcore_mv, ihost03_mv, ihost12_mv;

		vcore_mv = SCP_READ_CFG16(vcore.millivolts) +
				SCP_READ_CFG8(vcore.avs_cfg.additive_margin);
		ihost03_mv = SCP_READ_CFG16(ihost03.millivolts) +
				SCP_READ_CFG8(ihost03.avs_cfg.additive_margin);
		ihost12_mv = SCP_READ_CFG16(ihost12.millivolts) +
				SCP_READ_CFG8(ihost12.avs_cfg.additive_margin);

		if (vcore_mv || ihost03_mv || ihost12_mv) {
			INFO("AVS voltages from cfg (including margin)\n");
			if (vcore_mv > 0)
				INFO("%s\tVCORE: %dmv\n",
					SCP_READ_CFG8(vcore.avs_cfg.avs_set) ?
					"*" : "n/a", vcore_mv);
			if (ihost03_mv > 0)
				INFO("%s\tIHOST03: %dmv\n",
				SCP_READ_CFG8(ihost03.avs_cfg.avs_set) ?
					"*" : "n/a", ihost03_mv);
			if (ihost12_mv > 0)
				INFO("%s\tIHOST12: %dmv\n",
				SCP_READ_CFG8(ihost12.avs_cfg.avs_set) ?
					"*" : "n/a", ihost12_mv);
		} else {
			INFO("AVS settings not applicable\n");
		}
	}

#if (CLEAN_DDR && !defined(MMU_DISABLED) && !defined(EMULATION_SETUP))
	/* This will clean the DDR and enable ECC if set */
	check_ddr_clean();
#endif

#if (WARMBOOT_DDR_S3_SUPPORT && ELOG_STORE_MEDIA_DDR)
	elog_init_ddr_log();
#endif

#ifdef BCM_ELOG
	/* Prepare ELOG to use DDR */
	prepare_elog();
#endif

#ifndef EMULATION_SETUP
	/* Ask ddr_init to save obtained DDR information into DDR */
	ddr_info_save();
#endif

	/*
	 * Configure TMON DDR address.
	 * This cfg is common for all cases
	 */
	SCP_WRITE_CFG(tmon_cfg.ddr_desc, TMON_SHARED_DDR_ADDRESS);

	if (reset_state == SOFT_RESET_L3 && !mcu_ap_init_param) {
		INFO("SCP configuration after L3 RESET done.\n");
		return 0;
	}

	if (bcm_chimp_is_nic_mode())
		/* Configure AP WDT to not reset the NIC interface */
		SCP_WRITE_CFG(board_cfg.apwdt_reset_type, SOFT_RESET_L3);

#if (WARMBOOT_DDR_S3_SUPPORT && ELOG_STORE_MEDIA_DDR)
	/* When AP WDog triggers perform L3 reset if DDR err logging enabled */
	SCP_WRITE_CFG(board_cfg.apwdt_reset_type, SOFT_RESET_L3);
#endif

#ifndef EMULATION_SETUP

#ifdef DDR_SCRUB_ENA
	ddr_scrub_enable();
#endif
	/* Fill the Active channel information */
	active_ch_bitmap = get_active_ddr_channel();
	for (i = 0; i < MAX_NR_DDR_CH; i++)
		SCP_WRITE_CFG(ddr_cfg.ddr_cfg[i],
			      (active_ch_bitmap & BIT(i)) ? 1 : 0);
#endif
	return 0;
}