blob: d9b4715b5e3ef733a1bbc4cca342ad91d06f8ec9 [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>
6#include <arch/mmio.h>
7#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
Furquan Shaikh98bc9612020-05-09 19:31:55 -070013static uintptr_t espi_bar;
14
15void espi_update_static_bar(uintptr_t bar)
16{
17 espi_bar = bar;
18}
19
Martin Rothfe589772021-06-25 15:09:43 -060020__weak void mb_set_up_early_espi(void)
21{
22}
23
Furquan Shaikhf318e032020-05-04 23:38:53 -070024static uintptr_t espi_get_bar(void)
25{
Martin Rothb39e10d2020-07-14 11:08:55 -060026 if (ENV_X86 && !espi_bar)
27 espi_update_static_bar(lpc_get_spibase() + ESPI_OFFSET_FROM_BAR);
Furquan Shaikh98bc9612020-05-09 19:31:55 -070028 return espi_bar;
Furquan Shaikhf318e032020-05-04 23:38:53 -070029}
30
Felix Held92dd6782020-08-10 20:27:58 +020031static uint32_t espi_read32(unsigned int reg)
Furquan Shaikhf318e032020-05-04 23:38:53 -070032{
33 return read32((void *)(espi_get_bar() + reg));
34}
35
Felix Held92dd6782020-08-10 20:27:58 +020036static void espi_write32(unsigned int reg, uint32_t val)
Furquan Shaikhf318e032020-05-04 23:38:53 -070037{
38 write32((void *)(espi_get_bar() + reg), val);
39}
40
Felix Held92dd6782020-08-10 20:27:58 +020041static uint16_t espi_read16(unsigned int reg)
Furquan Shaikhf318e032020-05-04 23:38:53 -070042{
43 return read16((void *)(espi_get_bar() + reg));
44}
45
Felix Held92dd6782020-08-10 20:27:58 +020046static void espi_write16(unsigned int reg, uint16_t val)
Furquan Shaikhf318e032020-05-04 23:38:53 -070047{
48 write16((void *)(espi_get_bar() + reg), val);
49}
50
Felix Held92dd6782020-08-10 20:27:58 +020051static uint8_t espi_read8(unsigned int reg)
Furquan Shaikhf318e032020-05-04 23:38:53 -070052{
53 return read8((void *)(espi_get_bar() + reg));
54}
55
Felix Held92dd6782020-08-10 20:27:58 +020056static void espi_write8(unsigned int reg, uint8_t val)
Furquan Shaikhf318e032020-05-04 23:38:53 -070057{
58 write8((void *)(espi_get_bar() + reg), val);
59}
60
Felix Heldf08fbf82020-08-10 20:30:36 +020061static void espi_enable_decode(uint32_t decode_en)
Furquan Shaikhf318e032020-05-04 23:38:53 -070062{
63 uint32_t val;
64
65 val = espi_read32(ESPI_DECODE);
66 val |= decode_en;
67 espi_write32(ESPI_DECODE, val);
68}
69
Felix Heldf08fbf82020-08-10 20:30:36 +020070static bool espi_is_decode_enabled(uint32_t decode)
Furquan Shaikhf318e032020-05-04 23:38:53 -070071{
72 uint32_t val;
73
74 val = espi_read32(ESPI_DECODE);
75 return !!(val & decode);
76}
77
78static int espi_find_io_window(uint16_t win_base)
79{
80 int i;
81
82 for (i = 0; i < ESPI_GENERIC_IO_WIN_COUNT; i++) {
83 if (!espi_is_decode_enabled(ESPI_DECODE_IO_RANGE_EN(i)))
84 continue;
85
86 if (espi_read16(ESPI_IO_RANGE_BASE(i)) == win_base)
87 return i;
88 }
89
90 return -1;
91}
92
93static int espi_get_unused_io_window(void)
94{
95 int i;
96
97 for (i = 0; i < ESPI_GENERIC_IO_WIN_COUNT; i++) {
98 if (!espi_is_decode_enabled(ESPI_DECODE_IO_RANGE_EN(i)))
99 return i;
100 }
101
102 return -1;
103}
104
Raul E Rangelb95f8482021-04-02 13:47:09 -0600105static void espi_clear_decodes(void)
Martin Roth011bf132021-03-23 13:20:42 -0600106{
107 unsigned int idx;
108
109 /* First turn off all enable bits, then zero base, range, and size registers */
Raul E Rangel01792e32021-04-26 13:52:38 -0600110 espi_write16(ESPI_DECODE, 0);
Martin Roth011bf132021-03-23 13:20:42 -0600111
112 for (idx = 0; idx < ESPI_GENERIC_IO_WIN_COUNT; idx++) {
113 espi_write16(ESPI_IO_RANGE_BASE(idx), 0);
114 espi_write8(ESPI_IO_RANGE_SIZE(idx), 0);
115 }
116 for (idx = 0; idx < ESPI_GENERIC_MMIO_WIN_COUNT; idx++) {
117 espi_write32(ESPI_MMIO_RANGE_BASE(idx), 0);
118 espi_write16(ESPI_MMIO_RANGE_SIZE(idx), 0);
119 }
120}
121
Furquan Shaikhf318e032020-05-04 23:38:53 -0700122/*
123 * Returns decode enable bits for standard IO port addresses. If port address is not supported
124 * by standard decode or if the size of window is not 1, then it returns -1.
125 */
126static int espi_std_io_decode(uint16_t base, size_t size)
127{
Felix Heldc0d4eeb2020-08-10 20:37:16 +0200128 if (size == 2 && base == 0x2e)
129 return ESPI_DECODE_IO_0X2E_0X2F_EN;
130
Furquan Shaikhf318e032020-05-04 23:38:53 -0700131 if (size != 1)
Felix Held4bf419f2020-08-10 20:33:25 +0200132 return -1;
Furquan Shaikhf318e032020-05-04 23:38:53 -0700133
134 switch (base) {
135 case 0x80:
Felix Held4bf419f2020-08-10 20:33:25 +0200136 return ESPI_DECODE_IO_0x80_EN;
Furquan Shaikhf318e032020-05-04 23:38:53 -0700137 case 0x60:
138 case 0x64:
Felix Held4bf419f2020-08-10 20:33:25 +0200139 return ESPI_DECODE_IO_0X60_0X64_EN;
Furquan Shaikhf318e032020-05-04 23:38:53 -0700140 case 0x2e:
141 case 0x2f:
Felix Held4bf419f2020-08-10 20:33:25 +0200142 return ESPI_DECODE_IO_0X2E_0X2F_EN;
Furquan Shaikhf318e032020-05-04 23:38:53 -0700143 default:
Felix Held4bf419f2020-08-10 20:33:25 +0200144 return -1;
Furquan Shaikhf318e032020-05-04 23:38:53 -0700145 }
Furquan Shaikhf318e032020-05-04 23:38:53 -0700146}
147
148static size_t espi_get_io_window_size(int idx)
149{
150 return espi_read8(ESPI_IO_RANGE_SIZE(idx)) + 1;
151}
152
153static void espi_write_io_window(int idx, uint16_t base, size_t size)
154{
155 espi_write16(ESPI_IO_RANGE_BASE(idx), base);
156 espi_write8(ESPI_IO_RANGE_SIZE(idx), size - 1);
157}
158
Felix Heldaed38a92021-12-18 00:41:23 +0100159static enum cb_err espi_open_generic_io_window(uint16_t base, size_t size)
Furquan Shaikhf318e032020-05-04 23:38:53 -0700160{
161 size_t win_size;
162 int idx;
163
164 for (; size; size -= win_size, base += win_size) {
165 win_size = MIN(size, ESPI_GENERIC_IO_MAX_WIN_SIZE);
166
167 idx = espi_find_io_window(base);
168 if (idx != -1) {
169 size_t curr_size = espi_get_io_window_size(idx);
170
171 if (curr_size > win_size) {
172 printk(BIOS_INFO, "eSPI window already configured to be larger than requested! ");
173 printk(BIOS_INFO, "Base: 0x%x, Requested size: 0x%zx, Actual size: 0x%zx\n",
174 base, win_size, curr_size);
175 } else if (curr_size < win_size) {
176 espi_write_io_window(idx, base, win_size);
177 printk(BIOS_INFO, "eSPI window at base: 0x%x resized from 0x%zx to 0x%zx\n",
178 base, curr_size, win_size);
179 }
180
181 continue;
182 }
183
184 idx = espi_get_unused_io_window();
185 if (idx == -1) {
186 printk(BIOS_ERR, "Cannot open IO window base %x size %zx\n", base,
187 size);
188 printk(BIOS_ERR, "ERROR: No more available IO windows!\n");
Felix Heldaed38a92021-12-18 00:41:23 +0100189 return CB_ERR;
Furquan Shaikhf318e032020-05-04 23:38:53 -0700190 }
191
192 espi_write_io_window(idx, base, win_size);
193 espi_enable_decode(ESPI_DECODE_IO_RANGE_EN(idx));
194 }
195
Felix Heldaed38a92021-12-18 00:41:23 +0100196 return CB_SUCCESS;
Furquan Shaikhf318e032020-05-04 23:38:53 -0700197}
198
Felix Heldaed38a92021-12-18 00:41:23 +0100199enum cb_err espi_open_io_window(uint16_t base, size_t size)
Furquan Shaikhf318e032020-05-04 23:38:53 -0700200{
201 int std_io;
202
203 std_io = espi_std_io_decode(base, size);
204 if (std_io != -1) {
205 espi_enable_decode(std_io);
Felix Heldaed38a92021-12-18 00:41:23 +0100206 return CB_SUCCESS;
Felix Heldb026c7c2020-08-10 20:43:53 +0200207 } else {
208 return espi_open_generic_io_window(base, size);
Furquan Shaikhf318e032020-05-04 23:38:53 -0700209 }
Furquan Shaikhf318e032020-05-04 23:38:53 -0700210}
211
212static int espi_find_mmio_window(uint32_t win_base)
213{
214 int i;
215
216 for (i = 0; i < ESPI_GENERIC_MMIO_WIN_COUNT; i++) {
217 if (!espi_is_decode_enabled(ESPI_DECODE_MMIO_RANGE_EN(i)))
218 continue;
219
220 if (espi_read32(ESPI_MMIO_RANGE_BASE(i)) == win_base)
221 return i;
222 }
223
224 return -1;
225}
226
227static int espi_get_unused_mmio_window(void)
228{
229 int i;
230
231 for (i = 0; i < ESPI_GENERIC_MMIO_WIN_COUNT; i++) {
232 if (!espi_is_decode_enabled(ESPI_DECODE_MMIO_RANGE_EN(i)))
233 return i;
234 }
235
236 return -1;
237
238}
239
240static size_t espi_get_mmio_window_size(int idx)
241{
242 return espi_read16(ESPI_MMIO_RANGE_SIZE(idx)) + 1;
243}
244
245static void espi_write_mmio_window(int idx, uint32_t base, size_t size)
246{
247 espi_write32(ESPI_MMIO_RANGE_BASE(idx), base);
248 espi_write16(ESPI_MMIO_RANGE_SIZE(idx), size - 1);
249}
250
Felix Heldaed38a92021-12-18 00:41:23 +0100251enum cb_err espi_open_mmio_window(uint32_t base, size_t size)
Furquan Shaikhf318e032020-05-04 23:38:53 -0700252{
253 size_t win_size;
254 int idx;
255
256 for (; size; size -= win_size, base += win_size) {
257 win_size = MIN(size, ESPI_GENERIC_MMIO_MAX_WIN_SIZE);
258
259 idx = espi_find_mmio_window(base);
260 if (idx != -1) {
261 size_t curr_size = espi_get_mmio_window_size(idx);
262
263 if (curr_size > win_size) {
264 printk(BIOS_INFO, "eSPI window already configured to be larger than requested! ");
265 printk(BIOS_INFO, "Base: 0x%x, Requested size: 0x%zx, Actual size: 0x%zx\n",
266 base, win_size, curr_size);
267 } else if (curr_size < win_size) {
268 espi_write_mmio_window(idx, base, win_size);
269 printk(BIOS_INFO, "eSPI window at base: 0x%x resized from 0x%zx to 0x%zx\n",
270 base, curr_size, win_size);
271 }
272
273 continue;
274 }
275
276 idx = espi_get_unused_mmio_window();
277 if (idx == -1) {
278 printk(BIOS_ERR, "Cannot open IO window base %x size %zx\n", base,
279 size);
280 printk(BIOS_ERR, "ERROR: No more available MMIO windows!\n");
Felix Heldaed38a92021-12-18 00:41:23 +0100281 return CB_ERR;
Furquan Shaikhf318e032020-05-04 23:38:53 -0700282 }
283
284 espi_write_mmio_window(idx, base, win_size);
285 espi_enable_decode(ESPI_DECODE_MMIO_RANGE_EN(idx));
286 }
287
Felix Heldaed38a92021-12-18 00:41:23 +0100288 return CB_SUCCESS;
Furquan Shaikhf318e032020-05-04 23:38:53 -0700289}
290
291static const struct espi_config *espi_get_config(void)
292{
293 const struct soc_amd_common_config *soc_cfg = soc_get_common_config();
294
295 if (!soc_cfg)
296 die("Common config structure is NULL!\n");
297
298 return &soc_cfg->espi_config;
299}
300
Felix Heldaed38a92021-12-18 00:41:23 +0100301static enum cb_err espi_configure_decodes(const struct espi_config *cfg)
Furquan Shaikhf318e032020-05-04 23:38:53 -0700302{
Felix Held9e830542021-12-18 00:41:23 +0100303 int i;
Furquan Shaikhf318e032020-05-04 23:38:53 -0700304
305 espi_enable_decode(cfg->std_io_decode_bitmap);
306
307 for (i = 0; i < ESPI_GENERIC_IO_WIN_COUNT; i++) {
308 if (cfg->generic_io_range[i].size == 0)
309 continue;
Felix Held9e830542021-12-18 00:41:23 +0100310 if (espi_open_generic_io_window(cfg->generic_io_range[i].base,
Felix Heldaed38a92021-12-18 00:41:23 +0100311 cfg->generic_io_range[i].size) != CB_SUCCESS)
312 return CB_ERR;
Furquan Shaikhf318e032020-05-04 23:38:53 -0700313 }
Raul E Rangel61ac1bc2021-04-02 10:55:27 -0600314
Felix Heldaed38a92021-12-18 00:41:23 +0100315 return CB_SUCCESS;
Furquan Shaikhf318e032020-05-04 23:38:53 -0700316}
Furquan Shaikh70063ff52020-05-11 14:28:13 -0700317
318#define ESPI_DN_TX_HDR0 0x00
319enum espi_cmd_type {
320 CMD_TYPE_SET_CONFIGURATION = 0,
321 CMD_TYPE_GET_CONFIGURATION = 1,
322 CMD_TYPE_IN_BAND_RESET = 2,
323 CMD_TYPE_PERIPHERAL = 4,
324 CMD_TYPE_VW = 5,
325 CMD_TYPE_OOB = 6,
326 CMD_TYPE_FLASH = 7,
327};
328
329#define ESPI_DN_TX_HDR1 0x04
330#define ESPI_DN_TX_HDR2 0x08
331#define ESPI_DN_TX_DATA 0x0c
332
333#define ESPI_MASTER_CAP 0x2c
334#define ESPI_VW_MAX_SIZE_SHIFT 13
335#define ESPI_VW_MAX_SIZE_MASK (0x3f << ESPI_VW_MAX_SIZE_SHIFT)
336
Raul E Rangel1d0e4932021-04-02 10:27:11 -0600337#define ESPI_GLOBAL_CONTROL_0 0x30
338#define ESPI_WAIT_CNT_SHIFT 24
339#define ESPI_WAIT_CNT_MASK (0x3F << ESPI_WAIT_CNT_SHIFT)
340#define ESPI_WDG_CNT_SHIFT 8
341#define ESPI_WDG_CNT_MASK (0xFFFF << ESPI_WDG_CNT_SHIFT)
342#define ESPI_AL_IDLE_TIMER_SHIFT 4
343#define ESPI_AL_IDLE_TIMER_MASK (0x7 << ESPI_AL_IDLE_TIMER_SHIFT)
344#define ESPI_AL_STOP_EN (1 << 3)
345#define ESPI_PR_CLKGAT_EN (1 << 2)
346#define ESPI_WAIT_CHKEN (1 << 1)
347#define ESPI_WDG_EN (1 << 0)
348
Furquan Shaikh70063ff52020-05-11 14:28:13 -0700349#define ESPI_GLOBAL_CONTROL_1 0x34
Raul E Rangel1d0e4932021-04-02 10:27:11 -0600350#define ESPI_RGCMD_INT_MAP_SHIFT 13
351#define ESPI_RGCMD_INT_MAP_MASK (0x1F << ESPI_RGCMD_INT_MAP_SHIFT)
352#define ESPI_RGCMD_INT(irq) ((irq) << ESPI_RGCMD_INT_MAP_SHIFT)
353#define ESPI_RGCMD_INT_SMI (0x1F << ESPI_RGCMD_INT_MAP_SHIFT)
354#define ESPI_ERR_INT_MAP_SHIFT 8
355#define ESPI_ERR_INT_MAP_MASK (0x1F << ESPI_ERR_INT_MAP_SHIFT)
356#define ESPI_ERR_INT(irq) ((irq) << ESPI_ERR_INT_MAP_SHIFT)
357#define ESPI_ERR_INT_SMI (0x1F << ESPI_ERR_INT_MAP_SHIFT)
Furquan Shaikh70063ff52020-05-11 14:28:13 -0700358#define ESPI_SUB_DECODE_SLV_SHIFT 3
359#define ESPI_SUB_DECODE_SLV_MASK (0x3 << ESPI_SUB_DECODE_SLV_SHIFT)
360#define ESPI_SUB_DECODE_EN (1 << 2)
Raul E Rangel1d0e4932021-04-02 10:27:11 -0600361#define ESPI_BUS_MASTER_EN (1 << 1)
362#define ESPI_SW_RST (1 << 0)
Furquan Shaikh70063ff52020-05-11 14:28:13 -0700363
Raul E Rangel1d0e4932021-04-02 10:27:11 -0600364#define ESPI_SLAVE0_INT_EN 0x6C
Raul E Rangel47740122021-04-02 10:16:54 -0600365#define ESPI_SLAVE0_INT_STS 0x70
Furquan Shaikh70063ff52020-05-11 14:28:13 -0700366#define ESPI_STATUS_DNCMD_COMPLETE (1 << 28)
367#define ESPI_STATUS_NON_FATAL_ERROR (1 << 6)
368#define ESPI_STATUS_FATAL_ERROR (1 << 5)
369#define ESPI_STATUS_NO_RESPONSE (1 << 4)
370#define ESPI_STATUS_CRC_ERR (1 << 2)
371#define ESPI_STATUS_WAIT_TIMEOUT (1 << 1)
372#define ESPI_STATUS_BUS_ERROR (1 << 0)
373
374#define ESPI_RXVW_POLARITY 0xac
375
376#define ESPI_CMD_TIMEOUT_US 100
Raul E Rangel0318dc12021-05-21 16:31:52 -0600377#define ESPI_CH_READY_TIMEOUT_US 10000
Furquan Shaikh70063ff52020-05-11 14:28:13 -0700378
379union espi_txhdr0 {
380 uint32_t val;
381 struct {
382 uint32_t cmd_type:3;
383 uint32_t cmd_sts:1;
384 uint32_t slave_sel:2;
385 uint32_t rsvd:2;
386 uint32_t hdata0:8;
387 uint32_t hdata1:8;
388 uint32_t hdata2:8;
389 };
390} __packed;
391
392union espi_txhdr1 {
393 uint32_t val;
394 struct {
395 uint32_t hdata3:8;
396 uint32_t hdata4:8;
397 uint32_t hdata5:8;
398 uint32_t hdata6:8;
399 };
400} __packed;
401
402union espi_txhdr2 {
403 uint32_t val;
404 struct {
405 uint32_t hdata7:8;
406 uint32_t rsvd:24;
407 };
408} __packed;
409
410union espi_txdata {
411 uint32_t val;
412 struct {
413 uint32_t byte0:8;
414 uint32_t byte1:8;
415 uint32_t byte2:8;
416 uint32_t byte3:8;
417 };
418} __packed;
419
420struct espi_cmd {
421 union espi_txhdr0 hdr0;
422 union espi_txhdr1 hdr1;
423 union espi_txhdr2 hdr2;
424 union espi_txdata data;
Raul E Rangel12c05422021-05-11 11:13:38 -0600425 uint32_t expected_status_codes;
Furquan Shaikh70063ff52020-05-11 14:28:13 -0700426} __packed;
427
428/* Wait up to ESPI_CMD_TIMEOUT_US for hardware to clear DNCMD_STATUS bit. */
Felix Held4b4114f72021-12-18 00:41:23 +0100429static enum cb_err espi_wait_ready(void)
Furquan Shaikh70063ff52020-05-11 14:28:13 -0700430{
431 struct stopwatch sw;
432 union espi_txhdr0 hdr0;
433
434 stopwatch_init_usecs_expire(&sw, ESPI_CMD_TIMEOUT_US);
435 do {
436 hdr0.val = espi_read32(ESPI_DN_TX_HDR0);
437 if (!hdr0.cmd_sts)
Felix Held4b4114f72021-12-18 00:41:23 +0100438 return CB_SUCCESS;
Furquan Shaikh70063ff52020-05-11 14:28:13 -0700439 } while (!stopwatch_expired(&sw));
440
Felix Held4b4114f72021-12-18 00:41:23 +0100441 return CB_ERR;
Furquan Shaikh70063ff52020-05-11 14:28:13 -0700442}
443
444/* Clear interrupt status register */
445static void espi_clear_status(void)
446{
Raul E Rangel47740122021-04-02 10:16:54 -0600447 uint32_t status = espi_read32(ESPI_SLAVE0_INT_STS);
Furquan Shaikh70063ff52020-05-11 14:28:13 -0700448 if (status)
Raul E Rangel47740122021-04-02 10:16:54 -0600449 espi_write32(ESPI_SLAVE0_INT_STS, status);
Furquan Shaikh70063ff52020-05-11 14:28:13 -0700450}
451
452/*
453 * Wait up to ESPI_CMD_TIMEOUT_US for interrupt status register to update after sending a
454 * command.
455 */
Felix Held4b4114f72021-12-18 00:41:23 +0100456static enum cb_err espi_poll_status(uint32_t *status)
Furquan Shaikh70063ff52020-05-11 14:28:13 -0700457{
458 struct stopwatch sw;
459
460 stopwatch_init_usecs_expire(&sw, ESPI_CMD_TIMEOUT_US);
461 do {
Raul E Rangel47740122021-04-02 10:16:54 -0600462 *status = espi_read32(ESPI_SLAVE0_INT_STS);
Furquan Shaikh70063ff52020-05-11 14:28:13 -0700463 if (*status)
Felix Held4b4114f72021-12-18 00:41:23 +0100464 return CB_SUCCESS;
Furquan Shaikh70063ff52020-05-11 14:28:13 -0700465 } while (!stopwatch_expired(&sw));
466
467 printk(BIOS_ERR, "Error: eSPI timed out waiting for status update.\n");
468
Felix Held4b4114f72021-12-18 00:41:23 +0100469 return CB_ERR;
Furquan Shaikh70063ff52020-05-11 14:28:13 -0700470}
471
472static void espi_show_failure(const struct espi_cmd *cmd, const char *str, uint32_t status)
473{
474 printk(BIOS_ERR, "eSPI cmd0-cmd2: %08x %08x %08x data: %08x.\n",
475 cmd->hdr0.val, cmd->hdr1.val, cmd->hdr2.val, cmd->data.val);
476 printk(BIOS_ERR, "%s (Status = 0x%x)\n", str, status);
477}
478
Felix Held4b4114f72021-12-18 00:41:23 +0100479static enum cb_err espi_send_command(const struct espi_cmd *cmd)
Furquan Shaikh70063ff52020-05-11 14:28:13 -0700480{
481 uint32_t status;
482
483 if (CONFIG(ESPI_DEBUG))
Raul E Rangelf7027052021-06-29 13:12:19 -0600484 printk(BIOS_DEBUG, "eSPI cmd0-cmd2: %08x %08x %08x data: %08x.\n",
Furquan Shaikh70063ff52020-05-11 14:28:13 -0700485 cmd->hdr0.val, cmd->hdr1.val, cmd->hdr2.val, cmd->data.val);
486
Felix Held4b4114f72021-12-18 00:41:23 +0100487 if (espi_wait_ready() != CB_SUCCESS) {
Furquan Shaikh70063ff52020-05-11 14:28:13 -0700488 espi_show_failure(cmd, "Error: eSPI was not ready to accept a command", 0);
Felix Held4b4114f72021-12-18 00:41:23 +0100489 return CB_ERR;
Furquan Shaikh70063ff52020-05-11 14:28:13 -0700490 }
491
492 espi_clear_status();
493
494 espi_write32(ESPI_DN_TX_HDR1, cmd->hdr1.val);
495 espi_write32(ESPI_DN_TX_HDR2, cmd->hdr2.val);
496 espi_write32(ESPI_DN_TX_DATA, cmd->data.val);
497
498 /* Dword 0 must be last as this write triggers the transaction */
499 espi_write32(ESPI_DN_TX_HDR0, cmd->hdr0.val);
500
Felix Held4b4114f72021-12-18 00:41:23 +0100501 if (espi_wait_ready() != CB_SUCCESS) {
Furquan Shaikh70063ff52020-05-11 14:28:13 -0700502 espi_show_failure(cmd,
503 "Error: eSPI timed out waiting for command to complete", 0);
Felix Held4b4114f72021-12-18 00:41:23 +0100504 return CB_ERR;
Furquan Shaikh70063ff52020-05-11 14:28:13 -0700505 }
506
Felix Held4b4114f72021-12-18 00:41:23 +0100507 if (espi_poll_status(&status) != CB_SUCCESS) {
Felix Held1ba38332020-08-10 20:45:30 +0200508 espi_show_failure(cmd, "Error: eSPI poll status failed", 0);
Felix Held4b4114f72021-12-18 00:41:23 +0100509 return CB_ERR;
Furquan Shaikh70063ff52020-05-11 14:28:13 -0700510 }
511
512 /* If command did not complete downstream, return error. */
513 if (!(status & ESPI_STATUS_DNCMD_COMPLETE)) {
514 espi_show_failure(cmd, "Error: eSPI downstream command completion failure",
515 status);
Felix Held4b4114f72021-12-18 00:41:23 +0100516 return CB_ERR;
Furquan Shaikh70063ff52020-05-11 14:28:13 -0700517 }
518
Raul E Rangel12c05422021-05-11 11:13:38 -0600519 if (status & ~(ESPI_STATUS_DNCMD_COMPLETE | cmd->expected_status_codes)) {
Felix Held316d59c2020-08-10 20:42:20 +0200520 espi_show_failure(cmd, "Error: unexpected eSPI status register bits set",
521 status);
Felix Held4b4114f72021-12-18 00:41:23 +0100522 return CB_ERR;
Furquan Shaikh70063ff52020-05-11 14:28:13 -0700523 }
524
Raul E Rangel12c05422021-05-11 11:13:38 -0600525 espi_write32(ESPI_SLAVE0_INT_STS, status);
Raul E Rangel66c52ff2021-04-02 10:18:25 -0600526
Felix Held4b4114f72021-12-18 00:41:23 +0100527 return CB_SUCCESS;
Furquan Shaikh70063ff52020-05-11 14:28:13 -0700528}
529
Felix Held4b4114f72021-12-18 00:41:23 +0100530static enum cb_err espi_send_reset(void)
Furquan Shaikh70063ff52020-05-11 14:28:13 -0700531{
532 struct espi_cmd cmd = {
533 .hdr0 = {
534 .cmd_type = CMD_TYPE_IN_BAND_RESET,
535 .cmd_sts = 1,
536 },
Raul E Rangel12c05422021-05-11 11:13:38 -0600537
538 /*
539 * When performing an in-band reset the host controller and the
540 * peripheral can have mismatched IO configs.
541 *
542 * i.e., The eSPI peripheral can be in IO-4 mode while, the
543 * eSPI host will be in IO-1. This results in the peripheral
544 * getting invalid packets and thus not responding.
545 *
546 * If the peripheral is alerting when we perform an in-band
547 * reset, there is a race condition in espi_send_command.
548 * 1) espi_send_command clears the interrupt status.
549 * 2) eSPI host controller hardware notices the alert and sends
550 * a GET_STATUS.
551 * 3) espi_send_command writes the in-band reset command.
552 * 4) eSPI hardware enqueues the in-band reset until GET_STATUS
553 * is complete.
554 * 5) GET_STATUS fails with NO_RESPONSE and sets the interrupt
555 * status.
556 * 6) eSPI hardware performs in-band reset.
557 * 7) espi_send_command checks the status and sees a
558 * NO_RESPONSE bit.
559 *
560 * As a workaround we allow the NO_RESPONSE status code when
561 * we perform an in-band reset.
562 */
563 .expected_status_codes = ESPI_STATUS_NO_RESPONSE,
Furquan Shaikh70063ff52020-05-11 14:28:13 -0700564 };
565
566 return espi_send_command(&cmd);
567}
568
Felix Held4b4114f72021-12-18 00:41:23 +0100569static enum cb_err espi_send_pltrst(const struct espi_config *mb_cfg, bool assert)
Furquan Shaikh70063ff52020-05-11 14:28:13 -0700570{
571 struct espi_cmd cmd = {
572 .hdr0 = {
573 .cmd_type = CMD_TYPE_VW,
574 .cmd_sts = 1,
575 .hdata0 = 0, /* 1 VW group */
576 },
577 .data = {
578 .byte0 = ESPI_VW_INDEX_SYSTEM_EVENT_3,
Raul E Rangel43aa5272021-05-21 17:04:28 -0600579 .byte1 = assert ? ESPI_VW_SIGNAL_LOW(ESPI_VW_PLTRST)
580 : ESPI_VW_SIGNAL_HIGH(ESPI_VW_PLTRST),
Furquan Shaikh70063ff52020-05-11 14:28:13 -0700581 },
582 };
583
584 if (!mb_cfg->vw_ch_en)
Felix Held4b4114f72021-12-18 00:41:23 +0100585 return CB_SUCCESS;
Furquan Shaikh70063ff52020-05-11 14:28:13 -0700586
587 return espi_send_command(&cmd);
588}
589
590/*
591 * In case of get configuration command, hdata0 contains bits 15:8 of the slave register address
592 * and hdata1 contains bits 7:0 of the slave register address.
593 */
594#define ESPI_CONFIGURATION_HDATA0(a) (((a) >> 8) & 0xff)
595#define ESPI_CONFIGURATION_HDATA1(a) ((a) & 0xff)
596
Felix Held4b4114f72021-12-18 00:41:23 +0100597static enum cb_err espi_get_configuration(uint16_t slave_reg_addr, uint32_t *config)
Furquan Shaikh70063ff52020-05-11 14:28:13 -0700598{
599 struct espi_cmd cmd = {
600 .hdr0 = {
601 .cmd_type = CMD_TYPE_GET_CONFIGURATION,
602 .cmd_sts = 1,
603 .hdata0 = ESPI_CONFIGURATION_HDATA0(slave_reg_addr),
604 .hdata1 = ESPI_CONFIGURATION_HDATA1(slave_reg_addr),
605 },
606 };
607
608 *config = 0;
609
Felix Held4b4114f72021-12-18 00:41:23 +0100610 if (espi_send_command(&cmd) != CB_SUCCESS)
611 return CB_ERR;
Furquan Shaikh70063ff52020-05-11 14:28:13 -0700612
613 *config = espi_read32(ESPI_DN_TX_HDR1);
614
615 if (CONFIG(ESPI_DEBUG))
616 printk(BIOS_DEBUG, "Get configuration for slave register(0x%x): 0x%x\n",
617 slave_reg_addr, *config);
618
Felix Held4b4114f72021-12-18 00:41:23 +0100619 return CB_SUCCESS;
Furquan Shaikh70063ff52020-05-11 14:28:13 -0700620}
621
Felix Held4b4114f72021-12-18 00:41:23 +0100622static enum cb_err espi_set_configuration(uint16_t slave_reg_addr, uint32_t config)
Furquan Shaikh70063ff52020-05-11 14:28:13 -0700623{
624 struct espi_cmd cmd = {
625 .hdr0 = {
626 .cmd_type = CMD_TYPE_SET_CONFIGURATION,
627 .cmd_sts = 1,
628 .hdata0 = ESPI_CONFIGURATION_HDATA0(slave_reg_addr),
629 .hdata1 = ESPI_CONFIGURATION_HDATA1(slave_reg_addr),
630 },
631 .hdr1 = {
632 .val = config,
633 },
634 };
635
636 return espi_send_command(&cmd);
637}
638
Felix Held4b4114f72021-12-18 00:41:23 +0100639static enum cb_err espi_get_general_configuration(uint32_t *config)
Furquan Shaikh70063ff52020-05-11 14:28:13 -0700640{
Felix Held4b4114f72021-12-18 00:41:23 +0100641 if (espi_get_configuration(ESPI_SLAVE_GENERAL_CFG, config) != CB_SUCCESS)
642 return CB_ERR;
Furquan Shaikh70063ff52020-05-11 14:28:13 -0700643
644 espi_show_slave_general_configuration(*config);
Felix Held4b4114f72021-12-18 00:41:23 +0100645 return CB_SUCCESS;
Furquan Shaikh70063ff52020-05-11 14:28:13 -0700646}
647
648static void espi_set_io_mode_config(enum espi_io_mode mb_io_mode, uint32_t slave_caps,
649 uint32_t *slave_config, uint32_t *ctrlr_config)
650{
651 switch (mb_io_mode) {
652 case ESPI_IO_MODE_QUAD:
653 if (espi_slave_supports_quad_io(slave_caps)) {
654 *slave_config |= ESPI_SLAVE_IO_MODE_SEL_QUAD;
655 *ctrlr_config |= ESPI_IO_MODE_QUAD;
656 break;
657 }
658 printk(BIOS_ERR, "Error: eSPI Quad I/O not supported. Dropping to dual mode.\n");
659 /* Intentional fall-through */
660 case ESPI_IO_MODE_DUAL:
661 if (espi_slave_supports_dual_io(slave_caps)) {
662 *slave_config |= ESPI_SLAVE_IO_MODE_SEL_DUAL;
663 *ctrlr_config |= ESPI_IO_MODE_DUAL;
664 break;
665 }
666 printk(BIOS_ERR,
667 "Error: eSPI Dual I/O not supported. Dropping to single mode.\n");
668 /* Intentional fall-through */
669 case ESPI_IO_MODE_SINGLE:
670 /* Single I/O mode is always supported. */
671 *slave_config |= ESPI_SLAVE_IO_MODE_SEL_SINGLE;
672 *ctrlr_config |= ESPI_IO_MODE_SINGLE;
673 break;
674 default:
675 die("No supported eSPI I/O modes!\n");
676 }
677}
678
679static void espi_set_op_freq_config(enum espi_op_freq mb_op_freq, uint32_t slave_caps,
680 uint32_t *slave_config, uint32_t *ctrlr_config)
681{
682 int slave_max_speed_mhz = espi_slave_max_speed_mhz_supported(slave_caps);
683
684 switch (mb_op_freq) {
685 case ESPI_OP_FREQ_66_MHZ:
686 if (slave_max_speed_mhz >= 66) {
687 *slave_config |= ESPI_SLAVE_OP_FREQ_SEL_66_MHZ;
688 *ctrlr_config |= ESPI_OP_FREQ_66_MHZ;
689 break;
690 }
691 printk(BIOS_ERR, "Error: eSPI 66MHz not supported. Dropping to 33MHz.\n");
692 /* Intentional fall-through */
693 case ESPI_OP_FREQ_33_MHZ:
694 if (slave_max_speed_mhz >= 33) {
695 *slave_config |= ESPI_SLAVE_OP_FREQ_SEL_33_MHZ;
696 *ctrlr_config |= ESPI_OP_FREQ_33_MHZ;
697 break;
698 }
699 printk(BIOS_ERR, "Error: eSPI 33MHz not supported. Dropping to 16MHz.\n");
700 /* Intentional fall-through */
701 case ESPI_OP_FREQ_16_MHZ:
702 /*
703 * eSPI spec says the minimum frequency is 20MHz, but AMD datasheets support
704 * 16.7 Mhz.
705 */
706 if (slave_max_speed_mhz > 0) {
707 *slave_config |= ESPI_SLAVE_OP_FREQ_SEL_20_MHZ;
708 *ctrlr_config |= ESPI_OP_FREQ_16_MHZ;
709 break;
710 }
711 /* Intentional fall-through */
712 default:
713 die("No supported eSPI Operating Frequency!\n");
714 }
715}
716
Raul E Rangel8317e722021-05-05 13:38:27 -0600717static void espi_set_alert_pin_config(enum espi_alert_pin alert_pin, uint32_t slave_caps,
718 uint32_t *slave_config, uint32_t *ctrlr_config)
719{
720 switch (alert_pin) {
721 case ESPI_ALERT_PIN_IN_BAND:
722 *slave_config |= ESPI_SLAVE_ALERT_MODE_IO1;
723 return;
724 case ESPI_ALERT_PIN_PUSH_PULL:
725 *slave_config |= ESPI_SLAVE_ALERT_MODE_PIN | ESPI_SLAVE_PUSH_PULL_ALERT_SEL;
726 *ctrlr_config |= ESPI_ALERT_MODE;
727 return;
728 case ESPI_ALERT_PIN_OPEN_DRAIN:
729 if (!(slave_caps & ESPI_SLAVE_OPEN_DRAIN_ALERT_SUPP))
730 die("eSPI peripheral does not support open drain alert!");
731
732 *slave_config |= ESPI_SLAVE_ALERT_MODE_PIN | ESPI_SLAVE_OPEN_DRAIN_ALERT_SEL;
733 *ctrlr_config |= ESPI_ALERT_MODE;
734 return;
735 default:
736 die("Unknown espi alert config: %u!\n", alert_pin);
737 }
738}
739
Felix Held4b4114f72021-12-18 00:41:23 +0100740static enum cb_err espi_set_general_configuration(const struct espi_config *mb_cfg,
741 uint32_t slave_caps)
Furquan Shaikh70063ff52020-05-11 14:28:13 -0700742{
743 uint32_t slave_config = 0;
744 uint32_t ctrlr_config = 0;
745
746 if (mb_cfg->crc_check_enable) {
747 slave_config |= ESPI_SLAVE_CRC_ENABLE;
748 ctrlr_config |= ESPI_CRC_CHECKING_EN;
749 }
750
Raul E Rangel8317e722021-05-05 13:38:27 -0600751 espi_set_alert_pin_config(mb_cfg->alert_pin, slave_caps, &slave_config, &ctrlr_config);
Furquan Shaikh70063ff52020-05-11 14:28:13 -0700752 espi_set_io_mode_config(mb_cfg->io_mode, slave_caps, &slave_config, &ctrlr_config);
753 espi_set_op_freq_config(mb_cfg->op_freq_mhz, slave_caps, &slave_config, &ctrlr_config);
754
755 if (CONFIG(ESPI_DEBUG))
756 printk(BIOS_INFO, "Setting general configuration: slave: 0x%x controller: 0x%x\n",
757 slave_config, ctrlr_config);
758
Raul E Rangeld2d762a2021-05-05 13:30:10 -0600759 espi_show_slave_general_configuration(slave_config);
760
Felix Held4b4114f72021-12-18 00:41:23 +0100761 if (espi_set_configuration(ESPI_SLAVE_GENERAL_CFG, slave_config) != CB_SUCCESS)
762 return CB_ERR;
Furquan Shaikh70063ff52020-05-11 14:28:13 -0700763
764 espi_write32(ESPI_SLAVE0_CONFIG, ctrlr_config);
Felix Held4b4114f72021-12-18 00:41:23 +0100765 return CB_SUCCESS;
Furquan Shaikh70063ff52020-05-11 14:28:13 -0700766}
767
Felix Held4b4114f72021-12-18 00:41:23 +0100768static enum cb_err espi_wait_channel_ready(uint16_t slave_reg_addr)
Furquan Shaikh70063ff52020-05-11 14:28:13 -0700769{
770 struct stopwatch sw;
771 uint32_t config;
772
773 stopwatch_init_usecs_expire(&sw, ESPI_CH_READY_TIMEOUT_US);
774 do {
Felix Held5ba87a82021-12-18 00:41:23 +0100775 if (espi_get_configuration(slave_reg_addr, &config) != CB_SUCCESS)
776 return CB_ERR;
Furquan Shaikh70063ff52020-05-11 14:28:13 -0700777 if (espi_slave_is_channel_ready(config))
Felix Held4b4114f72021-12-18 00:41:23 +0100778 return CB_SUCCESS;
Furquan Shaikh70063ff52020-05-11 14:28:13 -0700779 } while (!stopwatch_expired(&sw));
780
781 printk(BIOS_ERR, "Error: Channel is not ready after %d usec (slave addr: 0x%x)\n",
782 ESPI_CH_READY_TIMEOUT_US, slave_reg_addr);
Felix Held4b4114f72021-12-18 00:41:23 +0100783 return CB_ERR;
Furquan Shaikh70063ff52020-05-11 14:28:13 -0700784
785}
786
787static void espi_enable_ctrlr_channel(uint32_t channel_en)
788{
789 uint32_t reg = espi_read32(ESPI_SLAVE0_CONFIG);
790
791 reg |= channel_en;
792
793 espi_write32(ESPI_SLAVE0_CONFIG, reg);
794}
795
Felix Held4b4114f72021-12-18 00:41:23 +0100796static enum cb_err espi_set_channel_configuration(uint32_t slave_config,
797 uint32_t slave_reg_addr,
798 uint32_t ctrlr_enable)
Furquan Shaikh70063ff52020-05-11 14:28:13 -0700799{
Felix Held4b4114f72021-12-18 00:41:23 +0100800 if (espi_set_configuration(slave_reg_addr, slave_config) != CB_SUCCESS)
801 return CB_ERR;
Furquan Shaikh70063ff52020-05-11 14:28:13 -0700802
803 if (!(slave_config & ESPI_SLAVE_CHANNEL_ENABLE))
Felix Held4b4114f72021-12-18 00:41:23 +0100804 return CB_SUCCESS;
Furquan Shaikh70063ff52020-05-11 14:28:13 -0700805
Felix Held4b4114f72021-12-18 00:41:23 +0100806 if (espi_wait_channel_ready(slave_reg_addr) != CB_SUCCESS)
807 return CB_ERR;
Furquan Shaikh70063ff52020-05-11 14:28:13 -0700808
809 espi_enable_ctrlr_channel(ctrlr_enable);
Felix Held4b4114f72021-12-18 00:41:23 +0100810 return CB_SUCCESS;
Furquan Shaikh70063ff52020-05-11 14:28:13 -0700811}
812
Felix Held4b4114f72021-12-18 00:41:23 +0100813static enum cb_err espi_setup_vw_channel(const struct espi_config *mb_cfg, uint32_t slave_caps)
Furquan Shaikh70063ff52020-05-11 14:28:13 -0700814{
815 uint32_t slave_vw_caps;
816 uint32_t ctrlr_vw_caps;
817 uint32_t slave_vw_count_supp;
818 uint32_t ctrlr_vw_count_supp;
819 uint32_t use_vw_count;
820 uint32_t slave_config;
821
822 if (!mb_cfg->vw_ch_en)
Felix Held4b4114f72021-12-18 00:41:23 +0100823 return CB_SUCCESS;
Furquan Shaikh70063ff52020-05-11 14:28:13 -0700824
825 if (!espi_slave_supports_vw_channel(slave_caps)) {
826 printk(BIOS_ERR, "Error: eSPI slave doesn't support VW channel!\n");
Felix Held4b4114f72021-12-18 00:41:23 +0100827 return CB_ERR;
Furquan Shaikh70063ff52020-05-11 14:28:13 -0700828 }
829
Felix Held4b4114f72021-12-18 00:41:23 +0100830 if (espi_get_configuration(ESPI_SLAVE_VW_CFG, &slave_vw_caps) != CB_SUCCESS)
831 return CB_ERR;
Furquan Shaikh70063ff52020-05-11 14:28:13 -0700832
833 ctrlr_vw_caps = espi_read32(ESPI_MASTER_CAP);
834 ctrlr_vw_count_supp = (ctrlr_vw_caps & ESPI_VW_MAX_SIZE_MASK) >> ESPI_VW_MAX_SIZE_SHIFT;
835
836 slave_vw_count_supp = espi_slave_get_vw_count_supp(slave_vw_caps);
837 use_vw_count = MIN(ctrlr_vw_count_supp, slave_vw_count_supp);
838
839 slave_config = ESPI_SLAVE_CHANNEL_ENABLE | ESPI_SLAVE_VW_COUNT_SEL_VAL(use_vw_count);
840 return espi_set_channel_configuration(slave_config, ESPI_SLAVE_VW_CFG, ESPI_VW_CH_EN);
841}
842
Felix Held4b4114f72021-12-18 00:41:23 +0100843static enum cb_err espi_setup_periph_channel(const struct espi_config *mb_cfg,
844 uint32_t slave_caps)
Furquan Shaikh70063ff52020-05-11 14:28:13 -0700845{
846 uint32_t slave_config;
847 /* Peripheral channel requires BME bit to be set when enabling the channel. */
Raul E Rangel8fef0b72021-05-24 13:02:40 -0600848 const uint32_t slave_en_mask =
849 ESPI_SLAVE_CHANNEL_ENABLE | ESPI_SLAVE_PERIPH_BUS_MASTER_ENABLE;
Furquan Shaikh70063ff52020-05-11 14:28:13 -0700850
Felix Held4b4114f72021-12-18 00:41:23 +0100851 if (espi_get_configuration(ESPI_SLAVE_PERIPH_CFG, &slave_config) != CB_SUCCESS)
852 return CB_ERR;
Furquan Shaikh70063ff52020-05-11 14:28:13 -0700853
854 /*
855 * Peripheral channel is the only one which is enabled on reset. So, if the mainboard
856 * wants to disable it, set configuration to disable peripheral channel. It also
857 * requires that BME bit be cleared.
858 */
859 if (mb_cfg->periph_ch_en) {
860 if (!espi_slave_supports_periph_channel(slave_caps)) {
861 printk(BIOS_ERR, "Error: eSPI slave doesn't support periph channel!\n");
Felix Held4b4114f72021-12-18 00:41:23 +0100862 return CB_ERR;
Furquan Shaikh70063ff52020-05-11 14:28:13 -0700863 }
864 slave_config |= slave_en_mask;
865 } else {
866 slave_config &= ~slave_en_mask;
867 }
868
Raul E Rangel7222f7e2021-04-09 14:15:42 -0600869 espi_show_slave_peripheral_channel_configuration(slave_config);
870
Furquan Shaikh70063ff52020-05-11 14:28:13 -0700871 return espi_set_channel_configuration(slave_config, ESPI_SLAVE_PERIPH_CFG,
872 ESPI_PERIPH_CH_EN);
873}
874
Felix Held4b4114f72021-12-18 00:41:23 +0100875static enum cb_err espi_setup_oob_channel(const struct espi_config *mb_cfg, uint32_t slave_caps)
Furquan Shaikh70063ff52020-05-11 14:28:13 -0700876{
877 uint32_t slave_config;
878
879 if (!mb_cfg->oob_ch_en)
Felix Held4b4114f72021-12-18 00:41:23 +0100880 return CB_SUCCESS;
Furquan Shaikh70063ff52020-05-11 14:28:13 -0700881
882 if (!espi_slave_supports_oob_channel(slave_caps)) {
883 printk(BIOS_ERR, "Error: eSPI slave doesn't support OOB channel!\n");
Felix Held4b4114f72021-12-18 00:41:23 +0100884 return CB_ERR;
Furquan Shaikh70063ff52020-05-11 14:28:13 -0700885 }
886
Felix Held4b4114f72021-12-18 00:41:23 +0100887 if (espi_get_configuration(ESPI_SLAVE_OOB_CFG, &slave_config) != CB_SUCCESS)
888 return CB_ERR;
Furquan Shaikh70063ff52020-05-11 14:28:13 -0700889
890 slave_config |= ESPI_SLAVE_CHANNEL_ENABLE;
891
892 return espi_set_channel_configuration(slave_config, ESPI_SLAVE_OOB_CFG,
893 ESPI_OOB_CH_EN);
894}
895
Felix Held4b4114f72021-12-18 00:41:23 +0100896static enum cb_err espi_setup_flash_channel(const struct espi_config *mb_cfg,
897 uint32_t slave_caps)
Furquan Shaikh70063ff52020-05-11 14:28:13 -0700898{
899 uint32_t slave_config;
900
901 if (!mb_cfg->flash_ch_en)
Felix Held4b4114f72021-12-18 00:41:23 +0100902 return CB_SUCCESS;
Furquan Shaikh70063ff52020-05-11 14:28:13 -0700903
904 if (!espi_slave_supports_flash_channel(slave_caps)) {
905 printk(BIOS_ERR, "Error: eSPI slave doesn't support flash channel!\n");
Felix Held4b4114f72021-12-18 00:41:23 +0100906 return CB_ERR;
Furquan Shaikh70063ff52020-05-11 14:28:13 -0700907 }
908
Felix Held4b4114f72021-12-18 00:41:23 +0100909 if (espi_get_configuration(ESPI_SLAVE_FLASH_CFG, &slave_config) != CB_SUCCESS)
910 return CB_ERR;
Furquan Shaikh70063ff52020-05-11 14:28:13 -0700911
912 slave_config |= ESPI_SLAVE_CHANNEL_ENABLE;
913
914 return espi_set_channel_configuration(slave_config, ESPI_SLAVE_FLASH_CFG,
915 ESPI_FLASH_CH_EN);
916}
917
918static void espi_set_initial_config(const struct espi_config *mb_cfg)
919{
920 uint32_t espi_initial_mode = ESPI_OP_FREQ_16_MHZ | ESPI_IO_MODE_SINGLE;
921
Raul E Rangeldcec4092021-05-07 15:35:10 -0600922 switch (mb_cfg->alert_pin) {
923 case ESPI_ALERT_PIN_IN_BAND:
924 break;
925 case ESPI_ALERT_PIN_PUSH_PULL:
926 case ESPI_ALERT_PIN_OPEN_DRAIN:
927 espi_initial_mode |= ESPI_ALERT_MODE;
928 break;
929 default:
930 die("Unknown espi alert config: %u!\n", mb_cfg->alert_pin);
931 }
932
Furquan Shaikh70063ff52020-05-11 14:28:13 -0700933 espi_write32(ESPI_SLAVE0_CONFIG, espi_initial_mode);
934}
935
936static void espi_setup_subtractive_decode(const struct espi_config *mb_cfg)
937{
938 uint32_t global_ctrl_reg;
939 global_ctrl_reg = espi_read32(ESPI_GLOBAL_CONTROL_1);
940
941 if (mb_cfg->subtractive_decode) {
942 global_ctrl_reg &= ~ESPI_SUB_DECODE_SLV_MASK;
943 global_ctrl_reg |= ESPI_SUB_DECODE_EN;
944
945 } else {
946 global_ctrl_reg &= ~ESPI_SUB_DECODE_EN;
947 }
948 espi_write32(ESPI_GLOBAL_CONTROL_1, global_ctrl_reg);
949}
950
Felix Heldaed38a92021-12-18 00:41:23 +0100951enum cb_err espi_setup(void)
Furquan Shaikh70063ff52020-05-11 14:28:13 -0700952{
953 uint32_t slave_caps;
954 const struct espi_config *cfg = espi_get_config();
955
Martin Roth7a2bfeb2021-05-14 10:57:31 -0600956 printk(BIOS_SPEW, "Initializing ESPI.\n");
957
Raul E Rangelb92383a2021-04-02 10:32:03 -0600958 espi_write32(ESPI_GLOBAL_CONTROL_0, ESPI_AL_STOP_EN);
959 espi_write32(ESPI_GLOBAL_CONTROL_1, ESPI_RGCMD_INT(23) | ESPI_ERR_INT_SMI);
960 espi_write32(ESPI_SLAVE0_INT_EN, 0);
961 espi_clear_status();
Raul E Rangelb95f8482021-04-02 13:47:09 -0600962 espi_clear_decodes();
Raul E Rangelb92383a2021-04-02 10:32:03 -0600963
Furquan Shaikh70063ff52020-05-11 14:28:13 -0700964 /*
965 * Boot sequence: Step 1
966 * Set correct initial configuration to talk to the slave:
967 * Set clock frequency to 16.7MHz and single IO mode.
968 */
969 espi_set_initial_config(cfg);
970
971 /*
972 * Boot sequence: Step 2
973 * Send in-band reset
974 * The resets affects both host and slave devices, so set initial config again.
975 */
Felix Held4b4114f72021-12-18 00:41:23 +0100976 if (espi_send_reset() != CB_SUCCESS) {
Furquan Shaikh70063ff52020-05-11 14:28:13 -0700977 printk(BIOS_ERR, "Error: In-band reset failed!\n");
Felix Heldaed38a92021-12-18 00:41:23 +0100978 return CB_ERR;
Furquan Shaikh70063ff52020-05-11 14:28:13 -0700979 }
980 espi_set_initial_config(cfg);
981
982 /*
983 * Boot sequence: Step 3
984 * Get configuration of slave device.
985 */
Felix Held4b4114f72021-12-18 00:41:23 +0100986 if (espi_get_general_configuration(&slave_caps) != CB_SUCCESS) {
Furquan Shaikh70063ff52020-05-11 14:28:13 -0700987 printk(BIOS_ERR, "Error: Slave GET_CONFIGURATION failed!\n");
Felix Heldaed38a92021-12-18 00:41:23 +0100988 return CB_ERR;
Furquan Shaikh70063ff52020-05-11 14:28:13 -0700989 }
990
991 /*
992 * Boot sequence:
993 * Step 4: Write slave device general config
994 * Step 5: Set host slave config
995 */
Felix Held4b4114f72021-12-18 00:41:23 +0100996 if (espi_set_general_configuration(cfg, slave_caps) != CB_SUCCESS) {
Furquan Shaikh70063ff52020-05-11 14:28:13 -0700997 printk(BIOS_ERR, "Error: Slave SET_CONFIGURATION failed!\n");
Felix Heldaed38a92021-12-18 00:41:23 +0100998 return CB_ERR;
Furquan Shaikh70063ff52020-05-11 14:28:13 -0700999 }
1000
1001 /*
1002 * Setup polarity before enabling the VW channel so any interrupts
1003 * received will have the correct polarity.
1004 */
1005 espi_write32(ESPI_RXVW_POLARITY, cfg->vw_irq_polarity);
1006
1007 /*
1008 * Boot Sequences: Steps 6 - 9
1009 * Channel setup
1010 */
1011 /* Set up VW first so we can deassert PLTRST#. */
Felix Held4b4114f72021-12-18 00:41:23 +01001012 if (espi_setup_vw_channel(cfg, slave_caps) != CB_SUCCESS) {
Furquan Shaikh70063ff52020-05-11 14:28:13 -07001013 printk(BIOS_ERR, "Error: Setup VW channel failed!\n");
Felix Heldaed38a92021-12-18 00:41:23 +01001014 return CB_ERR;
Furquan Shaikh70063ff52020-05-11 14:28:13 -07001015 }
1016
Raul E Rangel43aa5272021-05-21 17:04:28 -06001017 /* Assert PLTRST# if VW channel is enabled by mainboard. */
Felix Held4b4114f72021-12-18 00:41:23 +01001018 if (espi_send_pltrst(cfg, true) != CB_SUCCESS) {
Raul E Rangel43aa5272021-05-21 17:04:28 -06001019 printk(BIOS_ERR, "Error: PLTRST# assertion failed!\n");
Felix Heldaed38a92021-12-18 00:41:23 +01001020 return CB_ERR;
Raul E Rangel43aa5272021-05-21 17:04:28 -06001021 }
1022
Furquan Shaikh70063ff52020-05-11 14:28:13 -07001023 /* De-assert PLTRST# if VW channel is enabled by mainboard. */
Felix Held4b4114f72021-12-18 00:41:23 +01001024 if (espi_send_pltrst(cfg, false) != CB_SUCCESS) {
Raul E Rangel43aa5272021-05-21 17:04:28 -06001025 printk(BIOS_ERR, "Error: PLTRST# deassertion failed!\n");
Felix Heldaed38a92021-12-18 00:41:23 +01001026 return CB_ERR;
Furquan Shaikh70063ff52020-05-11 14:28:13 -07001027 }
1028
Felix Held4b4114f72021-12-18 00:41:23 +01001029 if (espi_setup_periph_channel(cfg, slave_caps) != CB_SUCCESS) {
Furquan Shaikh70063ff52020-05-11 14:28:13 -07001030 printk(BIOS_ERR, "Error: Setup Periph channel failed!\n");
Felix Heldaed38a92021-12-18 00:41:23 +01001031 return CB_ERR;
Furquan Shaikh70063ff52020-05-11 14:28:13 -07001032 }
1033
Felix Held4b4114f72021-12-18 00:41:23 +01001034 if (espi_setup_oob_channel(cfg, slave_caps) != CB_SUCCESS) {
Furquan Shaikh70063ff52020-05-11 14:28:13 -07001035 printk(BIOS_ERR, "Error: Setup OOB channel failed!\n");
Felix Heldaed38a92021-12-18 00:41:23 +01001036 return CB_ERR;
Furquan Shaikh70063ff52020-05-11 14:28:13 -07001037 }
1038
Felix Held4b4114f72021-12-18 00:41:23 +01001039 if (espi_setup_flash_channel(cfg, slave_caps) != CB_SUCCESS) {
Furquan Shaikh70063ff52020-05-11 14:28:13 -07001040 printk(BIOS_ERR, "Error: Setup Flash channel failed!\n");
Felix Heldaed38a92021-12-18 00:41:23 +01001041 return CB_ERR;
Furquan Shaikh70063ff52020-05-11 14:28:13 -07001042 }
1043
Felix Heldaed38a92021-12-18 00:41:23 +01001044 if (espi_configure_decodes(cfg) != CB_SUCCESS) {
Raul E Rangel61ac1bc2021-04-02 10:55:27 -06001045 printk(BIOS_ERR, "Error: Configuring decodes failed!\n");
Felix Heldaed38a92021-12-18 00:41:23 +01001046 return CB_ERR;
Raul E Rangel61ac1bc2021-04-02 10:55:27 -06001047 }
1048
Furquan Shaikh70063ff52020-05-11 14:28:13 -07001049 /* Enable subtractive decode if configured */
Felix Helda2642d02021-02-17 00:32:46 +01001050 espi_setup_subtractive_decode(cfg);
Furquan Shaikh70063ff52020-05-11 14:28:13 -07001051
Raul E Rangelb92383a2021-04-02 10:32:03 -06001052 espi_write32(ESPI_GLOBAL_CONTROL_1,
1053 espi_read32(ESPI_GLOBAL_CONTROL_1) | ESPI_BUS_MASTER_EN);
1054
Martin Roth7a2bfeb2021-05-14 10:57:31 -06001055 printk(BIOS_SPEW, "Finished initializing ESPI.\n");
1056
Felix Heldaed38a92021-12-18 00:41:23 +01001057 return CB_SUCCESS;
Furquan Shaikh70063ff52020-05-11 14:28:13 -07001058}
Felix Held1c03da52021-10-14 21:48:13 +02001059
1060/* Setup eSPI with any mainboard specific initialization. */
1061void configure_espi_with_mb_hook(void)
1062{
1063 mb_set_up_early_espi();
1064 espi_setup();
1065}