blob: f05575ab748c7ad8761d6e705b017244502e021d [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;
Furquan Shaikhf318e032020-05-04 23:38:53 -0700320}
321
322static size_t espi_get_mmio_window_size(int idx)
323{
Felix Held6ba6bc22022-02-07 21:11:25 +0100324 return espi_read16(espi_mmio_range_size_reg(idx)) + 1;
Furquan Shaikhf318e032020-05-04 23:38:53 -0700325}
326
327static void espi_write_mmio_window(int idx, uint32_t base, size_t size)
328{
Felix Held6ba6bc22022-02-07 21:11:25 +0100329 espi_write32(espi_mmio_range_base_reg(idx), base);
330 espi_write16(espi_mmio_range_size_reg(idx), size - 1);
Furquan Shaikhf318e032020-05-04 23:38:53 -0700331}
332
Felix Heldaed38a92021-12-18 00:41:23 +0100333enum cb_err espi_open_mmio_window(uint32_t base, size_t size)
Furquan Shaikhf318e032020-05-04 23:38:53 -0700334{
335 size_t win_size;
336 int idx;
337
338 for (; size; size -= win_size, base += win_size) {
339 win_size = MIN(size, ESPI_GENERIC_MMIO_MAX_WIN_SIZE);
340
341 idx = espi_find_mmio_window(base);
342 if (idx != -1) {
343 size_t curr_size = espi_get_mmio_window_size(idx);
344
345 if (curr_size > win_size) {
346 printk(BIOS_INFO, "eSPI window already configured to be larger than requested! ");
347 printk(BIOS_INFO, "Base: 0x%x, Requested size: 0x%zx, Actual size: 0x%zx\n",
348 base, win_size, curr_size);
349 } else if (curr_size < win_size) {
350 espi_write_mmio_window(idx, base, win_size);
351 printk(BIOS_INFO, "eSPI window at base: 0x%x resized from 0x%zx to 0x%zx\n",
352 base, curr_size, win_size);
353 }
354
355 continue;
356 }
357
358 idx = espi_get_unused_mmio_window();
359 if (idx == -1) {
360 printk(BIOS_ERR, "Cannot open IO window base %x size %zx\n", base,
361 size);
Julius Wernere9665952022-01-21 17:06:20 -0800362 printk(BIOS_ERR, "No more available MMIO windows!\n");
Felix Heldaed38a92021-12-18 00:41:23 +0100363 return CB_ERR;
Furquan Shaikhf318e032020-05-04 23:38:53 -0700364 }
365
366 espi_write_mmio_window(idx, base, win_size);
Felix Held6ba6bc22022-02-07 21:11:25 +0100367 espi_enable_decode(espi_decode_mmio_range_en_bit(idx));
Furquan Shaikhf318e032020-05-04 23:38:53 -0700368 }
369
Felix Heldaed38a92021-12-18 00:41:23 +0100370 return CB_SUCCESS;
Furquan Shaikhf318e032020-05-04 23:38:53 -0700371}
372
373static const struct espi_config *espi_get_config(void)
374{
375 const struct soc_amd_common_config *soc_cfg = soc_get_common_config();
Furquan Shaikhf318e032020-05-04 23:38:53 -0700376 return &soc_cfg->espi_config;
377}
378
Felix Heldaed38a92021-12-18 00:41:23 +0100379static enum cb_err espi_configure_decodes(const struct espi_config *cfg)
Furquan Shaikhf318e032020-05-04 23:38:53 -0700380{
Felix Held9e830542021-12-18 00:41:23 +0100381 int i;
Furquan Shaikhf318e032020-05-04 23:38:53 -0700382
383 espi_enable_decode(cfg->std_io_decode_bitmap);
384
385 for (i = 0; i < ESPI_GENERIC_IO_WIN_COUNT; i++) {
386 if (cfg->generic_io_range[i].size == 0)
387 continue;
Felix Held9e830542021-12-18 00:41:23 +0100388 if (espi_open_generic_io_window(cfg->generic_io_range[i].base,
Felix Heldaed38a92021-12-18 00:41:23 +0100389 cfg->generic_io_range[i].size) != CB_SUCCESS)
390 return CB_ERR;
Furquan Shaikhf318e032020-05-04 23:38:53 -0700391 }
Raul E Rangel61ac1bc2021-04-02 10:55:27 -0600392
Felix Heldaed38a92021-12-18 00:41:23 +0100393 return CB_SUCCESS;
Furquan Shaikhf318e032020-05-04 23:38:53 -0700394}
Furquan Shaikh70063ff52020-05-11 14:28:13 -0700395
Furquan Shaikh70063ff52020-05-11 14:28:13 -0700396enum espi_cmd_type {
397 CMD_TYPE_SET_CONFIGURATION = 0,
398 CMD_TYPE_GET_CONFIGURATION = 1,
399 CMD_TYPE_IN_BAND_RESET = 2,
400 CMD_TYPE_PERIPHERAL = 4,
401 CMD_TYPE_VW = 5,
402 CMD_TYPE_OOB = 6,
403 CMD_TYPE_FLASH = 7,
404};
405
Furquan Shaikh70063ff52020-05-11 14:28:13 -0700406#define ESPI_CMD_TIMEOUT_US 100
Raul E Rangel0318dc12021-05-21 16:31:52 -0600407#define ESPI_CH_READY_TIMEOUT_US 10000
Furquan Shaikh70063ff52020-05-11 14:28:13 -0700408
409union espi_txhdr0 {
410 uint32_t val;
411 struct {
412 uint32_t cmd_type:3;
413 uint32_t cmd_sts:1;
414 uint32_t slave_sel:2;
415 uint32_t rsvd:2;
416 uint32_t hdata0:8;
417 uint32_t hdata1:8;
418 uint32_t hdata2:8;
419 };
420} __packed;
421
422union espi_txhdr1 {
423 uint32_t val;
424 struct {
425 uint32_t hdata3:8;
426 uint32_t hdata4:8;
427 uint32_t hdata5:8;
428 uint32_t hdata6:8;
429 };
430} __packed;
431
432union espi_txhdr2 {
433 uint32_t val;
434 struct {
435 uint32_t hdata7:8;
436 uint32_t rsvd:24;
437 };
438} __packed;
439
440union espi_txdata {
441 uint32_t val;
442 struct {
443 uint32_t byte0:8;
444 uint32_t byte1:8;
445 uint32_t byte2:8;
446 uint32_t byte3:8;
447 };
448} __packed;
449
450struct espi_cmd {
451 union espi_txhdr0 hdr0;
452 union espi_txhdr1 hdr1;
453 union espi_txhdr2 hdr2;
454 union espi_txdata data;
Raul E Rangel12c05422021-05-11 11:13:38 -0600455 uint32_t expected_status_codes;
Furquan Shaikh70063ff52020-05-11 14:28:13 -0700456} __packed;
457
458/* Wait up to ESPI_CMD_TIMEOUT_US for hardware to clear DNCMD_STATUS bit. */
Felix Held4b4114f72021-12-18 00:41:23 +0100459static enum cb_err espi_wait_ready(void)
Furquan Shaikh70063ff52020-05-11 14:28:13 -0700460{
461 struct stopwatch sw;
462 union espi_txhdr0 hdr0;
463
464 stopwatch_init_usecs_expire(&sw, ESPI_CMD_TIMEOUT_US);
465 do {
466 hdr0.val = espi_read32(ESPI_DN_TX_HDR0);
467 if (!hdr0.cmd_sts)
Felix Held4b4114f72021-12-18 00:41:23 +0100468 return CB_SUCCESS;
Furquan Shaikh70063ff52020-05-11 14:28:13 -0700469 } while (!stopwatch_expired(&sw));
470
Felix Held4b4114f72021-12-18 00:41:23 +0100471 return CB_ERR;
Furquan Shaikh70063ff52020-05-11 14:28:13 -0700472}
473
474/* Clear interrupt status register */
475static void espi_clear_status(void)
476{
Raul E Rangel47740122021-04-02 10:16:54 -0600477 uint32_t status = espi_read32(ESPI_SLAVE0_INT_STS);
Furquan Shaikh70063ff52020-05-11 14:28:13 -0700478 if (status)
Raul E Rangel47740122021-04-02 10:16:54 -0600479 espi_write32(ESPI_SLAVE0_INT_STS, status);
Furquan Shaikh70063ff52020-05-11 14:28:13 -0700480}
481
482/*
483 * Wait up to ESPI_CMD_TIMEOUT_US for interrupt status register to update after sending a
484 * command.
485 */
Felix Held4b4114f72021-12-18 00:41:23 +0100486static enum cb_err espi_poll_status(uint32_t *status)
Furquan Shaikh70063ff52020-05-11 14:28:13 -0700487{
488 struct stopwatch sw;
489
490 stopwatch_init_usecs_expire(&sw, ESPI_CMD_TIMEOUT_US);
491 do {
Raul E Rangel47740122021-04-02 10:16:54 -0600492 *status = espi_read32(ESPI_SLAVE0_INT_STS);
Furquan Shaikh70063ff52020-05-11 14:28:13 -0700493 if (*status)
Felix Held4b4114f72021-12-18 00:41:23 +0100494 return CB_SUCCESS;
Furquan Shaikh70063ff52020-05-11 14:28:13 -0700495 } while (!stopwatch_expired(&sw));
496
Julius Wernere9665952022-01-21 17:06:20 -0800497 printk(BIOS_ERR, "eSPI timed out waiting for status update.\n");
Furquan Shaikh70063ff52020-05-11 14:28:13 -0700498
Felix Held4b4114f72021-12-18 00:41:23 +0100499 return CB_ERR;
Furquan Shaikh70063ff52020-05-11 14:28:13 -0700500}
501
502static void espi_show_failure(const struct espi_cmd *cmd, const char *str, uint32_t status)
503{
504 printk(BIOS_ERR, "eSPI cmd0-cmd2: %08x %08x %08x data: %08x.\n",
505 cmd->hdr0.val, cmd->hdr1.val, cmd->hdr2.val, cmd->data.val);
506 printk(BIOS_ERR, "%s (Status = 0x%x)\n", str, status);
507}
508
Felix Held4b4114f72021-12-18 00:41:23 +0100509static enum cb_err espi_send_command(const struct espi_cmd *cmd)
Furquan Shaikh70063ff52020-05-11 14:28:13 -0700510{
511 uint32_t status;
512
513 if (CONFIG(ESPI_DEBUG))
Raul E Rangelf7027052021-06-29 13:12:19 -0600514 printk(BIOS_DEBUG, "eSPI cmd0-cmd2: %08x %08x %08x data: %08x.\n",
Furquan Shaikh70063ff52020-05-11 14:28:13 -0700515 cmd->hdr0.val, cmd->hdr1.val, cmd->hdr2.val, cmd->data.val);
516
Felix Held4b4114f72021-12-18 00:41:23 +0100517 if (espi_wait_ready() != CB_SUCCESS) {
Furquan Shaikh70063ff52020-05-11 14:28:13 -0700518 espi_show_failure(cmd, "Error: eSPI was not ready to accept a command", 0);
Felix Held4b4114f72021-12-18 00:41:23 +0100519 return CB_ERR;
Furquan Shaikh70063ff52020-05-11 14:28:13 -0700520 }
521
522 espi_clear_status();
523
524 espi_write32(ESPI_DN_TX_HDR1, cmd->hdr1.val);
525 espi_write32(ESPI_DN_TX_HDR2, cmd->hdr2.val);
526 espi_write32(ESPI_DN_TX_DATA, cmd->data.val);
527
528 /* Dword 0 must be last as this write triggers the transaction */
529 espi_write32(ESPI_DN_TX_HDR0, cmd->hdr0.val);
530
Felix Held4b4114f72021-12-18 00:41:23 +0100531 if (espi_wait_ready() != CB_SUCCESS) {
Furquan Shaikh70063ff52020-05-11 14:28:13 -0700532 espi_show_failure(cmd,
533 "Error: eSPI timed out waiting for command to complete", 0);
Felix Held4b4114f72021-12-18 00:41:23 +0100534 return CB_ERR;
Furquan Shaikh70063ff52020-05-11 14:28:13 -0700535 }
536
Felix Held4b4114f72021-12-18 00:41:23 +0100537 if (espi_poll_status(&status) != CB_SUCCESS) {
Felix Held1ba38332020-08-10 20:45:30 +0200538 espi_show_failure(cmd, "Error: eSPI poll status failed", 0);
Felix Held4b4114f72021-12-18 00:41:23 +0100539 return CB_ERR;
Furquan Shaikh70063ff52020-05-11 14:28:13 -0700540 }
541
542 /* If command did not complete downstream, return error. */
543 if (!(status & ESPI_STATUS_DNCMD_COMPLETE)) {
544 espi_show_failure(cmd, "Error: eSPI downstream command completion failure",
545 status);
Felix Held4b4114f72021-12-18 00:41:23 +0100546 return CB_ERR;
Furquan Shaikh70063ff52020-05-11 14:28:13 -0700547 }
548
Raul E Rangel12c05422021-05-11 11:13:38 -0600549 if (status & ~(ESPI_STATUS_DNCMD_COMPLETE | cmd->expected_status_codes)) {
Felix Held316d59c2020-08-10 20:42:20 +0200550 espi_show_failure(cmd, "Error: unexpected eSPI status register bits set",
551 status);
Felix Held4b4114f72021-12-18 00:41:23 +0100552 return CB_ERR;
Furquan Shaikh70063ff52020-05-11 14:28:13 -0700553 }
554
Raul E Rangel12c05422021-05-11 11:13:38 -0600555 espi_write32(ESPI_SLAVE0_INT_STS, status);
Raul E Rangel66c52ff2021-04-02 10:18:25 -0600556
Felix Held4b4114f72021-12-18 00:41:23 +0100557 return CB_SUCCESS;
Furquan Shaikh70063ff52020-05-11 14:28:13 -0700558}
559
Felix Held4b4114f72021-12-18 00:41:23 +0100560static enum cb_err espi_send_reset(void)
Furquan Shaikh70063ff52020-05-11 14:28:13 -0700561{
562 struct espi_cmd cmd = {
563 .hdr0 = {
564 .cmd_type = CMD_TYPE_IN_BAND_RESET,
565 .cmd_sts = 1,
566 },
Raul E Rangel12c05422021-05-11 11:13:38 -0600567
568 /*
569 * When performing an in-band reset the host controller and the
570 * peripheral can have mismatched IO configs.
571 *
572 * i.e., The eSPI peripheral can be in IO-4 mode while, the
573 * eSPI host will be in IO-1. This results in the peripheral
574 * getting invalid packets and thus not responding.
575 *
576 * If the peripheral is alerting when we perform an in-band
577 * reset, there is a race condition in espi_send_command.
578 * 1) espi_send_command clears the interrupt status.
579 * 2) eSPI host controller hardware notices the alert and sends
580 * a GET_STATUS.
581 * 3) espi_send_command writes the in-band reset command.
582 * 4) eSPI hardware enqueues the in-band reset until GET_STATUS
583 * is complete.
584 * 5) GET_STATUS fails with NO_RESPONSE and sets the interrupt
585 * status.
586 * 6) eSPI hardware performs in-band reset.
587 * 7) espi_send_command checks the status and sees a
588 * NO_RESPONSE bit.
589 *
590 * As a workaround we allow the NO_RESPONSE status code when
591 * we perform an in-band reset.
592 */
593 .expected_status_codes = ESPI_STATUS_NO_RESPONSE,
Furquan Shaikh70063ff52020-05-11 14:28:13 -0700594 };
595
596 return espi_send_command(&cmd);
597}
598
Felix Held4b4114f72021-12-18 00:41:23 +0100599static enum cb_err espi_send_pltrst(const struct espi_config *mb_cfg, bool assert)
Furquan Shaikh70063ff52020-05-11 14:28:13 -0700600{
601 struct espi_cmd cmd = {
602 .hdr0 = {
603 .cmd_type = CMD_TYPE_VW,
604 .cmd_sts = 1,
605 .hdata0 = 0, /* 1 VW group */
606 },
607 .data = {
608 .byte0 = ESPI_VW_INDEX_SYSTEM_EVENT_3,
Raul E Rangel43aa5272021-05-21 17:04:28 -0600609 .byte1 = assert ? ESPI_VW_SIGNAL_LOW(ESPI_VW_PLTRST)
610 : ESPI_VW_SIGNAL_HIGH(ESPI_VW_PLTRST),
Furquan Shaikh70063ff52020-05-11 14:28:13 -0700611 },
612 };
613
614 if (!mb_cfg->vw_ch_en)
Felix Held4b4114f72021-12-18 00:41:23 +0100615 return CB_SUCCESS;
Furquan Shaikh70063ff52020-05-11 14:28:13 -0700616
617 return espi_send_command(&cmd);
618}
619
620/*
621 * In case of get configuration command, hdata0 contains bits 15:8 of the slave register address
622 * and hdata1 contains bits 7:0 of the slave register address.
623 */
624#define ESPI_CONFIGURATION_HDATA0(a) (((a) >> 8) & 0xff)
625#define ESPI_CONFIGURATION_HDATA1(a) ((a) & 0xff)
626
Felix Held4b4114f72021-12-18 00:41:23 +0100627static enum cb_err espi_get_configuration(uint16_t slave_reg_addr, uint32_t *config)
Furquan Shaikh70063ff52020-05-11 14:28:13 -0700628{
629 struct espi_cmd cmd = {
630 .hdr0 = {
631 .cmd_type = CMD_TYPE_GET_CONFIGURATION,
632 .cmd_sts = 1,
633 .hdata0 = ESPI_CONFIGURATION_HDATA0(slave_reg_addr),
634 .hdata1 = ESPI_CONFIGURATION_HDATA1(slave_reg_addr),
635 },
636 };
637
638 *config = 0;
639
Felix Held4b4114f72021-12-18 00:41:23 +0100640 if (espi_send_command(&cmd) != CB_SUCCESS)
641 return CB_ERR;
Furquan Shaikh70063ff52020-05-11 14:28:13 -0700642
643 *config = espi_read32(ESPI_DN_TX_HDR1);
644
645 if (CONFIG(ESPI_DEBUG))
646 printk(BIOS_DEBUG, "Get configuration for slave register(0x%x): 0x%x\n",
647 slave_reg_addr, *config);
648
Felix Held4b4114f72021-12-18 00:41:23 +0100649 return CB_SUCCESS;
Furquan Shaikh70063ff52020-05-11 14:28:13 -0700650}
651
Felix Held4b4114f72021-12-18 00:41:23 +0100652static enum cb_err espi_set_configuration(uint16_t slave_reg_addr, uint32_t config)
Furquan Shaikh70063ff52020-05-11 14:28:13 -0700653{
654 struct espi_cmd cmd = {
655 .hdr0 = {
656 .cmd_type = CMD_TYPE_SET_CONFIGURATION,
657 .cmd_sts = 1,
658 .hdata0 = ESPI_CONFIGURATION_HDATA0(slave_reg_addr),
659 .hdata1 = ESPI_CONFIGURATION_HDATA1(slave_reg_addr),
660 },
661 .hdr1 = {
662 .val = config,
663 },
664 };
665
666 return espi_send_command(&cmd);
667}
668
Felix Held4b4114f72021-12-18 00:41:23 +0100669static enum cb_err espi_get_general_configuration(uint32_t *config)
Furquan Shaikh70063ff52020-05-11 14:28:13 -0700670{
Felix Held4b4114f72021-12-18 00:41:23 +0100671 if (espi_get_configuration(ESPI_SLAVE_GENERAL_CFG, config) != CB_SUCCESS)
672 return CB_ERR;
Furquan Shaikh70063ff52020-05-11 14:28:13 -0700673
674 espi_show_slave_general_configuration(*config);
Felix Held4b4114f72021-12-18 00:41:23 +0100675 return CB_SUCCESS;
Furquan Shaikh70063ff52020-05-11 14:28:13 -0700676}
677
Felix Held84429e02022-12-13 17:01:22 +0100678static enum cb_err espi_set_io_mode_cfg(enum espi_io_mode mb_io_mode, uint32_t slave_caps,
679 uint32_t *slave_config, uint32_t *ctrlr_config)
Furquan Shaikh70063ff52020-05-11 14:28:13 -0700680{
681 switch (mb_io_mode) {
682 case ESPI_IO_MODE_QUAD:
683 if (espi_slave_supports_quad_io(slave_caps)) {
684 *slave_config |= ESPI_SLAVE_IO_MODE_SEL_QUAD;
685 *ctrlr_config |= ESPI_IO_MODE_QUAD;
686 break;
687 }
Julius Wernere9665952022-01-21 17:06:20 -0800688 printk(BIOS_ERR, "eSPI Quad I/O not supported. Dropping to dual mode.\n");
Felix Heldcbaf7532022-02-21 16:44:48 +0100689 __fallthrough;
Furquan Shaikh70063ff52020-05-11 14:28:13 -0700690 case ESPI_IO_MODE_DUAL:
691 if (espi_slave_supports_dual_io(slave_caps)) {
692 *slave_config |= ESPI_SLAVE_IO_MODE_SEL_DUAL;
693 *ctrlr_config |= ESPI_IO_MODE_DUAL;
694 break;
695 }
Julius Wernere9665952022-01-21 17:06:20 -0800696 printk(BIOS_ERR, "eSPI Dual I/O not supported. Dropping to single mode.\n");
Felix Heldcbaf7532022-02-21 16:44:48 +0100697 __fallthrough;
Furquan Shaikh70063ff52020-05-11 14:28:13 -0700698 case ESPI_IO_MODE_SINGLE:
699 /* Single I/O mode is always supported. */
700 *slave_config |= ESPI_SLAVE_IO_MODE_SEL_SINGLE;
701 *ctrlr_config |= ESPI_IO_MODE_SINGLE;
702 break;
703 default:
Felix Held84429e02022-12-13 17:01:22 +0100704 printk(BIOS_ERR, "No supported eSPI I/O modes!\n");
705 return CB_ERR;
Furquan Shaikh70063ff52020-05-11 14:28:13 -0700706 }
Felix Held84429e02022-12-13 17:01:22 +0100707 return CB_SUCCESS;
Furquan Shaikh70063ff52020-05-11 14:28:13 -0700708}
709
Felix Held84429e02022-12-13 17:01:22 +0100710static enum cb_err espi_set_op_freq_cfg(enum espi_op_freq mb_op_freq, uint32_t slave_caps,
711 uint32_t *slave_config, uint32_t *ctrlr_config)
Furquan Shaikh70063ff52020-05-11 14:28:13 -0700712{
713 int slave_max_speed_mhz = espi_slave_max_speed_mhz_supported(slave_caps);
714
715 switch (mb_op_freq) {
716 case ESPI_OP_FREQ_66_MHZ:
717 if (slave_max_speed_mhz >= 66) {
718 *slave_config |= ESPI_SLAVE_OP_FREQ_SEL_66_MHZ;
719 *ctrlr_config |= ESPI_OP_FREQ_66_MHZ;
720 break;
721 }
Julius Wernere9665952022-01-21 17:06:20 -0800722 printk(BIOS_ERR, "eSPI 66MHz not supported. Dropping to 33MHz.\n");
Felix Heldcbaf7532022-02-21 16:44:48 +0100723 __fallthrough;
Furquan Shaikh70063ff52020-05-11 14:28:13 -0700724 case ESPI_OP_FREQ_33_MHZ:
725 if (slave_max_speed_mhz >= 33) {
726 *slave_config |= ESPI_SLAVE_OP_FREQ_SEL_33_MHZ;
727 *ctrlr_config |= ESPI_OP_FREQ_33_MHZ;
728 break;
729 }
Julius Wernere9665952022-01-21 17:06:20 -0800730 printk(BIOS_ERR, "eSPI 33MHz not supported. Dropping to 16MHz.\n");
Felix Heldcbaf7532022-02-21 16:44:48 +0100731 __fallthrough;
Furquan Shaikh70063ff52020-05-11 14:28:13 -0700732 case ESPI_OP_FREQ_16_MHZ:
733 /*
734 * eSPI spec says the minimum frequency is 20MHz, but AMD datasheets support
735 * 16.7 Mhz.
736 */
737 if (slave_max_speed_mhz > 0) {
738 *slave_config |= ESPI_SLAVE_OP_FREQ_SEL_20_MHZ;
739 *ctrlr_config |= ESPI_OP_FREQ_16_MHZ;
740 break;
741 }
Felix Heldcbaf7532022-02-21 16:44:48 +0100742 __fallthrough;
Furquan Shaikh70063ff52020-05-11 14:28:13 -0700743 default:
Felix Held84429e02022-12-13 17:01:22 +0100744 printk(BIOS_ERR, "No supported eSPI Operating Frequency!\n");
745 return CB_ERR;
Furquan Shaikh70063ff52020-05-11 14:28:13 -0700746 }
Felix Held84429e02022-12-13 17:01:22 +0100747 return CB_SUCCESS;
Furquan Shaikh70063ff52020-05-11 14:28:13 -0700748}
749
Felix Held84429e02022-12-13 17:01:22 +0100750static enum cb_err espi_set_alert_pin_cfg(enum espi_alert_pin alert_pin, uint32_t slave_caps,
751 uint32_t *slave_config, uint32_t *ctrlr_config)
Raul E Rangel8317e722021-05-05 13:38:27 -0600752{
753 switch (alert_pin) {
754 case ESPI_ALERT_PIN_IN_BAND:
755 *slave_config |= ESPI_SLAVE_ALERT_MODE_IO1;
Felix Held84429e02022-12-13 17:01:22 +0100756 return CB_SUCCESS;
Raul E Rangel8317e722021-05-05 13:38:27 -0600757 case ESPI_ALERT_PIN_PUSH_PULL:
758 *slave_config |= ESPI_SLAVE_ALERT_MODE_PIN | ESPI_SLAVE_PUSH_PULL_ALERT_SEL;
759 *ctrlr_config |= ESPI_ALERT_MODE;
Felix Held84429e02022-12-13 17:01:22 +0100760 return CB_SUCCESS;
Raul E Rangel8317e722021-05-05 13:38:27 -0600761 case ESPI_ALERT_PIN_OPEN_DRAIN:
Felix Held84429e02022-12-13 17:01:22 +0100762 if (!(slave_caps & ESPI_SLAVE_OPEN_DRAIN_ALERT_SUPP)) {
763 printk(BIOS_ERR, "eSPI peripheral does not support open drain alert!");
764 return CB_ERR;
765 }
Raul E Rangel8317e722021-05-05 13:38:27 -0600766
767 *slave_config |= ESPI_SLAVE_ALERT_MODE_PIN | ESPI_SLAVE_OPEN_DRAIN_ALERT_SEL;
768 *ctrlr_config |= ESPI_ALERT_MODE;
Felix Held84429e02022-12-13 17:01:22 +0100769 return CB_SUCCESS;
Raul E Rangel8317e722021-05-05 13:38:27 -0600770 default:
Felix Held84429e02022-12-13 17:01:22 +0100771 printk(BIOS_ERR, "Unknown espi alert config: %u!\n", alert_pin);
772 return CB_ERR;
Raul E Rangel8317e722021-05-05 13:38:27 -0600773 }
774}
775
Felix Held4b4114f72021-12-18 00:41:23 +0100776static enum cb_err espi_set_general_configuration(const struct espi_config *mb_cfg,
777 uint32_t slave_caps)
Furquan Shaikh70063ff52020-05-11 14:28:13 -0700778{
779 uint32_t slave_config = 0;
780 uint32_t ctrlr_config = 0;
781
782 if (mb_cfg->crc_check_enable) {
783 slave_config |= ESPI_SLAVE_CRC_ENABLE;
784 ctrlr_config |= ESPI_CRC_CHECKING_EN;
785 }
786
Felix Held84429e02022-12-13 17:01:22 +0100787 if (espi_set_alert_pin_cfg(mb_cfg->alert_pin, slave_caps, &slave_config, &ctrlr_config)
788 != CB_SUCCESS)
789 return CB_ERR;
790 if (espi_set_io_mode_cfg(mb_cfg->io_mode, slave_caps, &slave_config, &ctrlr_config)
791 != CB_SUCCESS)
792 return CB_ERR;
793 if (espi_set_op_freq_cfg(mb_cfg->op_freq_mhz, slave_caps, &slave_config, &ctrlr_config)
794 != CB_SUCCESS)
795 return CB_ERR;
Furquan Shaikh70063ff52020-05-11 14:28:13 -0700796
797 if (CONFIG(ESPI_DEBUG))
798 printk(BIOS_INFO, "Setting general configuration: slave: 0x%x controller: 0x%x\n",
799 slave_config, ctrlr_config);
800
Raul E Rangeld2d762a2021-05-05 13:30:10 -0600801 espi_show_slave_general_configuration(slave_config);
802
Felix Held4b4114f72021-12-18 00:41:23 +0100803 if (espi_set_configuration(ESPI_SLAVE_GENERAL_CFG, slave_config) != CB_SUCCESS)
804 return CB_ERR;
Furquan Shaikh70063ff52020-05-11 14:28:13 -0700805
806 espi_write32(ESPI_SLAVE0_CONFIG, ctrlr_config);
Felix Held4b4114f72021-12-18 00:41:23 +0100807 return CB_SUCCESS;
Furquan Shaikh70063ff52020-05-11 14:28:13 -0700808}
809
Felix Held4b4114f72021-12-18 00:41:23 +0100810static enum cb_err espi_wait_channel_ready(uint16_t slave_reg_addr)
Furquan Shaikh70063ff52020-05-11 14:28:13 -0700811{
812 struct stopwatch sw;
813 uint32_t config;
814
815 stopwatch_init_usecs_expire(&sw, ESPI_CH_READY_TIMEOUT_US);
816 do {
Felix Held5ba87a82021-12-18 00:41:23 +0100817 if (espi_get_configuration(slave_reg_addr, &config) != CB_SUCCESS)
818 return CB_ERR;
Furquan Shaikh70063ff52020-05-11 14:28:13 -0700819 if (espi_slave_is_channel_ready(config))
Felix Held4b4114f72021-12-18 00:41:23 +0100820 return CB_SUCCESS;
Furquan Shaikh70063ff52020-05-11 14:28:13 -0700821 } while (!stopwatch_expired(&sw));
822
Julius Wernere9665952022-01-21 17:06:20 -0800823 printk(BIOS_ERR, "Channel is not ready after %d usec (slave addr: 0x%x)\n",
Furquan Shaikh70063ff52020-05-11 14:28:13 -0700824 ESPI_CH_READY_TIMEOUT_US, slave_reg_addr);
Felix Held4b4114f72021-12-18 00:41:23 +0100825 return CB_ERR;
Furquan Shaikh70063ff52020-05-11 14:28:13 -0700826}
827
828static void espi_enable_ctrlr_channel(uint32_t channel_en)
829{
830 uint32_t reg = espi_read32(ESPI_SLAVE0_CONFIG);
831
832 reg |= channel_en;
833
834 espi_write32(ESPI_SLAVE0_CONFIG, reg);
835}
836
Felix Held4b4114f72021-12-18 00:41:23 +0100837static enum cb_err espi_set_channel_configuration(uint32_t slave_config,
838 uint32_t slave_reg_addr,
839 uint32_t ctrlr_enable)
Furquan Shaikh70063ff52020-05-11 14:28:13 -0700840{
Felix Held4b4114f72021-12-18 00:41:23 +0100841 if (espi_set_configuration(slave_reg_addr, slave_config) != CB_SUCCESS)
842 return CB_ERR;
Furquan Shaikh70063ff52020-05-11 14:28:13 -0700843
844 if (!(slave_config & ESPI_SLAVE_CHANNEL_ENABLE))
Felix Held4b4114f72021-12-18 00:41:23 +0100845 return CB_SUCCESS;
Furquan Shaikh70063ff52020-05-11 14:28:13 -0700846
Felix Held4b4114f72021-12-18 00:41:23 +0100847 if (espi_wait_channel_ready(slave_reg_addr) != CB_SUCCESS)
848 return CB_ERR;
Furquan Shaikh70063ff52020-05-11 14:28:13 -0700849
850 espi_enable_ctrlr_channel(ctrlr_enable);
Felix Held4b4114f72021-12-18 00:41:23 +0100851 return CB_SUCCESS;
Furquan Shaikh70063ff52020-05-11 14:28:13 -0700852}
853
Felix Held4b4114f72021-12-18 00:41:23 +0100854static enum cb_err espi_setup_vw_channel(const struct espi_config *mb_cfg, uint32_t slave_caps)
Furquan Shaikh70063ff52020-05-11 14:28:13 -0700855{
856 uint32_t slave_vw_caps;
857 uint32_t ctrlr_vw_caps;
858 uint32_t slave_vw_count_supp;
859 uint32_t ctrlr_vw_count_supp;
860 uint32_t use_vw_count;
861 uint32_t slave_config;
862
863 if (!mb_cfg->vw_ch_en)
Felix Held4b4114f72021-12-18 00:41:23 +0100864 return CB_SUCCESS;
Furquan Shaikh70063ff52020-05-11 14:28:13 -0700865
866 if (!espi_slave_supports_vw_channel(slave_caps)) {
Julius Wernere9665952022-01-21 17:06:20 -0800867 printk(BIOS_ERR, "eSPI slave doesn't support VW channel!\n");
Felix Held4b4114f72021-12-18 00:41:23 +0100868 return CB_ERR;
Furquan Shaikh70063ff52020-05-11 14:28:13 -0700869 }
870
Felix Held4b4114f72021-12-18 00:41:23 +0100871 if (espi_get_configuration(ESPI_SLAVE_VW_CFG, &slave_vw_caps) != CB_SUCCESS)
872 return CB_ERR;
Furquan Shaikh70063ff52020-05-11 14:28:13 -0700873
874 ctrlr_vw_caps = espi_read32(ESPI_MASTER_CAP);
875 ctrlr_vw_count_supp = (ctrlr_vw_caps & ESPI_VW_MAX_SIZE_MASK) >> ESPI_VW_MAX_SIZE_SHIFT;
876
877 slave_vw_count_supp = espi_slave_get_vw_count_supp(slave_vw_caps);
878 use_vw_count = MIN(ctrlr_vw_count_supp, slave_vw_count_supp);
879
880 slave_config = ESPI_SLAVE_CHANNEL_ENABLE | ESPI_SLAVE_VW_COUNT_SEL_VAL(use_vw_count);
881 return espi_set_channel_configuration(slave_config, ESPI_SLAVE_VW_CFG, ESPI_VW_CH_EN);
882}
883
Felix Held4b4114f72021-12-18 00:41:23 +0100884static enum cb_err espi_setup_periph_channel(const struct espi_config *mb_cfg,
885 uint32_t slave_caps)
Furquan Shaikh70063ff52020-05-11 14:28:13 -0700886{
887 uint32_t slave_config;
888 /* Peripheral channel requires BME bit to be set when enabling the channel. */
Raul E Rangel8fef0b72021-05-24 13:02:40 -0600889 const uint32_t slave_en_mask =
890 ESPI_SLAVE_CHANNEL_ENABLE | ESPI_SLAVE_PERIPH_BUS_MASTER_ENABLE;
Furquan Shaikh70063ff52020-05-11 14:28:13 -0700891
Felix Held4b4114f72021-12-18 00:41:23 +0100892 if (espi_get_configuration(ESPI_SLAVE_PERIPH_CFG, &slave_config) != CB_SUCCESS)
893 return CB_ERR;
Furquan Shaikh70063ff52020-05-11 14:28:13 -0700894
895 /*
896 * Peripheral channel is the only one which is enabled on reset. So, if the mainboard
897 * wants to disable it, set configuration to disable peripheral channel. It also
898 * requires that BME bit be cleared.
899 */
900 if (mb_cfg->periph_ch_en) {
901 if (!espi_slave_supports_periph_channel(slave_caps)) {
Julius Wernere9665952022-01-21 17:06:20 -0800902 printk(BIOS_ERR, "eSPI slave doesn't support periph channel!\n");
Felix Held4b4114f72021-12-18 00:41:23 +0100903 return CB_ERR;
Furquan Shaikh70063ff52020-05-11 14:28:13 -0700904 }
905 slave_config |= slave_en_mask;
906 } else {
907 slave_config &= ~slave_en_mask;
908 }
909
Raul E Rangel7222f7e2021-04-09 14:15:42 -0600910 espi_show_slave_peripheral_channel_configuration(slave_config);
911
Furquan Shaikh70063ff52020-05-11 14:28:13 -0700912 return espi_set_channel_configuration(slave_config, ESPI_SLAVE_PERIPH_CFG,
913 ESPI_PERIPH_CH_EN);
914}
915
Felix Held4b4114f72021-12-18 00:41:23 +0100916static enum cb_err espi_setup_oob_channel(const struct espi_config *mb_cfg, uint32_t slave_caps)
Furquan Shaikh70063ff52020-05-11 14:28:13 -0700917{
918 uint32_t slave_config;
919
920 if (!mb_cfg->oob_ch_en)
Felix Held4b4114f72021-12-18 00:41:23 +0100921 return CB_SUCCESS;
Furquan Shaikh70063ff52020-05-11 14:28:13 -0700922
923 if (!espi_slave_supports_oob_channel(slave_caps)) {
Julius Wernere9665952022-01-21 17:06:20 -0800924 printk(BIOS_ERR, "eSPI slave doesn't support OOB channel!\n");
Felix Held4b4114f72021-12-18 00:41:23 +0100925 return CB_ERR;
Furquan Shaikh70063ff52020-05-11 14:28:13 -0700926 }
927
Felix Held4b4114f72021-12-18 00:41:23 +0100928 if (espi_get_configuration(ESPI_SLAVE_OOB_CFG, &slave_config) != CB_SUCCESS)
929 return CB_ERR;
Furquan Shaikh70063ff52020-05-11 14:28:13 -0700930
931 slave_config |= ESPI_SLAVE_CHANNEL_ENABLE;
932
933 return espi_set_channel_configuration(slave_config, ESPI_SLAVE_OOB_CFG,
934 ESPI_OOB_CH_EN);
935}
936
Felix Held4b4114f72021-12-18 00:41:23 +0100937static enum cb_err espi_setup_flash_channel(const struct espi_config *mb_cfg,
938 uint32_t slave_caps)
Furquan Shaikh70063ff52020-05-11 14:28:13 -0700939{
940 uint32_t slave_config;
941
942 if (!mb_cfg->flash_ch_en)
Felix Held4b4114f72021-12-18 00:41:23 +0100943 return CB_SUCCESS;
Furquan Shaikh70063ff52020-05-11 14:28:13 -0700944
945 if (!espi_slave_supports_flash_channel(slave_caps)) {
Julius Wernere9665952022-01-21 17:06:20 -0800946 printk(BIOS_ERR, "eSPI slave doesn't support flash channel!\n");
Felix Held4b4114f72021-12-18 00:41:23 +0100947 return CB_ERR;
Furquan Shaikh70063ff52020-05-11 14:28:13 -0700948 }
949
Felix Held4b4114f72021-12-18 00:41:23 +0100950 if (espi_get_configuration(ESPI_SLAVE_FLASH_CFG, &slave_config) != CB_SUCCESS)
951 return CB_ERR;
Furquan Shaikh70063ff52020-05-11 14:28:13 -0700952
953 slave_config |= ESPI_SLAVE_CHANNEL_ENABLE;
954
955 return espi_set_channel_configuration(slave_config, ESPI_SLAVE_FLASH_CFG,
956 ESPI_FLASH_CH_EN);
957}
958
Felix Held687ec6b2022-12-13 18:05:00 +0100959static enum cb_err espi_set_initial_config(const struct espi_config *mb_cfg)
Furquan Shaikh70063ff52020-05-11 14:28:13 -0700960{
961 uint32_t espi_initial_mode = ESPI_OP_FREQ_16_MHZ | ESPI_IO_MODE_SINGLE;
962
Raul E Rangeldcec4092021-05-07 15:35:10 -0600963 switch (mb_cfg->alert_pin) {
964 case ESPI_ALERT_PIN_IN_BAND:
965 break;
966 case ESPI_ALERT_PIN_PUSH_PULL:
967 case ESPI_ALERT_PIN_OPEN_DRAIN:
968 espi_initial_mode |= ESPI_ALERT_MODE;
969 break;
970 default:
Felix Held687ec6b2022-12-13 18:05:00 +0100971 printk(BIOS_ERR, "Unknown espi alert config: %u!\n", mb_cfg->alert_pin);
972 return CB_ERR;
Raul E Rangeldcec4092021-05-07 15:35:10 -0600973 }
974
Furquan Shaikh70063ff52020-05-11 14:28:13 -0700975 espi_write32(ESPI_SLAVE0_CONFIG, espi_initial_mode);
Felix Held687ec6b2022-12-13 18:05:00 +0100976 return CB_SUCCESS;
Furquan Shaikh70063ff52020-05-11 14:28:13 -0700977}
978
979static void espi_setup_subtractive_decode(const struct espi_config *mb_cfg)
980{
981 uint32_t global_ctrl_reg;
982 global_ctrl_reg = espi_read32(ESPI_GLOBAL_CONTROL_1);
983
984 if (mb_cfg->subtractive_decode) {
985 global_ctrl_reg &= ~ESPI_SUB_DECODE_SLV_MASK;
986 global_ctrl_reg |= ESPI_SUB_DECODE_EN;
987
988 } else {
989 global_ctrl_reg &= ~ESPI_SUB_DECODE_EN;
990 }
991 espi_write32(ESPI_GLOBAL_CONTROL_1, global_ctrl_reg);
992}
993
Felix Heldaed38a92021-12-18 00:41:23 +0100994enum cb_err espi_setup(void)
Furquan Shaikh70063ff52020-05-11 14:28:13 -0700995{
Raul E Rangeldbeae6a2022-04-25 13:32:35 -0600996 uint32_t slave_caps, ctrl;
Furquan Shaikh70063ff52020-05-11 14:28:13 -0700997 const struct espi_config *cfg = espi_get_config();
998
Martin Roth7a2bfeb2021-05-14 10:57:31 -0600999 printk(BIOS_SPEW, "Initializing ESPI.\n");
1000
Raul E Rangelb92383a2021-04-02 10:32:03 -06001001 espi_write32(ESPI_GLOBAL_CONTROL_0, ESPI_AL_STOP_EN);
1002 espi_write32(ESPI_GLOBAL_CONTROL_1, ESPI_RGCMD_INT(23) | ESPI_ERR_INT_SMI);
1003 espi_write32(ESPI_SLAVE0_INT_EN, 0);
1004 espi_clear_status();
Raul E Rangelb95f8482021-04-02 13:47:09 -06001005 espi_clear_decodes();
Raul E Rangelb92383a2021-04-02 10:32:03 -06001006
Furquan Shaikh70063ff52020-05-11 14:28:13 -07001007 /*
1008 * Boot sequence: Step 1
1009 * Set correct initial configuration to talk to the slave:
1010 * Set clock frequency to 16.7MHz and single IO mode.
1011 */
Felix Held687ec6b2022-12-13 18:05:00 +01001012 if (espi_set_initial_config(cfg) != CB_SUCCESS)
1013 return CB_ERR;
Furquan Shaikh70063ff52020-05-11 14:28:13 -07001014
1015 /*
1016 * Boot sequence: Step 2
1017 * Send in-band reset
1018 * The resets affects both host and slave devices, so set initial config again.
1019 */
Felix Held4b4114f72021-12-18 00:41:23 +01001020 if (espi_send_reset() != CB_SUCCESS) {
Julius Wernere9665952022-01-21 17:06:20 -08001021 printk(BIOS_ERR, "In-band reset failed!\n");
Felix Heldaed38a92021-12-18 00:41:23 +01001022 return CB_ERR;
Furquan Shaikh70063ff52020-05-11 14:28:13 -07001023 }
Felix Held687ec6b2022-12-13 18:05:00 +01001024
1025 if (espi_set_initial_config(cfg) != CB_SUCCESS)
1026 return CB_ERR;
Furquan Shaikh70063ff52020-05-11 14:28:13 -07001027
1028 /*
1029 * Boot sequence: Step 3
1030 * Get configuration of slave device.
1031 */
Felix Held4b4114f72021-12-18 00:41:23 +01001032 if (espi_get_general_configuration(&slave_caps) != CB_SUCCESS) {
Julius Wernere9665952022-01-21 17:06:20 -08001033 printk(BIOS_ERR, "Slave GET_CONFIGURATION failed!\n");
Felix Heldaed38a92021-12-18 00:41:23 +01001034 return CB_ERR;
Furquan Shaikh70063ff52020-05-11 14:28:13 -07001035 }
1036
1037 /*
1038 * Boot sequence:
1039 * Step 4: Write slave device general config
1040 * Step 5: Set host slave config
1041 */
Felix Held4b4114f72021-12-18 00:41:23 +01001042 if (espi_set_general_configuration(cfg, slave_caps) != CB_SUCCESS) {
Julius Wernere9665952022-01-21 17:06:20 -08001043 printk(BIOS_ERR, "Slave SET_CONFIGURATION failed!\n");
Felix Heldaed38a92021-12-18 00:41:23 +01001044 return CB_ERR;
Furquan Shaikh70063ff52020-05-11 14:28:13 -07001045 }
1046
1047 /*
1048 * Setup polarity before enabling the VW channel so any interrupts
1049 * received will have the correct polarity.
1050 */
1051 espi_write32(ESPI_RXVW_POLARITY, cfg->vw_irq_polarity);
1052
1053 /*
1054 * Boot Sequences: Steps 6 - 9
1055 * Channel setup
1056 */
1057 /* Set up VW first so we can deassert PLTRST#. */
Felix Held4b4114f72021-12-18 00:41:23 +01001058 if (espi_setup_vw_channel(cfg, slave_caps) != CB_SUCCESS) {
Julius Wernere9665952022-01-21 17:06:20 -08001059 printk(BIOS_ERR, "Setup VW channel failed!\n");
Felix Heldaed38a92021-12-18 00:41:23 +01001060 return CB_ERR;
Furquan Shaikh70063ff52020-05-11 14:28:13 -07001061 }
1062
Raul E Rangel43aa5272021-05-21 17:04:28 -06001063 /* Assert PLTRST# if VW channel is enabled by mainboard. */
Felix Held4b4114f72021-12-18 00:41:23 +01001064 if (espi_send_pltrst(cfg, true) != CB_SUCCESS) {
Julius Wernere9665952022-01-21 17:06:20 -08001065 printk(BIOS_ERR, "PLTRST# assertion failed!\n");
Felix Heldaed38a92021-12-18 00:41:23 +01001066 return CB_ERR;
Raul E Rangel43aa5272021-05-21 17:04:28 -06001067 }
1068
Furquan Shaikh70063ff52020-05-11 14:28:13 -07001069 /* De-assert PLTRST# if VW channel is enabled by mainboard. */
Felix Held4b4114f72021-12-18 00:41:23 +01001070 if (espi_send_pltrst(cfg, false) != CB_SUCCESS) {
Julius Wernere9665952022-01-21 17:06:20 -08001071 printk(BIOS_ERR, "PLTRST# deassertion failed!\n");
Felix Heldaed38a92021-12-18 00:41:23 +01001072 return CB_ERR;
Furquan Shaikh70063ff52020-05-11 14:28:13 -07001073 }
1074
Felix Held4b4114f72021-12-18 00:41:23 +01001075 if (espi_setup_periph_channel(cfg, slave_caps) != CB_SUCCESS) {
Julius Wernere9665952022-01-21 17:06:20 -08001076 printk(BIOS_ERR, "Setup Periph channel failed!\n");
Felix Heldaed38a92021-12-18 00:41:23 +01001077 return CB_ERR;
Furquan Shaikh70063ff52020-05-11 14:28:13 -07001078 }
1079
Felix Held4b4114f72021-12-18 00:41:23 +01001080 if (espi_setup_oob_channel(cfg, slave_caps) != CB_SUCCESS) {
Julius Wernere9665952022-01-21 17:06:20 -08001081 printk(BIOS_ERR, "Setup OOB channel failed!\n");
Felix Heldaed38a92021-12-18 00:41:23 +01001082 return CB_ERR;
Furquan Shaikh70063ff52020-05-11 14:28:13 -07001083 }
1084
Felix Held4b4114f72021-12-18 00:41:23 +01001085 if (espi_setup_flash_channel(cfg, slave_caps) != CB_SUCCESS) {
Julius Wernere9665952022-01-21 17:06:20 -08001086 printk(BIOS_ERR, "Setup Flash channel failed!\n");
Felix Heldaed38a92021-12-18 00:41:23 +01001087 return CB_ERR;
Furquan Shaikh70063ff52020-05-11 14:28:13 -07001088 }
1089
Felix Heldaed38a92021-12-18 00:41:23 +01001090 if (espi_configure_decodes(cfg) != CB_SUCCESS) {
Julius Wernere9665952022-01-21 17:06:20 -08001091 printk(BIOS_ERR, "Configuring decodes failed!\n");
Felix Heldaed38a92021-12-18 00:41:23 +01001092 return CB_ERR;
Raul E Rangel61ac1bc2021-04-02 10:55:27 -06001093 }
1094
Furquan Shaikh70063ff52020-05-11 14:28:13 -07001095 /* Enable subtractive decode if configured */
Felix Helda2642d02021-02-17 00:32:46 +01001096 espi_setup_subtractive_decode(cfg);
Furquan Shaikh70063ff52020-05-11 14:28:13 -07001097
Raul E Rangeldbeae6a2022-04-25 13:32:35 -06001098 ctrl = espi_read32(ESPI_GLOBAL_CONTROL_1);
1099 ctrl |= ESPI_BUS_MASTER_EN;
1100
1101 if (CONFIG(SOC_AMD_COMMON_BLOCK_HAS_ESPI_ALERT_ENABLE))
1102 ctrl |= ESPI_ALERT_ENABLE;
1103
1104 espi_write32(ESPI_GLOBAL_CONTROL_1, ctrl);
Raul E Rangelb92383a2021-04-02 10:32:03 -06001105
Martin Roth7a2bfeb2021-05-14 10:57:31 -06001106 printk(BIOS_SPEW, "Finished initializing ESPI.\n");
1107
Felix Heldaed38a92021-12-18 00:41:23 +01001108 return CB_SUCCESS;
Furquan Shaikh70063ff52020-05-11 14:28:13 -07001109}
Felix Held1c03da52021-10-14 21:48:13 +02001110
1111/* Setup eSPI with any mainboard specific initialization. */
1112void configure_espi_with_mb_hook(void)
1113{
1114 mb_set_up_early_espi();
1115 espi_setup();
1116}