blob: f8b1e6b326180283cca077c33aea026e7c027cb2 [file] [log] [blame]
Marshall Dawson68243a52017-06-15 16:59:20 -06001/*
2 * This file is part of the coreboot project.
3 *
Charles Marslett81655832018-07-24 10:43:33 -05004 * Copyright (C) 2012-2018 Advanced Micro Devices, Inc.
Marshall Dawson68243a52017-06-15 16:59:20 -06005 *
6 * This program is free software; you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License as published by
8 * the Free Software Foundation; version 2 of the License.
9 *
10 * This program is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 * GNU General Public License for more details.
14 */
15
16#include <arch/io.h>
Charles Marslett81655832018-07-24 10:43:33 -050017#include <cpu/x86/msr.h>
Marshall Dawson596ecec2017-10-12 16:04:08 -060018#include <cbfs.h>
19#include <region_file.h>
Marshall Dawson68243a52017-06-15 16:59:20 -060020#include <timer.h>
21#include <device/pci_def.h>
Marshall Dawsond1cc3c22017-12-08 12:46:11 -070022#include <bootstate.h>
Marshall Dawson68243a52017-06-15 16:59:20 -060023#include <console/console.h>
Charles Marslett81655832018-07-24 10:43:33 -050024#include <device/pci_ops.h>
Marshall Dawson68243a52017-06-15 16:59:20 -060025#include <amdblocks/psp.h>
Charles Marslett81655832018-07-24 10:43:33 -050026#include <soc/iomap.h>
27#include <soc/northbridge.h>
Marshall Dawson68243a52017-06-15 16:59:20 -060028
29static const char *psp_status_nobase = "error: PSP BAR3 not assigned";
30static const char *psp_status_halted = "error: PSP in halted state";
31static const char *psp_status_recovery = "error: PSP recovery required";
32static const char *psp_status_errcmd = "error sending command";
33static const char *psp_status_init_timeout = "error: PSP init timeout";
34static const char *psp_status_cmd_timeout = "error: PSP command timeout";
35static const char *psp_status_noerror = "";
36
Charles Marslett81655832018-07-24 10:43:33 -050037static void psp_bar_init_early(void)
38{
39 u32 psp_mmio_size;
40 u32 value32;
41 u32 base, limit;
42
43 /* Check for presence of the PSP */
44 if (pci_read_config32(SOC_PSP_DEV, PCI_VENDOR_ID) == 0xffffffff) {
45 printk(BIOS_WARNING, "PSP: SOC_PSP_DEV device not found at D%xF%x\n",
46 PSP_DEV, PSP_FUNC);
47 return;
48 }
49
50 /* Check if PSP BAR has been assigned, and if so, just return */
51 if (pci_read_config32(SOC_PSP_DEV, PCI_BASE_ADDRESS_4) &
52 ~PCI_BASE_ADDRESS_MEM_ATTR_MASK)
53 return;
54
55 /* Otherwise, do an early init of the BAR */
56 pci_write_config32(SOC_PSP_DEV, PCI_BASE_ADDRESS_4, 0xffffffff);
57 psp_mmio_size = ~pci_read_config32(SOC_PSP_DEV, PCI_BASE_ADDRESS_4) + 1;
58 printk(BIOS_SPEW, "PSP: BAR size is 0x%x\n", psp_mmio_size);
59 /* Assign BAR to an initial temporarily defined region */
60 pci_write_config32(SOC_PSP_DEV, PCI_BASE_ADDRESS_4,
61 PSP_MAILBOX_BAR3_BASE);
62
63 /* Route MMIO through the northbridge */
64 pci_write_config32(SOC_PSP_DEV, PCI_COMMAND,
65 (PCI_COMMAND_MEMORY | PCI_COMMAND_MASTER));
66 limit = ((PSP_MAILBOX_BAR3_BASE + psp_mmio_size - 1) >> 8) & ~0xff;
67 pci_write_config32(SOC_ADDR_DEV, NB_MMIO_LIMIT_LO(7), limit);
68 base = (PSP_MAILBOX_BAR3_BASE >> 8) | MMIO_WE | MMIO_RE;
69 pci_write_config32(SOC_ADDR_DEV, NB_MMIO_BASE_LO(7), base);
70 pci_write_config32(SOC_PSP_DEV, PSP_PCI_EXT_HDR_CTRL, MAGIC_ENABLES);
71
72 /* Update the capability chain */
73 value32 = pci_read_config32(SOC_PSP_DEV, PSP_PCI_MIRRORCTRL1_REG);
74 value32 &= ~PMNXTPTRW_MASK;
75 value32 |= PMNXTPTRW_EXPOSE;
76 pci_write_config32(SOC_PSP_DEV, PSP_PCI_MIRRORCTRL1_REG, value32);
77}
78
79static uintptr_t get_psp_bar3_addr(void)
80{
81 uintptr_t psp_mmio;
82
83 /* Check for presence of the PSP */
84 if (pci_read_config32(SOC_PSP_DEV, PCI_VENDOR_ID) == 0xffffffff) {
85 printk(BIOS_WARNING, "PSP: No SOC_PSP_DEV found at D%xF%x\n",
86 PSP_DEV, PSP_FUNC);
87 return 0;
88 }
89
90 /* D8F0x48[12] is the Bar3Hide flag, check it */
91 if (pci_read_config32(SOC_PSP_DEV, PSP_PCI_EXT_HDR_CTRL) & BAR3HIDE) {
92 psp_mmio = rdmsr(MSR_CU_CBBCFG).lo;
93 if (psp_mmio == 0xffffffff) {
94 printk(BIOS_WARNING, "PSP: BAR hidden, MSR val uninitialized\n");
95 return 0;
96 }
97 return psp_mmio;
98 } else {
99 return pci_read_config32(SOC_PSP_DEV, PCI_BASE_ADDRESS_4) &
100 ~PCI_BASE_ADDRESS_MEM_ATTR_MASK;
101 }
102}
103
Marshall Dawson68243a52017-06-15 16:59:20 -0600104static const char *status_to_string(int err)
105{
106 switch (err) {
107 case -PSPSTS_NOBASE:
108 return psp_status_nobase;
109 case -PSPSTS_HALTED:
110 return psp_status_halted;
111 case -PSPSTS_RECOVERY:
112 return psp_status_recovery;
113 case -PSPSTS_SEND_ERROR:
114 return psp_status_errcmd;
115 case -PSPSTS_INIT_TIMEOUT:
116 return psp_status_init_timeout;
117 case -PSPSTS_CMD_TIMEOUT:
118 return psp_status_cmd_timeout;
119 default:
120 return psp_status_noerror;
121 }
122}
123
124static struct psp_mbox *get_mbox_address(void)
125{
Marshall Dawson68243a52017-06-15 16:59:20 -0600126 uintptr_t baseptr;
127
Charles Marslett81655832018-07-24 10:43:33 -0500128 baseptr = get_psp_bar3_addr();
129 if (baseptr == 0) {
130 psp_bar_init_early();
131 baseptr = get_psp_bar3_addr();
132 if (baseptr == 0) {
133 printk(BIOS_WARNING, "PSP: %s(), psp_bar_init_early() failed...\n",
134 __func__);
135 return NULL;
136 }
Marshall Dawson68243a52017-06-15 16:59:20 -0600137 }
Marshall Dawson68243a52017-06-15 16:59:20 -0600138 return (struct psp_mbox *)(baseptr + PSP_MAILBOX_BASE);
139}
140
141static u32 rd_mbox_sts(struct psp_mbox *mbox)
142{
143 return read32(&mbox->mbox_status);
144}
145
146static void wr_mbox_cmd(struct psp_mbox *mbox, u32 cmd)
147{
148 write32(&mbox->mbox_command, cmd);
149}
150
151static u32 rd_mbox_cmd(struct psp_mbox *mbox)
152{
153 return read32(&mbox->mbox_command);
154}
155
156static void wr_mbox_cmd_resp(struct psp_mbox *mbox, void *buffer)
157{
158 write64(&mbox->cmd_response, (uintptr_t)buffer);
159}
160
161static u32 rd_resp_sts(struct mbox_default_buffer *buffer)
162{
163 return read32(&buffer->header.status);
164}
165
166static int wait_initialized(struct psp_mbox *mbox)
167{
168 struct stopwatch sw;
169
170 stopwatch_init_msecs_expire(&sw, PSP_INIT_TIMEOUT);
171
172 do {
173 if (rd_mbox_sts(mbox) & STATUS_INITIALIZED)
174 return 0;
175 } while (!stopwatch_expired(&sw));
176
177 return -PSPSTS_INIT_TIMEOUT;
178}
179
180static int wait_command(struct psp_mbox *mbox)
181{
182 struct stopwatch sw;
183
184 stopwatch_init_msecs_expire(&sw, PSP_CMD_TIMEOUT);
185
186 do {
187 if (!rd_mbox_cmd(mbox))
188 return 0;
189 } while (!stopwatch_expired(&sw));
190
191 return -PSPSTS_CMD_TIMEOUT;
192}
193
194static int send_psp_command(u32 command, void *buffer)
195{
Marshall Dawson68243a52017-06-15 16:59:20 -0600196 struct psp_mbox *mbox = get_mbox_address();
197 if (!mbox)
198 return -PSPSTS_NOBASE;
199
Marshall Dawson68243a52017-06-15 16:59:20 -0600200 /* check for PSP error conditions */
Marshall Dawson33c87732017-12-13 10:24:41 -0700201 if (rd_mbox_sts(mbox) & STATUS_HALT)
202 return -PSPSTS_HALTED;
203
204 if (rd_mbox_sts(mbox) & STATUS_RECOVERY)
205 return -PSPSTS_RECOVERY;
Marshall Dawson68243a52017-06-15 16:59:20 -0600206
207 /* PSP must be finished with init and ready to accept a command */
Marshall Dawson33c87732017-12-13 10:24:41 -0700208 if (wait_initialized(mbox))
209 return -PSPSTS_INIT_TIMEOUT;
210
211 if (wait_command(mbox))
212 return -PSPSTS_CMD_TIMEOUT;
Marshall Dawson68243a52017-06-15 16:59:20 -0600213
214 /* set address of command-response buffer and write command register */
215 wr_mbox_cmd_resp(mbox, buffer);
216 wr_mbox_cmd(mbox, command);
217
218 /* PSP clears command register when complete */
Marshall Dawson33c87732017-12-13 10:24:41 -0700219 if (wait_command(mbox))
220 return -PSPSTS_CMD_TIMEOUT;
Marshall Dawson68243a52017-06-15 16:59:20 -0600221
222 /* check delivery status */
Marshall Dawson33c87732017-12-13 10:24:41 -0700223 if (rd_mbox_sts(mbox) & (STATUS_ERROR | STATUS_TERMINATED))
224 return -PSPSTS_SEND_ERROR;
225
226 return 0;
Marshall Dawson68243a52017-06-15 16:59:20 -0600227}
228
229/*
230 * Notify the PSP that DRAM is present. Upon receiving this command, the PSP
231 * will load its OS into fenced DRAM that is not accessible to the x86 cores.
232 */
233int psp_notify_dram(void)
234{
Marshall Dawson68243a52017-06-15 16:59:20 -0600235 int cmd_status;
Marshall Dawson66dd3992017-12-13 10:51:13 -0700236 struct mbox_default_buffer buffer = {
237 .header = {
238 .size = sizeof(buffer)
239 }
240 };
Marshall Dawson68243a52017-06-15 16:59:20 -0600241
242 printk(BIOS_DEBUG, "PSP: Notify that DRAM is available... ");
243
Marshall Dawson68243a52017-06-15 16:59:20 -0600244 cmd_status = send_psp_command(MBOX_BIOS_CMD_DRAM_INFO, &buffer);
245
246 /* buffer's status shouldn't change but report it if it does */
247 if (rd_resp_sts(&buffer))
248 printk(BIOS_DEBUG, "buffer status=0x%x ",
249 rd_resp_sts(&buffer));
250 if (cmd_status)
251 printk(BIOS_DEBUG, "%s\n", status_to_string(cmd_status));
252 else
253 printk(BIOS_DEBUG, "OK\n");
254
255 return cmd_status;
256}
Marshall Dawson596ecec2017-10-12 16:04:08 -0600257
258/*
Marshall Dawsond1cc3c22017-12-08 12:46:11 -0700259 * Notify the PSP that the system is completing the boot process. Upon
260 * receiving this command, the PSP will only honor commands where the buffer
261 * is in SMM space.
262 */
263static void psp_notify_boot_done(void *unused)
264{
265 int cmd_status;
266 struct mbox_default_buffer buffer = {
267 .header = {
268 .size = sizeof(buffer)
269 }
270 };
271
272 printk(BIOS_DEBUG, "PSP: Notify that POST is finishing... ");
273
274 cmd_status = send_psp_command(MBOX_BIOS_CMD_BOOT_DONE, &buffer);
275
276 /* buffer's status shouldn't change but report it if it does */
277 if (rd_resp_sts(&buffer))
278 printk(BIOS_DEBUG, "buffer status=0x%x ",
279 rd_resp_sts(&buffer));
280 if (cmd_status)
281 printk(BIOS_DEBUG, "%s\n", status_to_string(cmd_status));
282 else
283 printk(BIOS_DEBUG, "OK\n");
284}
285
286/*
Marshall Dawson596ecec2017-10-12 16:04:08 -0600287 * Tell the PSP to load a firmware blob from a location in the BIOS image.
288 */
289static int psp_load_blob(int type, void *addr)
290{
291 int cmd_status;
292
293 if (!IS_ENABLED(CONFIG_SOC_AMD_PSP_SELECTABLE_SMU_FW)) {
294 printk(BIOS_ERR, "BUG: Selectable firmware is not supported\n");
295 return PSPSTS_UNSUPPORTED;
296 }
297
298 /* only two types currently supported */
299 if (type != MBOX_BIOS_CMD_SMU_FW && type != MBOX_BIOS_CMD_SMU_FW2) {
300 printk(BIOS_ERR, "BUG: Invalid PSP blob type %x\n", type);
301 return PSPSTS_INVALID_BLOB;
302 }
303
304 printk(BIOS_DEBUG, "PSP: Load blob type %x from @%p... ", type, addr);
305
306 /* Blob commands use the buffer registers as data, not pointer to buf */
307 cmd_status = send_psp_command(type, addr);
308
309 if (cmd_status)
310 printk(BIOS_DEBUG, "%s\n", status_to_string(cmd_status));
311 else
312 printk(BIOS_DEBUG, "OK\n");
313
314 return cmd_status;
315}
316
317int psp_load_named_blob(int type, const char *name)
318{
319 void *blob;
320 struct cbfsf cbfs_file;
321 struct region_device rdev;
322 int r;
323
324 if (cbfs_boot_locate(&cbfs_file, name, NULL)) {
325 printk(BIOS_ERR, "BUG: Cannot locate blob for PSP loading\n");
326 return PSPSTS_INVALID_NAME;
327 }
328
329 cbfs_file_data(&rdev, &cbfs_file);
330 blob = rdev_mmap_full(&rdev);
331 if (blob) {
332 r = psp_load_blob(type, blob);
333 rdev_munmap(&rdev, blob);
334 } else {
335 printk(BIOS_ERR, "BUG: Cannot map blob for PSP loading\n");
336 return PSPSTS_INVALID_NAME;
337 }
338 return r;
339}
Marshall Dawsond1cc3c22017-12-08 12:46:11 -0700340
341BOOT_STATE_INIT_ENTRY(BS_PAYLOAD_BOOT, BS_ON_ENTRY,
342 psp_notify_boot_done, NULL);