1 /* SPDX-License-Identifier: GPL-2.0-only */
3 #include <amdblocks/psp.h>
4 #include <amdblocks/smi.h>
5 #include <console/console.h>
6 #include <cpu/x86/cache.h>
7 #include <device/mmio.h>
10 #include "psp_smi_flash.h"
12 /* PSP to x86 commands */
13 #define MBOX_PSP_CMD_SPI_INFO 0x83
14 #define MBOX_PSP_CMD_SPI_READ 0x84
15 #define MBOX_PSP_CMD_SPI_WRITE 0x85
16 #define MBOX_PSP_CMD_SPI_ERASE 0x86
17 #define MBOX_PSP_CMD_SPI_RPMC_INC_MC 0x88
18 #define MBOX_PSP_CMD_SPI_RPMC_REQ_MC 0x89
21 uint8_t buffer
[P2C_BUFFER_MAXSIZE
];
22 } __aligned(32) p2c_buffer
;
24 static const uintptr_t p2c_mbox_base
= (uintptr_t)&p2c_buffer
.buffer
;
26 #define P2C_MBOX_COMMAND_OFFSET 0x00
27 #define P2C_MBOX_STATUS_OFFSET 0x04
28 #define P2C_MBOX_BUFFER_OFFSET 0x08
30 union p2c_mbox_status
{
32 uint32_t checksum
: 8; /* [ 0.. 7] */
33 uint32_t checksum_en
: 1; /* [ 8.. 8] */
34 uint32_t reserved
: 22; /* [ 9..30] */
35 uint32_t command_ready
: 1; /* [31..31] */
40 static uint8_t rd_bios_mbox_checksum(void)
42 union p2c_mbox_status status
;
44 status
.raw
= read32p(p2c_mbox_base
+ P2C_MBOX_STATUS_OFFSET
);
45 return status
.fields
.checksum
;
48 static void wr_bios_mbox_checksum(uint8_t checksum
)
50 union p2c_mbox_status status
;
52 status
.raw
= read32p(p2c_mbox_base
+ P2C_MBOX_STATUS_OFFSET
);
53 status
.fields
.checksum
= checksum
;
54 write32p(p2c_mbox_base
+ P2C_MBOX_STATUS_OFFSET
, status
.raw
);
57 static bool rd_bios_mbox_checksum_en(void)
59 union p2c_mbox_status status
;
61 status
.raw
= read32p(p2c_mbox_base
+ P2C_MBOX_STATUS_OFFSET
);
62 return !!status
.fields
.checksum_en
;
65 static void wr_bios_mbox_ready(bool ready
)
67 union p2c_mbox_status status
;
69 status
.raw
= read32p(p2c_mbox_base
+ P2C_MBOX_STATUS_OFFSET
);
70 status
.fields
.command_ready
= ready
;
71 write32p(p2c_mbox_base
+ P2C_MBOX_STATUS_OFFSET
, status
.raw
);
74 void enable_psp_smi(void)
76 wr_bios_mbox_ready(true);
79 static void disable_psp_smi(void)
81 wr_bios_mbox_ready(false);
84 static void clear_psp_command(void)
86 write32p(p2c_mbox_base
+ P2C_MBOX_COMMAND_OFFSET
, 0);
89 static uint32_t get_psp_command(void)
91 return read32p(p2c_mbox_base
+ P2C_MBOX_COMMAND_OFFSET
);
94 static struct mbox_default_buffer
*get_psp_command_buffer(void)
96 return (struct mbox_default_buffer
*)(p2c_mbox_base
+ P2C_MBOX_BUFFER_OFFSET
);
99 static uint32_t get_psp_cmd_buffer_length(void)
101 return read32(&get_psp_command_buffer()->header
.size
);
104 static uint8_t calc_psp_buffer_checksum8(void)
106 const uint8_t *data
= (const uint8_t *)get_psp_command_buffer();
107 const size_t size
= get_psp_cmd_buffer_length();
108 uint8_t checksum
= 0;
111 for (i
= 0; i
< size
; i
++)
112 checksum
+= read8(data
+ i
);
117 static void write_psp_cmd_buffer_status(enum mbox_p2c_status status
)
119 return write32(&get_psp_command_buffer()->header
.status
, status
);
122 static enum mbox_p2c_status
check_psp_command(void)
124 if (rd_bios_mbox_checksum_en() &&
125 calc_psp_buffer_checksum8() != rd_bios_mbox_checksum())
126 return MBOX_PSP_CRC_ERROR
;
128 if (get_psp_cmd_buffer_length() > P2C_BUFFER_MAXSIZE
- P2C_MBOX_BUFFER_OFFSET
)
129 return MBOX_PSP_INVALID_PARAMETER
;
131 return MBOX_PSP_SUCCESS
;
134 static void handle_psp_command(void)
136 enum mbox_p2c_status status
;
138 struct mbox_default_buffer
*const buffer
= get_psp_command_buffer();
140 status
= check_psp_command();
141 if (status
!= MBOX_PSP_SUCCESS
)
144 cmd
= get_psp_command();
147 case MBOX_PSP_CMD_SPI_INFO
:
148 status
= psp_smi_spi_get_info(buffer
);
150 case MBOX_PSP_CMD_SPI_READ
:
151 status
= psp_smi_spi_read(buffer
);
153 case MBOX_PSP_CMD_SPI_WRITE
:
154 status
= psp_smi_spi_write(buffer
);
156 case MBOX_PSP_CMD_SPI_ERASE
:
157 status
= psp_smi_spi_erase(buffer
);
159 case MBOX_PSP_CMD_SPI_RPMC_INC_MC
:
160 status
= psp_smi_spi_rpmc_inc_mc(buffer
);
162 case MBOX_PSP_CMD_SPI_RPMC_REQ_MC
:
163 status
= psp_smi_spi_rpmc_req_mc(buffer
);
166 printk(BIOS_ERR
, "PSP: Unknown command %d\n", cmd
);
167 status
= MBOX_PSP_UNSUPPORTED
;
172 write_psp_cmd_buffer_status(status
);
174 if (status
== MBOX_PSP_SUCCESS
&& rd_bios_mbox_checksum_en())
175 wr_bios_mbox_checksum(calc_psp_buffer_checksum8());
177 if (status
!= MBOX_PSP_SUCCESS
)
178 printk(BIOS_ERR
, "PSP: SMI processing error. staus code %#x\n", status
);
181 /* TODO: check if all wbinvd() calls are necessary */
182 void psp_smi_handler(void)
188 handle_psp_command();