1 /** @file
2 This file contains routines for eSPI
3
4 Copyright (c) 2019 Intel Corporation. All rights reserved. <BR>
5
6 SPDX-License-Identifier: BSD-2-Clause-Patent
7 **/
8
9 #include <Base.h>
10 #include <Uefi/UefiBaseType.h>
11 #include <Library/IoLib.h>
12 #include <Library/DebugLib.h>
13 #include <Library/BaseMemoryLib.h>
14 #include <Library/PchEspiLib.h>
15 #include <Library/PchPcrLib.h>
16 #include <Library/PchInfoLib.h>
17 #include <Library/TimerLib.h>
18 #include <PchLimits.h>
19 #include <Register/PchRegsPcr.h>
20 #include <Register/PchRegsLpc.h>
21
22 #define CHANNEL_RESET_TIMEOUT 100 ///< Channel reset timeout in us after which to report error
23 #define SLAVE_CHANNELS_MAX 7 ///< Max number of channels
24
25 //
26 // eSPI Slave registers
27 //
28 #define R_ESPI_SLAVE_GENCAP 0x08 ///< General Capabilities and Configurations
29 #define B_ESPI_SLAVE_GENCAP_SUPPCHAN 0xFF ///< Channels supported bit mask
30 #define R_ESPI_SLAVE_CHACAP_BASE 0x10 ///< Base address from which channel Cap and Conf registers start on slave
31 #define S_ESPI_SLAVE_CHACAP_OFFSET 0x10 ///< Offset for each channel from base
32 #define B_ESPI_SLAVE_CHACAP_CHEN BIT0 ///< Slave Channel enable bit
33 #define B_ESPI_SLAVE_CHACAP_CHRDY BIT1 ///< Slave Channel ready bit
34
35 /**
36 Checks if second slave capability is enabled
37
38 @retval TRUE There's second slave
39 @retval FALSE There's no second slave
40 **/
41 BOOLEAN
IsEspiSecondSlaveSupported(VOID)42 IsEspiSecondSlaveSupported (
43 VOID
44 )
45 {
46 return (IsPchH () && ((PchPcrRead32 (PID_ESPISPI, R_ESPI_PCR_SOFTSTRAPS) & R_ESPI_PCR_SOFTSTRAPS_CS1_EN) != 0));
47 }
48
49 /**
50 Checks in slave General Capabilities register if it supports channel with requested number
51
52 @param[in] SlaveId Id of slave to check
53 @param[in] ChannelNumber Number of channel of which to check
54
55 @retval TRUE Channel with requested number is supported by slave device
56 @retval FALSE Channel with requested number is not supported by slave device
57 **/
58 BOOLEAN
IsEspiSlaveChannelSupported(UINT8 SlaveId,UINT8 ChannelNumber)59 IsEspiSlaveChannelSupported (
60 UINT8 SlaveId,
61 UINT8 ChannelNumber
62 )
63 {
64 EFI_STATUS Status;
65 UINT32 Data32;
66 UINT8 SupportedChannels;
67
68 Status = PchEspiSlaveGetConfig (SlaveId, R_ESPI_SLAVE_GENCAP, &Data32);
69 if (EFI_ERROR (Status)) {
70 return FALSE;
71 }
72 SupportedChannels = (UINT8) (Data32 & B_ESPI_SLAVE_GENCAP_SUPPCHAN);
73
74 DEBUG ((DEBUG_INFO, "Slave %d supported channels 0x%4X\n", SlaveId, SupportedChannels));
75
76 if (ChannelNumber > SLAVE_CHANNELS_MAX || !(SupportedChannels & (BIT0 << ChannelNumber))) {
77 // Incorrect channel number was specified. Either exceeded max or Slave doesn't support that channel.
78 return FALSE;
79 }
80
81 return TRUE;
82 }
83
84 /**
85 Is eSPI enabled in strap.
86
87 @retval TRUE Espi is enabled in strap
88 @retval FALSE Espi is disabled in strap
89 **/
90 BOOLEAN
IsEspiEnabled(VOID)91 IsEspiEnabled (
92 VOID
93 )
94 {
95 return (PchPcrRead32 (PID_ESPISPI, R_ESPI_PCR_CFG_VAL) & B_ESPI_PCR_CFG_VAL_ESPI_EN) != 0;
96 }
97
98 /**
99 eSPI helper function to clear slave configuration register status
100
101 @retval EFI_SUCCESS Write to private config space succeed
102 @retval others Read / Write failed
103 **/
104 STATIC
105 VOID
EspiClearScrs(VOID)106 EspiClearScrs (
107 VOID
108 )
109 {
110 PchPcrAndThenOr32 (
111 PID_ESPISPI,
112 R_ESPI_PCR_SLV_CFG_REG_CTL,
113 (UINT32) ~0,
114 B_ESPI_PCR_SLV_CFG_REG_CTL_SCRS
115 );
116 }
117
118 /**
119 eSPI helper function to poll slave configuration register enable for 0
120 and to check for slave configuration register status
121
122 @retval EFI_SUCCESS Enable bit is zero and no error in status bits
123 @retval EFI_DEVICE_ERROR Error in SCRS
124 @retval others Read / Write to private config space failed
125 **/
126 STATIC
127 EFI_STATUS
EspiPollScreAndCheckScrs(VOID)128 EspiPollScreAndCheckScrs (
129 VOID
130 )
131 {
132 UINT32 ScrStat;
133
134 do {
135 ScrStat = PchPcrRead32 (PID_ESPISPI, R_ESPI_PCR_SLV_CFG_REG_CTL);
136 } while ((ScrStat & B_ESPI_PCR_SLV_CFG_REG_CTL_SCRE) != 0);
137
138 ScrStat = (ScrStat & B_ESPI_PCR_SLV_CFG_REG_CTL_SCRS) >> N_ESPI_PCR_SLV_CFG_REG_CTL_SCRS;
139 if (ScrStat != V_ESPI_PCR_SLV_CFG_REG_CTL_SCRS_NOERR) {
140 DEBUG ((DEBUG_ERROR, "eSPI slave config register status (error) is %x \n", ScrStat));
141 return EFI_DEVICE_ERROR;
142 }
143 return EFI_SUCCESS;
144 }
145
146 typedef enum {
147 EspiSlaveOperationConfigRead,
148 EspiSlaveOperationConfigWrite,
149 EspiSlaveOperationStatusRead,
150 EspiSlaveOperationInBandReset
151 } ESPI_SLAVE_OPERATION;
152
153 /**
154 Helper library to do all the operations regards to eSPI slave
155
156 @param[in] SlaveId eSPI Slave ID
157 @param[in] SlaveAddress Slave address to be put in R_ESPI_PCR_SLV_CFG_REG_CTL[11:0]
158 @param[in] SlaveOperation Based on ESPI_SLAVE_OPERATION
159 @param[in,out] Data
160
161 @retval EFI_SUCCESS Operation succeed
162 @retval EFI_INVALID_PARAMETER Slave ID is not supported or SlaveId 1 is used in PCH_LP
163 @retval EFI_INVALID_PARAMETER Slave configuration register address exceed maximum allowed
164 @retval EFI_INVALID_PARAMETER Slave configuration register address is not DWord aligned
165 @retval EFI_ACCESS_DENIED eSPI Slave write to address range 0 to 0x7FF has been locked
166 @retval EFI_DEVICE_ERROR Error in SCRS during polling stage of operation
167 **/
168 STATIC
169 EFI_STATUS
EspiSlaveOperationHelper(IN UINT32 SlaveId,IN UINT32 SlaveAddress,IN ESPI_SLAVE_OPERATION SlaveOperation,IN OUT UINT32 * Data)170 EspiSlaveOperationHelper (
171 IN UINT32 SlaveId,
172 IN UINT32 SlaveAddress,
173 IN ESPI_SLAVE_OPERATION SlaveOperation,
174 IN OUT UINT32 *Data
175 )
176 {
177 EFI_STATUS Status;
178 UINT32 Data32;
179
180 //
181 // Check the SlaveId is 0 or 1
182 //
183 if (SlaveId >= PCH_MAX_ESPI_SLAVES) {
184 DEBUG ((DEBUG_ERROR, "eSPI Slave ID of %d or more is not accepted \n", PCH_MAX_ESPI_SLAVES));
185 return EFI_INVALID_PARAMETER;
186 }
187 //
188 // Check if SlaveId 1 is used, it is a PCH_H
189 //
190 if ((SlaveId == 1) && (IsPchLp ())) {
191 DEBUG ((DEBUG_ERROR, "eSPI Slave ID of 1 is only available on PCH_H \n"));
192 return EFI_INVALID_PARAMETER;
193 }
194 //
195 // Check the address is not more then 0xFFF
196 //
197 if (SlaveAddress > B_ESPI_PCR_SLV_CFG_REG_CTL_SCRA) {
198 DEBUG ((DEBUG_ERROR, "eSPI Slave address must be less than 0x%x \n", (B_ESPI_PCR_SLV_CFG_REG_CTL_SCRA + 1)));
199 return EFI_INVALID_PARAMETER;
200 }
201 //
202 // Check the address is DWord aligned
203 //
204 if ((SlaveAddress & 0x3) != 0) {
205 DEBUG ((DEBUG_ERROR, "eSPI Slave address must be DWord aligned \n"));
206 return EFI_INVALID_PARAMETER;
207 }
208
209 //
210 // Check if write is allowed
211 //
212 if ((SlaveOperation == EspiSlaveOperationConfigWrite) &&
213 (SlaveAddress <= 0x7FF)) {
214
215 //
216 // If the SLCRR is not set in corresponding slave, we will check the lock bit
217 //
218 Data32 = PchPcrRead32 (PID_ESPISPI, (UINT16) (R_ESPI_PCR_LNKERR_SLV0 + (SlaveId * S_ESPI_PCR_LNKERR_SLV0)));
219 if ((Data32 & B_ESPI_PCR_LNKERR_SLV0_SLCRR) == 0) {
220
221 Data32 = PchPcrRead32 (PID_ESPISPI, (UINT16) R_ESPI_PCR_SLV_CFG_REG_CTL);
222 if ((Data32 & B_ESPI_PCR_SLV_CFG_REG_CTL_SBLCL) != 0) {
223 DEBUG ((DEBUG_ERROR, "eSPI Slave write to address range 0 to 0x7FF has been locked \n"));
224 return EFI_ACCESS_DENIED;
225 }
226 }
227 }
228
229 //
230 // Input check done, now go through all the processes
231 //
232 EspiClearScrs ();
233
234 if (SlaveOperation == EspiSlaveOperationConfigWrite) {
235 PchPcrWrite32 (
236 PID_ESPISPI,
237 (UINT16) R_ESPI_PCR_SLV_CFG_REG_DATA,
238 *Data
239 );
240 }
241
242 PchPcrAndThenOr32 (
243 PID_ESPISPI,
244 (UINT16) R_ESPI_PCR_SLV_CFG_REG_CTL,
245 (UINT32) ~(B_ESPI_PCR_SLV_CFG_REG_CTL_SID | B_ESPI_PCR_SLV_CFG_REG_CTL_SCRT | B_ESPI_PCR_SLV_CFG_REG_CTL_SCRA),
246 (B_ESPI_PCR_SLV_CFG_REG_CTL_SCRE |
247 (SlaveId << N_ESPI_PCR_SLV_CFG_REG_CTL_SID) |
248 (((UINT32) SlaveOperation) << N_ESPI_PCR_SLV_CFG_REG_CTL_SCRT) |
249 SlaveAddress
250 )
251 );
252
253 Status = EspiPollScreAndCheckScrs ();
254 if (EFI_ERROR (Status)) {
255 return Status;
256 }
257
258 if ((SlaveOperation == EspiSlaveOperationConfigRead) || (SlaveOperation == EspiSlaveOperationStatusRead)) {
259 Data32 = PchPcrRead32 (
260 PID_ESPISPI,
261 (UINT16) R_ESPI_PCR_SLV_CFG_REG_DATA
262 );
263 if (SlaveOperation == EspiSlaveOperationStatusRead) {
264 *Data = Data32 & 0xFFFF;
265 } else {
266 *Data = Data32;
267 }
268 }
269
270 return EFI_SUCCESS;
271 }
272
273 /**
274 Get configuration from eSPI slave
275
276 @param[in] SlaveId eSPI slave ID
277 @param[in] SlaveAddress Slave Configuration Register Address
278 @param[out] OutData Configuration data read
279
280 @retval EFI_SUCCESS Operation succeed
281 @retval EFI_INVALID_PARAMETER Slave ID is not supported
282 @retval EFI_INVALID_PARAMETER Slave ID is not supported or SlaveId 1 is used in PCH_LP
283 @retval EFI_INVALID_PARAMETER Slave configuration register address exceed maximum allowed
284 @retval EFI_INVALID_PARAMETER Slave configuration register address is not DWord aligned
285 @retval EFI_DEVICE_ERROR Error in SCRS during polling stage of operation
286 **/
287 EFI_STATUS
PchEspiSlaveGetConfig(IN UINT32 SlaveId,IN UINT32 SlaveAddress,OUT UINT32 * OutData)288 PchEspiSlaveGetConfig (
289 IN UINT32 SlaveId,
290 IN UINT32 SlaveAddress,
291 OUT UINT32 *OutData
292 )
293 {
294 //
295 // 1. Clear status from previous transaction by writing 111b to status in SCRS, PCR[eSPI] + 4000h [30:28]
296 // 2. Program SLV_CFG_REG_CTL with the right value (Bit[31]=01, Bit [20:19]=<SlvID>, Bit [17:16] = 00b, Bit[11:0] = <addr_xxx>.
297 // 3. Poll the SCRE (PCR[eSPI] +4000h [31]) to be set back to 0
298 // 4. Check the transaction status in SCRS (bits [30:28])
299 // 5. Read SLV_CFG_REG_DATA.
300 //
301 return EspiSlaveOperationHelper (SlaveId, SlaveAddress, EspiSlaveOperationConfigRead, OutData);
302 }
303
304 /**
305 Set eSPI slave configuration
306
307 Note: A Set_Configuration must always be followed by a Get_Configuration in order to ensure
308 that the internal state of the eSPI-MC is consistent with the Slave's register settings.
309
310 @param[in] SlaveId eSPI slave ID
311 @param[in] SlaveAddress Slave Configuration Register Address
312 @param[in] InData Configuration data to write
313
314 @retval EFI_SUCCESS Operation succeed
315 @retval EFI_INVALID_PARAMETER Slave ID is not supported or SlaveId 1 is used in PCH_LP
316 @retval EFI_INVALID_PARAMETER Slave configuration register address exceed maximum allowed
317 @retval EFI_INVALID_PARAMETER Slave configuration register address is not DWord aligned
318 @retval EFI_ACCESS_DENIED eSPI Slave write to address range 0 to 0x7FF has been locked
319 @retval EFI_DEVICE_ERROR Error in SCRS during polling stage of operation
320 **/
321 EFI_STATUS
PchEspiSlaveSetConfig(IN UINT32 SlaveId,IN UINT32 SlaveAddress,IN UINT32 InData)322 PchEspiSlaveSetConfig (
323 IN UINT32 SlaveId,
324 IN UINT32 SlaveAddress,
325 IN UINT32 InData
326 )
327 {
328 EFI_STATUS Status;
329 UINT32 Data32;
330
331 //
332 // 1. Clear status from previous transaction by writing 111b to status in SCRS, PCR[eSPI] + 4000h [30:28]
333 // 2. Program SLV_CFG_REG_DATA with the write value.
334 // 3. Program SLV_CFG_REG_CTL with the right value (Bit[31]=01, Bit [20:19]=<SlvID>, Bit [17:16] = 01b, Bit[11:0] = <addr_xxx>.
335 // 4. Poll the SCRE (PCR[eSPI] +4000h [31]) to be set back to 0
336 // 5. Check the transaction status in SCRS (bits [30:28])
337 //
338 Status = EspiSlaveOperationHelper (SlaveId, SlaveAddress, EspiSlaveOperationConfigWrite, &InData);
339 if (EFI_ERROR (Status)) {
340 return Status;
341 }
342 Status = PchEspiSlaveGetConfig (SlaveId, SlaveAddress, &Data32);
343 return Status;
344 }
345
346 /**
347 Get status from eSPI slave
348
349 @param[in] SlaveId eSPI slave ID
350 @param[out] OutData Configuration data read
351
352 @retval EFI_SUCCESS Operation succeed
353 @retval EFI_INVALID_PARAMETER Slave ID is not supported or SlaveId 1 is used in PCH_LP
354 @retval EFI_DEVICE_ERROR Error in SCRS during polling stage of operation
355 **/
356 EFI_STATUS
PchEspiSlaveGetStatus(IN UINT32 SlaveId,OUT UINT16 * OutData)357 PchEspiSlaveGetStatus (
358 IN UINT32 SlaveId,
359 OUT UINT16 *OutData
360 )
361 {
362 EFI_STATUS Status;
363 UINT32 TempOutData;
364
365 TempOutData = 0;
366
367 //
368 // 1. Clear status from previous transaction by writing 111b to status in SCRS, PCR[eSPI] + 4000h [30:28]
369 // 2. Program SLV_CFG_REG_CTL with the right value (Bit[31]=01, Bit [20:19]=<SlvID>, Bit [17:16] = 10b, Bit[11:0] = <addr_xxx>.
370 // 3. Poll the SCRE (PCR[eSPI] +4000h [31]) to be set back to 0
371 // 4. Check the transaction status in SCRS (bits [30:28])
372 // 5. Read SLV_CFG_REG_DATA [15:0].
373 //
374 Status = EspiSlaveOperationHelper (SlaveId, 0, EspiSlaveOperationStatusRead, &TempOutData);
375 *OutData = (UINT16) TempOutData;
376
377 return Status;
378 }
379
380 /**
381 eSPI slave in-band reset
382
383 @param[in] SlaveId eSPI slave ID
384
385 @retval EFI_SUCCESS Operation succeed
386 @retval EFI_INVALID_PARAMETER Slave ID is not supported or SlaveId 1 is used in PCH_LP
387 @retval EFI_DEVICE_ERROR Error in SCRS during polling stage of operation
388 **/
389 EFI_STATUS
PchEspiSlaveInBandReset(IN UINT32 SlaveId)390 PchEspiSlaveInBandReset (
391 IN UINT32 SlaveId
392 )
393 {
394 //
395 // 1. Clear status from previous transaction by writing 111b to status in SCRS, PCR[eSPI] + 4000h [30:28]
396 // 2. Program SLV_CFG_REG_CTL with the right value (Bit[31]=01, Bit [20:19]=<SlvID>, Bit [17:16] = 11b).
397 // 3. Poll the SCRE (PCR[eSPI] +4000h [31]) to be set back to 0
398 // 4. Check the transaction status in SCRS (bits [30:28])
399 //
400 return EspiSlaveOperationHelper (SlaveId, 0, EspiSlaveOperationInBandReset, NULL);
401 }
402
403 /**
404 eSPI Slave channel reset helper function
405
406 @param[in] SlaveId eSPI slave ID
407 @param[in] ChannelNumber Number of channel to reset
408
409 @retval EFI_SUCCESS Operation succeeded
410 @retval EFI_UNSUPPORTED Slave doesn't support that channel or invalid number specified
411 @retval EFI_TIMEOUT Operation has timeouted
412 **/
413 EFI_STATUS
PchEspiSlaveChannelReset(IN UINT8 SlaveId,IN UINT8 ChannelNumber)414 PchEspiSlaveChannelReset (
415 IN UINT8 SlaveId,
416 IN UINT8 ChannelNumber
417 )
418 {
419 UINT8 Timeout;
420 UINT32 Data32;
421 UINT32 SlaveChannelAddress;
422 BOOLEAN SlaveBmeSet;
423 EFI_STATUS Status;
424
425 DEBUG ((DEBUG_INFO, "eSPI slave %d channel %d reset\n", SlaveId, ChannelNumber));
426
427 Timeout = CHANNEL_RESET_TIMEOUT;
428 SlaveBmeSet = FALSE;
429
430 if (!IsEspiSlaveChannelSupported (SlaveId, ChannelNumber)) {
431 // Incorrect channel number was specified. Either exceeded max or Slave doesn't support that channel.
432 DEBUG ((DEBUG_ERROR, "Channel %d is not valid channel number for slave %d!\n", ChannelNumber, SlaveId));
433 return EFI_UNSUPPORTED;
434 }
435
436 // Calculating slave channel address
437 SlaveChannelAddress = R_ESPI_SLAVE_CHACAP_BASE + (S_ESPI_SLAVE_CHACAP_OFFSET * ChannelNumber);
438
439 // If we're resetting Peripheral Channel then we need to disable Bus Mastering first and reenable after reset
440 if (ChannelNumber == 0) {
441 Status = PchEspiSlaveGetConfig (SlaveId, SlaveChannelAddress, &Data32);
442 if (EFI_ERROR (Status)) {
443 return Status;
444 }
445 if ((Data32 & B_ESPI_SLAVE_BME) != 0) {
446 Data32 &= ~(B_ESPI_SLAVE_BME);
447 Status = PchEspiSlaveSetConfig (SlaveId, SlaveChannelAddress, Data32);
448 if (EFI_ERROR (Status)) {
449 return Status;
450 }
451 SlaveBmeSet = TRUE;
452 }
453 }
454
455 // Disable channel
456 Status = PchEspiSlaveGetConfig (SlaveId, SlaveChannelAddress, &Data32);
457 if (EFI_ERROR (Status)) {
458 return Status;
459 }
460 Data32 &= ~(B_ESPI_SLAVE_CHACAP_CHEN);
461 Status = PchEspiSlaveSetConfig (SlaveId, SlaveChannelAddress, Data32);
462 if (EFI_ERROR (Status)) {
463 return Status;
464 }
465 // Enable channel
466 Status = PchEspiSlaveGetConfig (SlaveId, SlaveChannelAddress, &Data32);
467 if (EFI_ERROR (Status)) {
468 return Status;
469 }
470 Data32 |= B_ESPI_SLAVE_CHACAP_CHEN;
471 Status = PchEspiSlaveSetConfig (SlaveId, SlaveChannelAddress, Data32);
472 if (EFI_ERROR (Status)) {
473 return Status;
474 }
475 DEBUG ((DEBUG_INFO, "Waiting for Channel Ready bit\n"));
476 // Wait until channel is ready by polling Channel Ready bit
477 while (((Data32 & B_ESPI_SLAVE_CHACAP_CHRDY) == 0) && (Timeout > 0)) {
478 Status = PchEspiSlaveGetConfig (SlaveId, SlaveChannelAddress, &Data32);
479 if (EFI_ERROR (Status)) {
480 return Status;
481 }
482 MicroSecondDelay (1);
483 --Timeout;
484 }
485
486 if (Timeout == 0) {
487 // The waiting for channel to be ready has timed out
488 DEBUG ((DEBUG_ERROR, "The operation of channel %d reset for slave %d has timed out!\n", ChannelNumber, SlaveId));
489 return EFI_TIMEOUT;
490 }
491
492 if (ChannelNumber == 0 && SlaveBmeSet) {
493 Status = PchEspiSlaveGetConfig (SlaveId, SlaveChannelAddress, &Data32);
494 if (EFI_ERROR (Status)) {
495 return Status;
496 }
497 Data32 |= B_ESPI_SLAVE_BME;
498 Status = PchEspiSlaveSetConfig (SlaveId, SlaveChannelAddress, Data32);
499 if (EFI_ERROR (Status)) {
500 return Status;
501 }
502 }
503
504 return EFI_SUCCESS;
505 }
506