blob: b724408022ba252b1995778b8800953276afcd65 [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
Furquan Shaikhf318e032020-05-04 23:38:53 -070020static uintptr_t espi_get_bar(void)
21{
Martin Rothb39e10d2020-07-14 11:08:55 -060022 if (ENV_X86 && !espi_bar)
23 espi_update_static_bar(lpc_get_spibase() + ESPI_OFFSET_FROM_BAR);
Furquan Shaikh98bc9612020-05-09 19:31:55 -070024 return espi_bar;
Furquan Shaikhf318e032020-05-04 23:38:53 -070025}
26
Felix Held92dd6782020-08-10 20:27:58 +020027static uint32_t espi_read32(unsigned int reg)
Furquan Shaikhf318e032020-05-04 23:38:53 -070028{
29 return read32((void *)(espi_get_bar() + reg));
30}
31
Felix Held92dd6782020-08-10 20:27:58 +020032static void espi_write32(unsigned int reg, uint32_t val)
Furquan Shaikhf318e032020-05-04 23:38:53 -070033{
34 write32((void *)(espi_get_bar() + reg), val);
35}
36
Felix Held92dd6782020-08-10 20:27:58 +020037static uint16_t espi_read16(unsigned int reg)
Furquan Shaikhf318e032020-05-04 23:38:53 -070038{
39 return read16((void *)(espi_get_bar() + reg));
40}
41
Felix Held92dd6782020-08-10 20:27:58 +020042static void espi_write16(unsigned int reg, uint16_t val)
Furquan Shaikhf318e032020-05-04 23:38:53 -070043{
44 write16((void *)(espi_get_bar() + reg), val);
45}
46
Felix Held92dd6782020-08-10 20:27:58 +020047static uint8_t espi_read8(unsigned int reg)
Furquan Shaikhf318e032020-05-04 23:38:53 -070048{
49 return read8((void *)(espi_get_bar() + reg));
50}
51
Felix Held92dd6782020-08-10 20:27:58 +020052static void espi_write8(unsigned int reg, uint8_t val)
Furquan Shaikhf318e032020-05-04 23:38:53 -070053{
54 write8((void *)(espi_get_bar() + reg), val);
55}
56
Felix Heldf08fbf82020-08-10 20:30:36 +020057static void espi_enable_decode(uint32_t decode_en)
Furquan Shaikhf318e032020-05-04 23:38:53 -070058{
59 uint32_t val;
60
61 val = espi_read32(ESPI_DECODE);
62 val |= decode_en;
63 espi_write32(ESPI_DECODE, val);
64}
65
Felix Heldf08fbf82020-08-10 20:30:36 +020066static bool espi_is_decode_enabled(uint32_t decode)
Furquan Shaikhf318e032020-05-04 23:38:53 -070067{
68 uint32_t val;
69
70 val = espi_read32(ESPI_DECODE);
71 return !!(val & decode);
72}
73
74static int espi_find_io_window(uint16_t win_base)
75{
76 int i;
77
78 for (i = 0; i < ESPI_GENERIC_IO_WIN_COUNT; i++) {
79 if (!espi_is_decode_enabled(ESPI_DECODE_IO_RANGE_EN(i)))
80 continue;
81
82 if (espi_read16(ESPI_IO_RANGE_BASE(i)) == win_base)
83 return i;
84 }
85
86 return -1;
87}
88
89static int espi_get_unused_io_window(void)
90{
91 int i;
92
93 for (i = 0; i < ESPI_GENERIC_IO_WIN_COUNT; i++) {
94 if (!espi_is_decode_enabled(ESPI_DECODE_IO_RANGE_EN(i)))
95 return i;
96 }
97
98 return -1;
99}
100
Raul E Rangelb95f8482021-04-02 13:47:09 -0600101static void espi_clear_decodes(void)
Martin Roth011bf132021-03-23 13:20:42 -0600102{
103 unsigned int idx;
104
105 /* First turn off all enable bits, then zero base, range, and size registers */
Raul E Rangel01792e32021-04-26 13:52:38 -0600106 espi_write16(ESPI_DECODE, 0);
Martin Roth011bf132021-03-23 13:20:42 -0600107
108 for (idx = 0; idx < ESPI_GENERIC_IO_WIN_COUNT; idx++) {
109 espi_write16(ESPI_IO_RANGE_BASE(idx), 0);
110 espi_write8(ESPI_IO_RANGE_SIZE(idx), 0);
111 }
112 for (idx = 0; idx < ESPI_GENERIC_MMIO_WIN_COUNT; idx++) {
113 espi_write32(ESPI_MMIO_RANGE_BASE(idx), 0);
114 espi_write16(ESPI_MMIO_RANGE_SIZE(idx), 0);
115 }
116}
117
Furquan Shaikhf318e032020-05-04 23:38:53 -0700118/*
119 * Returns decode enable bits for standard IO port addresses. If port address is not supported
120 * by standard decode or if the size of window is not 1, then it returns -1.
121 */
122static int espi_std_io_decode(uint16_t base, size_t size)
123{
Felix Heldc0d4eeb2020-08-10 20:37:16 +0200124 if (size == 2 && base == 0x2e)
125 return ESPI_DECODE_IO_0X2E_0X2F_EN;
126
Furquan Shaikhf318e032020-05-04 23:38:53 -0700127 if (size != 1)
Felix Held4bf419f2020-08-10 20:33:25 +0200128 return -1;
Furquan Shaikhf318e032020-05-04 23:38:53 -0700129
130 switch (base) {
131 case 0x80:
Felix Held4bf419f2020-08-10 20:33:25 +0200132 return ESPI_DECODE_IO_0x80_EN;
Furquan Shaikhf318e032020-05-04 23:38:53 -0700133 case 0x60:
134 case 0x64:
Felix Held4bf419f2020-08-10 20:33:25 +0200135 return ESPI_DECODE_IO_0X60_0X64_EN;
Furquan Shaikhf318e032020-05-04 23:38:53 -0700136 case 0x2e:
137 case 0x2f:
Felix Held4bf419f2020-08-10 20:33:25 +0200138 return ESPI_DECODE_IO_0X2E_0X2F_EN;
Furquan Shaikhf318e032020-05-04 23:38:53 -0700139 default:
Felix Held4bf419f2020-08-10 20:33:25 +0200140 return -1;
Furquan Shaikhf318e032020-05-04 23:38:53 -0700141 }
Furquan Shaikhf318e032020-05-04 23:38:53 -0700142}
143
144static size_t espi_get_io_window_size(int idx)
145{
146 return espi_read8(ESPI_IO_RANGE_SIZE(idx)) + 1;
147}
148
149static void espi_write_io_window(int idx, uint16_t base, size_t size)
150{
151 espi_write16(ESPI_IO_RANGE_BASE(idx), base);
152 espi_write8(ESPI_IO_RANGE_SIZE(idx), size - 1);
153}
154
155static int espi_open_generic_io_window(uint16_t base, size_t size)
156{
157 size_t win_size;
158 int idx;
159
160 for (; size; size -= win_size, base += win_size) {
161 win_size = MIN(size, ESPI_GENERIC_IO_MAX_WIN_SIZE);
162
163 idx = espi_find_io_window(base);
164 if (idx != -1) {
165 size_t curr_size = espi_get_io_window_size(idx);
166
167 if (curr_size > win_size) {
168 printk(BIOS_INFO, "eSPI window already configured to be larger than requested! ");
169 printk(BIOS_INFO, "Base: 0x%x, Requested size: 0x%zx, Actual size: 0x%zx\n",
170 base, win_size, curr_size);
171 } else if (curr_size < win_size) {
172 espi_write_io_window(idx, base, win_size);
173 printk(BIOS_INFO, "eSPI window at base: 0x%x resized from 0x%zx to 0x%zx\n",
174 base, curr_size, win_size);
175 }
176
177 continue;
178 }
179
180 idx = espi_get_unused_io_window();
181 if (idx == -1) {
182 printk(BIOS_ERR, "Cannot open IO window base %x size %zx\n", base,
183 size);
184 printk(BIOS_ERR, "ERROR: No more available IO windows!\n");
185 return -1;
186 }
187
188 espi_write_io_window(idx, base, win_size);
189 espi_enable_decode(ESPI_DECODE_IO_RANGE_EN(idx));
190 }
191
192 return 0;
193}
194
195int espi_open_io_window(uint16_t base, size_t size)
196{
197 int std_io;
198
199 std_io = espi_std_io_decode(base, size);
200 if (std_io != -1) {
201 espi_enable_decode(std_io);
202 return 0;
Felix Heldb026c7c2020-08-10 20:43:53 +0200203 } else {
204 return espi_open_generic_io_window(base, size);
Furquan Shaikhf318e032020-05-04 23:38:53 -0700205 }
Furquan Shaikhf318e032020-05-04 23:38:53 -0700206}
207
208static int espi_find_mmio_window(uint32_t win_base)
209{
210 int i;
211
212 for (i = 0; i < ESPI_GENERIC_MMIO_WIN_COUNT; i++) {
213 if (!espi_is_decode_enabled(ESPI_DECODE_MMIO_RANGE_EN(i)))
214 continue;
215
216 if (espi_read32(ESPI_MMIO_RANGE_BASE(i)) == win_base)
217 return i;
218 }
219
220 return -1;
221}
222
223static int espi_get_unused_mmio_window(void)
224{
225 int i;
226
227 for (i = 0; i < ESPI_GENERIC_MMIO_WIN_COUNT; i++) {
228 if (!espi_is_decode_enabled(ESPI_DECODE_MMIO_RANGE_EN(i)))
229 return i;
230 }
231
232 return -1;
233
234}
235
236static size_t espi_get_mmio_window_size(int idx)
237{
238 return espi_read16(ESPI_MMIO_RANGE_SIZE(idx)) + 1;
239}
240
241static void espi_write_mmio_window(int idx, uint32_t base, size_t size)
242{
243 espi_write32(ESPI_MMIO_RANGE_BASE(idx), base);
244 espi_write16(ESPI_MMIO_RANGE_SIZE(idx), size - 1);
245}
246
247int espi_open_mmio_window(uint32_t base, size_t size)
248{
249 size_t win_size;
250 int idx;
251
252 for (; size; size -= win_size, base += win_size) {
253 win_size = MIN(size, ESPI_GENERIC_MMIO_MAX_WIN_SIZE);
254
255 idx = espi_find_mmio_window(base);
256 if (idx != -1) {
257 size_t curr_size = espi_get_mmio_window_size(idx);
258
259 if (curr_size > win_size) {
260 printk(BIOS_INFO, "eSPI window already configured to be larger than requested! ");
261 printk(BIOS_INFO, "Base: 0x%x, Requested size: 0x%zx, Actual size: 0x%zx\n",
262 base, win_size, curr_size);
263 } else if (curr_size < win_size) {
264 espi_write_mmio_window(idx, base, win_size);
265 printk(BIOS_INFO, "eSPI window at base: 0x%x resized from 0x%zx to 0x%zx\n",
266 base, curr_size, win_size);
267 }
268
269 continue;
270 }
271
272 idx = espi_get_unused_mmio_window();
273 if (idx == -1) {
274 printk(BIOS_ERR, "Cannot open IO window base %x size %zx\n", base,
275 size);
276 printk(BIOS_ERR, "ERROR: No more available MMIO windows!\n");
277 return -1;
278 }
279
280 espi_write_mmio_window(idx, base, win_size);
281 espi_enable_decode(ESPI_DECODE_MMIO_RANGE_EN(idx));
282 }
283
284 return 0;
285}
286
287static const struct espi_config *espi_get_config(void)
288{
289 const struct soc_amd_common_config *soc_cfg = soc_get_common_config();
290
291 if (!soc_cfg)
292 die("Common config structure is NULL!\n");
293
294 return &soc_cfg->espi_config;
295}
296
Raul E Rangel61ac1bc2021-04-02 10:55:27 -0600297static int espi_configure_decodes(const struct espi_config *cfg)
Furquan Shaikhf318e032020-05-04 23:38:53 -0700298{
Raul E Rangel61ac1bc2021-04-02 10:55:27 -0600299 int i, ret;
Furquan Shaikhf318e032020-05-04 23:38:53 -0700300
301 espi_enable_decode(cfg->std_io_decode_bitmap);
302
303 for (i = 0; i < ESPI_GENERIC_IO_WIN_COUNT; i++) {
304 if (cfg->generic_io_range[i].size == 0)
305 continue;
Raul E Rangel61ac1bc2021-04-02 10:55:27 -0600306 ret = espi_open_generic_io_window(cfg->generic_io_range[i].base,
307 cfg->generic_io_range[i].size);
308 if (ret)
309 return ret;
Furquan Shaikhf318e032020-05-04 23:38:53 -0700310 }
Raul E Rangel61ac1bc2021-04-02 10:55:27 -0600311
312 return 0;
Furquan Shaikhf318e032020-05-04 23:38:53 -0700313}
Furquan Shaikh70063ff52020-05-11 14:28:13 -0700314
315#define ESPI_DN_TX_HDR0 0x00
316enum espi_cmd_type {
317 CMD_TYPE_SET_CONFIGURATION = 0,
318 CMD_TYPE_GET_CONFIGURATION = 1,
319 CMD_TYPE_IN_BAND_RESET = 2,
320 CMD_TYPE_PERIPHERAL = 4,
321 CMD_TYPE_VW = 5,
322 CMD_TYPE_OOB = 6,
323 CMD_TYPE_FLASH = 7,
324};
325
326#define ESPI_DN_TX_HDR1 0x04
327#define ESPI_DN_TX_HDR2 0x08
328#define ESPI_DN_TX_DATA 0x0c
329
330#define ESPI_MASTER_CAP 0x2c
331#define ESPI_VW_MAX_SIZE_SHIFT 13
332#define ESPI_VW_MAX_SIZE_MASK (0x3f << ESPI_VW_MAX_SIZE_SHIFT)
333
Raul E Rangel1d0e4932021-04-02 10:27:11 -0600334#define ESPI_GLOBAL_CONTROL_0 0x30
335#define ESPI_WAIT_CNT_SHIFT 24
336#define ESPI_WAIT_CNT_MASK (0x3F << ESPI_WAIT_CNT_SHIFT)
337#define ESPI_WDG_CNT_SHIFT 8
338#define ESPI_WDG_CNT_MASK (0xFFFF << ESPI_WDG_CNT_SHIFT)
339#define ESPI_AL_IDLE_TIMER_SHIFT 4
340#define ESPI_AL_IDLE_TIMER_MASK (0x7 << ESPI_AL_IDLE_TIMER_SHIFT)
341#define ESPI_AL_STOP_EN (1 << 3)
342#define ESPI_PR_CLKGAT_EN (1 << 2)
343#define ESPI_WAIT_CHKEN (1 << 1)
344#define ESPI_WDG_EN (1 << 0)
345
Furquan Shaikh70063ff52020-05-11 14:28:13 -0700346#define ESPI_GLOBAL_CONTROL_1 0x34
Raul E Rangel1d0e4932021-04-02 10:27:11 -0600347#define ESPI_RGCMD_INT_MAP_SHIFT 13
348#define ESPI_RGCMD_INT_MAP_MASK (0x1F << ESPI_RGCMD_INT_MAP_SHIFT)
349#define ESPI_RGCMD_INT(irq) ((irq) << ESPI_RGCMD_INT_MAP_SHIFT)
350#define ESPI_RGCMD_INT_SMI (0x1F << ESPI_RGCMD_INT_MAP_SHIFT)
351#define ESPI_ERR_INT_MAP_SHIFT 8
352#define ESPI_ERR_INT_MAP_MASK (0x1F << ESPI_ERR_INT_MAP_SHIFT)
353#define ESPI_ERR_INT(irq) ((irq) << ESPI_ERR_INT_MAP_SHIFT)
354#define ESPI_ERR_INT_SMI (0x1F << ESPI_ERR_INT_MAP_SHIFT)
Furquan Shaikh70063ff52020-05-11 14:28:13 -0700355#define ESPI_SUB_DECODE_SLV_SHIFT 3
356#define ESPI_SUB_DECODE_SLV_MASK (0x3 << ESPI_SUB_DECODE_SLV_SHIFT)
357#define ESPI_SUB_DECODE_EN (1 << 2)
Raul E Rangel1d0e4932021-04-02 10:27:11 -0600358#define ESPI_BUS_MASTER_EN (1 << 1)
359#define ESPI_SW_RST (1 << 0)
Furquan Shaikh70063ff52020-05-11 14:28:13 -0700360
Raul E Rangel1d0e4932021-04-02 10:27:11 -0600361#define ESPI_SLAVE0_INT_EN 0x6C
Raul E Rangel47740122021-04-02 10:16:54 -0600362#define ESPI_SLAVE0_INT_STS 0x70
Furquan Shaikh70063ff52020-05-11 14:28:13 -0700363#define ESPI_STATUS_DNCMD_COMPLETE (1 << 28)
364#define ESPI_STATUS_NON_FATAL_ERROR (1 << 6)
365#define ESPI_STATUS_FATAL_ERROR (1 << 5)
366#define ESPI_STATUS_NO_RESPONSE (1 << 4)
367#define ESPI_STATUS_CRC_ERR (1 << 2)
368#define ESPI_STATUS_WAIT_TIMEOUT (1 << 1)
369#define ESPI_STATUS_BUS_ERROR (1 << 0)
370
371#define ESPI_RXVW_POLARITY 0xac
372
373#define ESPI_CMD_TIMEOUT_US 100
Raul E Rangel0318dc12021-05-21 16:31:52 -0600374#define ESPI_CH_READY_TIMEOUT_US 10000
Furquan Shaikh70063ff52020-05-11 14:28:13 -0700375
376union espi_txhdr0 {
377 uint32_t val;
378 struct {
379 uint32_t cmd_type:3;
380 uint32_t cmd_sts:1;
381 uint32_t slave_sel:2;
382 uint32_t rsvd:2;
383 uint32_t hdata0:8;
384 uint32_t hdata1:8;
385 uint32_t hdata2:8;
386 };
387} __packed;
388
389union espi_txhdr1 {
390 uint32_t val;
391 struct {
392 uint32_t hdata3:8;
393 uint32_t hdata4:8;
394 uint32_t hdata5:8;
395 uint32_t hdata6:8;
396 };
397} __packed;
398
399union espi_txhdr2 {
400 uint32_t val;
401 struct {
402 uint32_t hdata7:8;
403 uint32_t rsvd:24;
404 };
405} __packed;
406
407union espi_txdata {
408 uint32_t val;
409 struct {
410 uint32_t byte0:8;
411 uint32_t byte1:8;
412 uint32_t byte2:8;
413 uint32_t byte3:8;
414 };
415} __packed;
416
417struct espi_cmd {
418 union espi_txhdr0 hdr0;
419 union espi_txhdr1 hdr1;
420 union espi_txhdr2 hdr2;
421 union espi_txdata data;
Raul E Rangel12c05422021-05-11 11:13:38 -0600422 uint32_t expected_status_codes;
Furquan Shaikh70063ff52020-05-11 14:28:13 -0700423} __packed;
424
425/* Wait up to ESPI_CMD_TIMEOUT_US for hardware to clear DNCMD_STATUS bit. */
426static int espi_wait_ready(void)
427{
428 struct stopwatch sw;
429 union espi_txhdr0 hdr0;
430
431 stopwatch_init_usecs_expire(&sw, ESPI_CMD_TIMEOUT_US);
432 do {
433 hdr0.val = espi_read32(ESPI_DN_TX_HDR0);
434 if (!hdr0.cmd_sts)
435 return 0;
436 } while (!stopwatch_expired(&sw));
437
438 return -1;
439}
440
441/* Clear interrupt status register */
442static void espi_clear_status(void)
443{
Raul E Rangel47740122021-04-02 10:16:54 -0600444 uint32_t status = espi_read32(ESPI_SLAVE0_INT_STS);
Furquan Shaikh70063ff52020-05-11 14:28:13 -0700445 if (status)
Raul E Rangel47740122021-04-02 10:16:54 -0600446 espi_write32(ESPI_SLAVE0_INT_STS, status);
Furquan Shaikh70063ff52020-05-11 14:28:13 -0700447}
448
449/*
450 * Wait up to ESPI_CMD_TIMEOUT_US for interrupt status register to update after sending a
451 * command.
452 */
Felix Held1ba38332020-08-10 20:45:30 +0200453static int espi_poll_status(uint32_t *status)
Furquan Shaikh70063ff52020-05-11 14:28:13 -0700454{
455 struct stopwatch sw;
456
457 stopwatch_init_usecs_expire(&sw, ESPI_CMD_TIMEOUT_US);
458 do {
Raul E Rangel47740122021-04-02 10:16:54 -0600459 *status = espi_read32(ESPI_SLAVE0_INT_STS);
Furquan Shaikh70063ff52020-05-11 14:28:13 -0700460 if (*status)
461 return 0;
462 } while (!stopwatch_expired(&sw));
463
464 printk(BIOS_ERR, "Error: eSPI timed out waiting for status update.\n");
465
466 return -1;
467}
468
469static void espi_show_failure(const struct espi_cmd *cmd, const char *str, uint32_t status)
470{
471 printk(BIOS_ERR, "eSPI cmd0-cmd2: %08x %08x %08x data: %08x.\n",
472 cmd->hdr0.val, cmd->hdr1.val, cmd->hdr2.val, cmd->data.val);
473 printk(BIOS_ERR, "%s (Status = 0x%x)\n", str, status);
474}
475
476static int espi_send_command(const struct espi_cmd *cmd)
477{
478 uint32_t status;
479
480 if (CONFIG(ESPI_DEBUG))
481 printk(BIOS_ERR, "eSPI cmd0-cmd2: %08x %08x %08x data: %08x.\n",
482 cmd->hdr0.val, cmd->hdr1.val, cmd->hdr2.val, cmd->data.val);
483
484 if (espi_wait_ready() == -1) {
485 espi_show_failure(cmd, "Error: eSPI was not ready to accept a command", 0);
486 return -1;
487 }
488
489 espi_clear_status();
490
491 espi_write32(ESPI_DN_TX_HDR1, cmd->hdr1.val);
492 espi_write32(ESPI_DN_TX_HDR2, cmd->hdr2.val);
493 espi_write32(ESPI_DN_TX_DATA, cmd->data.val);
494
495 /* Dword 0 must be last as this write triggers the transaction */
496 espi_write32(ESPI_DN_TX_HDR0, cmd->hdr0.val);
497
498 if (espi_wait_ready() == -1) {
499 espi_show_failure(cmd,
500 "Error: eSPI timed out waiting for command to complete", 0);
501 return -1;
502 }
503
Felix Held1ba38332020-08-10 20:45:30 +0200504 if (espi_poll_status(&status) == -1) {
505 espi_show_failure(cmd, "Error: eSPI poll status failed", 0);
Furquan Shaikh70063ff52020-05-11 14:28:13 -0700506 return -1;
507 }
508
509 /* If command did not complete downstream, return error. */
510 if (!(status & ESPI_STATUS_DNCMD_COMPLETE)) {
511 espi_show_failure(cmd, "Error: eSPI downstream command completion failure",
512 status);
513 return -1;
514 }
515
Raul E Rangel12c05422021-05-11 11:13:38 -0600516 if (status & ~(ESPI_STATUS_DNCMD_COMPLETE | cmd->expected_status_codes)) {
Felix Held316d59c2020-08-10 20:42:20 +0200517 espi_show_failure(cmd, "Error: unexpected eSPI status register bits set",
518 status);
Furquan Shaikh70063ff52020-05-11 14:28:13 -0700519 return -1;
520 }
521
Raul E Rangel12c05422021-05-11 11:13:38 -0600522 espi_write32(ESPI_SLAVE0_INT_STS, status);
Raul E Rangel66c52ff2021-04-02 10:18:25 -0600523
Furquan Shaikh70063ff52020-05-11 14:28:13 -0700524 return 0;
525}
526
527static int espi_send_reset(void)
528{
529 struct espi_cmd cmd = {
530 .hdr0 = {
531 .cmd_type = CMD_TYPE_IN_BAND_RESET,
532 .cmd_sts = 1,
533 },
Raul E Rangel12c05422021-05-11 11:13:38 -0600534
535 /*
536 * When performing an in-band reset the host controller and the
537 * peripheral can have mismatched IO configs.
538 *
539 * i.e., The eSPI peripheral can be in IO-4 mode while, the
540 * eSPI host will be in IO-1. This results in the peripheral
541 * getting invalid packets and thus not responding.
542 *
543 * If the peripheral is alerting when we perform an in-band
544 * reset, there is a race condition in espi_send_command.
545 * 1) espi_send_command clears the interrupt status.
546 * 2) eSPI host controller hardware notices the alert and sends
547 * a GET_STATUS.
548 * 3) espi_send_command writes the in-band reset command.
549 * 4) eSPI hardware enqueues the in-band reset until GET_STATUS
550 * is complete.
551 * 5) GET_STATUS fails with NO_RESPONSE and sets the interrupt
552 * status.
553 * 6) eSPI hardware performs in-band reset.
554 * 7) espi_send_command checks the status and sees a
555 * NO_RESPONSE bit.
556 *
557 * As a workaround we allow the NO_RESPONSE status code when
558 * we perform an in-band reset.
559 */
560 .expected_status_codes = ESPI_STATUS_NO_RESPONSE,
Furquan Shaikh70063ff52020-05-11 14:28:13 -0700561 };
562
563 return espi_send_command(&cmd);
564}
565
Raul E Rangel43aa5272021-05-21 17:04:28 -0600566static int espi_send_pltrst(const struct espi_config *mb_cfg, bool assert)
Furquan Shaikh70063ff52020-05-11 14:28:13 -0700567{
568 struct espi_cmd cmd = {
569 .hdr0 = {
570 .cmd_type = CMD_TYPE_VW,
571 .cmd_sts = 1,
572 .hdata0 = 0, /* 1 VW group */
573 },
574 .data = {
575 .byte0 = ESPI_VW_INDEX_SYSTEM_EVENT_3,
Raul E Rangel43aa5272021-05-21 17:04:28 -0600576 .byte1 = assert ? ESPI_VW_SIGNAL_LOW(ESPI_VW_PLTRST)
577 : ESPI_VW_SIGNAL_HIGH(ESPI_VW_PLTRST),
Furquan Shaikh70063ff52020-05-11 14:28:13 -0700578 },
579 };
580
581 if (!mb_cfg->vw_ch_en)
582 return 0;
583
584 return espi_send_command(&cmd);
585}
586
587/*
588 * In case of get configuration command, hdata0 contains bits 15:8 of the slave register address
589 * and hdata1 contains bits 7:0 of the slave register address.
590 */
591#define ESPI_CONFIGURATION_HDATA0(a) (((a) >> 8) & 0xff)
592#define ESPI_CONFIGURATION_HDATA1(a) ((a) & 0xff)
593
594static int espi_get_configuration(uint16_t slave_reg_addr, uint32_t *config)
595{
596 struct espi_cmd cmd = {
597 .hdr0 = {
598 .cmd_type = CMD_TYPE_GET_CONFIGURATION,
599 .cmd_sts = 1,
600 .hdata0 = ESPI_CONFIGURATION_HDATA0(slave_reg_addr),
601 .hdata1 = ESPI_CONFIGURATION_HDATA1(slave_reg_addr),
602 },
603 };
604
605 *config = 0;
606
607 if (espi_send_command(&cmd))
608 return -1;
609
610 *config = espi_read32(ESPI_DN_TX_HDR1);
611
612 if (CONFIG(ESPI_DEBUG))
613 printk(BIOS_DEBUG, "Get configuration for slave register(0x%x): 0x%x\n",
614 slave_reg_addr, *config);
615
616 return 0;
617}
618
619static int espi_set_configuration(uint16_t slave_reg_addr, uint32_t config)
620{
621 struct espi_cmd cmd = {
622 .hdr0 = {
623 .cmd_type = CMD_TYPE_SET_CONFIGURATION,
624 .cmd_sts = 1,
625 .hdata0 = ESPI_CONFIGURATION_HDATA0(slave_reg_addr),
626 .hdata1 = ESPI_CONFIGURATION_HDATA1(slave_reg_addr),
627 },
628 .hdr1 = {
629 .val = config,
630 },
631 };
632
633 return espi_send_command(&cmd);
634}
635
636static int espi_get_general_configuration(uint32_t *config)
637{
638 int ret = espi_get_configuration(ESPI_SLAVE_GENERAL_CFG, config);
639 if (ret == -1)
640 return -1;
641
642 espi_show_slave_general_configuration(*config);
643 return 0;
644}
645
646static void espi_set_io_mode_config(enum espi_io_mode mb_io_mode, uint32_t slave_caps,
647 uint32_t *slave_config, uint32_t *ctrlr_config)
648{
649 switch (mb_io_mode) {
650 case ESPI_IO_MODE_QUAD:
651 if (espi_slave_supports_quad_io(slave_caps)) {
652 *slave_config |= ESPI_SLAVE_IO_MODE_SEL_QUAD;
653 *ctrlr_config |= ESPI_IO_MODE_QUAD;
654 break;
655 }
656 printk(BIOS_ERR, "Error: eSPI Quad I/O not supported. Dropping to dual mode.\n");
657 /* Intentional fall-through */
658 case ESPI_IO_MODE_DUAL:
659 if (espi_slave_supports_dual_io(slave_caps)) {
660 *slave_config |= ESPI_SLAVE_IO_MODE_SEL_DUAL;
661 *ctrlr_config |= ESPI_IO_MODE_DUAL;
662 break;
663 }
664 printk(BIOS_ERR,
665 "Error: eSPI Dual I/O not supported. Dropping to single mode.\n");
666 /* Intentional fall-through */
667 case ESPI_IO_MODE_SINGLE:
668 /* Single I/O mode is always supported. */
669 *slave_config |= ESPI_SLAVE_IO_MODE_SEL_SINGLE;
670 *ctrlr_config |= ESPI_IO_MODE_SINGLE;
671 break;
672 default:
673 die("No supported eSPI I/O modes!\n");
674 }
675}
676
677static void espi_set_op_freq_config(enum espi_op_freq mb_op_freq, uint32_t slave_caps,
678 uint32_t *slave_config, uint32_t *ctrlr_config)
679{
680 int slave_max_speed_mhz = espi_slave_max_speed_mhz_supported(slave_caps);
681
682 switch (mb_op_freq) {
683 case ESPI_OP_FREQ_66_MHZ:
684 if (slave_max_speed_mhz >= 66) {
685 *slave_config |= ESPI_SLAVE_OP_FREQ_SEL_66_MHZ;
686 *ctrlr_config |= ESPI_OP_FREQ_66_MHZ;
687 break;
688 }
689 printk(BIOS_ERR, "Error: eSPI 66MHz not supported. Dropping to 33MHz.\n");
690 /* Intentional fall-through */
691 case ESPI_OP_FREQ_33_MHZ:
692 if (slave_max_speed_mhz >= 33) {
693 *slave_config |= ESPI_SLAVE_OP_FREQ_SEL_33_MHZ;
694 *ctrlr_config |= ESPI_OP_FREQ_33_MHZ;
695 break;
696 }
697 printk(BIOS_ERR, "Error: eSPI 33MHz not supported. Dropping to 16MHz.\n");
698 /* Intentional fall-through */
699 case ESPI_OP_FREQ_16_MHZ:
700 /*
701 * eSPI spec says the minimum frequency is 20MHz, but AMD datasheets support
702 * 16.7 Mhz.
703 */
704 if (slave_max_speed_mhz > 0) {
705 *slave_config |= ESPI_SLAVE_OP_FREQ_SEL_20_MHZ;
706 *ctrlr_config |= ESPI_OP_FREQ_16_MHZ;
707 break;
708 }
709 /* Intentional fall-through */
710 default:
711 die("No supported eSPI Operating Frequency!\n");
712 }
713}
714
Raul E Rangel8317e722021-05-05 13:38:27 -0600715static void espi_set_alert_pin_config(enum espi_alert_pin alert_pin, uint32_t slave_caps,
716 uint32_t *slave_config, uint32_t *ctrlr_config)
717{
718 switch (alert_pin) {
719 case ESPI_ALERT_PIN_IN_BAND:
720 *slave_config |= ESPI_SLAVE_ALERT_MODE_IO1;
721 return;
722 case ESPI_ALERT_PIN_PUSH_PULL:
723 *slave_config |= ESPI_SLAVE_ALERT_MODE_PIN | ESPI_SLAVE_PUSH_PULL_ALERT_SEL;
724 *ctrlr_config |= ESPI_ALERT_MODE;
725 return;
726 case ESPI_ALERT_PIN_OPEN_DRAIN:
727 if (!(slave_caps & ESPI_SLAVE_OPEN_DRAIN_ALERT_SUPP))
728 die("eSPI peripheral does not support open drain alert!");
729
730 *slave_config |= ESPI_SLAVE_ALERT_MODE_PIN | ESPI_SLAVE_OPEN_DRAIN_ALERT_SEL;
731 *ctrlr_config |= ESPI_ALERT_MODE;
732 return;
733 default:
734 die("Unknown espi alert config: %u!\n", alert_pin);
735 }
736}
737
Furquan Shaikh70063ff52020-05-11 14:28:13 -0700738static int espi_set_general_configuration(const struct espi_config *mb_cfg, uint32_t slave_caps)
739{
740 uint32_t slave_config = 0;
741 uint32_t ctrlr_config = 0;
742
743 if (mb_cfg->crc_check_enable) {
744 slave_config |= ESPI_SLAVE_CRC_ENABLE;
745 ctrlr_config |= ESPI_CRC_CHECKING_EN;
746 }
747
Raul E Rangel8317e722021-05-05 13:38:27 -0600748 espi_set_alert_pin_config(mb_cfg->alert_pin, slave_caps, &slave_config, &ctrlr_config);
Furquan Shaikh70063ff52020-05-11 14:28:13 -0700749 espi_set_io_mode_config(mb_cfg->io_mode, slave_caps, &slave_config, &ctrlr_config);
750 espi_set_op_freq_config(mb_cfg->op_freq_mhz, slave_caps, &slave_config, &ctrlr_config);
751
752 if (CONFIG(ESPI_DEBUG))
753 printk(BIOS_INFO, "Setting general configuration: slave: 0x%x controller: 0x%x\n",
754 slave_config, ctrlr_config);
755
Raul E Rangeld2d762a2021-05-05 13:30:10 -0600756 espi_show_slave_general_configuration(slave_config);
757
Furquan Shaikh70063ff52020-05-11 14:28:13 -0700758 if (espi_set_configuration(ESPI_SLAVE_GENERAL_CFG, slave_config) == -1)
759 return -1;
760
761 espi_write32(ESPI_SLAVE0_CONFIG, ctrlr_config);
762 return 0;
763}
764
765static int espi_wait_channel_ready(uint16_t slave_reg_addr)
766{
767 struct stopwatch sw;
768 uint32_t config;
769
770 stopwatch_init_usecs_expire(&sw, ESPI_CH_READY_TIMEOUT_US);
771 do {
772 espi_get_configuration(slave_reg_addr, &config);
773 if (espi_slave_is_channel_ready(config))
774 return 0;
775 } while (!stopwatch_expired(&sw));
776
777 printk(BIOS_ERR, "Error: Channel is not ready after %d usec (slave addr: 0x%x)\n",
778 ESPI_CH_READY_TIMEOUT_US, slave_reg_addr);
779 return -1;
780
781}
782
783static void espi_enable_ctrlr_channel(uint32_t channel_en)
784{
785 uint32_t reg = espi_read32(ESPI_SLAVE0_CONFIG);
786
787 reg |= channel_en;
788
789 espi_write32(ESPI_SLAVE0_CONFIG, reg);
790}
791
792static int espi_set_channel_configuration(uint32_t slave_config, uint32_t slave_reg_addr,
793 uint32_t ctrlr_enable)
794{
795 if (espi_set_configuration(slave_reg_addr, slave_config) == -1)
796 return -1;
797
798 if (!(slave_config & ESPI_SLAVE_CHANNEL_ENABLE))
799 return 0;
800
801 if (espi_wait_channel_ready(slave_reg_addr) == -1)
802 return -1;
803
804 espi_enable_ctrlr_channel(ctrlr_enable);
805 return 0;
806}
807
808static int espi_setup_vw_channel(const struct espi_config *mb_cfg, uint32_t slave_caps)
809{
810 uint32_t slave_vw_caps;
811 uint32_t ctrlr_vw_caps;
812 uint32_t slave_vw_count_supp;
813 uint32_t ctrlr_vw_count_supp;
814 uint32_t use_vw_count;
815 uint32_t slave_config;
816
817 if (!mb_cfg->vw_ch_en)
818 return 0;
819
820 if (!espi_slave_supports_vw_channel(slave_caps)) {
821 printk(BIOS_ERR, "Error: eSPI slave doesn't support VW channel!\n");
822 return -1;
823 }
824
825 if (espi_get_configuration(ESPI_SLAVE_VW_CFG, &slave_vw_caps) == -1)
826 return -1;
827
828 ctrlr_vw_caps = espi_read32(ESPI_MASTER_CAP);
829 ctrlr_vw_count_supp = (ctrlr_vw_caps & ESPI_VW_MAX_SIZE_MASK) >> ESPI_VW_MAX_SIZE_SHIFT;
830
831 slave_vw_count_supp = espi_slave_get_vw_count_supp(slave_vw_caps);
832 use_vw_count = MIN(ctrlr_vw_count_supp, slave_vw_count_supp);
833
834 slave_config = ESPI_SLAVE_CHANNEL_ENABLE | ESPI_SLAVE_VW_COUNT_SEL_VAL(use_vw_count);
835 return espi_set_channel_configuration(slave_config, ESPI_SLAVE_VW_CFG, ESPI_VW_CH_EN);
836}
837
838static int espi_setup_periph_channel(const struct espi_config *mb_cfg, uint32_t slave_caps)
839{
840 uint32_t slave_config;
841 /* Peripheral channel requires BME bit to be set when enabling the channel. */
Raul E Rangel8fef0b72021-05-24 13:02:40 -0600842 const uint32_t slave_en_mask =
843 ESPI_SLAVE_CHANNEL_ENABLE | ESPI_SLAVE_PERIPH_BUS_MASTER_ENABLE;
Furquan Shaikh70063ff52020-05-11 14:28:13 -0700844
845 if (espi_get_configuration(ESPI_SLAVE_PERIPH_CFG, &slave_config) == -1)
846 return -1;
847
848 /*
849 * Peripheral channel is the only one which is enabled on reset. So, if the mainboard
850 * wants to disable it, set configuration to disable peripheral channel. It also
851 * requires that BME bit be cleared.
852 */
853 if (mb_cfg->periph_ch_en) {
854 if (!espi_slave_supports_periph_channel(slave_caps)) {
855 printk(BIOS_ERR, "Error: eSPI slave doesn't support periph channel!\n");
856 return -1;
857 }
858 slave_config |= slave_en_mask;
859 } else {
860 slave_config &= ~slave_en_mask;
861 }
862
Raul E Rangel7222f7e2021-04-09 14:15:42 -0600863 espi_show_slave_peripheral_channel_configuration(slave_config);
864
Furquan Shaikh70063ff52020-05-11 14:28:13 -0700865 return espi_set_channel_configuration(slave_config, ESPI_SLAVE_PERIPH_CFG,
866 ESPI_PERIPH_CH_EN);
867}
868
869static int espi_setup_oob_channel(const struct espi_config *mb_cfg, uint32_t slave_caps)
870{
871 uint32_t slave_config;
872
873 if (!mb_cfg->oob_ch_en)
874 return 0;
875
876 if (!espi_slave_supports_oob_channel(slave_caps)) {
877 printk(BIOS_ERR, "Error: eSPI slave doesn't support OOB channel!\n");
878 return -1;
879 }
880
881 if (espi_get_configuration(ESPI_SLAVE_OOB_CFG, &slave_config) == -1)
882 return -1;
883
884 slave_config |= ESPI_SLAVE_CHANNEL_ENABLE;
885
886 return espi_set_channel_configuration(slave_config, ESPI_SLAVE_OOB_CFG,
887 ESPI_OOB_CH_EN);
888}
889
890static int espi_setup_flash_channel(const struct espi_config *mb_cfg, uint32_t slave_caps)
891{
892 uint32_t slave_config;
893
894 if (!mb_cfg->flash_ch_en)
895 return 0;
896
897 if (!espi_slave_supports_flash_channel(slave_caps)) {
898 printk(BIOS_ERR, "Error: eSPI slave doesn't support flash channel!\n");
899 return -1;
900 }
901
902 if (espi_get_configuration(ESPI_SLAVE_FLASH_CFG, &slave_config) == -1)
903 return -1;
904
905 slave_config |= ESPI_SLAVE_CHANNEL_ENABLE;
906
907 return espi_set_channel_configuration(slave_config, ESPI_SLAVE_FLASH_CFG,
908 ESPI_FLASH_CH_EN);
909}
910
911static void espi_set_initial_config(const struct espi_config *mb_cfg)
912{
913 uint32_t espi_initial_mode = ESPI_OP_FREQ_16_MHZ | ESPI_IO_MODE_SINGLE;
914
Raul E Rangeldcec4092021-05-07 15:35:10 -0600915 switch (mb_cfg->alert_pin) {
916 case ESPI_ALERT_PIN_IN_BAND:
917 break;
918 case ESPI_ALERT_PIN_PUSH_PULL:
919 case ESPI_ALERT_PIN_OPEN_DRAIN:
920 espi_initial_mode |= ESPI_ALERT_MODE;
921 break;
922 default:
923 die("Unknown espi alert config: %u!\n", mb_cfg->alert_pin);
924 }
925
Furquan Shaikh70063ff52020-05-11 14:28:13 -0700926 espi_write32(ESPI_SLAVE0_CONFIG, espi_initial_mode);
927}
928
929static void espi_setup_subtractive_decode(const struct espi_config *mb_cfg)
930{
931 uint32_t global_ctrl_reg;
932 global_ctrl_reg = espi_read32(ESPI_GLOBAL_CONTROL_1);
933
934 if (mb_cfg->subtractive_decode) {
935 global_ctrl_reg &= ~ESPI_SUB_DECODE_SLV_MASK;
936 global_ctrl_reg |= ESPI_SUB_DECODE_EN;
937
938 } else {
939 global_ctrl_reg &= ~ESPI_SUB_DECODE_EN;
940 }
941 espi_write32(ESPI_GLOBAL_CONTROL_1, global_ctrl_reg);
942}
943
944int espi_setup(void)
945{
946 uint32_t slave_caps;
947 const struct espi_config *cfg = espi_get_config();
948
Martin Roth7a2bfeb2021-05-14 10:57:31 -0600949 printk(BIOS_SPEW, "Initializing ESPI.\n");
950
Raul E Rangelb92383a2021-04-02 10:32:03 -0600951 espi_write32(ESPI_GLOBAL_CONTROL_0, ESPI_AL_STOP_EN);
952 espi_write32(ESPI_GLOBAL_CONTROL_1, ESPI_RGCMD_INT(23) | ESPI_ERR_INT_SMI);
953 espi_write32(ESPI_SLAVE0_INT_EN, 0);
954 espi_clear_status();
Raul E Rangelb95f8482021-04-02 13:47:09 -0600955 espi_clear_decodes();
Raul E Rangelb92383a2021-04-02 10:32:03 -0600956
Furquan Shaikh70063ff52020-05-11 14:28:13 -0700957 /*
958 * Boot sequence: Step 1
959 * Set correct initial configuration to talk to the slave:
960 * Set clock frequency to 16.7MHz and single IO mode.
961 */
962 espi_set_initial_config(cfg);
963
964 /*
965 * Boot sequence: Step 2
966 * Send in-band reset
967 * The resets affects both host and slave devices, so set initial config again.
968 */
969 if (espi_send_reset() == -1) {
970 printk(BIOS_ERR, "Error: In-band reset failed!\n");
971 return -1;
972 }
973 espi_set_initial_config(cfg);
974
975 /*
976 * Boot sequence: Step 3
977 * Get configuration of slave device.
978 */
979 if (espi_get_general_configuration(&slave_caps) == -1) {
980 printk(BIOS_ERR, "Error: Slave GET_CONFIGURATION failed!\n");
981 return -1;
982 }
983
984 /*
985 * Boot sequence:
986 * Step 4: Write slave device general config
987 * Step 5: Set host slave config
988 */
989 if (espi_set_general_configuration(cfg, slave_caps) == -1) {
990 printk(BIOS_ERR, "Error: Slave SET_CONFIGURATION failed!\n");
991 return -1;
992 }
993
994 /*
995 * Setup polarity before enabling the VW channel so any interrupts
996 * received will have the correct polarity.
997 */
998 espi_write32(ESPI_RXVW_POLARITY, cfg->vw_irq_polarity);
999
1000 /*
1001 * Boot Sequences: Steps 6 - 9
1002 * Channel setup
1003 */
1004 /* Set up VW first so we can deassert PLTRST#. */
1005 if (espi_setup_vw_channel(cfg, slave_caps) == -1) {
1006 printk(BIOS_ERR, "Error: Setup VW channel failed!\n");
1007 return -1;
1008 }
1009
Raul E Rangel43aa5272021-05-21 17:04:28 -06001010 /* Assert PLTRST# if VW channel is enabled by mainboard. */
1011 if (espi_send_pltrst(cfg, true) == -1) {
1012 printk(BIOS_ERR, "Error: PLTRST# assertion failed!\n");
1013 return -1;
1014 }
1015
Furquan Shaikh70063ff52020-05-11 14:28:13 -07001016 /* De-assert PLTRST# if VW channel is enabled by mainboard. */
Raul E Rangel43aa5272021-05-21 17:04:28 -06001017 if (espi_send_pltrst(cfg, false) == -1) {
1018 printk(BIOS_ERR, "Error: PLTRST# deassertion failed!\n");
Furquan Shaikh70063ff52020-05-11 14:28:13 -07001019 return -1;
1020 }
1021
1022 if (espi_setup_periph_channel(cfg, slave_caps) == -1) {
1023 printk(BIOS_ERR, "Error: Setup Periph channel failed!\n");
1024 return -1;
1025 }
1026
1027 if (espi_setup_oob_channel(cfg, slave_caps) == -1) {
1028 printk(BIOS_ERR, "Error: Setup OOB channel failed!\n");
1029 return -1;
1030 }
1031
1032 if (espi_setup_flash_channel(cfg, slave_caps) == -1) {
1033 printk(BIOS_ERR, "Error: Setup Flash channel failed!\n");
1034 return -1;
1035 }
1036
Raul E Rangel61ac1bc2021-04-02 10:55:27 -06001037 if (espi_configure_decodes(cfg) == -1) {
1038 printk(BIOS_ERR, "Error: Configuring decodes failed!\n");
1039 return -1;
1040 }
1041
Furquan Shaikh70063ff52020-05-11 14:28:13 -07001042 /* Enable subtractive decode if configured */
Felix Helda2642d02021-02-17 00:32:46 +01001043 espi_setup_subtractive_decode(cfg);
Furquan Shaikh70063ff52020-05-11 14:28:13 -07001044
Raul E Rangelb92383a2021-04-02 10:32:03 -06001045 espi_write32(ESPI_GLOBAL_CONTROL_1,
1046 espi_read32(ESPI_GLOBAL_CONTROL_1) | ESPI_BUS_MASTER_EN);
1047
Martin Roth7a2bfeb2021-05-14 10:57:31 -06001048 printk(BIOS_SPEW, "Finished initializing ESPI.\n");
1049
Furquan Shaikh70063ff52020-05-11 14:28:13 -07001050 return 0;
1051}