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