summaryrefslogtreecommitdiffstats
path: root/src/drivers/intel/fsp2_0/silicon_init.c
blob: 26ff59dbf211601af435ed141fffa75ed1575798 (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
228
229
230
231
232
233
/* SPDX-License-Identifier: GPL-2.0-or-later */

#include <cbfs.h>
#include <cbmem.h>
#include <commonlib/fsp.h>
#include <commonlib/stdlib.h>
#include <console/console.h>
#include <fsp/api.h>
#include <fsp/util.h>
#include <program_loading.h>
#include <soc/intel/common/vbt.h>
#include <stage_cache.h>
#include <string.h>
#include <timestamp.h>
#include <types.h>
#include <mode_switch.h>

struct fsp_header fsps_hdr;

struct fsp_multi_phase_get_number_of_phases_params {
	uint32_t number_of_phases;
	uint32_t phases_executed;
};

/* Callbacks for SoC/Mainboard specific overrides */
void __weak platform_fsp_multi_phase_init_cb(uint32_t phase_index)
{
	/* Leave for the SoC/Mainboard to implement if necessary. */
}

int __weak soc_fsp_multi_phase_init_is_enable(void)
{
	return 1;
}

/* FSP Specification < 2.2 has only 1 stage like FspSiliconInit. FSP specification >= 2.2
 * has multiple stages as below.
 */
enum fsp_silicon_init_phases {
	FSP_SILICON_INIT_API,
	FSP_MULTI_PHASE_SI_INIT_GET_NUMBER_OF_PHASES_API,
	FSP_MULTI_PHASE_SI_INIT_EXECUTE_PHASE_API
};

static void fsps_return_value_handler(enum fsp_silicon_init_phases phases, uint32_t status)
{
	uint8_t postcode;

	/* Handle any reset request returned by FSP-S APIs */
	fsp_handle_reset(status);

	if (status == FSP_SUCCESS)
		return;
	/* Handle all other errors returned by FSP-S APIs */
	/* Assume video failure if attempted to initialize graphics */
	if (CONFIG(RUN_FSP_GOP) && vbt_get())
		postcode = POST_VIDEO_FAILURE;
	else
		postcode = POST_HW_INIT_FAILURE; /* else generic */

	switch (phases) {
	case FSP_SILICON_INIT_API:
		die_with_post_code(postcode, "FspSiliconInit returned with error 0x%08x\n",
				status);
		break;
	case FSP_MULTI_PHASE_SI_INIT_GET_NUMBER_OF_PHASES_API:
		printk(BIOS_SPEW, "FspMultiPhaseSiInit NumberOfPhases returned 0x%08x\n",
				status);
		break;
	case FSP_MULTI_PHASE_SI_INIT_EXECUTE_PHASE_API:
		printk(BIOS_SPEW, "FspMultiPhaseSiInit ExecutePhase returned 0x%08x\n",
				status);
		break;
	default:
		break;
	}
}

static void do_silicon_init(struct fsp_header *hdr)
{
	FSPS_UPD *upd, *supd;
	fsp_silicon_init_fn silicon_init;
	uint32_t status;
	const struct cbmem_entry *logo_entry = NULL;
	fsp_multi_phase_si_init_fn multi_phase_si_init;
	struct fsp_multi_phase_params multi_phase_params;
	struct fsp_multi_phase_get_number_of_phases_params multi_phase_get_number;

	supd = (FSPS_UPD *) (hdr->cfg_region_offset + hdr->image_base);

	fsp_verify_upd_header_signature(supd->FspUpdHeader.Signature, FSPS_UPD_SIGNATURE);

	/* Disallow invalid config regions.  Default settings are likely bad
	 * choices for coreboot, and different sized UPD from what the region
	 * allows is potentially a build problem.
	 */
	if (!hdr->cfg_region_size || hdr->cfg_region_size != sizeof(FSPS_UPD))
		die_with_post_code(POST_INVALID_VENDOR_BINARY,
			"Invalid FSPS UPD region\n");

	upd = xmalloc(hdr->cfg_region_size);

	memcpy(upd, supd, hdr->cfg_region_size);

	/* Give SoC/mainboard a chance to populate entries */
	platform_fsp_silicon_init_params_cb(upd);

	/* Populate logo related entries */
	if (CONFIG(FSP2_0_DISPLAY_LOGO))
		logo_entry = soc_load_logo(upd);

	/* Call SiliconInit */
	silicon_init = (void *) (hdr->image_base +
				 hdr->silicon_init_entry_offset);
	fsp_debug_before_silicon_init(silicon_init, supd, upd);

	timestamp_add_now(TS_FSP_SILICON_INIT_START);
	post_code(POST_FSP_SILICON_INIT);

	if (ENV_X86_64)
		status = protected_mode_call_1arg(silicon_init, (uintptr_t)upd);
	else
		status = silicon_init(upd);

	printk(BIOS_ERR, "FSPS returned %x\n", status);

	timestamp_add_now(TS_FSP_SILICON_INIT_END);
	post_code(POST_FSP_SILICON_EXIT);

	if (logo_entry)
		cbmem_entry_remove(logo_entry);

	fsp_debug_after_silicon_init(status);
	fsps_return_value_handler(FSP_SILICON_INIT_API, status);

	/* Reinitialize CPUs if FSP-S has done MP Init */
	if (CONFIG(USE_INTEL_FSP_MP_INIT))
		do_mpinit_after_fsp();

	if (!CONFIG(PLATFORM_USES_FSP2_2))
		return;

	/* Check if SoC user would like to call Multi Phase Init */
	if (!soc_fsp_multi_phase_init_is_enable())
		return;

	/* Call MultiPhaseSiInit */
	multi_phase_si_init = (void *) (hdr->image_base +
			 hdr->multi_phase_si_init_entry_offset);

	/* Implementing multi_phase_si_init() is optional as per FSP 2.2 spec */
	if (multi_phase_si_init == NULL)
		return;

	post_code(POST_FSP_MULTI_PHASE_SI_INIT_ENTRY);
	timestamp_add_now(TS_FSP_MULTI_PHASE_SI_INIT_START);
	/* Get NumberOfPhases Value */
	multi_phase_params.multi_phase_action = GET_NUMBER_OF_PHASES;
	multi_phase_params.phase_index = 0;
	multi_phase_params.multi_phase_param_ptr = &multi_phase_get_number;
	status = multi_phase_si_init(&multi_phase_params);
	fsps_return_value_handler(FSP_MULTI_PHASE_SI_INIT_GET_NUMBER_OF_PHASES_API, status);

	/* Execute Multi Phase Execution */
	for (int i = 1; i <= multi_phase_get_number.number_of_phases; i++) {
		printk(BIOS_SPEW, "Executing Phase %d of FspMultiPhaseSiInit\n", i);
		/*
		 * Give SoC/mainboard a chance to perform any operation before
		 * Multi Phase Execution
		 */
		platform_fsp_multi_phase_init_cb(i);

		multi_phase_params.multi_phase_action = EXECUTE_PHASE;
		multi_phase_params.phase_index = i;
		multi_phase_params.multi_phase_param_ptr = NULL;
		status = multi_phase_si_init(&multi_phase_params);
		fsps_return_value_handler(FSP_MULTI_PHASE_SI_INIT_EXECUTE_PHASE_API, status);
	}
	timestamp_add_now(TS_FSP_MULTI_PHASE_SI_INIT_END);
	post_code(POST_FSP_MULTI_PHASE_SI_INIT_EXIT);
}

static int fsps_get_dest(const struct fsp_load_descriptor *fspld, void **dest,
				size_t size, const struct region_device *source)
{
	*dest = cbmem_add(CBMEM_ID_REFCODE, size);

	if (*dest == NULL)
		return -1;

	return 0;
}

void fsps_load(bool s3wake)
{
	struct fsp_load_descriptor fspld = {
		.fsp_prog = PROG_INIT(PROG_REFCODE, CONFIG_FSP_S_CBFS),
		.get_destination = fsps_get_dest,
	};
	struct prog *fsps = &fspld.fsp_prog;
	static int load_done;

	if (load_done)
		return;

	if (resume_from_stage_cache()) {
		printk(BIOS_DEBUG, "Loading FSPS from stage_cache\n");
		stage_cache_load_stage(STAGE_REFCODE, fsps);
		if (fsp_validate_component(&fsps_hdr, prog_rdev(fsps)) != CB_SUCCESS)
			die("On resume fsps header is invalid\n");
		load_done = 1;
		return;
	}

	if (fsp_load_component(&fspld, &fsps_hdr) != CB_SUCCESS)
		die("FSP-S failed to load\n");

	stage_cache_add(STAGE_REFCODE, fsps);

	load_done = 1;
}

void fsp_silicon_init(bool s3wake)
{
	fsps_load(s3wake);
	do_silicon_init(&fsps_hdr);
}

/* Load bmp and set FSP parameters, fsp_load_logo can be used */
__weak const struct cbmem_entry *soc_load_logo(FSPS_UPD *supd)
{
	return NULL;
}