blob: 0294422c3d0a0e4403bf12172e0cadd93fa9d243 [file] [log] [blame]
Marshall Dawson68243a52017-06-15 16:59:20 -06001/*
2 * This file is part of the coreboot project.
3 *
Marshall Dawson68243a52017-06-15 16:59:20 -06004 *
5 * This program is free software; you can redistribute it and/or modify
6 * it under the terms of the GNU General Public License as published by
7 * the Free Software Foundation; version 2 of the License.
8 *
9 * This program is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 * GNU General Public License for more details.
13 */
14
Kyösti Mälkki13f66502019-03-03 08:01:05 +020015#include <device/mmio.h>
Charles Marslett81655832018-07-24 10:43:33 -050016#include <cpu/x86/msr.h>
Marshall Dawson596ecec2017-10-12 16:04:08 -060017#include <cbfs.h>
18#include <region_file.h>
Marshall Dawson68243a52017-06-15 16:59:20 -060019#include <timer.h>
20#include <device/pci_def.h>
Marshall Dawsond1cc3c22017-12-08 12:46:11 -070021#include <bootstate.h>
Marshall Dawson68243a52017-06-15 16:59:20 -060022#include <console/console.h>
Charles Marslett81655832018-07-24 10:43:33 -050023#include <device/pci_ops.h>
Marshall Dawson68243a52017-06-15 16:59:20 -060024#include <amdblocks/psp.h>
Charles Marslett81655832018-07-24 10:43:33 -050025#include <soc/iomap.h>
26#include <soc/northbridge.h>
Marshall Dawson68243a52017-06-15 16:59:20 -060027
28static const char *psp_status_nobase = "error: PSP BAR3 not assigned";
29static const char *psp_status_halted = "error: PSP in halted state";
30static const char *psp_status_recovery = "error: PSP recovery required";
31static const char *psp_status_errcmd = "error sending command";
32static const char *psp_status_init_timeout = "error: PSP init timeout";
33static const char *psp_status_cmd_timeout = "error: PSP command timeout";
34static const char *psp_status_noerror = "";
35
Charles Marslett81655832018-07-24 10:43:33 -050036static void psp_bar_init_early(void)
37{
38 u32 psp_mmio_size;
39 u32 value32;
40 u32 base, limit;
41
42 /* Check for presence of the PSP */
43 if (pci_read_config32(SOC_PSP_DEV, PCI_VENDOR_ID) == 0xffffffff) {
44 printk(BIOS_WARNING, "PSP: SOC_PSP_DEV device not found at D%xF%x\n",
45 PSP_DEV, PSP_FUNC);
46 return;
47 }
48
49 /* Check if PSP BAR has been assigned, and if so, just return */
50 if (pci_read_config32(SOC_PSP_DEV, PCI_BASE_ADDRESS_4) &
51 ~PCI_BASE_ADDRESS_MEM_ATTR_MASK)
52 return;
53
54 /* Otherwise, do an early init of the BAR */
55 pci_write_config32(SOC_PSP_DEV, PCI_BASE_ADDRESS_4, 0xffffffff);
56 psp_mmio_size = ~pci_read_config32(SOC_PSP_DEV, PCI_BASE_ADDRESS_4) + 1;
57 printk(BIOS_SPEW, "PSP: BAR size is 0x%x\n", psp_mmio_size);
58 /* Assign BAR to an initial temporarily defined region */
59 pci_write_config32(SOC_PSP_DEV, PCI_BASE_ADDRESS_4,
60 PSP_MAILBOX_BAR3_BASE);
61
62 /* Route MMIO through the northbridge */
63 pci_write_config32(SOC_PSP_DEV, PCI_COMMAND,
64 (PCI_COMMAND_MEMORY | PCI_COMMAND_MASTER));
65 limit = ((PSP_MAILBOX_BAR3_BASE + psp_mmio_size - 1) >> 8) & ~0xff;
66 pci_write_config32(SOC_ADDR_DEV, NB_MMIO_LIMIT_LO(7), limit);
67 base = (PSP_MAILBOX_BAR3_BASE >> 8) | MMIO_WE | MMIO_RE;
68 pci_write_config32(SOC_ADDR_DEV, NB_MMIO_BASE_LO(7), base);
69 pci_write_config32(SOC_PSP_DEV, PSP_PCI_EXT_HDR_CTRL, MAGIC_ENABLES);
70
71 /* Update the capability chain */
72 value32 = pci_read_config32(SOC_PSP_DEV, PSP_PCI_MIRRORCTRL1_REG);
73 value32 &= ~PMNXTPTRW_MASK;
74 value32 |= PMNXTPTRW_EXPOSE;
75 pci_write_config32(SOC_PSP_DEV, PSP_PCI_MIRRORCTRL1_REG, value32);
76}
77
78static uintptr_t get_psp_bar3_addr(void)
79{
80 uintptr_t psp_mmio;
81
82 /* Check for presence of the PSP */
83 if (pci_read_config32(SOC_PSP_DEV, PCI_VENDOR_ID) == 0xffffffff) {
84 printk(BIOS_WARNING, "PSP: No SOC_PSP_DEV found at D%xF%x\n",
85 PSP_DEV, PSP_FUNC);
86 return 0;
87 }
88
89 /* D8F0x48[12] is the Bar3Hide flag, check it */
90 if (pci_read_config32(SOC_PSP_DEV, PSP_PCI_EXT_HDR_CTRL) & BAR3HIDE) {
91 psp_mmio = rdmsr(MSR_CU_CBBCFG).lo;
92 if (psp_mmio == 0xffffffff) {
93 printk(BIOS_WARNING, "PSP: BAR hidden, MSR val uninitialized\n");
94 return 0;
95 }
96 return psp_mmio;
97 } else {
98 return pci_read_config32(SOC_PSP_DEV, PCI_BASE_ADDRESS_4) &
99 ~PCI_BASE_ADDRESS_MEM_ATTR_MASK;
100 }
101}
102
Marshall Dawson68243a52017-06-15 16:59:20 -0600103static const char *status_to_string(int err)
104{
105 switch (err) {
106 case -PSPSTS_NOBASE:
107 return psp_status_nobase;
108 case -PSPSTS_HALTED:
109 return psp_status_halted;
110 case -PSPSTS_RECOVERY:
111 return psp_status_recovery;
112 case -PSPSTS_SEND_ERROR:
113 return psp_status_errcmd;
114 case -PSPSTS_INIT_TIMEOUT:
115 return psp_status_init_timeout;
116 case -PSPSTS_CMD_TIMEOUT:
117 return psp_status_cmd_timeout;
118 default:
119 return psp_status_noerror;
120 }
121}
122
123static struct psp_mbox *get_mbox_address(void)
124{
Marshall Dawson68243a52017-06-15 16:59:20 -0600125 uintptr_t baseptr;
126
Charles Marslett81655832018-07-24 10:43:33 -0500127 baseptr = get_psp_bar3_addr();
128 if (baseptr == 0) {
129 psp_bar_init_early();
130 baseptr = get_psp_bar3_addr();
131 if (baseptr == 0) {
132 printk(BIOS_WARNING, "PSP: %s(), psp_bar_init_early() failed...\n",
133 __func__);
134 return NULL;
135 }
Marshall Dawson68243a52017-06-15 16:59:20 -0600136 }
Marshall Dawson68243a52017-06-15 16:59:20 -0600137 return (struct psp_mbox *)(baseptr + PSP_MAILBOX_BASE);
138}
139
140static u32 rd_mbox_sts(struct psp_mbox *mbox)
141{
142 return read32(&mbox->mbox_status);
143}
144
145static void wr_mbox_cmd(struct psp_mbox *mbox, u32 cmd)
146{
147 write32(&mbox->mbox_command, cmd);
148}
149
150static u32 rd_mbox_cmd(struct psp_mbox *mbox)
151{
152 return read32(&mbox->mbox_command);
153}
154
155static void wr_mbox_cmd_resp(struct psp_mbox *mbox, void *buffer)
156{
157 write64(&mbox->cmd_response, (uintptr_t)buffer);
158}
159
160static u32 rd_resp_sts(struct mbox_default_buffer *buffer)
161{
162 return read32(&buffer->header.status);
163}
164
165static int wait_initialized(struct psp_mbox *mbox)
166{
167 struct stopwatch sw;
168
169 stopwatch_init_msecs_expire(&sw, PSP_INIT_TIMEOUT);
170
171 do {
172 if (rd_mbox_sts(mbox) & STATUS_INITIALIZED)
173 return 0;
174 } while (!stopwatch_expired(&sw));
175
176 return -PSPSTS_INIT_TIMEOUT;
177}
178
179static int wait_command(struct psp_mbox *mbox)
180{
181 struct stopwatch sw;
182
183 stopwatch_init_msecs_expire(&sw, PSP_CMD_TIMEOUT);
184
185 do {
186 if (!rd_mbox_cmd(mbox))
187 return 0;
188 } while (!stopwatch_expired(&sw));
189
190 return -PSPSTS_CMD_TIMEOUT;
191}
192
193static int send_psp_command(u32 command, void *buffer)
194{
Marshall Dawson68243a52017-06-15 16:59:20 -0600195 struct psp_mbox *mbox = get_mbox_address();
196 if (!mbox)
197 return -PSPSTS_NOBASE;
198
Marshall Dawson68243a52017-06-15 16:59:20 -0600199 /* check for PSP error conditions */
Marshall Dawson33c87732017-12-13 10:24:41 -0700200 if (rd_mbox_sts(mbox) & STATUS_HALT)
201 return -PSPSTS_HALTED;
202
203 if (rd_mbox_sts(mbox) & STATUS_RECOVERY)
204 return -PSPSTS_RECOVERY;
Marshall Dawson68243a52017-06-15 16:59:20 -0600205
206 /* PSP must be finished with init and ready to accept a command */
Marshall Dawson33c87732017-12-13 10:24:41 -0700207 if (wait_initialized(mbox))
208 return -PSPSTS_INIT_TIMEOUT;
209
210 if (wait_command(mbox))
211 return -PSPSTS_CMD_TIMEOUT;
Marshall Dawson68243a52017-06-15 16:59:20 -0600212
213 /* set address of command-response buffer and write command register */
214 wr_mbox_cmd_resp(mbox, buffer);
215 wr_mbox_cmd(mbox, command);
216
217 /* PSP clears command register when complete */
Marshall Dawson33c87732017-12-13 10:24:41 -0700218 if (wait_command(mbox))
219 return -PSPSTS_CMD_TIMEOUT;
Marshall Dawson68243a52017-06-15 16:59:20 -0600220
221 /* check delivery status */
Marshall Dawson33c87732017-12-13 10:24:41 -0700222 if (rd_mbox_sts(mbox) & (STATUS_ERROR | STATUS_TERMINATED))
223 return -PSPSTS_SEND_ERROR;
224
225 return 0;
Marshall Dawson68243a52017-06-15 16:59:20 -0600226}
227
228/*
Marshall Dawson5646a642020-01-19 16:12:25 -0700229 * Print meaningful status to the console. Caller only passes a pointer to a
230 * buffer if it's expected to contain its own status.
231 */
232static void print_cmd_status(int cmd_status, struct mbox_default_buffer *buffer)
233{
234 if (buffer && rd_resp_sts(buffer))
235 printk(BIOS_DEBUG, "buffer status=0x%x ", rd_resp_sts(buffer));
236
237 if (cmd_status)
238 printk(BIOS_DEBUG, "%s\n", status_to_string(cmd_status));
239 else
240 printk(BIOS_DEBUG, "OK\n");
241}
242
243/*
Marshall Dawson68243a52017-06-15 16:59:20 -0600244 * Notify the PSP that DRAM is present. Upon receiving this command, the PSP
245 * will load its OS into fenced DRAM that is not accessible to the x86 cores.
246 */
247int psp_notify_dram(void)
248{
Marshall Dawson68243a52017-06-15 16:59:20 -0600249 int cmd_status;
Marshall Dawson66dd3992017-12-13 10:51:13 -0700250 struct mbox_default_buffer buffer = {
251 .header = {
252 .size = sizeof(buffer)
253 }
254 };
Marshall Dawson68243a52017-06-15 16:59:20 -0600255
256 printk(BIOS_DEBUG, "PSP: Notify that DRAM is available... ");
257
Marshall Dawson68243a52017-06-15 16:59:20 -0600258 cmd_status = send_psp_command(MBOX_BIOS_CMD_DRAM_INFO, &buffer);
259
260 /* buffer's status shouldn't change but report it if it does */
Marshall Dawson5646a642020-01-19 16:12:25 -0700261 print_cmd_status(cmd_status, &buffer);
Marshall Dawson68243a52017-06-15 16:59:20 -0600262
263 return cmd_status;
264}
Marshall Dawson596ecec2017-10-12 16:04:08 -0600265
266/*
Marshall Dawsond1cc3c22017-12-08 12:46:11 -0700267 * Notify the PSP that the system is completing the boot process. Upon
268 * receiving this command, the PSP will only honor commands where the buffer
269 * is in SMM space.
270 */
271static void psp_notify_boot_done(void *unused)
272{
273 int cmd_status;
274 struct mbox_default_buffer buffer = {
275 .header = {
276 .size = sizeof(buffer)
277 }
278 };
279
280 printk(BIOS_DEBUG, "PSP: Notify that POST is finishing... ");
281
282 cmd_status = send_psp_command(MBOX_BIOS_CMD_BOOT_DONE, &buffer);
283
284 /* buffer's status shouldn't change but report it if it does */
Marshall Dawson5646a642020-01-19 16:12:25 -0700285 print_cmd_status(cmd_status, &buffer);
Marshall Dawsond1cc3c22017-12-08 12:46:11 -0700286}
287
288/*
Marshall Dawson596ecec2017-10-12 16:04:08 -0600289 * Tell the PSP to load a firmware blob from a location in the BIOS image.
290 */
291static int psp_load_blob(int type, void *addr)
292{
293 int cmd_status;
294
Julius Wernercd49cce2019-03-05 16:53:33 -0800295 if (!CONFIG(SOC_AMD_PSP_SELECTABLE_SMU_FW)) {
Marshall Dawson596ecec2017-10-12 16:04:08 -0600296 printk(BIOS_ERR, "BUG: Selectable firmware is not supported\n");
297 return PSPSTS_UNSUPPORTED;
298 }
299
300 /* only two types currently supported */
301 if (type != MBOX_BIOS_CMD_SMU_FW && type != MBOX_BIOS_CMD_SMU_FW2) {
302 printk(BIOS_ERR, "BUG: Invalid PSP blob type %x\n", type);
303 return PSPSTS_INVALID_BLOB;
304 }
305
306 printk(BIOS_DEBUG, "PSP: Load blob type %x from @%p... ", type, addr);
307
308 /* Blob commands use the buffer registers as data, not pointer to buf */
309 cmd_status = send_psp_command(type, addr);
310
Marshall Dawson5646a642020-01-19 16:12:25 -0700311 print_cmd_status(cmd_status, NULL);
Marshall Dawson596ecec2017-10-12 16:04:08 -0600312
313 return cmd_status;
314}
315
316int psp_load_named_blob(int type, const char *name)
317{
318 void *blob;
319 struct cbfsf cbfs_file;
320 struct region_device rdev;
321 int r;
322
323 if (cbfs_boot_locate(&cbfs_file, name, NULL)) {
324 printk(BIOS_ERR, "BUG: Cannot locate blob for PSP loading\n");
325 return PSPSTS_INVALID_NAME;
326 }
327
328 cbfs_file_data(&rdev, &cbfs_file);
329 blob = rdev_mmap_full(&rdev);
330 if (blob) {
331 r = psp_load_blob(type, blob);
332 rdev_munmap(&rdev, blob);
333 } else {
334 printk(BIOS_ERR, "BUG: Cannot map blob for PSP loading\n");
335 return PSPSTS_INVALID_NAME;
336 }
337 return r;
338}
Marshall Dawsond1cc3c22017-12-08 12:46:11 -0700339
340BOOT_STATE_INIT_ENTRY(BS_PAYLOAD_BOOT, BS_ON_ENTRY,
341 psp_notify_boot_done, NULL);