blob: c35f41b20c19ba4bebf00595d401c04fcc9aec3c [file] [log] [blame]
Angel Ponsae593872020-04-04 18:50:57 +02001/* SPDX-License-Identifier: GPL-2.0-only */
2/* This file is part of the coreboot project. */
Marshall Dawson68243a52017-06-15 16:59:20 -06003
Kyösti Mälkki13f66502019-03-03 08:01:05 +02004#include <device/mmio.h>
Charles Marslett81655832018-07-24 10:43:33 -05005#include <cpu/x86/msr.h>
Marshall Dawson596ecec2017-10-12 16:04:08 -06006#include <cbfs.h>
7#include <region_file.h>
Marshall Dawson68243a52017-06-15 16:59:20 -06008#include <timer.h>
9#include <device/pci_def.h>
Marshall Dawsond1cc3c22017-12-08 12:46:11 -070010#include <bootstate.h>
Marshall Dawson68243a52017-06-15 16:59:20 -060011#include <console/console.h>
Charles Marslett81655832018-07-24 10:43:33 -050012#include <device/pci_ops.h>
Marshall Dawson68243a52017-06-15 16:59:20 -060013#include <amdblocks/psp.h>
Charles Marslett81655832018-07-24 10:43:33 -050014#include <soc/iomap.h>
15#include <soc/northbridge.h>
Marshall Dawson3c578192020-01-19 17:16:01 -070016#include "psp_def.h"
Marshall Dawson68243a52017-06-15 16:59:20 -060017
18static const char *psp_status_nobase = "error: PSP BAR3 not assigned";
19static const char *psp_status_halted = "error: PSP in halted state";
20static const char *psp_status_recovery = "error: PSP recovery required";
21static const char *psp_status_errcmd = "error sending command";
22static const char *psp_status_init_timeout = "error: PSP init timeout";
23static const char *psp_status_cmd_timeout = "error: PSP command timeout";
24static const char *psp_status_noerror = "";
25
26static const char *status_to_string(int err)
27{
28 switch (err) {
29 case -PSPSTS_NOBASE:
30 return psp_status_nobase;
31 case -PSPSTS_HALTED:
32 return psp_status_halted;
33 case -PSPSTS_RECOVERY:
34 return psp_status_recovery;
35 case -PSPSTS_SEND_ERROR:
36 return psp_status_errcmd;
37 case -PSPSTS_INIT_TIMEOUT:
38 return psp_status_init_timeout;
39 case -PSPSTS_CMD_TIMEOUT:
40 return psp_status_cmd_timeout;
41 default:
42 return psp_status_noerror;
43 }
44}
45
Marshall Dawson68243a52017-06-15 16:59:20 -060046static u32 rd_mbox_sts(struct psp_mbox *mbox)
47{
48 return read32(&mbox->mbox_status);
49}
50
51static void wr_mbox_cmd(struct psp_mbox *mbox, u32 cmd)
52{
53 write32(&mbox->mbox_command, cmd);
54}
55
56static u32 rd_mbox_cmd(struct psp_mbox *mbox)
57{
58 return read32(&mbox->mbox_command);
59}
60
61static void wr_mbox_cmd_resp(struct psp_mbox *mbox, void *buffer)
62{
63 write64(&mbox->cmd_response, (uintptr_t)buffer);
64}
65
66static u32 rd_resp_sts(struct mbox_default_buffer *buffer)
67{
68 return read32(&buffer->header.status);
69}
70
71static int wait_initialized(struct psp_mbox *mbox)
72{
73 struct stopwatch sw;
74
75 stopwatch_init_msecs_expire(&sw, PSP_INIT_TIMEOUT);
76
77 do {
78 if (rd_mbox_sts(mbox) & STATUS_INITIALIZED)
79 return 0;
80 } while (!stopwatch_expired(&sw));
81
82 return -PSPSTS_INIT_TIMEOUT;
83}
84
85static int wait_command(struct psp_mbox *mbox)
86{
87 struct stopwatch sw;
88
89 stopwatch_init_msecs_expire(&sw, PSP_CMD_TIMEOUT);
90
91 do {
92 if (!rd_mbox_cmd(mbox))
93 return 0;
94 } while (!stopwatch_expired(&sw));
95
96 return -PSPSTS_CMD_TIMEOUT;
97}
98
99static int send_psp_command(u32 command, void *buffer)
100{
Felix Helddba32292020-03-31 23:54:44 +0200101 struct psp_mbox *mbox = soc_get_mbox_address();
Marshall Dawson68243a52017-06-15 16:59:20 -0600102 if (!mbox)
103 return -PSPSTS_NOBASE;
104
Marshall Dawson68243a52017-06-15 16:59:20 -0600105 /* check for PSP error conditions */
Marshall Dawson33c87732017-12-13 10:24:41 -0700106 if (rd_mbox_sts(mbox) & STATUS_HALT)
107 return -PSPSTS_HALTED;
108
109 if (rd_mbox_sts(mbox) & STATUS_RECOVERY)
110 return -PSPSTS_RECOVERY;
Marshall Dawson68243a52017-06-15 16:59:20 -0600111
112 /* PSP must be finished with init and ready to accept a command */
Marshall Dawson33c87732017-12-13 10:24:41 -0700113 if (wait_initialized(mbox))
114 return -PSPSTS_INIT_TIMEOUT;
115
116 if (wait_command(mbox))
117 return -PSPSTS_CMD_TIMEOUT;
Marshall Dawson68243a52017-06-15 16:59:20 -0600118
119 /* set address of command-response buffer and write command register */
120 wr_mbox_cmd_resp(mbox, buffer);
121 wr_mbox_cmd(mbox, command);
122
123 /* PSP clears command register when complete */
Marshall Dawson33c87732017-12-13 10:24:41 -0700124 if (wait_command(mbox))
125 return -PSPSTS_CMD_TIMEOUT;
Marshall Dawson68243a52017-06-15 16:59:20 -0600126
127 /* check delivery status */
Marshall Dawson33c87732017-12-13 10:24:41 -0700128 if (rd_mbox_sts(mbox) & (STATUS_ERROR | STATUS_TERMINATED))
129 return -PSPSTS_SEND_ERROR;
130
131 return 0;
Marshall Dawson68243a52017-06-15 16:59:20 -0600132}
133
134/*
Marshall Dawson5646a642020-01-19 16:12:25 -0700135 * Print meaningful status to the console. Caller only passes a pointer to a
136 * buffer if it's expected to contain its own status.
137 */
138static void print_cmd_status(int cmd_status, struct mbox_default_buffer *buffer)
139{
140 if (buffer && rd_resp_sts(buffer))
141 printk(BIOS_DEBUG, "buffer status=0x%x ", rd_resp_sts(buffer));
142
143 if (cmd_status)
144 printk(BIOS_DEBUG, "%s\n", status_to_string(cmd_status));
145 else
146 printk(BIOS_DEBUG, "OK\n");
147}
148
149/*
Marshall Dawson68243a52017-06-15 16:59:20 -0600150 * Notify the PSP that DRAM is present. Upon receiving this command, the PSP
151 * will load its OS into fenced DRAM that is not accessible to the x86 cores.
152 */
153int psp_notify_dram(void)
154{
Marshall Dawson68243a52017-06-15 16:59:20 -0600155 int cmd_status;
Marshall Dawson66dd3992017-12-13 10:51:13 -0700156 struct mbox_default_buffer buffer = {
157 .header = {
158 .size = sizeof(buffer)
159 }
160 };
Marshall Dawson68243a52017-06-15 16:59:20 -0600161
162 printk(BIOS_DEBUG, "PSP: Notify that DRAM is available... ");
163
Marshall Dawson68243a52017-06-15 16:59:20 -0600164 cmd_status = send_psp_command(MBOX_BIOS_CMD_DRAM_INFO, &buffer);
165
166 /* buffer's status shouldn't change but report it if it does */
Marshall Dawson5646a642020-01-19 16:12:25 -0700167 print_cmd_status(cmd_status, &buffer);
Marshall Dawson68243a52017-06-15 16:59:20 -0600168
169 return cmd_status;
170}
Marshall Dawson596ecec2017-10-12 16:04:08 -0600171
172/*
Marshall Dawsond1cc3c22017-12-08 12:46:11 -0700173 * Notify the PSP that the system is completing the boot process. Upon
174 * receiving this command, the PSP will only honor commands where the buffer
175 * is in SMM space.
176 */
177static void psp_notify_boot_done(void *unused)
178{
179 int cmd_status;
180 struct mbox_default_buffer buffer = {
181 .header = {
182 .size = sizeof(buffer)
183 }
184 };
185
186 printk(BIOS_DEBUG, "PSP: Notify that POST is finishing... ");
187
188 cmd_status = send_psp_command(MBOX_BIOS_CMD_BOOT_DONE, &buffer);
189
190 /* buffer's status shouldn't change but report it if it does */
Marshall Dawson5646a642020-01-19 16:12:25 -0700191 print_cmd_status(cmd_status, &buffer);
Marshall Dawsond1cc3c22017-12-08 12:46:11 -0700192}
193
194/*
Marshall Dawson596ecec2017-10-12 16:04:08 -0600195 * Tell the PSP to load a firmware blob from a location in the BIOS image.
196 */
Marshall Dawson737e56a2020-01-19 16:32:08 -0700197int psp_load_named_blob(enum psp_blob_type type, const char *name)
Marshall Dawson596ecec2017-10-12 16:04:08 -0600198{
199 int cmd_status;
Marshall Dawson737e56a2020-01-19 16:32:08 -0700200 u32 command;
Marshall Dawson596ecec2017-10-12 16:04:08 -0600201 void *blob;
202 struct cbfsf cbfs_file;
203 struct region_device rdev;
Marshall Dawson737e56a2020-01-19 16:32:08 -0700204
205 switch (type) {
206 case BLOB_SMU_FW:
207 command = MBOX_BIOS_CMD_SMU_FW;
208 break;
209 case BLOB_SMU_FW2:
210 command = MBOX_BIOS_CMD_SMU_FW2;
211 break;
212 default:
213 printk(BIOS_ERR, "BUG: Invalid PSP blob type %x\n", type);
214 return -PSPSTS_INVALID_BLOB;
215 }
216
217 /* type can only be BLOB_SMU_FW or BLOB_SMU_FW2 here, so don't re-check for this */
218 if (!CONFIG(SOC_AMD_PSP_SELECTABLE_SMU_FW)) {
219 printk(BIOS_ERR, "BUG: Selectable firmware is not supported\n");
220 return -PSPSTS_UNSUPPORTED;
221 }
Marshall Dawson596ecec2017-10-12 16:04:08 -0600222
223 if (cbfs_boot_locate(&cbfs_file, name, NULL)) {
224 printk(BIOS_ERR, "BUG: Cannot locate blob for PSP loading\n");
Marshall Dawson737e56a2020-01-19 16:32:08 -0700225 return -PSPSTS_INVALID_NAME;
Marshall Dawson596ecec2017-10-12 16:04:08 -0600226 }
227
228 cbfs_file_data(&rdev, &cbfs_file);
229 blob = rdev_mmap_full(&rdev);
Marshall Dawson737e56a2020-01-19 16:32:08 -0700230 if (!blob) {
Marshall Dawson596ecec2017-10-12 16:04:08 -0600231 printk(BIOS_ERR, "BUG: Cannot map blob for PSP loading\n");
Marshall Dawson737e56a2020-01-19 16:32:08 -0700232 return -PSPSTS_INVALID_NAME;
Marshall Dawson596ecec2017-10-12 16:04:08 -0600233 }
Marshall Dawson737e56a2020-01-19 16:32:08 -0700234
235 printk(BIOS_DEBUG, "PSP: Load blob type %x from @%p... ", type, blob);
236
237 /* Blob commands use the buffer registers as data, not pointer to buf */
238 cmd_status = send_psp_command(command, blob);
239 print_cmd_status(cmd_status, NULL);
240
241 rdev_munmap(&rdev, blob);
242 return cmd_status;
Marshall Dawson596ecec2017-10-12 16:04:08 -0600243}
Marshall Dawsond1cc3c22017-12-08 12:46:11 -0700244
245BOOT_STATE_INIT_ENTRY(BS_PAYLOAD_BOOT, BS_ON_ENTRY,
246 psp_notify_boot_done, NULL);