TianoCore EDK2 master
Loading...
Searching...
No Matches
SpiBus.c
Go to the documentation of this file.
1
9#include <Library/BaseLib.h>
10#include <Library/DebugLib.h>
13#include <Protocol/SpiHc.h>
14#include <Protocol/SpiIo.h>
15#include "SpiBus.h"
16
26BOOLEAN
27EFIAPI
31 )
32{
33 UINTN Size1;
34 UINTN Size2;
35
36 Size1 = GetDevicePathSize (DevicePath1);
37 Size2 = GetDevicePathSize (DevicePath2);
38
39 if (Size1 != Size2) {
40 return FALSE;
41 }
42
43 if (CompareMem (DevicePath1, DevicePath2, Size1) != 0) {
44 return FALSE;
45 }
46
47 return TRUE;
48}
49
61EFIAPI
63 IN CONST SPI_IO_CHIP *SpiChip,
64 IN BOOLEAN PinValue
65 )
66{
67 EFI_STATUS Status;
68
69 // Check which chip select function to use
70 if (SpiChip->Protocol.SpiPeripheral->ChipSelect != NULL) {
71 Status = SpiChip->Protocol.SpiPeripheral->ChipSelect (
72 SpiChip->BusTransaction.SpiPeripheral,
73 PinValue
74 );
75 } else {
76 Status = SpiChip->SpiHc->ChipSelect (
77 SpiChip->SpiHc,
78 SpiChip->BusTransaction.SpiPeripheral,
79 PinValue
80 );
81 }
82
83 return Status;
84}
85
110EFIAPI
112 IN SPI_IO_CHIP *SpiChip
113 )
114{
115 // Error checking
116 if (SpiChip->BusTransaction.TransactionType > SPI_TRANSACTION_WRITE_THEN_READ) {
117 return EFI_INVALID_PARAMETER;
118 }
119
120 if (((SpiChip->BusTransaction.BusWidth != 1) && (SpiChip->BusTransaction.BusWidth != 2) && (SpiChip->BusTransaction.BusWidth != 4) &&
121 (SpiChip->BusTransaction.BusWidth != 8)) || (SpiChip->BusTransaction.FrameSize == 0))
122 {
123 return EFI_INVALID_PARAMETER;
124 }
125
126 if ((SpiChip->BusTransaction.BusWidth == 8) && (((SpiChip->Protocol.Attributes & SPI_IO_SUPPORTS_8_BIT_DATA_BUS_WIDTH) != SPI_IO_SUPPORTS_8_BIT_DATA_BUS_WIDTH) ||
127 ((SpiChip->BusTransaction.SpiPeripheral->Attributes & SPI_PART_SUPPORTS_8_BIT_DATA_BUS_WIDTH) != SPI_PART_SUPPORTS_8_BIT_DATA_BUS_WIDTH)))
128 {
129 return EFI_INVALID_PARAMETER;
130 } else if ((SpiChip->BusTransaction.BusWidth == 4) && (((SpiChip->Protocol.Attributes & SPI_IO_SUPPORTS_4_BIT_DATA_BUS_WIDTH) != SPI_IO_SUPPORTS_4_BIT_DATA_BUS_WIDTH) ||
131 ((SpiChip->BusTransaction.SpiPeripheral->Attributes & SPI_PART_SUPPORTS_4_BIT_DATA_BUS_WIDTH) != SPI_PART_SUPPORTS_4_BIT_DATA_BUS_WIDTH)))
132 {
133 return EFI_INVALID_PARAMETER;
134 } else if ((SpiChip->BusTransaction.BusWidth == 2) && (((SpiChip->Protocol.Attributes & SPI_IO_SUPPORTS_4_BIT_DATA_BUS_WIDTH) != SPI_IO_SUPPORTS_4_BIT_DATA_BUS_WIDTH) ||
135 ((SpiChip->BusTransaction.SpiPeripheral->Attributes & SPI_PART_SUPPORTS_2_BIT_DATA_BUS_WIDTH) != SPI_PART_SUPPORTS_2_BIT_DATA_BUS_WIDTH)))
136 {
137 return EFI_INVALID_PARAMETER;
138 }
139
140 if (((SpiChip->BusTransaction.WriteBytes > 0) && (SpiChip->BusTransaction.WriteBuffer == NULL)) || ((SpiChip->BusTransaction.ReadBytes > 0) && (SpiChip->BusTransaction.ReadBuffer == NULL))) {
141 return EFI_INVALID_PARAMETER;
142 }
143
144 if ((SpiChip->BusTransaction.TransactionType == SPI_TRANSACTION_FULL_DUPLEX) && (SpiChip->BusTransaction.ReadBytes != SpiChip->BusTransaction.WriteBytes)) {
145 return EFI_INVALID_PARAMETER;
146 }
147
148 // Check frame size, passed parameter is in bits
149 if ((SpiChip->Protocol.FrameSizeSupportMask & (1<<(SpiChip->BusTransaction.FrameSize-1))) == 0) {
150 return EFI_UNSUPPORTED;
151 }
152
153 return EFI_SUCCESS;
154}
155
230EFIAPI
233 IN EFI_SPI_TRANSACTION_TYPE TransactionType,
234 IN BOOLEAN DebugTransaction,
235 IN UINT32 ClockHz OPTIONAL,
236 IN UINT32 BusWidth,
237 IN UINT32 FrameSize,
238 IN UINT32 WriteBytes,
239 IN UINT8 *WriteBuffer,
240 IN UINT32 ReadBytes,
241 OUT UINT8 *ReadBuffer
242 )
243{
244 EFI_STATUS Status;
245 SPI_IO_CHIP *SpiChip;
246 UINT32 MaxClockHz;
247 UINT8 *DummyReadBuffer;
248 UINT8 *DummyWriteBuffer;
249
250 SpiChip = SPI_IO_CHIP_FROM_THIS (This);
251 SpiChip->BusTransaction.SpiPeripheral =
252 (EFI_SPI_PERIPHERAL *)SpiChip->Protocol.SpiPeripheral;
253 SpiChip->BusTransaction.TransactionType = TransactionType;
254 SpiChip->BusTransaction.DebugTransaction = DebugTransaction;
255 SpiChip->BusTransaction.BusWidth = BusWidth;
256 SpiChip->BusTransaction.FrameSize = FrameSize;
257 SpiChip->BusTransaction.WriteBytes = WriteBytes;
258 SpiChip->BusTransaction.WriteBuffer = WriteBuffer;
259 SpiChip->BusTransaction.ReadBytes = ReadBytes;
260 SpiChip->BusTransaction.ReadBuffer = ReadBuffer;
261
262 // Ensure valid spi transaction parameters
263 Status = IsValidSpiTransaction (SpiChip);
264 if (EFI_ERROR (Status)) {
265 return Status;
266 }
267
268 // Setup the proper clock frequency
269 if (SpiChip->BusTransaction.SpiPeripheral->MaxClockHz != 0) {
270 MaxClockHz = SpiChip->BusTransaction.SpiPeripheral->MaxClockHz;
271 } else {
272 MaxClockHz = SpiChip->BusTransaction.SpiPeripheral->SpiPart->MaxClockHz;
273 }
274
275 // Call proper clock function
276 if (SpiChip->Protocol.SpiPeripheral->SpiBus->Clock != NULL) {
277 Status = SpiChip->Protocol.SpiPeripheral->SpiBus->Clock (
278 SpiChip->BusTransaction.SpiPeripheral,
279 &MaxClockHz
280 );
281 } else {
282 Status = SpiChip->SpiHc->Clock (
283 SpiChip->SpiHc,
284 SpiChip->BusTransaction.SpiPeripheral,
285 &MaxClockHz
286 );
287 }
288
289 if (EFI_ERROR (Status)) {
290 return Status;
291 }
292
293 Status = SpiChipSelect (SpiChip, SpiChip->BusTransaction.SpiPeripheral->SpiPart->ChipSelectPolarity);
294
295 if (EFI_ERROR (Status)) {
296 return Status;
297 }
298
299 // Check transaction types and match to HC capabilities
300 if ((TransactionType == SPI_TRANSACTION_WRITE_ONLY) &&
302 {
303 // Convert to full duplex transaction
304 SpiChip->BusTransaction.ReadBytes = SpiChip->BusTransaction.WriteBytes;
305 SpiChip->BusTransaction.ReadBuffer = AllocateZeroPool (SpiChip->BusTransaction.ReadBytes);
306
307 Status = SpiChip->SpiHc->Transaction (
308 SpiChip->SpiHc,
309 &SpiChip->BusTransaction
310 );
311
312 SpiChip->BusTransaction.ReadBytes = ReadBytes; // assign to passed parameter
313 FreePool (SpiChip->BusTransaction.ReadBuffer); // Free temporary buffer
314 } else if ((TransactionType == SPI_TRANSACTION_READ_ONLY) &&
315 ((SpiChip->SpiHc->Attributes & HC_SUPPORTS_READ_ONLY_OPERATIONS) != HC_SUPPORTS_READ_ONLY_OPERATIONS))
316 {
317 // Convert to full duplex transaction
318 SpiChip->BusTransaction.WriteBytes = SpiChip->BusTransaction.WriteBytes;
319 SpiChip->BusTransaction.WriteBuffer = AllocateZeroPool (SpiChip->BusTransaction.WriteBytes);
320
321 Status = SpiChip->SpiHc->Transaction (
322 SpiChip->SpiHc,
323 &SpiChip->BusTransaction
324 );
325
326 SpiChip->BusTransaction.WriteBytes = WriteBytes;
327 FreePool (SpiChip->BusTransaction.WriteBuffer);
328 } else if ((TransactionType == SPI_TRANSACTION_WRITE_THEN_READ) &&
329 ((SpiChip->SpiHc->Attributes & HC_SUPPORTS_WRITE_THEN_READ_OPERATIONS) != HC_SUPPORTS_WRITE_THEN_READ_OPERATIONS))
330 {
331 // Convert to full duplex transaction
332 DummyReadBuffer = AllocateZeroPool (WriteBytes);
333 DummyWriteBuffer = AllocateZeroPool (ReadBytes);
334 SpiChip->BusTransaction.ReadBuffer = DummyReadBuffer;
335 SpiChip->BusTransaction.ReadBytes = WriteBytes;
336
337 Status = SpiChip->SpiHc->Transaction (
338 SpiChip->SpiHc,
339 &SpiChip->BusTransaction
340 );
341
342 if (EFI_ERROR (Status)) {
343 return Status;
344 }
345
346 // Write is done, now need to read, restore passed in read buffer info
347 SpiChip->BusTransaction.ReadBuffer = ReadBuffer;
348 SpiChip->BusTransaction.ReadBytes = ReadBytes;
349
350 SpiChip->BusTransaction.WriteBuffer = DummyWriteBuffer;
351 SpiChip->BusTransaction.WriteBytes = ReadBytes;
352
353 Status = SpiChip->SpiHc->Transaction (
354 SpiChip->SpiHc,
355 &SpiChip->BusTransaction
356 );
357 // Restore write data
358 SpiChip->BusTransaction.WriteBuffer = WriteBuffer;
359 SpiChip->BusTransaction.WriteBytes = WriteBytes;
360
361 FreePool (DummyReadBuffer);
362 FreePool (DummyWriteBuffer);
363 } else {
364 // Supported transaction type, just pass info the SPI HC Protocol Transaction
365 Status = SpiChip->SpiHc->Transaction (
366 SpiChip->SpiHc,
367 &SpiChip->BusTransaction
368 );
369 }
370
371 if (EFI_ERROR (Status)) {
372 return Status;
373 }
374
375 Status = SpiChipSelect (SpiChip, !SpiChip->BusTransaction.SpiPeripheral->SpiPart->ChipSelectPolarity);
376
377 return Status;
378}
379
398EFIAPI
401 IN CONST EFI_SPI_PERIPHERAL *SpiPeripheral
402 )
403{
404 EFI_STATUS Status;
405 SPI_IO_CHIP *SpiChip;
406
407 DEBUG ((DEBUG_VERBOSE, "%a: SPI Bus - Entry\n", __func__));
408
409 SpiChip = SPI_IO_CHIP_FROM_THIS (This);
410
411 if ((SpiPeripheral == NULL) || (SpiPeripheral->SpiBus == NULL) ||
412 (SpiPeripheral->SpiPart == NULL))
413 {
414 return EFI_INVALID_PARAMETER;
415 }
416
417 // EFI_INVALID_PARAMETER if SpiPeripheral->SpiBus is pointing at wrong bus
418 if (!DevicePathsAreEqual (SpiPeripheral->SpiBus->ControllerPath, SpiChip->SpiBus->ControllerPath)) {
419 return EFI_INVALID_PARAMETER;
420 }
421
422 SpiChip->Protocol.OriginalSpiPeripheral = SpiChip->Protocol.SpiPeripheral;
423 SpiChip->Protocol.SpiPeripheral = SpiPeripheral;
424
425 Status = EFI_SUCCESS;
426 DEBUG ((
427 DEBUG_VERBOSE,
428 "%a: SPI Bus - Exit Status=%r\n",
429 __func__,
430 Status
431 ));
432 return Status;
433}
UINT64 UINTN
INTN EFIAPI CompareMem(IN CONST VOID *DestinationBuffer, IN CONST VOID *SourceBuffer, IN UINTN Length)
UINTN EFIAPI GetDevicePathSize(IN CONST EFI_DEVICE_PATH_PROTOCOL *DevicePath)
VOID *EFIAPI AllocateZeroPool(IN UINTN AllocationSize)
VOID EFIAPI FreePool(IN VOID *Buffer)
#define NULL
Definition: Base.h:319
#define CONST
Definition: Base.h:259
#define TRUE
Definition: Base.h:301
#define FALSE
Definition: Base.h:307
#define IN
Definition: Base.h:279
#define OUT
Definition: Base.h:284
#define DEBUG(Expression)
Definition: DebugLib.h:434
#define HC_SUPPORTS_WRITE_ONLY_OPERATIONS
Definition: SpiHc.h:128
EFI_STATUS EFIAPI SpiChipSelect(IN CONST SPI_IO_CHIP *SpiChip, IN BOOLEAN PinValue)
Definition: SpiBus.c:62
EFI_STATUS EFIAPI UpdateSpiPeripheral(IN CONST EFI_SPI_IO_PROTOCOL *This, IN CONST EFI_SPI_PERIPHERAL *SpiPeripheral)
Definition: SpiBus.c:399
EFI_STATUS EFIAPI Transaction(IN CONST EFI_SPI_IO_PROTOCOL *This, IN EFI_SPI_TRANSACTION_TYPE TransactionType, IN BOOLEAN DebugTransaction, IN UINT32 ClockHz OPTIONAL, IN UINT32 BusWidth, IN UINT32 FrameSize, IN UINT32 WriteBytes, IN UINT8 *WriteBuffer, IN UINT32 ReadBytes, OUT UINT8 *ReadBuffer)
Definition: SpiBus.c:231
BOOLEAN EFIAPI DevicePathsAreEqual(IN CONST EFI_DEVICE_PATH_PROTOCOL *DevicePath1, IN CONST EFI_DEVICE_PATH_PROTOCOL *DevicePath2)
Definition: SpiBus.c:28
EFI_STATUS EFIAPI IsValidSpiTransaction(IN SPI_IO_CHIP *SpiChip)
Definition: SpiBus.c:111
#define SPI_PART_SUPPORTS_2_BIT_DATA_BUS_WIDTH
EFI_SPI_TRANSACTION_TYPE
Definition: SpiIo.h:25
@ SPI_TRANSACTION_FULL_DUPLEX
Definition: SpiIo.h:31
@ SPI_TRANSACTION_READ_ONLY
Definition: SpiIo.h:43
@ SPI_TRANSACTION_WRITE_ONLY
Definition: SpiIo.h:37
@ SPI_TRANSACTION_WRITE_THEN_READ
Definition: SpiIo.h:51
RETURN_STATUS EFI_STATUS
Definition: UefiBaseType.h:29
#define EFI_SUCCESS
Definition: UefiBaseType.h:112
BOOLEAN DebugTransaction
Definition: SpiIo.h:189
CONST EFI_SPI_PERIPHERAL * SpiPeripheral
Definition: SpiIo.h:175
EFI_SPI_TRANSACTION_TYPE TransactionType
Definition: SpiIo.h:181
CONST EFI_DEVICE_PATH_PROTOCOL * ControllerPath
EFI_SPI_CLOCK Clock
EFI_SPI_HC_PROTOCOL_TRANSACTION Transaction
Definition: SpiHc.h:197
EFI_SPI_HC_PROTOCOL_CLOCK Clock
Definition: SpiHc.h:191
UINT32 Attributes
Definition: SpiHc.h:168
CONST EFI_SPI_PERIPHERAL * SpiPeripheral
Definition: SpiIo.h:245
CONST EFI_SPI_PERIPHERAL * OriginalSpiPeripheral
Definition: SpiIo.h:251
BOOLEAN ChipSelectPolarity
CONST EFI_SPI_BUS * SpiBus
CONST EFI_SPI_PART * SpiPart