xref: /aosp_15_r20/external/coreboot/src/soc/amd/common/block/psp/psp_gen1.c (revision b9411a12aaaa7e1e6a6fb7c5e057f44ee179a49c)
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