blob: c0f2354f4f4f602c42b1aafee61ae9726517f721 [file] [log] [blame]
Furquan Shaikhf318e032020-05-04 23:38:53 -07001/* SPDX-License-Identifier: GPL-2.0-only */
Furquan Shaikhf318e032020-05-04 23:38:53 -07002
3#include <amdblocks/chip.h>
4#include <amdblocks/espi.h>
5#include <amdblocks/lpc.h>
Felix Held6f9e8172022-09-29 16:13:26 +02006#include <device/mmio.h>
Furquan Shaikhf318e032020-05-04 23:38:53 -07007#include <console/console.h>
Furquan Shaikh70063ff52020-05-11 14:28:13 -07008#include <espi.h>
Furquan Shaikhf318e032020-05-04 23:38:53 -07009#include <soc/pci_devs.h>
Furquan Shaikh70063ff52020-05-11 14:28:13 -070010#include <timer.h>
Furquan Shaikhf318e032020-05-04 23:38:53 -070011#include <types.h>
12
Felix Held38712b82022-01-04 21:02:00 +010013#include "espi_def.h"
14
Furquan Shaikh98bc9612020-05-09 19:31:55 -070015static uintptr_t espi_bar;
16
17void espi_update_static_bar(uintptr_t bar)
18{
19 espi_bar = bar;
20}
21
Martin Rothfe589772021-06-25 15:09:43 -060022__weak void mb_set_up_early_espi(void)
23{
24}
25
Furquan Shaikhf318e032020-05-04 23:38:53 -070026static uintptr_t espi_get_bar(void)
27{
Martin Rothb39e10d2020-07-14 11:08:55 -060028 if (ENV_X86 && !espi_bar)
29 espi_update_static_bar(lpc_get_spibase() + ESPI_OFFSET_FROM_BAR);
Furquan Shaikh98bc9612020-05-09 19:31:55 -070030 return espi_bar;
Furquan Shaikhf318e032020-05-04 23:38:53 -070031}
32
Felix Held92dd6782020-08-10 20:27:58 +020033static uint32_t espi_read32(unsigned int reg)
Furquan Shaikhf318e032020-05-04 23:38:53 -070034{
Felix Held6f9e8172022-09-29 16:13:26 +020035 return read32p(espi_get_bar() + reg);
Furquan Shaikhf318e032020-05-04 23:38:53 -070036}
37
Felix Held92dd6782020-08-10 20:27:58 +020038static void espi_write32(unsigned int reg, uint32_t val)
Furquan Shaikhf318e032020-05-04 23:38:53 -070039{
Felix Held6f9e8172022-09-29 16:13:26 +020040 write32p(espi_get_bar() + reg, val);
Furquan Shaikhf318e032020-05-04 23:38:53 -070041}
42
Felix Held92dd6782020-08-10 20:27:58 +020043static uint16_t espi_read16(unsigned int reg)
Furquan Shaikhf318e032020-05-04 23:38:53 -070044{
Felix Held6f9e8172022-09-29 16:13:26 +020045 return read16p(espi_get_bar() + reg);
Furquan Shaikhf318e032020-05-04 23:38:53 -070046}
47
Felix Held92dd6782020-08-10 20:27:58 +020048static void espi_write16(unsigned int reg, uint16_t val)
Furquan Shaikhf318e032020-05-04 23:38:53 -070049{
Felix Held6f9e8172022-09-29 16:13:26 +020050 write16p(espi_get_bar() + reg, val);
Furquan Shaikhf318e032020-05-04 23:38:53 -070051}
52
Felix Held92dd6782020-08-10 20:27:58 +020053static uint8_t espi_read8(unsigned int reg)
Furquan Shaikhf318e032020-05-04 23:38:53 -070054{
Felix Held6f9e8172022-09-29 16:13:26 +020055 return read8p(espi_get_bar() + reg);
Furquan Shaikhf318e032020-05-04 23:38:53 -070056}
57
Felix Held92dd6782020-08-10 20:27:58 +020058static void espi_write8(unsigned int reg, uint8_t val)
Furquan Shaikhf318e032020-05-04 23:38:53 -070059{
Felix Held6f9e8172022-09-29 16:13:26 +020060 write8p(espi_get_bar() + reg, val);
Furquan Shaikhf318e032020-05-04 23:38:53 -070061}
62
Felix Held6ba6bc22022-02-07 21:11:25 +010063static inline uint32_t espi_decode_io_range_en_bit(unsigned int idx)
64{
Felix Held62d42c32022-05-04 19:04:33 +020065 if (ESPI_DECODE_RANGE_TO_REG_GROUP(idx) == 0)
66 return ESPI_DECODE_IO_RANGE_EN(idx);
67 else
68 return ESPI_DECODE_IO_RANGE_EXT_EN(idx - ESPI_DECODE_RANGES_PER_REG_GROUP);
Felix Held6ba6bc22022-02-07 21:11:25 +010069}
70
71static inline uint32_t espi_decode_mmio_range_en_bit(unsigned int idx)
72{
Felix Held62d42c32022-05-04 19:04:33 +020073 if (ESPI_DECODE_RANGE_TO_REG_GROUP(idx) == 0)
74 return ESPI_DECODE_MMIO_RANGE_EN(idx);
75 else
76 return ESPI_DECODE_MMIO_RANGE_EXT_EN(idx - ESPI_DECODE_RANGES_PER_REG_GROUP);
Felix Held6ba6bc22022-02-07 21:11:25 +010077}
78
79static inline unsigned int espi_io_range_base_reg(unsigned int idx)
80{
Felix Held62d42c32022-05-04 19:04:33 +020081 unsigned int reg_base;
82 switch (ESPI_DECODE_RANGE_TO_REG_GROUP(idx)) {
83 case 0:
84 reg_base = ESPI_IO_BASE_REG0;
85 break;
86 case 1:
87 reg_base = ESPI_IO_BASE_REG2;
88 break;
89 case 2:
90 reg_base = ESPI_IO_BASE_REG4;
91 break;
92 default: /* case 3 */
93 reg_base = ESPI_IO_BASE_REG6;
94 break;
95 }
96 return ESPI_IO_RANGE_BASE_REG(reg_base, ESPI_DECODE_RANGE_TO_REG_OFFSET(idx));
Felix Held6ba6bc22022-02-07 21:11:25 +010097}
98
99static inline unsigned int espi_io_range_size_reg(unsigned int idx)
100{
Felix Held62d42c32022-05-04 19:04:33 +0200101 unsigned int reg_base;
102 switch (ESPI_DECODE_RANGE_TO_REG_GROUP(idx)) {
103 case 0:
104 reg_base = ESPI_IO_SIZE0;
105 break;
106 case 1:
107 reg_base = ESPI_IO_SIZE1;
108 break;
109 case 2:
110 reg_base = ESPI_IO_SIZE2;
111 break;
112 default: /* case 3 */
113 reg_base = ESPI_IO_SIZE3;
114 break;
115 }
116 return ESPI_IO_RANGE_SIZE_REG(reg_base, ESPI_DECODE_RANGE_TO_REG_OFFSET(idx));
Felix Held6ba6bc22022-02-07 21:11:25 +0100117}
118
119static inline unsigned int espi_mmio_range_base_reg(unsigned int idx)
120{
Felix Held62d42c32022-05-04 19:04:33 +0200121 unsigned int reg_base;
122 if (ESPI_DECODE_RANGE_TO_REG_GROUP(idx) == 0)
123 reg_base = ESPI_MMIO_BASE_REG0;
124 else
125 reg_base = ESPI_MMIO_BASE_REG4;
126
127 return ESPI_MMIO_RANGE_BASE_REG(reg_base, ESPI_DECODE_RANGE_TO_REG_OFFSET(idx));
Felix Held6ba6bc22022-02-07 21:11:25 +0100128}
129
130static inline unsigned int espi_mmio_range_size_reg(unsigned int idx)
131{
Felix Held62d42c32022-05-04 19:04:33 +0200132 unsigned int reg_base;
133 if (ESPI_DECODE_RANGE_TO_REG_GROUP(idx) == 0)
134 reg_base = ESPI_MMIO_SIZE_REG0;
135 else
136 reg_base = ESPI_MMIO_SIZE_REG2;
137
138 return ESPI_MMIO_RANGE_SIZE_REG(reg_base, ESPI_DECODE_RANGE_TO_REG_OFFSET(idx));
Felix Held6ba6bc22022-02-07 21:11:25 +0100139}
140
Felix Heldf08fbf82020-08-10 20:30:36 +0200141static void espi_enable_decode(uint32_t decode_en)
Furquan Shaikhf318e032020-05-04 23:38:53 -0700142{
143 uint32_t val;
144
145 val = espi_read32(ESPI_DECODE);
146 val |= decode_en;
147 espi_write32(ESPI_DECODE, val);
148}
149
Felix Heldf08fbf82020-08-10 20:30:36 +0200150static bool espi_is_decode_enabled(uint32_t decode)
Furquan Shaikhf318e032020-05-04 23:38:53 -0700151{
152 uint32_t val;
153
154 val = espi_read32(ESPI_DECODE);
155 return !!(val & decode);
156}
157
158static int espi_find_io_window(uint16_t win_base)
159{
160 int i;
161
162 for (i = 0; i < ESPI_GENERIC_IO_WIN_COUNT; i++) {
Felix Held6ba6bc22022-02-07 21:11:25 +0100163 if (!espi_is_decode_enabled(espi_decode_io_range_en_bit(i)))
Furquan Shaikhf318e032020-05-04 23:38:53 -0700164 continue;
165
Felix Held6ba6bc22022-02-07 21:11:25 +0100166 if (espi_read16(espi_io_range_base_reg(i)) == win_base)
Furquan Shaikhf318e032020-05-04 23:38:53 -0700167 return i;
168 }
169
170 return -1;
171}
172
173static int espi_get_unused_io_window(void)
174{
175 int i;
176
177 for (i = 0; i < ESPI_GENERIC_IO_WIN_COUNT; i++) {
Felix Held6ba6bc22022-02-07 21:11:25 +0100178 if (!espi_is_decode_enabled(espi_decode_io_range_en_bit(i)))
Furquan Shaikhf318e032020-05-04 23:38:53 -0700179 return i;
180 }
181
182 return -1;
183}
184
Raul E Rangelb95f8482021-04-02 13:47:09 -0600185static void espi_clear_decodes(void)
Martin Roth011bf132021-03-23 13:20:42 -0600186{
187 unsigned int idx;
188
189 /* First turn off all enable bits, then zero base, range, and size registers */
Karthikeyan Ramasubramanian284831e2022-03-25 10:21:03 -0600190 if (CONFIG(SOC_AMD_COMMON_BLOCK_ESPI_RETAIN_PORT80_EN))
191 espi_write16(ESPI_DECODE, (espi_read16(ESPI_DECODE) & ESPI_DECODE_IO_0x80_EN));
192 else
193 espi_write16(ESPI_DECODE, 0);
Martin Roth011bf132021-03-23 13:20:42 -0600194
195 for (idx = 0; idx < ESPI_GENERIC_IO_WIN_COUNT; idx++) {
Felix Held6ba6bc22022-02-07 21:11:25 +0100196 espi_write16(espi_io_range_base_reg(idx), 0);
197 espi_write8(espi_io_range_size_reg(idx), 0);
Martin Roth011bf132021-03-23 13:20:42 -0600198 }
199 for (idx = 0; idx < ESPI_GENERIC_MMIO_WIN_COUNT; idx++) {
Felix Held6ba6bc22022-02-07 21:11:25 +0100200 espi_write32(espi_mmio_range_base_reg(idx), 0);
201 espi_write16(espi_mmio_range_size_reg(idx), 0);
Martin Roth011bf132021-03-23 13:20:42 -0600202 }
203}
204
Furquan Shaikhf318e032020-05-04 23:38:53 -0700205/*
206 * Returns decode enable bits for standard IO port addresses. If port address is not supported
207 * by standard decode or if the size of window is not 1, then it returns -1.
208 */
209static int espi_std_io_decode(uint16_t base, size_t size)
210{
Felix Heldc0d4eeb2020-08-10 20:37:16 +0200211 if (size == 2 && base == 0x2e)
212 return ESPI_DECODE_IO_0X2E_0X2F_EN;
213
Furquan Shaikhf318e032020-05-04 23:38:53 -0700214 if (size != 1)
Felix Held4bf419f2020-08-10 20:33:25 +0200215 return -1;
Furquan Shaikhf318e032020-05-04 23:38:53 -0700216
217 switch (base) {
218 case 0x80:
Felix Held4bf419f2020-08-10 20:33:25 +0200219 return ESPI_DECODE_IO_0x80_EN;
Furquan Shaikhf318e032020-05-04 23:38:53 -0700220 case 0x60:
221 case 0x64:
Felix Held4bf419f2020-08-10 20:33:25 +0200222 return ESPI_DECODE_IO_0X60_0X64_EN;
Furquan Shaikhf318e032020-05-04 23:38:53 -0700223 case 0x2e:
224 case 0x2f:
Felix Held4bf419f2020-08-10 20:33:25 +0200225 return ESPI_DECODE_IO_0X2E_0X2F_EN;
Furquan Shaikhf318e032020-05-04 23:38:53 -0700226 default:
Felix Held4bf419f2020-08-10 20:33:25 +0200227 return -1;
Furquan Shaikhf318e032020-05-04 23:38:53 -0700228 }
Furquan Shaikhf318e032020-05-04 23:38:53 -0700229}
230
231static size_t espi_get_io_window_size(int idx)
232{
Felix Held6ba6bc22022-02-07 21:11:25 +0100233 return espi_read8(espi_io_range_size_reg(idx)) + 1;
Furquan Shaikhf318e032020-05-04 23:38:53 -0700234}
235
236static void espi_write_io_window(int idx, uint16_t base, size_t size)
237{
Felix Held6ba6bc22022-02-07 21:11:25 +0100238 espi_write16(espi_io_range_base_reg(idx), base);
239 espi_write8(espi_io_range_size_reg(idx), size - 1);
Furquan Shaikhf318e032020-05-04 23:38:53 -0700240}
241
Felix Heldaed38a92021-12-18 00:41:23 +0100242static enum cb_err espi_open_generic_io_window(uint16_t base, size_t size)
Furquan Shaikhf318e032020-05-04 23:38:53 -0700243{
244 size_t win_size;
245 int idx;
246
247 for (; size; size -= win_size, base += win_size) {
248 win_size = MIN(size, ESPI_GENERIC_IO_MAX_WIN_SIZE);
249
250 idx = espi_find_io_window(base);
251 if (idx != -1) {
252 size_t curr_size = espi_get_io_window_size(idx);
253
254 if (curr_size > win_size) {
255 printk(BIOS_INFO, "eSPI window already configured to be larger than requested! ");
256 printk(BIOS_INFO, "Base: 0x%x, Requested size: 0x%zx, Actual size: 0x%zx\n",
257 base, win_size, curr_size);
258 } else if (curr_size < win_size) {
259 espi_write_io_window(idx, base, win_size);
260 printk(BIOS_INFO, "eSPI window at base: 0x%x resized from 0x%zx to 0x%zx\n",
261 base, curr_size, win_size);
262 }
263
264 continue;
265 }
266
267 idx = espi_get_unused_io_window();
268 if (idx == -1) {
269 printk(BIOS_ERR, "Cannot open IO window base %x size %zx\n", base,
270 size);
Julius Wernere9665952022-01-21 17:06:20 -0800271 printk(BIOS_ERR, "No more available IO windows!\n");
Felix Heldaed38a92021-12-18 00:41:23 +0100272 return CB_ERR;
Furquan Shaikhf318e032020-05-04 23:38:53 -0700273 }
274
275 espi_write_io_window(idx, base, win_size);
Felix Held6ba6bc22022-02-07 21:11:25 +0100276 espi_enable_decode(espi_decode_io_range_en_bit(idx));
Furquan Shaikhf318e032020-05-04 23:38:53 -0700277 }
278
Felix Heldaed38a92021-12-18 00:41:23 +0100279 return CB_SUCCESS;
Furquan Shaikhf318e032020-05-04 23:38:53 -0700280}
281
Felix Heldaed38a92021-12-18 00:41:23 +0100282enum cb_err espi_open_io_window(uint16_t base, size_t size)
Furquan Shaikhf318e032020-05-04 23:38:53 -0700283{
284 int std_io;
285
286 std_io = espi_std_io_decode(base, size);
287 if (std_io != -1) {
288 espi_enable_decode(std_io);
Felix Heldaed38a92021-12-18 00:41:23 +0100289 return CB_SUCCESS;
Felix Heldb026c7c2020-08-10 20:43:53 +0200290 } else {
291 return espi_open_generic_io_window(base, size);
Furquan Shaikhf318e032020-05-04 23:38:53 -0700292 }
Furquan Shaikhf318e032020-05-04 23:38:53 -0700293}
294
295static int espi_find_mmio_window(uint32_t win_base)
296{
297 int i;
298
299 for (i = 0; i < ESPI_GENERIC_MMIO_WIN_COUNT; i++) {
Felix Held6ba6bc22022-02-07 21:11:25 +0100300 if (!espi_is_decode_enabled(espi_decode_mmio_range_en_bit(i)))
Furquan Shaikhf318e032020-05-04 23:38:53 -0700301 continue;
302
Felix Held6ba6bc22022-02-07 21:11:25 +0100303 if (espi_read32(espi_mmio_range_base_reg(i)) == win_base)
Furquan Shaikhf318e032020-05-04 23:38:53 -0700304 return i;
305 }
306
307 return -1;
308}
309
310static int espi_get_unused_mmio_window(void)
311{
312 int i;
313
314 for (i = 0; i < ESPI_GENERIC_MMIO_WIN_COUNT; i++) {
Felix Held6ba6bc22022-02-07 21:11:25 +0100315 if (!espi_is_decode_enabled(espi_decode_mmio_range_en_bit(i)))
Furquan Shaikhf318e032020-05-04 23:38:53 -0700316 return i;
317 }
318
319 return -1;
320
321}
322
323static size_t espi_get_mmio_window_size(int idx)
324{
Felix Held6ba6bc22022-02-07 21:11:25 +0100325 return espi_read16(espi_mmio_range_size_reg(idx)) + 1;
Furquan Shaikhf318e032020-05-04 23:38:53 -0700326}
327
328static void espi_write_mmio_window(int idx, uint32_t base, size_t size)
329{
Felix Held6ba6bc22022-02-07 21:11:25 +0100330 espi_write32(espi_mmio_range_base_reg(idx), base);
331 espi_write16(espi_mmio_range_size_reg(idx), size - 1);
Furquan Shaikhf318e032020-05-04 23:38:53 -0700332}
333
Felix Heldaed38a92021-12-18 00:41:23 +0100334enum cb_err espi_open_mmio_window(uint32_t base, size_t size)
Furquan Shaikhf318e032020-05-04 23:38:53 -0700335{
336 size_t win_size;
337 int idx;
338
339 for (; size; size -= win_size, base += win_size) {
340 win_size = MIN(size, ESPI_GENERIC_MMIO_MAX_WIN_SIZE);
341
342 idx = espi_find_mmio_window(base);
343 if (idx != -1) {
344 size_t curr_size = espi_get_mmio_window_size(idx);
345
346 if (curr_size > win_size) {
347 printk(BIOS_INFO, "eSPI window already configured to be larger than requested! ");
348 printk(BIOS_INFO, "Base: 0x%x, Requested size: 0x%zx, Actual size: 0x%zx\n",
349 base, win_size, curr_size);
350 } else if (curr_size < win_size) {
351 espi_write_mmio_window(idx, base, win_size);
352 printk(BIOS_INFO, "eSPI window at base: 0x%x resized from 0x%zx to 0x%zx\n",
353 base, curr_size, win_size);
354 }
355
356 continue;
357 }
358
359 idx = espi_get_unused_mmio_window();
360 if (idx == -1) {
361 printk(BIOS_ERR, "Cannot open IO window base %x size %zx\n", base,
362 size);
Julius Wernere9665952022-01-21 17:06:20 -0800363 printk(BIOS_ERR, "No more available MMIO windows!\n");
Felix Heldaed38a92021-12-18 00:41:23 +0100364 return CB_ERR;
Furquan Shaikhf318e032020-05-04 23:38:53 -0700365 }
366
367 espi_write_mmio_window(idx, base, win_size);
Felix Held6ba6bc22022-02-07 21:11:25 +0100368 espi_enable_decode(espi_decode_mmio_range_en_bit(idx));
Furquan Shaikhf318e032020-05-04 23:38:53 -0700369 }
370
Felix Heldaed38a92021-12-18 00:41:23 +0100371 return CB_SUCCESS;
Furquan Shaikhf318e032020-05-04 23:38:53 -0700372}
373
374static const struct espi_config *espi_get_config(void)
375{
376 const struct soc_amd_common_config *soc_cfg = soc_get_common_config();
Furquan Shaikhf318e032020-05-04 23:38:53 -0700377 return &soc_cfg->espi_config;
378}
379
Felix Heldaed38a92021-12-18 00:41:23 +0100380static enum cb_err espi_configure_decodes(const struct espi_config *cfg)
Furquan Shaikhf318e032020-05-04 23:38:53 -0700381{
Felix Held9e830542021-12-18 00:41:23 +0100382 int i;
Furquan Shaikhf318e032020-05-04 23:38:53 -0700383
384 espi_enable_decode(cfg->std_io_decode_bitmap);
385
386 for (i = 0; i < ESPI_GENERIC_IO_WIN_COUNT; i++) {
387 if (cfg->generic_io_range[i].size == 0)
388 continue;
Felix Held9e830542021-12-18 00:41:23 +0100389 if (espi_open_generic_io_window(cfg->generic_io_range[i].base,
Felix Heldaed38a92021-12-18 00:41:23 +0100390 cfg->generic_io_range[i].size) != CB_SUCCESS)
391 return CB_ERR;
Furquan Shaikhf318e032020-05-04 23:38:53 -0700392 }
Raul E Rangel61ac1bc2021-04-02 10:55:27 -0600393
Felix Heldaed38a92021-12-18 00:41:23 +0100394 return CB_SUCCESS;
Furquan Shaikhf318e032020-05-04 23:38:53 -0700395}
Furquan Shaikh70063ff52020-05-11 14:28:13 -0700396
Furquan Shaikh70063ff52020-05-11 14:28:13 -0700397enum espi_cmd_type {
398 CMD_TYPE_SET_CONFIGURATION = 0,
399 CMD_TYPE_GET_CONFIGURATION = 1,
400 CMD_TYPE_IN_BAND_RESET = 2,
401 CMD_TYPE_PERIPHERAL = 4,
402 CMD_TYPE_VW = 5,
403 CMD_TYPE_OOB = 6,
404 CMD_TYPE_FLASH = 7,
405};
406
Furquan Shaikh70063ff52020-05-11 14:28:13 -0700407#define ESPI_CMD_TIMEOUT_US 100
Raul E Rangel0318dc12021-05-21 16:31:52 -0600408#define ESPI_CH_READY_TIMEOUT_US 10000
Furquan Shaikh70063ff52020-05-11 14:28:13 -0700409
410union espi_txhdr0 {
411 uint32_t val;
412 struct {
413 uint32_t cmd_type:3;
414 uint32_t cmd_sts:1;
415 uint32_t slave_sel:2;
416 uint32_t rsvd:2;
417 uint32_t hdata0:8;
418 uint32_t hdata1:8;
419 uint32_t hdata2:8;
420 };
421} __packed;
422
423union espi_txhdr1 {
424 uint32_t val;
425 struct {
426 uint32_t hdata3:8;
427 uint32_t hdata4:8;
428 uint32_t hdata5:8;
429 uint32_t hdata6:8;
430 };
431} __packed;
432
433union espi_txhdr2 {
434 uint32_t val;
435 struct {
436 uint32_t hdata7:8;
437 uint32_t rsvd:24;
438 };
439} __packed;
440
441union espi_txdata {
442 uint32_t val;
443 struct {
444 uint32_t byte0:8;
445 uint32_t byte1:8;
446 uint32_t byte2:8;
447 uint32_t byte3:8;
448 };
449} __packed;
450
451struct espi_cmd {
452 union espi_txhdr0 hdr0;
453 union espi_txhdr1 hdr1;
454 union espi_txhdr2 hdr2;
455 union espi_txdata data;
Raul E Rangel12c05422021-05-11 11:13:38 -0600456 uint32_t expected_status_codes;
Furquan Shaikh70063ff52020-05-11 14:28:13 -0700457} __packed;
458
459/* Wait up to ESPI_CMD_TIMEOUT_US for hardware to clear DNCMD_STATUS bit. */
Felix Held4b4114f72021-12-18 00:41:23 +0100460static enum cb_err espi_wait_ready(void)
Furquan Shaikh70063ff52020-05-11 14:28:13 -0700461{
462 struct stopwatch sw;
463 union espi_txhdr0 hdr0;
464
465 stopwatch_init_usecs_expire(&sw, ESPI_CMD_TIMEOUT_US);
466 do {
467 hdr0.val = espi_read32(ESPI_DN_TX_HDR0);
468 if (!hdr0.cmd_sts)
Felix Held4b4114f72021-12-18 00:41:23 +0100469 return CB_SUCCESS;
Furquan Shaikh70063ff52020-05-11 14:28:13 -0700470 } while (!stopwatch_expired(&sw));
471
Felix Held4b4114f72021-12-18 00:41:23 +0100472 return CB_ERR;
Furquan Shaikh70063ff52020-05-11 14:28:13 -0700473}
474
475/* Clear interrupt status register */
476static void espi_clear_status(void)
477{
Raul E Rangel47740122021-04-02 10:16:54 -0600478 uint32_t status = espi_read32(ESPI_SLAVE0_INT_STS);
Furquan Shaikh70063ff52020-05-11 14:28:13 -0700479 if (status)
Raul E Rangel47740122021-04-02 10:16:54 -0600480 espi_write32(ESPI_SLAVE0_INT_STS, status);
Furquan Shaikh70063ff52020-05-11 14:28:13 -0700481}
482
483/*
484 * Wait up to ESPI_CMD_TIMEOUT_US for interrupt status register to update after sending a
485 * command.
486 */
Felix Held4b4114f72021-12-18 00:41:23 +0100487static enum cb_err espi_poll_status(uint32_t *status)
Furquan Shaikh70063ff52020-05-11 14:28:13 -0700488{
489 struct stopwatch sw;
490
491 stopwatch_init_usecs_expire(&sw, ESPI_CMD_TIMEOUT_US);
492 do {
Raul E Rangel47740122021-04-02 10:16:54 -0600493 *status = espi_read32(ESPI_SLAVE0_INT_STS);
Furquan Shaikh70063ff52020-05-11 14:28:13 -0700494 if (*status)
Felix Held4b4114f72021-12-18 00:41:23 +0100495 return CB_SUCCESS;
Furquan Shaikh70063ff52020-05-11 14:28:13 -0700496 } while (!stopwatch_expired(&sw));
497
Julius Wernere9665952022-01-21 17:06:20 -0800498 printk(BIOS_ERR, "eSPI timed out waiting for status update.\n");
Furquan Shaikh70063ff52020-05-11 14:28:13 -0700499
Felix Held4b4114f72021-12-18 00:41:23 +0100500 return CB_ERR;
Furquan Shaikh70063ff52020-05-11 14:28:13 -0700501}
502
503static void espi_show_failure(const struct espi_cmd *cmd, const char *str, uint32_t status)
504{
505 printk(BIOS_ERR, "eSPI cmd0-cmd2: %08x %08x %08x data: %08x.\n",
506 cmd->hdr0.val, cmd->hdr1.val, cmd->hdr2.val, cmd->data.val);
507 printk(BIOS_ERR, "%s (Status = 0x%x)\n", str, status);
508}
509
Felix Held4b4114f72021-12-18 00:41:23 +0100510static enum cb_err espi_send_command(const struct espi_cmd *cmd)
Furquan Shaikh70063ff52020-05-11 14:28:13 -0700511{
512 uint32_t status;
513
514 if (CONFIG(ESPI_DEBUG))
Raul E Rangelf7027052021-06-29 13:12:19 -0600515 printk(BIOS_DEBUG, "eSPI cmd0-cmd2: %08x %08x %08x data: %08x.\n",
Furquan Shaikh70063ff52020-05-11 14:28:13 -0700516 cmd->hdr0.val, cmd->hdr1.val, cmd->hdr2.val, cmd->data.val);
517
Felix Held4b4114f72021-12-18 00:41:23 +0100518 if (espi_wait_ready() != CB_SUCCESS) {
Furquan Shaikh70063ff52020-05-11 14:28:13 -0700519 espi_show_failure(cmd, "Error: eSPI was not ready to accept a command", 0);
Felix Held4b4114f72021-12-18 00:41:23 +0100520 return CB_ERR;
Furquan Shaikh70063ff52020-05-11 14:28:13 -0700521 }
522
523 espi_clear_status();
524
525 espi_write32(ESPI_DN_TX_HDR1, cmd->hdr1.val);
526 espi_write32(ESPI_DN_TX_HDR2, cmd->hdr2.val);
527 espi_write32(ESPI_DN_TX_DATA, cmd->data.val);
528
529 /* Dword 0 must be last as this write triggers the transaction */
530 espi_write32(ESPI_DN_TX_HDR0, cmd->hdr0.val);
531
Felix Held4b4114f72021-12-18 00:41:23 +0100532 if (espi_wait_ready() != CB_SUCCESS) {
Furquan Shaikh70063ff52020-05-11 14:28:13 -0700533 espi_show_failure(cmd,
534 "Error: eSPI timed out waiting for command to complete", 0);
Felix Held4b4114f72021-12-18 00:41:23 +0100535 return CB_ERR;
Furquan Shaikh70063ff52020-05-11 14:28:13 -0700536 }
537
Felix Held4b4114f72021-12-18 00:41:23 +0100538 if (espi_poll_status(&status) != CB_SUCCESS) {
Felix Held1ba38332020-08-10 20:45:30 +0200539 espi_show_failure(cmd, "Error: eSPI poll status failed", 0);
Felix Held4b4114f72021-12-18 00:41:23 +0100540 return CB_ERR;
Furquan Shaikh70063ff52020-05-11 14:28:13 -0700541 }
542
543 /* If command did not complete downstream, return error. */
544 if (!(status & ESPI_STATUS_DNCMD_COMPLETE)) {
545 espi_show_failure(cmd, "Error: eSPI downstream command completion failure",
546 status);
Felix Held4b4114f72021-12-18 00:41:23 +0100547 return CB_ERR;
Furquan Shaikh70063ff52020-05-11 14:28:13 -0700548 }
549
Raul E Rangel12c05422021-05-11 11:13:38 -0600550 if (status & ~(ESPI_STATUS_DNCMD_COMPLETE | cmd->expected_status_codes)) {
Felix Held316d59c2020-08-10 20:42:20 +0200551 espi_show_failure(cmd, "Error: unexpected eSPI status register bits set",
552 status);
Felix Held4b4114f72021-12-18 00:41:23 +0100553 return CB_ERR;
Furquan Shaikh70063ff52020-05-11 14:28:13 -0700554 }
555
Raul E Rangel12c05422021-05-11 11:13:38 -0600556 espi_write32(ESPI_SLAVE0_INT_STS, status);
Raul E Rangel66c52ff2021-04-02 10:18:25 -0600557
Felix Held4b4114f72021-12-18 00:41:23 +0100558 return CB_SUCCESS;
Furquan Shaikh70063ff52020-05-11 14:28:13 -0700559}
560
Felix Held4b4114f72021-12-18 00:41:23 +0100561static enum cb_err espi_send_reset(void)
Furquan Shaikh70063ff52020-05-11 14:28:13 -0700562{
563 struct espi_cmd cmd = {
564 .hdr0 = {
565 .cmd_type = CMD_TYPE_IN_BAND_RESET,
566 .cmd_sts = 1,
567 },
Raul E Rangel12c05422021-05-11 11:13:38 -0600568
569 /*
570 * When performing an in-band reset the host controller and the
571 * peripheral can have mismatched IO configs.
572 *
573 * i.e., The eSPI peripheral can be in IO-4 mode while, the
574 * eSPI host will be in IO-1. This results in the peripheral
575 * getting invalid packets and thus not responding.
576 *
577 * If the peripheral is alerting when we perform an in-band
578 * reset, there is a race condition in espi_send_command.
579 * 1) espi_send_command clears the interrupt status.
580 * 2) eSPI host controller hardware notices the alert and sends
581 * a GET_STATUS.
582 * 3) espi_send_command writes the in-band reset command.
583 * 4) eSPI hardware enqueues the in-band reset until GET_STATUS
584 * is complete.
585 * 5) GET_STATUS fails with NO_RESPONSE and sets the interrupt
586 * status.
587 * 6) eSPI hardware performs in-band reset.
588 * 7) espi_send_command checks the status and sees a
589 * NO_RESPONSE bit.
590 *
591 * As a workaround we allow the NO_RESPONSE status code when
592 * we perform an in-band reset.
593 */
594 .expected_status_codes = ESPI_STATUS_NO_RESPONSE,
Furquan Shaikh70063ff52020-05-11 14:28:13 -0700595 };
596
597 return espi_send_command(&cmd);
598}
599
Felix Held4b4114f72021-12-18 00:41:23 +0100600static enum cb_err espi_send_pltrst(const struct espi_config *mb_cfg, bool assert)
Furquan Shaikh70063ff52020-05-11 14:28:13 -0700601{
602 struct espi_cmd cmd = {
603 .hdr0 = {
604 .cmd_type = CMD_TYPE_VW,
605 .cmd_sts = 1,
606 .hdata0 = 0, /* 1 VW group */
607 },
608 .data = {
609 .byte0 = ESPI_VW_INDEX_SYSTEM_EVENT_3,
Raul E Rangel43aa5272021-05-21 17:04:28 -0600610 .byte1 = assert ? ESPI_VW_SIGNAL_LOW(ESPI_VW_PLTRST)
611 : ESPI_VW_SIGNAL_HIGH(ESPI_VW_PLTRST),
Furquan Shaikh70063ff52020-05-11 14:28:13 -0700612 },
613 };
614
615 if (!mb_cfg->vw_ch_en)
Felix Held4b4114f72021-12-18 00:41:23 +0100616 return CB_SUCCESS;
Furquan Shaikh70063ff52020-05-11 14:28:13 -0700617
618 return espi_send_command(&cmd);
619}
620
621/*
622 * In case of get configuration command, hdata0 contains bits 15:8 of the slave register address
623 * and hdata1 contains bits 7:0 of the slave register address.
624 */
625#define ESPI_CONFIGURATION_HDATA0(a) (((a) >> 8) & 0xff)
626#define ESPI_CONFIGURATION_HDATA1(a) ((a) & 0xff)
627
Felix Held4b4114f72021-12-18 00:41:23 +0100628static enum cb_err espi_get_configuration(uint16_t slave_reg_addr, uint32_t *config)
Furquan Shaikh70063ff52020-05-11 14:28:13 -0700629{
630 struct espi_cmd cmd = {
631 .hdr0 = {
632 .cmd_type = CMD_TYPE_GET_CONFIGURATION,
633 .cmd_sts = 1,
634 .hdata0 = ESPI_CONFIGURATION_HDATA0(slave_reg_addr),
635 .hdata1 = ESPI_CONFIGURATION_HDATA1(slave_reg_addr),
636 },
637 };
638
639 *config = 0;
640
Felix Held4b4114f72021-12-18 00:41:23 +0100641 if (espi_send_command(&cmd) != CB_SUCCESS)
642 return CB_ERR;
Furquan Shaikh70063ff52020-05-11 14:28:13 -0700643
644 *config = espi_read32(ESPI_DN_TX_HDR1);
645
646 if (CONFIG(ESPI_DEBUG))
647 printk(BIOS_DEBUG, "Get configuration for slave register(0x%x): 0x%x\n",
648 slave_reg_addr, *config);
649
Felix Held4b4114f72021-12-18 00:41:23 +0100650 return CB_SUCCESS;
Furquan Shaikh70063ff52020-05-11 14:28:13 -0700651}
652
Felix Held4b4114f72021-12-18 00:41:23 +0100653static enum cb_err espi_set_configuration(uint16_t slave_reg_addr, uint32_t config)
Furquan Shaikh70063ff52020-05-11 14:28:13 -0700654{
655 struct espi_cmd cmd = {
656 .hdr0 = {
657 .cmd_type = CMD_TYPE_SET_CONFIGURATION,
658 .cmd_sts = 1,
659 .hdata0 = ESPI_CONFIGURATION_HDATA0(slave_reg_addr),
660 .hdata1 = ESPI_CONFIGURATION_HDATA1(slave_reg_addr),
661 },
662 .hdr1 = {
663 .val = config,
664 },
665 };
666
667 return espi_send_command(&cmd);
668}
669
Felix Held4b4114f72021-12-18 00:41:23 +0100670static enum cb_err espi_get_general_configuration(uint32_t *config)
Furquan Shaikh70063ff52020-05-11 14:28:13 -0700671{
Felix Held4b4114f72021-12-18 00:41:23 +0100672 if (espi_get_configuration(ESPI_SLAVE_GENERAL_CFG, config) != CB_SUCCESS)
673 return CB_ERR;
Furquan Shaikh70063ff52020-05-11 14:28:13 -0700674
675 espi_show_slave_general_configuration(*config);
Felix Held4b4114f72021-12-18 00:41:23 +0100676 return CB_SUCCESS;
Furquan Shaikh70063ff52020-05-11 14:28:13 -0700677}
678
Felix Held84429e02022-12-13 17:01:22 +0100679static enum cb_err espi_set_io_mode_cfg(enum espi_io_mode mb_io_mode, uint32_t slave_caps,
680 uint32_t *slave_config, uint32_t *ctrlr_config)
Furquan Shaikh70063ff52020-05-11 14:28:13 -0700681{
682 switch (mb_io_mode) {
683 case ESPI_IO_MODE_QUAD:
684 if (espi_slave_supports_quad_io(slave_caps)) {
685 *slave_config |= ESPI_SLAVE_IO_MODE_SEL_QUAD;
686 *ctrlr_config |= ESPI_IO_MODE_QUAD;
687 break;
688 }
Julius Wernere9665952022-01-21 17:06:20 -0800689 printk(BIOS_ERR, "eSPI Quad I/O not supported. Dropping to dual mode.\n");
Felix Heldcbaf7532022-02-21 16:44:48 +0100690 __fallthrough;
Furquan Shaikh70063ff52020-05-11 14:28:13 -0700691 case ESPI_IO_MODE_DUAL:
692 if (espi_slave_supports_dual_io(slave_caps)) {
693 *slave_config |= ESPI_SLAVE_IO_MODE_SEL_DUAL;
694 *ctrlr_config |= ESPI_IO_MODE_DUAL;
695 break;
696 }
Julius Wernere9665952022-01-21 17:06:20 -0800697 printk(BIOS_ERR, "eSPI Dual I/O not supported. Dropping to single mode.\n");
Felix Heldcbaf7532022-02-21 16:44:48 +0100698 __fallthrough;
Furquan Shaikh70063ff52020-05-11 14:28:13 -0700699 case ESPI_IO_MODE_SINGLE:
700 /* Single I/O mode is always supported. */
701 *slave_config |= ESPI_SLAVE_IO_MODE_SEL_SINGLE;
702 *ctrlr_config |= ESPI_IO_MODE_SINGLE;
703 break;
704 default:
Felix Held84429e02022-12-13 17:01:22 +0100705 printk(BIOS_ERR, "No supported eSPI I/O modes!\n");
706 return CB_ERR;
Furquan Shaikh70063ff52020-05-11 14:28:13 -0700707 }
Felix Held84429e02022-12-13 17:01:22 +0100708 return CB_SUCCESS;
Furquan Shaikh70063ff52020-05-11 14:28:13 -0700709}
710
Felix Held84429e02022-12-13 17:01:22 +0100711static enum cb_err espi_set_op_freq_cfg(enum espi_op_freq mb_op_freq, uint32_t slave_caps,
712 uint32_t *slave_config, uint32_t *ctrlr_config)
Furquan Shaikh70063ff52020-05-11 14:28:13 -0700713{
714 int slave_max_speed_mhz = espi_slave_max_speed_mhz_supported(slave_caps);
715
716 switch (mb_op_freq) {
717 case ESPI_OP_FREQ_66_MHZ:
718 if (slave_max_speed_mhz >= 66) {
719 *slave_config |= ESPI_SLAVE_OP_FREQ_SEL_66_MHZ;
720 *ctrlr_config |= ESPI_OP_FREQ_66_MHZ;
721 break;
722 }
Julius Wernere9665952022-01-21 17:06:20 -0800723 printk(BIOS_ERR, "eSPI 66MHz not supported. Dropping to 33MHz.\n");
Felix Heldcbaf7532022-02-21 16:44:48 +0100724 __fallthrough;
Furquan Shaikh70063ff52020-05-11 14:28:13 -0700725 case ESPI_OP_FREQ_33_MHZ:
726 if (slave_max_speed_mhz >= 33) {
727 *slave_config |= ESPI_SLAVE_OP_FREQ_SEL_33_MHZ;
728 *ctrlr_config |= ESPI_OP_FREQ_33_MHZ;
729 break;
730 }
Julius Wernere9665952022-01-21 17:06:20 -0800731 printk(BIOS_ERR, "eSPI 33MHz not supported. Dropping to 16MHz.\n");
Felix Heldcbaf7532022-02-21 16:44:48 +0100732 __fallthrough;
Furquan Shaikh70063ff52020-05-11 14:28:13 -0700733 case ESPI_OP_FREQ_16_MHZ:
734 /*
735 * eSPI spec says the minimum frequency is 20MHz, but AMD datasheets support
736 * 16.7 Mhz.
737 */
738 if (slave_max_speed_mhz > 0) {
739 *slave_config |= ESPI_SLAVE_OP_FREQ_SEL_20_MHZ;
740 *ctrlr_config |= ESPI_OP_FREQ_16_MHZ;
741 break;
742 }
Felix Heldcbaf7532022-02-21 16:44:48 +0100743 __fallthrough;
Furquan Shaikh70063ff52020-05-11 14:28:13 -0700744 default:
Felix Held84429e02022-12-13 17:01:22 +0100745 printk(BIOS_ERR, "No supported eSPI Operating Frequency!\n");
746 return CB_ERR;
Furquan Shaikh70063ff52020-05-11 14:28:13 -0700747 }
Felix Held84429e02022-12-13 17:01:22 +0100748 return CB_SUCCESS;
Furquan Shaikh70063ff52020-05-11 14:28:13 -0700749}
750
Felix Held84429e02022-12-13 17:01:22 +0100751static enum cb_err espi_set_alert_pin_cfg(enum espi_alert_pin alert_pin, uint32_t slave_caps,
752 uint32_t *slave_config, uint32_t *ctrlr_config)
Raul E Rangel8317e722021-05-05 13:38:27 -0600753{
754 switch (alert_pin) {
755 case ESPI_ALERT_PIN_IN_BAND:
756 *slave_config |= ESPI_SLAVE_ALERT_MODE_IO1;
Felix Held84429e02022-12-13 17:01:22 +0100757 return CB_SUCCESS;
Raul E Rangel8317e722021-05-05 13:38:27 -0600758 case ESPI_ALERT_PIN_PUSH_PULL:
759 *slave_config |= ESPI_SLAVE_ALERT_MODE_PIN | ESPI_SLAVE_PUSH_PULL_ALERT_SEL;
760 *ctrlr_config |= ESPI_ALERT_MODE;
Felix Held84429e02022-12-13 17:01:22 +0100761 return CB_SUCCESS;
Raul E Rangel8317e722021-05-05 13:38:27 -0600762 case ESPI_ALERT_PIN_OPEN_DRAIN:
Felix Held84429e02022-12-13 17:01:22 +0100763 if (!(slave_caps & ESPI_SLAVE_OPEN_DRAIN_ALERT_SUPP)) {
764 printk(BIOS_ERR, "eSPI peripheral does not support open drain alert!");
765 return CB_ERR;
766 }
Raul E Rangel8317e722021-05-05 13:38:27 -0600767
768 *slave_config |= ESPI_SLAVE_ALERT_MODE_PIN | ESPI_SLAVE_OPEN_DRAIN_ALERT_SEL;
769 *ctrlr_config |= ESPI_ALERT_MODE;
Felix Held84429e02022-12-13 17:01:22 +0100770 return CB_SUCCESS;
Raul E Rangel8317e722021-05-05 13:38:27 -0600771 default:
Felix Held84429e02022-12-13 17:01:22 +0100772 printk(BIOS_ERR, "Unknown espi alert config: %u!\n", alert_pin);
773 return CB_ERR;
Raul E Rangel8317e722021-05-05 13:38:27 -0600774 }
775}
776
Felix Held4b4114f72021-12-18 00:41:23 +0100777static enum cb_err espi_set_general_configuration(const struct espi_config *mb_cfg,
778 uint32_t slave_caps)
Furquan Shaikh70063ff52020-05-11 14:28:13 -0700779{
780 uint32_t slave_config = 0;
781 uint32_t ctrlr_config = 0;
782
783 if (mb_cfg->crc_check_enable) {
784 slave_config |= ESPI_SLAVE_CRC_ENABLE;
785 ctrlr_config |= ESPI_CRC_CHECKING_EN;
786 }
787
Felix Held84429e02022-12-13 17:01:22 +0100788 if (espi_set_alert_pin_cfg(mb_cfg->alert_pin, slave_caps, &slave_config, &ctrlr_config)
789 != CB_SUCCESS)
790 return CB_ERR;
791 if (espi_set_io_mode_cfg(mb_cfg->io_mode, slave_caps, &slave_config, &ctrlr_config)
792 != CB_SUCCESS)
793 return CB_ERR;
794 if (espi_set_op_freq_cfg(mb_cfg->op_freq_mhz, slave_caps, &slave_config, &ctrlr_config)
795 != CB_SUCCESS)
796 return CB_ERR;
Furquan Shaikh70063ff52020-05-11 14:28:13 -0700797
798 if (CONFIG(ESPI_DEBUG))
799 printk(BIOS_INFO, "Setting general configuration: slave: 0x%x controller: 0x%x\n",
800 slave_config, ctrlr_config);
801
Raul E Rangeld2d762a2021-05-05 13:30:10 -0600802 espi_show_slave_general_configuration(slave_config);
803
Felix Held4b4114f72021-12-18 00:41:23 +0100804 if (espi_set_configuration(ESPI_SLAVE_GENERAL_CFG, slave_config) != CB_SUCCESS)
805 return CB_ERR;
Furquan Shaikh70063ff52020-05-11 14:28:13 -0700806
807 espi_write32(ESPI_SLAVE0_CONFIG, ctrlr_config);
Felix Held4b4114f72021-12-18 00:41:23 +0100808 return CB_SUCCESS;
Furquan Shaikh70063ff52020-05-11 14:28:13 -0700809}
810
Felix Held4b4114f72021-12-18 00:41:23 +0100811static enum cb_err espi_wait_channel_ready(uint16_t slave_reg_addr)
Furquan Shaikh70063ff52020-05-11 14:28:13 -0700812{
813 struct stopwatch sw;
814 uint32_t config;
815
816 stopwatch_init_usecs_expire(&sw, ESPI_CH_READY_TIMEOUT_US);
817 do {
Felix Held5ba87a82021-12-18 00:41:23 +0100818 if (espi_get_configuration(slave_reg_addr, &config) != CB_SUCCESS)
819 return CB_ERR;
Furquan Shaikh70063ff52020-05-11 14:28:13 -0700820 if (espi_slave_is_channel_ready(config))
Felix Held4b4114f72021-12-18 00:41:23 +0100821 return CB_SUCCESS;
Furquan Shaikh70063ff52020-05-11 14:28:13 -0700822 } while (!stopwatch_expired(&sw));
823
Julius Wernere9665952022-01-21 17:06:20 -0800824 printk(BIOS_ERR, "Channel is not ready after %d usec (slave addr: 0x%x)\n",
Furquan Shaikh70063ff52020-05-11 14:28:13 -0700825 ESPI_CH_READY_TIMEOUT_US, slave_reg_addr);
Felix Held4b4114f72021-12-18 00:41:23 +0100826 return CB_ERR;
Furquan Shaikh70063ff52020-05-11 14:28:13 -0700827
828}
829
830static void espi_enable_ctrlr_channel(uint32_t channel_en)
831{
832 uint32_t reg = espi_read32(ESPI_SLAVE0_CONFIG);
833
834 reg |= channel_en;
835
836 espi_write32(ESPI_SLAVE0_CONFIG, reg);
837}
838
Felix Held4b4114f72021-12-18 00:41:23 +0100839static enum cb_err espi_set_channel_configuration(uint32_t slave_config,
840 uint32_t slave_reg_addr,
841 uint32_t ctrlr_enable)
Furquan Shaikh70063ff52020-05-11 14:28:13 -0700842{
Felix Held4b4114f72021-12-18 00:41:23 +0100843 if (espi_set_configuration(slave_reg_addr, slave_config) != CB_SUCCESS)
844 return CB_ERR;
Furquan Shaikh70063ff52020-05-11 14:28:13 -0700845
846 if (!(slave_config & ESPI_SLAVE_CHANNEL_ENABLE))
Felix Held4b4114f72021-12-18 00:41:23 +0100847 return CB_SUCCESS;
Furquan Shaikh70063ff52020-05-11 14:28:13 -0700848
Felix Held4b4114f72021-12-18 00:41:23 +0100849 if (espi_wait_channel_ready(slave_reg_addr) != CB_SUCCESS)
850 return CB_ERR;
Furquan Shaikh70063ff52020-05-11 14:28:13 -0700851
852 espi_enable_ctrlr_channel(ctrlr_enable);
Felix Held4b4114f72021-12-18 00:41:23 +0100853 return CB_SUCCESS;
Furquan Shaikh70063ff52020-05-11 14:28:13 -0700854}
855
Felix Held4b4114f72021-12-18 00:41:23 +0100856static enum cb_err espi_setup_vw_channel(const struct espi_config *mb_cfg, uint32_t slave_caps)
Furquan Shaikh70063ff52020-05-11 14:28:13 -0700857{
858 uint32_t slave_vw_caps;
859 uint32_t ctrlr_vw_caps;
860 uint32_t slave_vw_count_supp;
861 uint32_t ctrlr_vw_count_supp;
862 uint32_t use_vw_count;
863 uint32_t slave_config;
864
865 if (!mb_cfg->vw_ch_en)
Felix Held4b4114f72021-12-18 00:41:23 +0100866 return CB_SUCCESS;
Furquan Shaikh70063ff52020-05-11 14:28:13 -0700867
868 if (!espi_slave_supports_vw_channel(slave_caps)) {
Julius Wernere9665952022-01-21 17:06:20 -0800869 printk(BIOS_ERR, "eSPI slave doesn't support VW channel!\n");
Felix Held4b4114f72021-12-18 00:41:23 +0100870 return CB_ERR;
Furquan Shaikh70063ff52020-05-11 14:28:13 -0700871 }
872
Felix Held4b4114f72021-12-18 00:41:23 +0100873 if (espi_get_configuration(ESPI_SLAVE_VW_CFG, &slave_vw_caps) != CB_SUCCESS)
874 return CB_ERR;
Furquan Shaikh70063ff52020-05-11 14:28:13 -0700875
876 ctrlr_vw_caps = espi_read32(ESPI_MASTER_CAP);
877 ctrlr_vw_count_supp = (ctrlr_vw_caps & ESPI_VW_MAX_SIZE_MASK) >> ESPI_VW_MAX_SIZE_SHIFT;
878
879 slave_vw_count_supp = espi_slave_get_vw_count_supp(slave_vw_caps);
880 use_vw_count = MIN(ctrlr_vw_count_supp, slave_vw_count_supp);
881
882 slave_config = ESPI_SLAVE_CHANNEL_ENABLE | ESPI_SLAVE_VW_COUNT_SEL_VAL(use_vw_count);
883 return espi_set_channel_configuration(slave_config, ESPI_SLAVE_VW_CFG, ESPI_VW_CH_EN);
884}
885
Felix Held4b4114f72021-12-18 00:41:23 +0100886static enum cb_err espi_setup_periph_channel(const struct espi_config *mb_cfg,
887 uint32_t slave_caps)
Furquan Shaikh70063ff52020-05-11 14:28:13 -0700888{
889 uint32_t slave_config;
890 /* Peripheral channel requires BME bit to be set when enabling the channel. */
Raul E Rangel8fef0b72021-05-24 13:02:40 -0600891 const uint32_t slave_en_mask =
892 ESPI_SLAVE_CHANNEL_ENABLE | ESPI_SLAVE_PERIPH_BUS_MASTER_ENABLE;
Furquan Shaikh70063ff52020-05-11 14:28:13 -0700893
Felix Held4b4114f72021-12-18 00:41:23 +0100894 if (espi_get_configuration(ESPI_SLAVE_PERIPH_CFG, &slave_config) != CB_SUCCESS)
895 return CB_ERR;
Furquan Shaikh70063ff52020-05-11 14:28:13 -0700896
897 /*
898 * Peripheral channel is the only one which is enabled on reset. So, if the mainboard
899 * wants to disable it, set configuration to disable peripheral channel. It also
900 * requires that BME bit be cleared.
901 */
902 if (mb_cfg->periph_ch_en) {
903 if (!espi_slave_supports_periph_channel(slave_caps)) {
Julius Wernere9665952022-01-21 17:06:20 -0800904 printk(BIOS_ERR, "eSPI slave doesn't support periph channel!\n");
Felix Held4b4114f72021-12-18 00:41:23 +0100905 return CB_ERR;
Furquan Shaikh70063ff52020-05-11 14:28:13 -0700906 }
907 slave_config |= slave_en_mask;
908 } else {
909 slave_config &= ~slave_en_mask;
910 }
911
Raul E Rangel7222f7e2021-04-09 14:15:42 -0600912 espi_show_slave_peripheral_channel_configuration(slave_config);
913
Furquan Shaikh70063ff52020-05-11 14:28:13 -0700914 return espi_set_channel_configuration(slave_config, ESPI_SLAVE_PERIPH_CFG,
915 ESPI_PERIPH_CH_EN);
916}
917
Felix Held4b4114f72021-12-18 00:41:23 +0100918static enum cb_err espi_setup_oob_channel(const struct espi_config *mb_cfg, uint32_t slave_caps)
Furquan Shaikh70063ff52020-05-11 14:28:13 -0700919{
920 uint32_t slave_config;
921
922 if (!mb_cfg->oob_ch_en)
Felix Held4b4114f72021-12-18 00:41:23 +0100923 return CB_SUCCESS;
Furquan Shaikh70063ff52020-05-11 14:28:13 -0700924
925 if (!espi_slave_supports_oob_channel(slave_caps)) {
Julius Wernere9665952022-01-21 17:06:20 -0800926 printk(BIOS_ERR, "eSPI slave doesn't support OOB channel!\n");
Felix Held4b4114f72021-12-18 00:41:23 +0100927 return CB_ERR;
Furquan Shaikh70063ff52020-05-11 14:28:13 -0700928 }
929
Felix Held4b4114f72021-12-18 00:41:23 +0100930 if (espi_get_configuration(ESPI_SLAVE_OOB_CFG, &slave_config) != CB_SUCCESS)
931 return CB_ERR;
Furquan Shaikh70063ff52020-05-11 14:28:13 -0700932
933 slave_config |= ESPI_SLAVE_CHANNEL_ENABLE;
934
935 return espi_set_channel_configuration(slave_config, ESPI_SLAVE_OOB_CFG,
936 ESPI_OOB_CH_EN);
937}
938
Felix Held4b4114f72021-12-18 00:41:23 +0100939static enum cb_err espi_setup_flash_channel(const struct espi_config *mb_cfg,
940 uint32_t slave_caps)
Furquan Shaikh70063ff52020-05-11 14:28:13 -0700941{
942 uint32_t slave_config;
943
944 if (!mb_cfg->flash_ch_en)
Felix Held4b4114f72021-12-18 00:41:23 +0100945 return CB_SUCCESS;
Furquan Shaikh70063ff52020-05-11 14:28:13 -0700946
947 if (!espi_slave_supports_flash_channel(slave_caps)) {
Julius Wernere9665952022-01-21 17:06:20 -0800948 printk(BIOS_ERR, "eSPI slave doesn't support flash channel!\n");
Felix Held4b4114f72021-12-18 00:41:23 +0100949 return CB_ERR;
Furquan Shaikh70063ff52020-05-11 14:28:13 -0700950 }
951
Felix Held4b4114f72021-12-18 00:41:23 +0100952 if (espi_get_configuration(ESPI_SLAVE_FLASH_CFG, &slave_config) != CB_SUCCESS)
953 return CB_ERR;
Furquan Shaikh70063ff52020-05-11 14:28:13 -0700954
955 slave_config |= ESPI_SLAVE_CHANNEL_ENABLE;
956
957 return espi_set_channel_configuration(slave_config, ESPI_SLAVE_FLASH_CFG,
958 ESPI_FLASH_CH_EN);
959}
960
Felix Held687ec6b2022-12-13 18:05:00 +0100961static enum cb_err espi_set_initial_config(const struct espi_config *mb_cfg)
Furquan Shaikh70063ff52020-05-11 14:28:13 -0700962{
963 uint32_t espi_initial_mode = ESPI_OP_FREQ_16_MHZ | ESPI_IO_MODE_SINGLE;
964
Raul E Rangeldcec4092021-05-07 15:35:10 -0600965 switch (mb_cfg->alert_pin) {
966 case ESPI_ALERT_PIN_IN_BAND:
967 break;
968 case ESPI_ALERT_PIN_PUSH_PULL:
969 case ESPI_ALERT_PIN_OPEN_DRAIN:
970 espi_initial_mode |= ESPI_ALERT_MODE;
971 break;
972 default:
Felix Held687ec6b2022-12-13 18:05:00 +0100973 printk(BIOS_ERR, "Unknown espi alert config: %u!\n", mb_cfg->alert_pin);
974 return CB_ERR;
Raul E Rangeldcec4092021-05-07 15:35:10 -0600975 }
976
Furquan Shaikh70063ff52020-05-11 14:28:13 -0700977 espi_write32(ESPI_SLAVE0_CONFIG, espi_initial_mode);
Felix Held687ec6b2022-12-13 18:05:00 +0100978 return CB_SUCCESS;
Furquan Shaikh70063ff52020-05-11 14:28:13 -0700979}
980
981static void espi_setup_subtractive_decode(const struct espi_config *mb_cfg)
982{
983 uint32_t global_ctrl_reg;
984 global_ctrl_reg = espi_read32(ESPI_GLOBAL_CONTROL_1);
985
986 if (mb_cfg->subtractive_decode) {
987 global_ctrl_reg &= ~ESPI_SUB_DECODE_SLV_MASK;
988 global_ctrl_reg |= ESPI_SUB_DECODE_EN;
989
990 } else {
991 global_ctrl_reg &= ~ESPI_SUB_DECODE_EN;
992 }
993 espi_write32(ESPI_GLOBAL_CONTROL_1, global_ctrl_reg);
994}
995
Felix Heldaed38a92021-12-18 00:41:23 +0100996enum cb_err espi_setup(void)
Furquan Shaikh70063ff52020-05-11 14:28:13 -0700997{
Raul E Rangeldbeae6a2022-04-25 13:32:35 -0600998 uint32_t slave_caps, ctrl;
Furquan Shaikh70063ff52020-05-11 14:28:13 -0700999 const struct espi_config *cfg = espi_get_config();
1000
Martin Roth7a2bfeb2021-05-14 10:57:31 -06001001 printk(BIOS_SPEW, "Initializing ESPI.\n");
1002
Raul E Rangelb92383a2021-04-02 10:32:03 -06001003 espi_write32(ESPI_GLOBAL_CONTROL_0, ESPI_AL_STOP_EN);
1004 espi_write32(ESPI_GLOBAL_CONTROL_1, ESPI_RGCMD_INT(23) | ESPI_ERR_INT_SMI);
1005 espi_write32(ESPI_SLAVE0_INT_EN, 0);
1006 espi_clear_status();
Raul E Rangelb95f8482021-04-02 13:47:09 -06001007 espi_clear_decodes();
Raul E Rangelb92383a2021-04-02 10:32:03 -06001008
Furquan Shaikh70063ff52020-05-11 14:28:13 -07001009 /*
1010 * Boot sequence: Step 1
1011 * Set correct initial configuration to talk to the slave:
1012 * Set clock frequency to 16.7MHz and single IO mode.
1013 */
Felix Held687ec6b2022-12-13 18:05:00 +01001014 if (espi_set_initial_config(cfg) != CB_SUCCESS)
1015 return CB_ERR;
Furquan Shaikh70063ff52020-05-11 14:28:13 -07001016
1017 /*
1018 * Boot sequence: Step 2
1019 * Send in-band reset
1020 * The resets affects both host and slave devices, so set initial config again.
1021 */
Felix Held4b4114f72021-12-18 00:41:23 +01001022 if (espi_send_reset() != CB_SUCCESS) {
Julius Wernere9665952022-01-21 17:06:20 -08001023 printk(BIOS_ERR, "In-band reset failed!\n");
Felix Heldaed38a92021-12-18 00:41:23 +01001024 return CB_ERR;
Furquan Shaikh70063ff52020-05-11 14:28:13 -07001025 }
Felix Held687ec6b2022-12-13 18:05:00 +01001026
1027 if (espi_set_initial_config(cfg) != CB_SUCCESS)
1028 return CB_ERR;
Furquan Shaikh70063ff52020-05-11 14:28:13 -07001029
1030 /*
1031 * Boot sequence: Step 3
1032 * Get configuration of slave device.
1033 */
Felix Held4b4114f72021-12-18 00:41:23 +01001034 if (espi_get_general_configuration(&slave_caps) != CB_SUCCESS) {
Julius Wernere9665952022-01-21 17:06:20 -08001035 printk(BIOS_ERR, "Slave GET_CONFIGURATION failed!\n");
Felix Heldaed38a92021-12-18 00:41:23 +01001036 return CB_ERR;
Furquan Shaikh70063ff52020-05-11 14:28:13 -07001037 }
1038
1039 /*
1040 * Boot sequence:
1041 * Step 4: Write slave device general config
1042 * Step 5: Set host slave config
1043 */
Felix Held4b4114f72021-12-18 00:41:23 +01001044 if (espi_set_general_configuration(cfg, slave_caps) != CB_SUCCESS) {
Julius Wernere9665952022-01-21 17:06:20 -08001045 printk(BIOS_ERR, "Slave SET_CONFIGURATION failed!\n");
Felix Heldaed38a92021-12-18 00:41:23 +01001046 return CB_ERR;
Furquan Shaikh70063ff52020-05-11 14:28:13 -07001047 }
1048
1049 /*
1050 * Setup polarity before enabling the VW channel so any interrupts
1051 * received will have the correct polarity.
1052 */
1053 espi_write32(ESPI_RXVW_POLARITY, cfg->vw_irq_polarity);
1054
1055 /*
1056 * Boot Sequences: Steps 6 - 9
1057 * Channel setup
1058 */
1059 /* Set up VW first so we can deassert PLTRST#. */
Felix Held4b4114f72021-12-18 00:41:23 +01001060 if (espi_setup_vw_channel(cfg, slave_caps) != CB_SUCCESS) {
Julius Wernere9665952022-01-21 17:06:20 -08001061 printk(BIOS_ERR, "Setup VW channel failed!\n");
Felix Heldaed38a92021-12-18 00:41:23 +01001062 return CB_ERR;
Furquan Shaikh70063ff52020-05-11 14:28:13 -07001063 }
1064
Raul E Rangel43aa5272021-05-21 17:04:28 -06001065 /* Assert PLTRST# if VW channel is enabled by mainboard. */
Felix Held4b4114f72021-12-18 00:41:23 +01001066 if (espi_send_pltrst(cfg, true) != CB_SUCCESS) {
Julius Wernere9665952022-01-21 17:06:20 -08001067 printk(BIOS_ERR, "PLTRST# assertion failed!\n");
Felix Heldaed38a92021-12-18 00:41:23 +01001068 return CB_ERR;
Raul E Rangel43aa5272021-05-21 17:04:28 -06001069 }
1070
Furquan Shaikh70063ff52020-05-11 14:28:13 -07001071 /* De-assert PLTRST# if VW channel is enabled by mainboard. */
Felix Held4b4114f72021-12-18 00:41:23 +01001072 if (espi_send_pltrst(cfg, false) != CB_SUCCESS) {
Julius Wernere9665952022-01-21 17:06:20 -08001073 printk(BIOS_ERR, "PLTRST# deassertion failed!\n");
Felix Heldaed38a92021-12-18 00:41:23 +01001074 return CB_ERR;
Furquan Shaikh70063ff52020-05-11 14:28:13 -07001075 }
1076
Felix Held4b4114f72021-12-18 00:41:23 +01001077 if (espi_setup_periph_channel(cfg, slave_caps) != CB_SUCCESS) {
Julius Wernere9665952022-01-21 17:06:20 -08001078 printk(BIOS_ERR, "Setup Periph channel failed!\n");
Felix Heldaed38a92021-12-18 00:41:23 +01001079 return CB_ERR;
Furquan Shaikh70063ff52020-05-11 14:28:13 -07001080 }
1081
Felix Held4b4114f72021-12-18 00:41:23 +01001082 if (espi_setup_oob_channel(cfg, slave_caps) != CB_SUCCESS) {
Julius Wernere9665952022-01-21 17:06:20 -08001083 printk(BIOS_ERR, "Setup OOB channel failed!\n");
Felix Heldaed38a92021-12-18 00:41:23 +01001084 return CB_ERR;
Furquan Shaikh70063ff52020-05-11 14:28:13 -07001085 }
1086
Felix Held4b4114f72021-12-18 00:41:23 +01001087 if (espi_setup_flash_channel(cfg, slave_caps) != CB_SUCCESS) {
Julius Wernere9665952022-01-21 17:06:20 -08001088 printk(BIOS_ERR, "Setup Flash channel failed!\n");
Felix Heldaed38a92021-12-18 00:41:23 +01001089 return CB_ERR;
Furquan Shaikh70063ff52020-05-11 14:28:13 -07001090 }
1091
Felix Heldaed38a92021-12-18 00:41:23 +01001092 if (espi_configure_decodes(cfg) != CB_SUCCESS) {
Julius Wernere9665952022-01-21 17:06:20 -08001093 printk(BIOS_ERR, "Configuring decodes failed!\n");
Felix Heldaed38a92021-12-18 00:41:23 +01001094 return CB_ERR;
Raul E Rangel61ac1bc2021-04-02 10:55:27 -06001095 }
1096
Furquan Shaikh70063ff52020-05-11 14:28:13 -07001097 /* Enable subtractive decode if configured */
Felix Helda2642d02021-02-17 00:32:46 +01001098 espi_setup_subtractive_decode(cfg);
Furquan Shaikh70063ff52020-05-11 14:28:13 -07001099
Raul E Rangeldbeae6a2022-04-25 13:32:35 -06001100 ctrl = espi_read32(ESPI_GLOBAL_CONTROL_1);
1101 ctrl |= ESPI_BUS_MASTER_EN;
1102
1103 if (CONFIG(SOC_AMD_COMMON_BLOCK_HAS_ESPI_ALERT_ENABLE))
1104 ctrl |= ESPI_ALERT_ENABLE;
1105
1106 espi_write32(ESPI_GLOBAL_CONTROL_1, ctrl);
Raul E Rangelb92383a2021-04-02 10:32:03 -06001107
Martin Roth7a2bfeb2021-05-14 10:57:31 -06001108 printk(BIOS_SPEW, "Finished initializing ESPI.\n");
1109
Felix Heldaed38a92021-12-18 00:41:23 +01001110 return CB_SUCCESS;
Furquan Shaikh70063ff52020-05-11 14:28:13 -07001111}
Felix Held1c03da52021-10-14 21:48:13 +02001112
1113/* Setup eSPI with any mainboard specific initialization. */
1114void configure_espi_with_mb_hook(void)
1115{
1116 mb_set_up_early_espi();
1117 espi_setup();
1118}