mb/google/nissa/var/rull: Configure Acoustic noise mitigation
[coreboot2.git] / src / soc / amd / common / block / psp / psp_smi.c
blob762c8ee9c130438468edc15ddeaf22737f71a72e
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>
8 #include <types.h>
9 #include "psp_def.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
20 extern struct {
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 {
31 struct {
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] */
36 } __packed fields;
37 uint32_t raw;
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;
109 size_t i;
111 for (i = 0; i < size; i++)
112 checksum += read8(data + i);
114 return checksum;
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;
137 uint32_t cmd;
138 struct mbox_default_buffer *const buffer = get_psp_command_buffer();
140 status = check_psp_command();
141 if (status != MBOX_PSP_SUCCESS)
142 goto out;
144 cmd = get_psp_command();
146 switch (cmd) {
147 case MBOX_PSP_CMD_SPI_INFO:
148 status = psp_smi_spi_get_info(buffer);
149 break;
150 case MBOX_PSP_CMD_SPI_READ:
151 status = psp_smi_spi_read(buffer);
152 break;
153 case MBOX_PSP_CMD_SPI_WRITE:
154 status = psp_smi_spi_write(buffer);
155 break;
156 case MBOX_PSP_CMD_SPI_ERASE:
157 status = psp_smi_spi_erase(buffer);
158 break;
159 case MBOX_PSP_CMD_SPI_RPMC_INC_MC:
160 status = psp_smi_spi_rpmc_inc_mc(buffer);
161 break;
162 case MBOX_PSP_CMD_SPI_RPMC_REQ_MC:
163 status = psp_smi_spi_rpmc_req_mc(buffer);
164 break;
165 default:
166 printk(BIOS_ERR, "PSP: Unknown command %d\n", cmd);
167 status = MBOX_PSP_UNSUPPORTED;
168 break;
171 out:
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)
184 disable_psp_smi();
186 wbinvd();
188 handle_psp_command();
190 wbinvd();
192 clear_psp_command();
193 enable_psp_smi();
195 wbinvd();
197 reset_psp_smi();