1 /* SPDX-License-Identifier: GPL-2.0-only */
2
3 #include <cpu/amd/msr.h>
4 #include <cpu/x86/msr.h>
5 #include <device/mmio.h>
6 #include <device/pci_ops.h>
7 #include <device/pci_def.h>
8 #include <cbfs.h>
9 #include <region_file.h>
10 #include <timer.h>
11 #include <console/console.h>
12 #include <amdblocks/psp.h>
13 #include <soc/iomap.h>
14 #include <soc/northbridge.h>
15 #include <soc/pci_devs.h>
16 #include <soc/southbridge.h>
17 #include "psp_def.h"
18
19 #define PSP_MAILBOX_OFFSET 0x70
20
21 /* generic PSP interface status, v1 */
22 #define PSPV1_STATUS_INITIALIZED BIT(0)
23 #define PSPV1_STATUS_ERROR BIT(1)
24 #define PSPV1_STATUS_TERMINATED BIT(2)
25 #define PSPV1_STATUS_HALT BIT(3)
26 #define PSPV1_STATUS_RECOVERY BIT(4)
27
28 /*
29 * pspv1_mbox consists of hardware registers beginning at PSPx000070
30 * mbox_command: BIOS->PSP command, cleared by PSP when complete
31 * mbox_status: BIOS->PSP interface status
32 * cmd_response: pointer to command/response buffer
33 */
34 struct pspv1_mbox {
35 u32 mbox_command;
36 u32 mbox_status;
37 u64 cmd_response; /* definition conflicts w/BKDG but matches agesa */
38 } __packed;
39
soc_get_mbox_address(void)40 static void *soc_get_mbox_address(void)
41 {
42 uintptr_t psp_mmio;
43
44 /* Check for presence of the PSP */
45 if (pci_read_config32(SOC_PSP_DEV, PCI_VENDOR_ID) == 0xffffffff) {
46 printk(BIOS_WARNING, "PSP: No SOC_PSP_DEV found at D%xF%x\n",
47 PSP_DEV, PSP_FUNC);
48 return 0;
49 }
50
51 /* Determine if Bar3Hide has been set, and if hidden get the base from
52 * the MSR instead. */
53 if (pci_read_config32(SOC_PSP_DEV, PSP_BAR_ENABLES) & BAR3HIDE) {
54 psp_mmio = rdmsr(PSP_ADDR_MSR).lo;
55 if (!psp_mmio) {
56 printk(BIOS_WARNING, "PSP: BAR hidden, PSP_ADDR_MSR uninitialized\n");
57 return 0;
58 }
59 } else {
60 psp_mmio = pci_read_config32(SOC_PSP_DEV, PSP_MAILBOX_BAR) &
61 ~PCI_BASE_ADDRESS_MEM_ATTR_MASK;
62 }
63
64 return (void *)(psp_mmio + PSP_MAILBOX_OFFSET);
65 }
66
rd_mbox_sts(struct pspv1_mbox * mbox)67 static u32 rd_mbox_sts(struct pspv1_mbox *mbox)
68 {
69 return read32(&mbox->mbox_status);
70 }
71
wr_mbox_cmd(struct pspv1_mbox * mbox,u32 cmd)72 static void wr_mbox_cmd(struct pspv1_mbox *mbox, u32 cmd)
73 {
74 write32(&mbox->mbox_command, cmd);
75 }
76
rd_mbox_cmd(struct pspv1_mbox * mbox)77 static u32 rd_mbox_cmd(struct pspv1_mbox *mbox)
78 {
79 return read32(&mbox->mbox_command);
80 }
81
wr_mbox_cmd_resp(struct pspv1_mbox * mbox,void * buffer)82 static void wr_mbox_cmd_resp(struct pspv1_mbox *mbox, void *buffer)
83 {
84 write64(&mbox->cmd_response, (uintptr_t)buffer);
85 }
86
wait_initialized(struct pspv1_mbox * mbox)87 static int wait_initialized(struct pspv1_mbox *mbox)
88 {
89 struct stopwatch sw;
90
91 stopwatch_init_msecs_expire(&sw, PSP_INIT_TIMEOUT);
92
93 do {
94 if (rd_mbox_sts(mbox) & PSPV1_STATUS_INITIALIZED)
95 return 0;
96 } while (!stopwatch_expired(&sw));
97
98 return -PSPSTS_INIT_TIMEOUT;
99 }
100
wait_command(struct pspv1_mbox * mbox)101 static int wait_command(struct pspv1_mbox *mbox)
102 {
103 struct stopwatch sw;
104
105 stopwatch_init_msecs_expire(&sw, PSP_CMD_TIMEOUT);
106
107 do {
108 if (!rd_mbox_cmd(mbox))
109 return 0;
110 } while (!stopwatch_expired(&sw));
111
112 return -PSPSTS_CMD_TIMEOUT;
113 }
114
send_psp_command(u32 command,void * buffer)115 int send_psp_command(u32 command, void *buffer)
116 {
117 struct pspv1_mbox *mbox = soc_get_mbox_address();
118 if (!mbox)
119 return -PSPSTS_NOBASE;
120
121 /* check for PSP error conditions */
122 if (rd_mbox_sts(mbox) & PSPV1_STATUS_HALT)
123 return -PSPSTS_HALTED;
124
125 if (rd_mbox_sts(mbox) & PSPV1_STATUS_RECOVERY)
126 return -PSPSTS_RECOVERY;
127
128 /* PSP must be finished with init and ready to accept a command */
129 if (wait_initialized(mbox))
130 return -PSPSTS_INIT_TIMEOUT;
131
132 if (wait_command(mbox))
133 return -PSPSTS_CMD_TIMEOUT;
134
135 /* set address of command-response buffer and write command register */
136 wr_mbox_cmd_resp(mbox, buffer);
137 wr_mbox_cmd(mbox, command);
138
139 /* PSP clears command register when complete */
140 if (wait_command(mbox))
141 return -PSPSTS_CMD_TIMEOUT;
142
143 /* check delivery status */
144 if (rd_mbox_sts(mbox) & (PSPV1_STATUS_ERROR | PSPV1_STATUS_TERMINATED))
145 return -PSPSTS_SEND_ERROR;
146
147 return 0;
148 }
149
150 /*
151 * Tell the PSP to load a firmware blob from a location in the BIOS image.
152 */
psp_load_named_blob(enum psp_blob_type type,const char * name)153 int psp_load_named_blob(enum psp_blob_type type, const char *name)
154 {
155 int cmd_status;
156 u32 command;
157 void *blob;
158
159 switch (type) {
160 case BLOB_SMU_FW:
161 command = MBOX_BIOS_CMD_SMU_FW;
162 break;
163 case BLOB_SMU_FW2:
164 command = MBOX_BIOS_CMD_SMU_FW2;
165 break;
166 default:
167 printk(BIOS_ERR, "BUG: Invalid PSP blob type %x\n", type);
168 return -PSPSTS_INVALID_BLOB;
169 }
170
171 /* type can only be BLOB_SMU_FW or BLOB_SMU_FW2 here, so don't re-check for this */
172 if (!CONFIG(SOC_AMD_PSP_SELECTABLE_SMU_FW)) {
173 printk(BIOS_ERR, "BUG: Selectable firmware is not supported\n");
174 return -PSPSTS_UNSUPPORTED;
175 }
176
177 blob = cbfs_map(name, NULL);
178 if (!blob) {
179 printk(BIOS_ERR, "BUG: Cannot map blob for PSP loading\n");
180 return -PSPSTS_INVALID_NAME;
181 }
182
183 printk(BIOS_DEBUG, "PSP: Load blob type %x from @%p... ", type, blob);
184
185 /* Blob commands use the buffer registers as data, not pointer to buf */
186 cmd_status = send_psp_command(command, blob);
187 psp_print_cmd_status(cmd_status, NULL);
188
189 cbfs_unmap(blob);
190 return cmd_status;
191 }
192
193 /*
194 * Notify the PSP that DRAM is present. Upon receiving this command, the PSP
195 * will load its OS into fenced DRAM that is not accessible to the x86 cores.
196 */
psp_notify_dram(void)197 int psp_notify_dram(void)
198 {
199 int cmd_status;
200 struct mbox_default_buffer buffer = {
201 .header = {
202 .size = sizeof(buffer)
203 }
204 };
205
206 printk(BIOS_DEBUG, "PSP: Notify that DRAM is available... ");
207
208 cmd_status = send_psp_command(MBOX_BIOS_CMD_DRAM_INFO, &buffer);
209
210 /* buffer's status shouldn't change but report it if it does */
211 psp_print_cmd_status(cmd_status, &buffer.header);
212
213 return cmd_status;
214 }
215