blob: c1d0a5799ad7aa98851058eb9c88e76d30485a51 [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
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{
35 return read32((void *)(espi_get_bar() + reg));
36}
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{
40 write32((void *)(espi_get_bar() + reg), val);
41}
42
Felix Held92dd6782020-08-10 20:27:58 +020043static uint16_t espi_read16(unsigned int reg)
Furquan Shaikhf318e032020-05-04 23:38:53 -070044{
45 return read16((void *)(espi_get_bar() + reg));
46}
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{
50 write16((void *)(espi_get_bar() + reg), val);
51}
52
Felix Held92dd6782020-08-10 20:27:58 +020053static uint8_t espi_read8(unsigned int reg)
Furquan Shaikhf318e032020-05-04 23:38:53 -070054{
55 return read8((void *)(espi_get_bar() + reg));
56}
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{
60 write8((void *)(espi_get_bar() + reg), val);
61}
62
Felix Heldf08fbf82020-08-10 20:30:36 +020063static void espi_enable_decode(uint32_t decode_en)
Furquan Shaikhf318e032020-05-04 23:38:53 -070064{
65 uint32_t val;
66
67 val = espi_read32(ESPI_DECODE);
68 val |= decode_en;
69 espi_write32(ESPI_DECODE, val);
70}
71
Felix Heldf08fbf82020-08-10 20:30:36 +020072static bool espi_is_decode_enabled(uint32_t decode)
Furquan Shaikhf318e032020-05-04 23:38:53 -070073{
74 uint32_t val;
75
76 val = espi_read32(ESPI_DECODE);
77 return !!(val & decode);
78}
79
80static int espi_find_io_window(uint16_t win_base)
81{
82 int i;
83
84 for (i = 0; i < ESPI_GENERIC_IO_WIN_COUNT; i++) {
85 if (!espi_is_decode_enabled(ESPI_DECODE_IO_RANGE_EN(i)))
86 continue;
87
88 if (espi_read16(ESPI_IO_RANGE_BASE(i)) == win_base)
89 return i;
90 }
91
92 return -1;
93}
94
95static int espi_get_unused_io_window(void)
96{
97 int i;
98
99 for (i = 0; i < ESPI_GENERIC_IO_WIN_COUNT; i++) {
100 if (!espi_is_decode_enabled(ESPI_DECODE_IO_RANGE_EN(i)))
101 return i;
102 }
103
104 return -1;
105}
106
Raul E Rangelb95f8482021-04-02 13:47:09 -0600107static void espi_clear_decodes(void)
Martin Roth011bf132021-03-23 13:20:42 -0600108{
109 unsigned int idx;
110
111 /* First turn off all enable bits, then zero base, range, and size registers */
Raul E Rangel01792e32021-04-26 13:52:38 -0600112 espi_write16(ESPI_DECODE, 0);
Martin Roth011bf132021-03-23 13:20:42 -0600113
114 for (idx = 0; idx < ESPI_GENERIC_IO_WIN_COUNT; idx++) {
115 espi_write16(ESPI_IO_RANGE_BASE(idx), 0);
116 espi_write8(ESPI_IO_RANGE_SIZE(idx), 0);
117 }
118 for (idx = 0; idx < ESPI_GENERIC_MMIO_WIN_COUNT; idx++) {
119 espi_write32(ESPI_MMIO_RANGE_BASE(idx), 0);
120 espi_write16(ESPI_MMIO_RANGE_SIZE(idx), 0);
121 }
122}
123
Furquan Shaikhf318e032020-05-04 23:38:53 -0700124/*
125 * Returns decode enable bits for standard IO port addresses. If port address is not supported
126 * by standard decode or if the size of window is not 1, then it returns -1.
127 */
128static int espi_std_io_decode(uint16_t base, size_t size)
129{
Felix Heldc0d4eeb2020-08-10 20:37:16 +0200130 if (size == 2 && base == 0x2e)
131 return ESPI_DECODE_IO_0X2E_0X2F_EN;
132
Furquan Shaikhf318e032020-05-04 23:38:53 -0700133 if (size != 1)
Felix Held4bf419f2020-08-10 20:33:25 +0200134 return -1;
Furquan Shaikhf318e032020-05-04 23:38:53 -0700135
136 switch (base) {
137 case 0x80:
Felix Held4bf419f2020-08-10 20:33:25 +0200138 return ESPI_DECODE_IO_0x80_EN;
Furquan Shaikhf318e032020-05-04 23:38:53 -0700139 case 0x60:
140 case 0x64:
Felix Held4bf419f2020-08-10 20:33:25 +0200141 return ESPI_DECODE_IO_0X60_0X64_EN;
Furquan Shaikhf318e032020-05-04 23:38:53 -0700142 case 0x2e:
143 case 0x2f:
Felix Held4bf419f2020-08-10 20:33:25 +0200144 return ESPI_DECODE_IO_0X2E_0X2F_EN;
Furquan Shaikhf318e032020-05-04 23:38:53 -0700145 default:
Felix Held4bf419f2020-08-10 20:33:25 +0200146 return -1;
Furquan Shaikhf318e032020-05-04 23:38:53 -0700147 }
Furquan Shaikhf318e032020-05-04 23:38:53 -0700148}
149
150static size_t espi_get_io_window_size(int idx)
151{
152 return espi_read8(ESPI_IO_RANGE_SIZE(idx)) + 1;
153}
154
155static void espi_write_io_window(int idx, uint16_t base, size_t size)
156{
157 espi_write16(ESPI_IO_RANGE_BASE(idx), base);
158 espi_write8(ESPI_IO_RANGE_SIZE(idx), size - 1);
159}
160
Felix Heldaed38a92021-12-18 00:41:23 +0100161static enum cb_err espi_open_generic_io_window(uint16_t base, size_t size)
Furquan Shaikhf318e032020-05-04 23:38:53 -0700162{
163 size_t win_size;
164 int idx;
165
166 for (; size; size -= win_size, base += win_size) {
167 win_size = MIN(size, ESPI_GENERIC_IO_MAX_WIN_SIZE);
168
169 idx = espi_find_io_window(base);
170 if (idx != -1) {
171 size_t curr_size = espi_get_io_window_size(idx);
172
173 if (curr_size > win_size) {
174 printk(BIOS_INFO, "eSPI window already configured to be larger than requested! ");
175 printk(BIOS_INFO, "Base: 0x%x, Requested size: 0x%zx, Actual size: 0x%zx\n",
176 base, win_size, curr_size);
177 } else if (curr_size < win_size) {
178 espi_write_io_window(idx, base, win_size);
179 printk(BIOS_INFO, "eSPI window at base: 0x%x resized from 0x%zx to 0x%zx\n",
180 base, curr_size, win_size);
181 }
182
183 continue;
184 }
185
186 idx = espi_get_unused_io_window();
187 if (idx == -1) {
188 printk(BIOS_ERR, "Cannot open IO window base %x size %zx\n", base,
189 size);
Julius Wernere9665952022-01-21 17:06:20 -0800190 printk(BIOS_ERR, "No more available IO windows!\n");
Felix Heldaed38a92021-12-18 00:41:23 +0100191 return CB_ERR;
Furquan Shaikhf318e032020-05-04 23:38:53 -0700192 }
193
194 espi_write_io_window(idx, base, win_size);
195 espi_enable_decode(ESPI_DECODE_IO_RANGE_EN(idx));
196 }
197
Felix Heldaed38a92021-12-18 00:41:23 +0100198 return CB_SUCCESS;
Furquan Shaikhf318e032020-05-04 23:38:53 -0700199}
200
Felix Heldaed38a92021-12-18 00:41:23 +0100201enum cb_err espi_open_io_window(uint16_t base, size_t size)
Furquan Shaikhf318e032020-05-04 23:38:53 -0700202{
203 int std_io;
204
205 std_io = espi_std_io_decode(base, size);
206 if (std_io != -1) {
207 espi_enable_decode(std_io);
Felix Heldaed38a92021-12-18 00:41:23 +0100208 return CB_SUCCESS;
Felix Heldb026c7c2020-08-10 20:43:53 +0200209 } else {
210 return espi_open_generic_io_window(base, size);
Furquan Shaikhf318e032020-05-04 23:38:53 -0700211 }
Furquan Shaikhf318e032020-05-04 23:38:53 -0700212}
213
214static int espi_find_mmio_window(uint32_t win_base)
215{
216 int i;
217
218 for (i = 0; i < ESPI_GENERIC_MMIO_WIN_COUNT; i++) {
219 if (!espi_is_decode_enabled(ESPI_DECODE_MMIO_RANGE_EN(i)))
220 continue;
221
222 if (espi_read32(ESPI_MMIO_RANGE_BASE(i)) == win_base)
223 return i;
224 }
225
226 return -1;
227}
228
229static int espi_get_unused_mmio_window(void)
230{
231 int i;
232
233 for (i = 0; i < ESPI_GENERIC_MMIO_WIN_COUNT; i++) {
234 if (!espi_is_decode_enabled(ESPI_DECODE_MMIO_RANGE_EN(i)))
235 return i;
236 }
237
238 return -1;
239
240}
241
242static size_t espi_get_mmio_window_size(int idx)
243{
244 return espi_read16(ESPI_MMIO_RANGE_SIZE(idx)) + 1;
245}
246
247static void espi_write_mmio_window(int idx, uint32_t base, size_t size)
248{
249 espi_write32(ESPI_MMIO_RANGE_BASE(idx), base);
250 espi_write16(ESPI_MMIO_RANGE_SIZE(idx), size - 1);
251}
252
Felix Heldaed38a92021-12-18 00:41:23 +0100253enum cb_err espi_open_mmio_window(uint32_t base, size_t size)
Furquan Shaikhf318e032020-05-04 23:38:53 -0700254{
255 size_t win_size;
256 int idx;
257
258 for (; size; size -= win_size, base += win_size) {
259 win_size = MIN(size, ESPI_GENERIC_MMIO_MAX_WIN_SIZE);
260
261 idx = espi_find_mmio_window(base);
262 if (idx != -1) {
263 size_t curr_size = espi_get_mmio_window_size(idx);
264
265 if (curr_size > win_size) {
266 printk(BIOS_INFO, "eSPI window already configured to be larger than requested! ");
267 printk(BIOS_INFO, "Base: 0x%x, Requested size: 0x%zx, Actual size: 0x%zx\n",
268 base, win_size, curr_size);
269 } else if (curr_size < win_size) {
270 espi_write_mmio_window(idx, base, win_size);
271 printk(BIOS_INFO, "eSPI window at base: 0x%x resized from 0x%zx to 0x%zx\n",
272 base, curr_size, win_size);
273 }
274
275 continue;
276 }
277
278 idx = espi_get_unused_mmio_window();
279 if (idx == -1) {
280 printk(BIOS_ERR, "Cannot open IO window base %x size %zx\n", base,
281 size);
Julius Wernere9665952022-01-21 17:06:20 -0800282 printk(BIOS_ERR, "No more available MMIO windows!\n");
Felix Heldaed38a92021-12-18 00:41:23 +0100283 return CB_ERR;
Furquan Shaikhf318e032020-05-04 23:38:53 -0700284 }
285
286 espi_write_mmio_window(idx, base, win_size);
287 espi_enable_decode(ESPI_DECODE_MMIO_RANGE_EN(idx));
288 }
289
Felix Heldaed38a92021-12-18 00:41:23 +0100290 return CB_SUCCESS;
Furquan Shaikhf318e032020-05-04 23:38:53 -0700291}
292
293static const struct espi_config *espi_get_config(void)
294{
295 const struct soc_amd_common_config *soc_cfg = soc_get_common_config();
296
297 if (!soc_cfg)
298 die("Common config structure is NULL!\n");
299
300 return &soc_cfg->espi_config;
301}
302
Felix Heldaed38a92021-12-18 00:41:23 +0100303static enum cb_err espi_configure_decodes(const struct espi_config *cfg)
Furquan Shaikhf318e032020-05-04 23:38:53 -0700304{
Felix Held9e830542021-12-18 00:41:23 +0100305 int i;
Furquan Shaikhf318e032020-05-04 23:38:53 -0700306
307 espi_enable_decode(cfg->std_io_decode_bitmap);
308
309 for (i = 0; i < ESPI_GENERIC_IO_WIN_COUNT; i++) {
310 if (cfg->generic_io_range[i].size == 0)
311 continue;
Felix Held9e830542021-12-18 00:41:23 +0100312 if (espi_open_generic_io_window(cfg->generic_io_range[i].base,
Felix Heldaed38a92021-12-18 00:41:23 +0100313 cfg->generic_io_range[i].size) != CB_SUCCESS)
314 return CB_ERR;
Furquan Shaikhf318e032020-05-04 23:38:53 -0700315 }
Raul E Rangel61ac1bc2021-04-02 10:55:27 -0600316
Felix Heldaed38a92021-12-18 00:41:23 +0100317 return CB_SUCCESS;
Furquan Shaikhf318e032020-05-04 23:38:53 -0700318}
Furquan Shaikh70063ff52020-05-11 14:28:13 -0700319
Furquan Shaikh70063ff52020-05-11 14:28:13 -0700320enum espi_cmd_type {
321 CMD_TYPE_SET_CONFIGURATION = 0,
322 CMD_TYPE_GET_CONFIGURATION = 1,
323 CMD_TYPE_IN_BAND_RESET = 2,
324 CMD_TYPE_PERIPHERAL = 4,
325 CMD_TYPE_VW = 5,
326 CMD_TYPE_OOB = 6,
327 CMD_TYPE_FLASH = 7,
328};
329
Furquan Shaikh70063ff52020-05-11 14:28:13 -0700330#define ESPI_CMD_TIMEOUT_US 100
Raul E Rangel0318dc12021-05-21 16:31:52 -0600331#define ESPI_CH_READY_TIMEOUT_US 10000
Furquan Shaikh70063ff52020-05-11 14:28:13 -0700332
333union espi_txhdr0 {
334 uint32_t val;
335 struct {
336 uint32_t cmd_type:3;
337 uint32_t cmd_sts:1;
338 uint32_t slave_sel:2;
339 uint32_t rsvd:2;
340 uint32_t hdata0:8;
341 uint32_t hdata1:8;
342 uint32_t hdata2:8;
343 };
344} __packed;
345
346union espi_txhdr1 {
347 uint32_t val;
348 struct {
349 uint32_t hdata3:8;
350 uint32_t hdata4:8;
351 uint32_t hdata5:8;
352 uint32_t hdata6:8;
353 };
354} __packed;
355
356union espi_txhdr2 {
357 uint32_t val;
358 struct {
359 uint32_t hdata7:8;
360 uint32_t rsvd:24;
361 };
362} __packed;
363
364union espi_txdata {
365 uint32_t val;
366 struct {
367 uint32_t byte0:8;
368 uint32_t byte1:8;
369 uint32_t byte2:8;
370 uint32_t byte3:8;
371 };
372} __packed;
373
374struct espi_cmd {
375 union espi_txhdr0 hdr0;
376 union espi_txhdr1 hdr1;
377 union espi_txhdr2 hdr2;
378 union espi_txdata data;
Raul E Rangel12c05422021-05-11 11:13:38 -0600379 uint32_t expected_status_codes;
Furquan Shaikh70063ff52020-05-11 14:28:13 -0700380} __packed;
381
382/* Wait up to ESPI_CMD_TIMEOUT_US for hardware to clear DNCMD_STATUS bit. */
Felix Held4b4114f72021-12-18 00:41:23 +0100383static enum cb_err espi_wait_ready(void)
Furquan Shaikh70063ff52020-05-11 14:28:13 -0700384{
385 struct stopwatch sw;
386 union espi_txhdr0 hdr0;
387
388 stopwatch_init_usecs_expire(&sw, ESPI_CMD_TIMEOUT_US);
389 do {
390 hdr0.val = espi_read32(ESPI_DN_TX_HDR0);
391 if (!hdr0.cmd_sts)
Felix Held4b4114f72021-12-18 00:41:23 +0100392 return CB_SUCCESS;
Furquan Shaikh70063ff52020-05-11 14:28:13 -0700393 } while (!stopwatch_expired(&sw));
394
Felix Held4b4114f72021-12-18 00:41:23 +0100395 return CB_ERR;
Furquan Shaikh70063ff52020-05-11 14:28:13 -0700396}
397
398/* Clear interrupt status register */
399static void espi_clear_status(void)
400{
Raul E Rangel47740122021-04-02 10:16:54 -0600401 uint32_t status = espi_read32(ESPI_SLAVE0_INT_STS);
Furquan Shaikh70063ff52020-05-11 14:28:13 -0700402 if (status)
Raul E Rangel47740122021-04-02 10:16:54 -0600403 espi_write32(ESPI_SLAVE0_INT_STS, status);
Furquan Shaikh70063ff52020-05-11 14:28:13 -0700404}
405
406/*
407 * Wait up to ESPI_CMD_TIMEOUT_US for interrupt status register to update after sending a
408 * command.
409 */
Felix Held4b4114f72021-12-18 00:41:23 +0100410static enum cb_err espi_poll_status(uint32_t *status)
Furquan Shaikh70063ff52020-05-11 14:28:13 -0700411{
412 struct stopwatch sw;
413
414 stopwatch_init_usecs_expire(&sw, ESPI_CMD_TIMEOUT_US);
415 do {
Raul E Rangel47740122021-04-02 10:16:54 -0600416 *status = espi_read32(ESPI_SLAVE0_INT_STS);
Furquan Shaikh70063ff52020-05-11 14:28:13 -0700417 if (*status)
Felix Held4b4114f72021-12-18 00:41:23 +0100418 return CB_SUCCESS;
Furquan Shaikh70063ff52020-05-11 14:28:13 -0700419 } while (!stopwatch_expired(&sw));
420
Julius Wernere9665952022-01-21 17:06:20 -0800421 printk(BIOS_ERR, "eSPI timed out waiting for status update.\n");
Furquan Shaikh70063ff52020-05-11 14:28:13 -0700422
Felix Held4b4114f72021-12-18 00:41:23 +0100423 return CB_ERR;
Furquan Shaikh70063ff52020-05-11 14:28:13 -0700424}
425
426static void espi_show_failure(const struct espi_cmd *cmd, const char *str, uint32_t status)
427{
428 printk(BIOS_ERR, "eSPI cmd0-cmd2: %08x %08x %08x data: %08x.\n",
429 cmd->hdr0.val, cmd->hdr1.val, cmd->hdr2.val, cmd->data.val);
430 printk(BIOS_ERR, "%s (Status = 0x%x)\n", str, status);
431}
432
Felix Held4b4114f72021-12-18 00:41:23 +0100433static enum cb_err espi_send_command(const struct espi_cmd *cmd)
Furquan Shaikh70063ff52020-05-11 14:28:13 -0700434{
435 uint32_t status;
436
437 if (CONFIG(ESPI_DEBUG))
Raul E Rangelf7027052021-06-29 13:12:19 -0600438 printk(BIOS_DEBUG, "eSPI cmd0-cmd2: %08x %08x %08x data: %08x.\n",
Furquan Shaikh70063ff52020-05-11 14:28:13 -0700439 cmd->hdr0.val, cmd->hdr1.val, cmd->hdr2.val, cmd->data.val);
440
Felix Held4b4114f72021-12-18 00:41:23 +0100441 if (espi_wait_ready() != CB_SUCCESS) {
Furquan Shaikh70063ff52020-05-11 14:28:13 -0700442 espi_show_failure(cmd, "Error: eSPI was not ready to accept a command", 0);
Felix Held4b4114f72021-12-18 00:41:23 +0100443 return CB_ERR;
Furquan Shaikh70063ff52020-05-11 14:28:13 -0700444 }
445
446 espi_clear_status();
447
448 espi_write32(ESPI_DN_TX_HDR1, cmd->hdr1.val);
449 espi_write32(ESPI_DN_TX_HDR2, cmd->hdr2.val);
450 espi_write32(ESPI_DN_TX_DATA, cmd->data.val);
451
452 /* Dword 0 must be last as this write triggers the transaction */
453 espi_write32(ESPI_DN_TX_HDR0, cmd->hdr0.val);
454
Felix Held4b4114f72021-12-18 00:41:23 +0100455 if (espi_wait_ready() != CB_SUCCESS) {
Furquan Shaikh70063ff52020-05-11 14:28:13 -0700456 espi_show_failure(cmd,
457 "Error: eSPI timed out waiting for command to complete", 0);
Felix Held4b4114f72021-12-18 00:41:23 +0100458 return CB_ERR;
Furquan Shaikh70063ff52020-05-11 14:28:13 -0700459 }
460
Felix Held4b4114f72021-12-18 00:41:23 +0100461 if (espi_poll_status(&status) != CB_SUCCESS) {
Felix Held1ba38332020-08-10 20:45:30 +0200462 espi_show_failure(cmd, "Error: eSPI poll status failed", 0);
Felix Held4b4114f72021-12-18 00:41:23 +0100463 return CB_ERR;
Furquan Shaikh70063ff52020-05-11 14:28:13 -0700464 }
465
466 /* If command did not complete downstream, return error. */
467 if (!(status & ESPI_STATUS_DNCMD_COMPLETE)) {
468 espi_show_failure(cmd, "Error: eSPI downstream command completion failure",
469 status);
Felix Held4b4114f72021-12-18 00:41:23 +0100470 return CB_ERR;
Furquan Shaikh70063ff52020-05-11 14:28:13 -0700471 }
472
Raul E Rangel12c05422021-05-11 11:13:38 -0600473 if (status & ~(ESPI_STATUS_DNCMD_COMPLETE | cmd->expected_status_codes)) {
Felix Held316d59c2020-08-10 20:42:20 +0200474 espi_show_failure(cmd, "Error: unexpected eSPI status register bits set",
475 status);
Felix Held4b4114f72021-12-18 00:41:23 +0100476 return CB_ERR;
Furquan Shaikh70063ff52020-05-11 14:28:13 -0700477 }
478
Raul E Rangel12c05422021-05-11 11:13:38 -0600479 espi_write32(ESPI_SLAVE0_INT_STS, status);
Raul E Rangel66c52ff2021-04-02 10:18:25 -0600480
Felix Held4b4114f72021-12-18 00:41:23 +0100481 return CB_SUCCESS;
Furquan Shaikh70063ff52020-05-11 14:28:13 -0700482}
483
Felix Held4b4114f72021-12-18 00:41:23 +0100484static enum cb_err espi_send_reset(void)
Furquan Shaikh70063ff52020-05-11 14:28:13 -0700485{
486 struct espi_cmd cmd = {
487 .hdr0 = {
488 .cmd_type = CMD_TYPE_IN_BAND_RESET,
489 .cmd_sts = 1,
490 },
Raul E Rangel12c05422021-05-11 11:13:38 -0600491
492 /*
493 * When performing an in-band reset the host controller and the
494 * peripheral can have mismatched IO configs.
495 *
496 * i.e., The eSPI peripheral can be in IO-4 mode while, the
497 * eSPI host will be in IO-1. This results in the peripheral
498 * getting invalid packets and thus not responding.
499 *
500 * If the peripheral is alerting when we perform an in-band
501 * reset, there is a race condition in espi_send_command.
502 * 1) espi_send_command clears the interrupt status.
503 * 2) eSPI host controller hardware notices the alert and sends
504 * a GET_STATUS.
505 * 3) espi_send_command writes the in-band reset command.
506 * 4) eSPI hardware enqueues the in-band reset until GET_STATUS
507 * is complete.
508 * 5) GET_STATUS fails with NO_RESPONSE and sets the interrupt
509 * status.
510 * 6) eSPI hardware performs in-band reset.
511 * 7) espi_send_command checks the status and sees a
512 * NO_RESPONSE bit.
513 *
514 * As a workaround we allow the NO_RESPONSE status code when
515 * we perform an in-band reset.
516 */
517 .expected_status_codes = ESPI_STATUS_NO_RESPONSE,
Furquan Shaikh70063ff52020-05-11 14:28:13 -0700518 };
519
520 return espi_send_command(&cmd);
521}
522
Felix Held4b4114f72021-12-18 00:41:23 +0100523static enum cb_err espi_send_pltrst(const struct espi_config *mb_cfg, bool assert)
Furquan Shaikh70063ff52020-05-11 14:28:13 -0700524{
525 struct espi_cmd cmd = {
526 .hdr0 = {
527 .cmd_type = CMD_TYPE_VW,
528 .cmd_sts = 1,
529 .hdata0 = 0, /* 1 VW group */
530 },
531 .data = {
532 .byte0 = ESPI_VW_INDEX_SYSTEM_EVENT_3,
Raul E Rangel43aa5272021-05-21 17:04:28 -0600533 .byte1 = assert ? ESPI_VW_SIGNAL_LOW(ESPI_VW_PLTRST)
534 : ESPI_VW_SIGNAL_HIGH(ESPI_VW_PLTRST),
Furquan Shaikh70063ff52020-05-11 14:28:13 -0700535 },
536 };
537
538 if (!mb_cfg->vw_ch_en)
Felix Held4b4114f72021-12-18 00:41:23 +0100539 return CB_SUCCESS;
Furquan Shaikh70063ff52020-05-11 14:28:13 -0700540
541 return espi_send_command(&cmd);
542}
543
544/*
545 * In case of get configuration command, hdata0 contains bits 15:8 of the slave register address
546 * and hdata1 contains bits 7:0 of the slave register address.
547 */
548#define ESPI_CONFIGURATION_HDATA0(a) (((a) >> 8) & 0xff)
549#define ESPI_CONFIGURATION_HDATA1(a) ((a) & 0xff)
550
Felix Held4b4114f72021-12-18 00:41:23 +0100551static enum cb_err espi_get_configuration(uint16_t slave_reg_addr, uint32_t *config)
Furquan Shaikh70063ff52020-05-11 14:28:13 -0700552{
553 struct espi_cmd cmd = {
554 .hdr0 = {
555 .cmd_type = CMD_TYPE_GET_CONFIGURATION,
556 .cmd_sts = 1,
557 .hdata0 = ESPI_CONFIGURATION_HDATA0(slave_reg_addr),
558 .hdata1 = ESPI_CONFIGURATION_HDATA1(slave_reg_addr),
559 },
560 };
561
562 *config = 0;
563
Felix Held4b4114f72021-12-18 00:41:23 +0100564 if (espi_send_command(&cmd) != CB_SUCCESS)
565 return CB_ERR;
Furquan Shaikh70063ff52020-05-11 14:28:13 -0700566
567 *config = espi_read32(ESPI_DN_TX_HDR1);
568
569 if (CONFIG(ESPI_DEBUG))
570 printk(BIOS_DEBUG, "Get configuration for slave register(0x%x): 0x%x\n",
571 slave_reg_addr, *config);
572
Felix Held4b4114f72021-12-18 00:41:23 +0100573 return CB_SUCCESS;
Furquan Shaikh70063ff52020-05-11 14:28:13 -0700574}
575
Felix Held4b4114f72021-12-18 00:41:23 +0100576static enum cb_err espi_set_configuration(uint16_t slave_reg_addr, uint32_t config)
Furquan Shaikh70063ff52020-05-11 14:28:13 -0700577{
578 struct espi_cmd cmd = {
579 .hdr0 = {
580 .cmd_type = CMD_TYPE_SET_CONFIGURATION,
581 .cmd_sts = 1,
582 .hdata0 = ESPI_CONFIGURATION_HDATA0(slave_reg_addr),
583 .hdata1 = ESPI_CONFIGURATION_HDATA1(slave_reg_addr),
584 },
585 .hdr1 = {
586 .val = config,
587 },
588 };
589
590 return espi_send_command(&cmd);
591}
592
Felix Held4b4114f72021-12-18 00:41:23 +0100593static enum cb_err espi_get_general_configuration(uint32_t *config)
Furquan Shaikh70063ff52020-05-11 14:28:13 -0700594{
Felix Held4b4114f72021-12-18 00:41:23 +0100595 if (espi_get_configuration(ESPI_SLAVE_GENERAL_CFG, config) != CB_SUCCESS)
596 return CB_ERR;
Furquan Shaikh70063ff52020-05-11 14:28:13 -0700597
598 espi_show_slave_general_configuration(*config);
Felix Held4b4114f72021-12-18 00:41:23 +0100599 return CB_SUCCESS;
Furquan Shaikh70063ff52020-05-11 14:28:13 -0700600}
601
602static void espi_set_io_mode_config(enum espi_io_mode mb_io_mode, uint32_t slave_caps,
603 uint32_t *slave_config, uint32_t *ctrlr_config)
604{
605 switch (mb_io_mode) {
606 case ESPI_IO_MODE_QUAD:
607 if (espi_slave_supports_quad_io(slave_caps)) {
608 *slave_config |= ESPI_SLAVE_IO_MODE_SEL_QUAD;
609 *ctrlr_config |= ESPI_IO_MODE_QUAD;
610 break;
611 }
Julius Wernere9665952022-01-21 17:06:20 -0800612 printk(BIOS_ERR, "eSPI Quad I/O not supported. Dropping to dual mode.\n");
Furquan Shaikh70063ff52020-05-11 14:28:13 -0700613 /* Intentional fall-through */
614 case ESPI_IO_MODE_DUAL:
615 if (espi_slave_supports_dual_io(slave_caps)) {
616 *slave_config |= ESPI_SLAVE_IO_MODE_SEL_DUAL;
617 *ctrlr_config |= ESPI_IO_MODE_DUAL;
618 break;
619 }
Julius Wernere9665952022-01-21 17:06:20 -0800620 printk(BIOS_ERR, "eSPI Dual I/O not supported. Dropping to single mode.\n");
Furquan Shaikh70063ff52020-05-11 14:28:13 -0700621 /* Intentional fall-through */
622 case ESPI_IO_MODE_SINGLE:
623 /* Single I/O mode is always supported. */
624 *slave_config |= ESPI_SLAVE_IO_MODE_SEL_SINGLE;
625 *ctrlr_config |= ESPI_IO_MODE_SINGLE;
626 break;
627 default:
628 die("No supported eSPI I/O modes!\n");
629 }
630}
631
632static void espi_set_op_freq_config(enum espi_op_freq mb_op_freq, uint32_t slave_caps,
633 uint32_t *slave_config, uint32_t *ctrlr_config)
634{
635 int slave_max_speed_mhz = espi_slave_max_speed_mhz_supported(slave_caps);
636
637 switch (mb_op_freq) {
638 case ESPI_OP_FREQ_66_MHZ:
639 if (slave_max_speed_mhz >= 66) {
640 *slave_config |= ESPI_SLAVE_OP_FREQ_SEL_66_MHZ;
641 *ctrlr_config |= ESPI_OP_FREQ_66_MHZ;
642 break;
643 }
Julius Wernere9665952022-01-21 17:06:20 -0800644 printk(BIOS_ERR, "eSPI 66MHz not supported. Dropping to 33MHz.\n");
Furquan Shaikh70063ff52020-05-11 14:28:13 -0700645 /* Intentional fall-through */
646 case ESPI_OP_FREQ_33_MHZ:
647 if (slave_max_speed_mhz >= 33) {
648 *slave_config |= ESPI_SLAVE_OP_FREQ_SEL_33_MHZ;
649 *ctrlr_config |= ESPI_OP_FREQ_33_MHZ;
650 break;
651 }
Julius Wernere9665952022-01-21 17:06:20 -0800652 printk(BIOS_ERR, "eSPI 33MHz not supported. Dropping to 16MHz.\n");
Furquan Shaikh70063ff52020-05-11 14:28:13 -0700653 /* Intentional fall-through */
654 case ESPI_OP_FREQ_16_MHZ:
655 /*
656 * eSPI spec says the minimum frequency is 20MHz, but AMD datasheets support
657 * 16.7 Mhz.
658 */
659 if (slave_max_speed_mhz > 0) {
660 *slave_config |= ESPI_SLAVE_OP_FREQ_SEL_20_MHZ;
661 *ctrlr_config |= ESPI_OP_FREQ_16_MHZ;
662 break;
663 }
664 /* Intentional fall-through */
665 default:
666 die("No supported eSPI Operating Frequency!\n");
667 }
668}
669
Raul E Rangel8317e722021-05-05 13:38:27 -0600670static void espi_set_alert_pin_config(enum espi_alert_pin alert_pin, uint32_t slave_caps,
671 uint32_t *slave_config, uint32_t *ctrlr_config)
672{
673 switch (alert_pin) {
674 case ESPI_ALERT_PIN_IN_BAND:
675 *slave_config |= ESPI_SLAVE_ALERT_MODE_IO1;
676 return;
677 case ESPI_ALERT_PIN_PUSH_PULL:
678 *slave_config |= ESPI_SLAVE_ALERT_MODE_PIN | ESPI_SLAVE_PUSH_PULL_ALERT_SEL;
679 *ctrlr_config |= ESPI_ALERT_MODE;
680 return;
681 case ESPI_ALERT_PIN_OPEN_DRAIN:
682 if (!(slave_caps & ESPI_SLAVE_OPEN_DRAIN_ALERT_SUPP))
683 die("eSPI peripheral does not support open drain alert!");
684
685 *slave_config |= ESPI_SLAVE_ALERT_MODE_PIN | ESPI_SLAVE_OPEN_DRAIN_ALERT_SEL;
686 *ctrlr_config |= ESPI_ALERT_MODE;
687 return;
688 default:
689 die("Unknown espi alert config: %u!\n", alert_pin);
690 }
691}
692
Felix Held4b4114f72021-12-18 00:41:23 +0100693static enum cb_err espi_set_general_configuration(const struct espi_config *mb_cfg,
694 uint32_t slave_caps)
Furquan Shaikh70063ff52020-05-11 14:28:13 -0700695{
696 uint32_t slave_config = 0;
697 uint32_t ctrlr_config = 0;
698
699 if (mb_cfg->crc_check_enable) {
700 slave_config |= ESPI_SLAVE_CRC_ENABLE;
701 ctrlr_config |= ESPI_CRC_CHECKING_EN;
702 }
703
Raul E Rangel8317e722021-05-05 13:38:27 -0600704 espi_set_alert_pin_config(mb_cfg->alert_pin, slave_caps, &slave_config, &ctrlr_config);
Furquan Shaikh70063ff52020-05-11 14:28:13 -0700705 espi_set_io_mode_config(mb_cfg->io_mode, slave_caps, &slave_config, &ctrlr_config);
706 espi_set_op_freq_config(mb_cfg->op_freq_mhz, slave_caps, &slave_config, &ctrlr_config);
707
708 if (CONFIG(ESPI_DEBUG))
709 printk(BIOS_INFO, "Setting general configuration: slave: 0x%x controller: 0x%x\n",
710 slave_config, ctrlr_config);
711
Raul E Rangeld2d762a2021-05-05 13:30:10 -0600712 espi_show_slave_general_configuration(slave_config);
713
Felix Held4b4114f72021-12-18 00:41:23 +0100714 if (espi_set_configuration(ESPI_SLAVE_GENERAL_CFG, slave_config) != CB_SUCCESS)
715 return CB_ERR;
Furquan Shaikh70063ff52020-05-11 14:28:13 -0700716
717 espi_write32(ESPI_SLAVE0_CONFIG, ctrlr_config);
Felix Held4b4114f72021-12-18 00:41:23 +0100718 return CB_SUCCESS;
Furquan Shaikh70063ff52020-05-11 14:28:13 -0700719}
720
Felix Held4b4114f72021-12-18 00:41:23 +0100721static enum cb_err espi_wait_channel_ready(uint16_t slave_reg_addr)
Furquan Shaikh70063ff52020-05-11 14:28:13 -0700722{
723 struct stopwatch sw;
724 uint32_t config;
725
726 stopwatch_init_usecs_expire(&sw, ESPI_CH_READY_TIMEOUT_US);
727 do {
Felix Held5ba87a82021-12-18 00:41:23 +0100728 if (espi_get_configuration(slave_reg_addr, &config) != CB_SUCCESS)
729 return CB_ERR;
Furquan Shaikh70063ff52020-05-11 14:28:13 -0700730 if (espi_slave_is_channel_ready(config))
Felix Held4b4114f72021-12-18 00:41:23 +0100731 return CB_SUCCESS;
Furquan Shaikh70063ff52020-05-11 14:28:13 -0700732 } while (!stopwatch_expired(&sw));
733
Julius Wernere9665952022-01-21 17:06:20 -0800734 printk(BIOS_ERR, "Channel is not ready after %d usec (slave addr: 0x%x)\n",
Furquan Shaikh70063ff52020-05-11 14:28:13 -0700735 ESPI_CH_READY_TIMEOUT_US, slave_reg_addr);
Felix Held4b4114f72021-12-18 00:41:23 +0100736 return CB_ERR;
Furquan Shaikh70063ff52020-05-11 14:28:13 -0700737
738}
739
740static void espi_enable_ctrlr_channel(uint32_t channel_en)
741{
742 uint32_t reg = espi_read32(ESPI_SLAVE0_CONFIG);
743
744 reg |= channel_en;
745
746 espi_write32(ESPI_SLAVE0_CONFIG, reg);
747}
748
Felix Held4b4114f72021-12-18 00:41:23 +0100749static enum cb_err espi_set_channel_configuration(uint32_t slave_config,
750 uint32_t slave_reg_addr,
751 uint32_t ctrlr_enable)
Furquan Shaikh70063ff52020-05-11 14:28:13 -0700752{
Felix Held4b4114f72021-12-18 00:41:23 +0100753 if (espi_set_configuration(slave_reg_addr, slave_config) != CB_SUCCESS)
754 return CB_ERR;
Furquan Shaikh70063ff52020-05-11 14:28:13 -0700755
756 if (!(slave_config & ESPI_SLAVE_CHANNEL_ENABLE))
Felix Held4b4114f72021-12-18 00:41:23 +0100757 return CB_SUCCESS;
Furquan Shaikh70063ff52020-05-11 14:28:13 -0700758
Felix Held4b4114f72021-12-18 00:41:23 +0100759 if (espi_wait_channel_ready(slave_reg_addr) != CB_SUCCESS)
760 return CB_ERR;
Furquan Shaikh70063ff52020-05-11 14:28:13 -0700761
762 espi_enable_ctrlr_channel(ctrlr_enable);
Felix Held4b4114f72021-12-18 00:41:23 +0100763 return CB_SUCCESS;
Furquan Shaikh70063ff52020-05-11 14:28:13 -0700764}
765
Felix Held4b4114f72021-12-18 00:41:23 +0100766static enum cb_err espi_setup_vw_channel(const struct espi_config *mb_cfg, uint32_t slave_caps)
Furquan Shaikh70063ff52020-05-11 14:28:13 -0700767{
768 uint32_t slave_vw_caps;
769 uint32_t ctrlr_vw_caps;
770 uint32_t slave_vw_count_supp;
771 uint32_t ctrlr_vw_count_supp;
772 uint32_t use_vw_count;
773 uint32_t slave_config;
774
775 if (!mb_cfg->vw_ch_en)
Felix Held4b4114f72021-12-18 00:41:23 +0100776 return CB_SUCCESS;
Furquan Shaikh70063ff52020-05-11 14:28:13 -0700777
778 if (!espi_slave_supports_vw_channel(slave_caps)) {
Julius Wernere9665952022-01-21 17:06:20 -0800779 printk(BIOS_ERR, "eSPI slave doesn't support VW channel!\n");
Felix Held4b4114f72021-12-18 00:41:23 +0100780 return CB_ERR;
Furquan Shaikh70063ff52020-05-11 14:28:13 -0700781 }
782
Felix Held4b4114f72021-12-18 00:41:23 +0100783 if (espi_get_configuration(ESPI_SLAVE_VW_CFG, &slave_vw_caps) != CB_SUCCESS)
784 return CB_ERR;
Furquan Shaikh70063ff52020-05-11 14:28:13 -0700785
786 ctrlr_vw_caps = espi_read32(ESPI_MASTER_CAP);
787 ctrlr_vw_count_supp = (ctrlr_vw_caps & ESPI_VW_MAX_SIZE_MASK) >> ESPI_VW_MAX_SIZE_SHIFT;
788
789 slave_vw_count_supp = espi_slave_get_vw_count_supp(slave_vw_caps);
790 use_vw_count = MIN(ctrlr_vw_count_supp, slave_vw_count_supp);
791
792 slave_config = ESPI_SLAVE_CHANNEL_ENABLE | ESPI_SLAVE_VW_COUNT_SEL_VAL(use_vw_count);
793 return espi_set_channel_configuration(slave_config, ESPI_SLAVE_VW_CFG, ESPI_VW_CH_EN);
794}
795
Felix Held4b4114f72021-12-18 00:41:23 +0100796static enum cb_err espi_setup_periph_channel(const struct espi_config *mb_cfg,
797 uint32_t slave_caps)
Furquan Shaikh70063ff52020-05-11 14:28:13 -0700798{
799 uint32_t slave_config;
800 /* Peripheral channel requires BME bit to be set when enabling the channel. */
Raul E Rangel8fef0b72021-05-24 13:02:40 -0600801 const uint32_t slave_en_mask =
802 ESPI_SLAVE_CHANNEL_ENABLE | ESPI_SLAVE_PERIPH_BUS_MASTER_ENABLE;
Furquan Shaikh70063ff52020-05-11 14:28:13 -0700803
Felix Held4b4114f72021-12-18 00:41:23 +0100804 if (espi_get_configuration(ESPI_SLAVE_PERIPH_CFG, &slave_config) != CB_SUCCESS)
805 return CB_ERR;
Furquan Shaikh70063ff52020-05-11 14:28:13 -0700806
807 /*
808 * Peripheral channel is the only one which is enabled on reset. So, if the mainboard
809 * wants to disable it, set configuration to disable peripheral channel. It also
810 * requires that BME bit be cleared.
811 */
812 if (mb_cfg->periph_ch_en) {
813 if (!espi_slave_supports_periph_channel(slave_caps)) {
Julius Wernere9665952022-01-21 17:06:20 -0800814 printk(BIOS_ERR, "eSPI slave doesn't support periph channel!\n");
Felix Held4b4114f72021-12-18 00:41:23 +0100815 return CB_ERR;
Furquan Shaikh70063ff52020-05-11 14:28:13 -0700816 }
817 slave_config |= slave_en_mask;
818 } else {
819 slave_config &= ~slave_en_mask;
820 }
821
Raul E Rangel7222f7e2021-04-09 14:15:42 -0600822 espi_show_slave_peripheral_channel_configuration(slave_config);
823
Furquan Shaikh70063ff52020-05-11 14:28:13 -0700824 return espi_set_channel_configuration(slave_config, ESPI_SLAVE_PERIPH_CFG,
825 ESPI_PERIPH_CH_EN);
826}
827
Felix Held4b4114f72021-12-18 00:41:23 +0100828static enum cb_err espi_setup_oob_channel(const struct espi_config *mb_cfg, uint32_t slave_caps)
Furquan Shaikh70063ff52020-05-11 14:28:13 -0700829{
830 uint32_t slave_config;
831
832 if (!mb_cfg->oob_ch_en)
Felix Held4b4114f72021-12-18 00:41:23 +0100833 return CB_SUCCESS;
Furquan Shaikh70063ff52020-05-11 14:28:13 -0700834
835 if (!espi_slave_supports_oob_channel(slave_caps)) {
Julius Wernere9665952022-01-21 17:06:20 -0800836 printk(BIOS_ERR, "eSPI slave doesn't support OOB channel!\n");
Felix Held4b4114f72021-12-18 00:41:23 +0100837 return CB_ERR;
Furquan Shaikh70063ff52020-05-11 14:28:13 -0700838 }
839
Felix Held4b4114f72021-12-18 00:41:23 +0100840 if (espi_get_configuration(ESPI_SLAVE_OOB_CFG, &slave_config) != CB_SUCCESS)
841 return CB_ERR;
Furquan Shaikh70063ff52020-05-11 14:28:13 -0700842
843 slave_config |= ESPI_SLAVE_CHANNEL_ENABLE;
844
845 return espi_set_channel_configuration(slave_config, ESPI_SLAVE_OOB_CFG,
846 ESPI_OOB_CH_EN);
847}
848
Felix Held4b4114f72021-12-18 00:41:23 +0100849static enum cb_err espi_setup_flash_channel(const struct espi_config *mb_cfg,
850 uint32_t slave_caps)
Furquan Shaikh70063ff52020-05-11 14:28:13 -0700851{
852 uint32_t slave_config;
853
854 if (!mb_cfg->flash_ch_en)
Felix Held4b4114f72021-12-18 00:41:23 +0100855 return CB_SUCCESS;
Furquan Shaikh70063ff52020-05-11 14:28:13 -0700856
857 if (!espi_slave_supports_flash_channel(slave_caps)) {
Julius Wernere9665952022-01-21 17:06:20 -0800858 printk(BIOS_ERR, "eSPI slave doesn't support flash channel!\n");
Felix Held4b4114f72021-12-18 00:41:23 +0100859 return CB_ERR;
Furquan Shaikh70063ff52020-05-11 14:28:13 -0700860 }
861
Felix Held4b4114f72021-12-18 00:41:23 +0100862 if (espi_get_configuration(ESPI_SLAVE_FLASH_CFG, &slave_config) != CB_SUCCESS)
863 return CB_ERR;
Furquan Shaikh70063ff52020-05-11 14:28:13 -0700864
865 slave_config |= ESPI_SLAVE_CHANNEL_ENABLE;
866
867 return espi_set_channel_configuration(slave_config, ESPI_SLAVE_FLASH_CFG,
868 ESPI_FLASH_CH_EN);
869}
870
871static void espi_set_initial_config(const struct espi_config *mb_cfg)
872{
873 uint32_t espi_initial_mode = ESPI_OP_FREQ_16_MHZ | ESPI_IO_MODE_SINGLE;
874
Raul E Rangeldcec4092021-05-07 15:35:10 -0600875 switch (mb_cfg->alert_pin) {
876 case ESPI_ALERT_PIN_IN_BAND:
877 break;
878 case ESPI_ALERT_PIN_PUSH_PULL:
879 case ESPI_ALERT_PIN_OPEN_DRAIN:
880 espi_initial_mode |= ESPI_ALERT_MODE;
881 break;
882 default:
883 die("Unknown espi alert config: %u!\n", mb_cfg->alert_pin);
884 }
885
Furquan Shaikh70063ff52020-05-11 14:28:13 -0700886 espi_write32(ESPI_SLAVE0_CONFIG, espi_initial_mode);
887}
888
889static void espi_setup_subtractive_decode(const struct espi_config *mb_cfg)
890{
891 uint32_t global_ctrl_reg;
892 global_ctrl_reg = espi_read32(ESPI_GLOBAL_CONTROL_1);
893
894 if (mb_cfg->subtractive_decode) {
895 global_ctrl_reg &= ~ESPI_SUB_DECODE_SLV_MASK;
896 global_ctrl_reg |= ESPI_SUB_DECODE_EN;
897
898 } else {
899 global_ctrl_reg &= ~ESPI_SUB_DECODE_EN;
900 }
901 espi_write32(ESPI_GLOBAL_CONTROL_1, global_ctrl_reg);
902}
903
Felix Heldaed38a92021-12-18 00:41:23 +0100904enum cb_err espi_setup(void)
Furquan Shaikh70063ff52020-05-11 14:28:13 -0700905{
906 uint32_t slave_caps;
907 const struct espi_config *cfg = espi_get_config();
908
Martin Roth7a2bfeb2021-05-14 10:57:31 -0600909 printk(BIOS_SPEW, "Initializing ESPI.\n");
910
Raul E Rangelb92383a2021-04-02 10:32:03 -0600911 espi_write32(ESPI_GLOBAL_CONTROL_0, ESPI_AL_STOP_EN);
912 espi_write32(ESPI_GLOBAL_CONTROL_1, ESPI_RGCMD_INT(23) | ESPI_ERR_INT_SMI);
913 espi_write32(ESPI_SLAVE0_INT_EN, 0);
914 espi_clear_status();
Raul E Rangelb95f8482021-04-02 13:47:09 -0600915 espi_clear_decodes();
Raul E Rangelb92383a2021-04-02 10:32:03 -0600916
Furquan Shaikh70063ff52020-05-11 14:28:13 -0700917 /*
918 * Boot sequence: Step 1
919 * Set correct initial configuration to talk to the slave:
920 * Set clock frequency to 16.7MHz and single IO mode.
921 */
922 espi_set_initial_config(cfg);
923
924 /*
925 * Boot sequence: Step 2
926 * Send in-band reset
927 * The resets affects both host and slave devices, so set initial config again.
928 */
Felix Held4b4114f72021-12-18 00:41:23 +0100929 if (espi_send_reset() != CB_SUCCESS) {
Julius Wernere9665952022-01-21 17:06:20 -0800930 printk(BIOS_ERR, "In-band reset failed!\n");
Felix Heldaed38a92021-12-18 00:41:23 +0100931 return CB_ERR;
Furquan Shaikh70063ff52020-05-11 14:28:13 -0700932 }
933 espi_set_initial_config(cfg);
934
935 /*
936 * Boot sequence: Step 3
937 * Get configuration of slave device.
938 */
Felix Held4b4114f72021-12-18 00:41:23 +0100939 if (espi_get_general_configuration(&slave_caps) != CB_SUCCESS) {
Julius Wernere9665952022-01-21 17:06:20 -0800940 printk(BIOS_ERR, "Slave GET_CONFIGURATION failed!\n");
Felix Heldaed38a92021-12-18 00:41:23 +0100941 return CB_ERR;
Furquan Shaikh70063ff52020-05-11 14:28:13 -0700942 }
943
944 /*
945 * Boot sequence:
946 * Step 4: Write slave device general config
947 * Step 5: Set host slave config
948 */
Felix Held4b4114f72021-12-18 00:41:23 +0100949 if (espi_set_general_configuration(cfg, slave_caps) != CB_SUCCESS) {
Julius Wernere9665952022-01-21 17:06:20 -0800950 printk(BIOS_ERR, "Slave SET_CONFIGURATION failed!\n");
Felix Heldaed38a92021-12-18 00:41:23 +0100951 return CB_ERR;
Furquan Shaikh70063ff52020-05-11 14:28:13 -0700952 }
953
954 /*
955 * Setup polarity before enabling the VW channel so any interrupts
956 * received will have the correct polarity.
957 */
958 espi_write32(ESPI_RXVW_POLARITY, cfg->vw_irq_polarity);
959
960 /*
961 * Boot Sequences: Steps 6 - 9
962 * Channel setup
963 */
964 /* Set up VW first so we can deassert PLTRST#. */
Felix Held4b4114f72021-12-18 00:41:23 +0100965 if (espi_setup_vw_channel(cfg, slave_caps) != CB_SUCCESS) {
Julius Wernere9665952022-01-21 17:06:20 -0800966 printk(BIOS_ERR, "Setup VW channel failed!\n");
Felix Heldaed38a92021-12-18 00:41:23 +0100967 return CB_ERR;
Furquan Shaikh70063ff52020-05-11 14:28:13 -0700968 }
969
Raul E Rangel43aa5272021-05-21 17:04:28 -0600970 /* Assert PLTRST# if VW channel is enabled by mainboard. */
Felix Held4b4114f72021-12-18 00:41:23 +0100971 if (espi_send_pltrst(cfg, true) != CB_SUCCESS) {
Julius Wernere9665952022-01-21 17:06:20 -0800972 printk(BIOS_ERR, "PLTRST# assertion failed!\n");
Felix Heldaed38a92021-12-18 00:41:23 +0100973 return CB_ERR;
Raul E Rangel43aa5272021-05-21 17:04:28 -0600974 }
975
Furquan Shaikh70063ff52020-05-11 14:28:13 -0700976 /* De-assert PLTRST# if VW channel is enabled by mainboard. */
Felix Held4b4114f72021-12-18 00:41:23 +0100977 if (espi_send_pltrst(cfg, false) != CB_SUCCESS) {
Julius Wernere9665952022-01-21 17:06:20 -0800978 printk(BIOS_ERR, "PLTRST# deassertion failed!\n");
Felix Heldaed38a92021-12-18 00:41:23 +0100979 return CB_ERR;
Furquan Shaikh70063ff52020-05-11 14:28:13 -0700980 }
981
Felix Held4b4114f72021-12-18 00:41:23 +0100982 if (espi_setup_periph_channel(cfg, slave_caps) != CB_SUCCESS) {
Julius Wernere9665952022-01-21 17:06:20 -0800983 printk(BIOS_ERR, "Setup Periph channel failed!\n");
Felix Heldaed38a92021-12-18 00:41:23 +0100984 return CB_ERR;
Furquan Shaikh70063ff52020-05-11 14:28:13 -0700985 }
986
Felix Held4b4114f72021-12-18 00:41:23 +0100987 if (espi_setup_oob_channel(cfg, slave_caps) != CB_SUCCESS) {
Julius Wernere9665952022-01-21 17:06:20 -0800988 printk(BIOS_ERR, "Setup OOB channel failed!\n");
Felix Heldaed38a92021-12-18 00:41:23 +0100989 return CB_ERR;
Furquan Shaikh70063ff52020-05-11 14:28:13 -0700990 }
991
Felix Held4b4114f72021-12-18 00:41:23 +0100992 if (espi_setup_flash_channel(cfg, slave_caps) != CB_SUCCESS) {
Julius Wernere9665952022-01-21 17:06:20 -0800993 printk(BIOS_ERR, "Setup Flash channel failed!\n");
Felix Heldaed38a92021-12-18 00:41:23 +0100994 return CB_ERR;
Furquan Shaikh70063ff52020-05-11 14:28:13 -0700995 }
996
Felix Heldaed38a92021-12-18 00:41:23 +0100997 if (espi_configure_decodes(cfg) != CB_SUCCESS) {
Julius Wernere9665952022-01-21 17:06:20 -0800998 printk(BIOS_ERR, "Configuring decodes failed!\n");
Felix Heldaed38a92021-12-18 00:41:23 +0100999 return CB_ERR;
Raul E Rangel61ac1bc2021-04-02 10:55:27 -06001000 }
1001
Furquan Shaikh70063ff52020-05-11 14:28:13 -07001002 /* Enable subtractive decode if configured */
Felix Helda2642d02021-02-17 00:32:46 +01001003 espi_setup_subtractive_decode(cfg);
Furquan Shaikh70063ff52020-05-11 14:28:13 -07001004
Raul E Rangelb92383a2021-04-02 10:32:03 -06001005 espi_write32(ESPI_GLOBAL_CONTROL_1,
1006 espi_read32(ESPI_GLOBAL_CONTROL_1) | ESPI_BUS_MASTER_EN);
1007
Martin Roth7a2bfeb2021-05-14 10:57:31 -06001008 printk(BIOS_SPEW, "Finished initializing ESPI.\n");
1009
Felix Heldaed38a92021-12-18 00:41:23 +01001010 return CB_SUCCESS;
Furquan Shaikh70063ff52020-05-11 14:28:13 -07001011}
Felix Held1c03da52021-10-14 21:48:13 +02001012
1013/* Setup eSPI with any mainboard specific initialization. */
1014void configure_espi_with_mb_hook(void)
1015{
1016 mb_set_up_early_espi();
1017 espi_setup();
1018}