1 /** @file
2  *
3  *  Copyright (c) 2020, Pete Batard <pete@akeo.ie>
4  *  Copyright (c) 2019, ARM Limited. All rights reserved.
5  *  Copyright (c) 2017-2020, Andrei Warkentin <andrey.warkentin@gmail.com>
6  *  Copyright (c) 2016, Linaro, Ltd. All rights reserved.
7  *
8  *  SPDX-License-Identifier: BSD-2-Clause-Patent
9  *
10  **/
11 
12 #include <PiDxe.h>
13 
14 #include <Library/ArmLib.h>
15 #include <Library/DmaLib.h>
16 #include <Library/BaseLib.h>
17 #include <Library/BaseMemoryLib.h>
18 #include <Library/DebugLib.h>
19 #include <Library/IoLib.h>
20 #include <Library/SynchronizationLib.h>
21 #include <Library/UefiBootServicesTableLib.h>
22 #include <Library/UefiLib.h>
23 
24 #include <IndustryStandard/Bcm2836.h>
25 #include <IndustryStandard/RpiMbox.h>
26 
27 #include <Protocol/RpiFirmware.h>
28 
29 //
30 // The number of statically allocated buffer pages
31 //
32 #define NUM_PAGES   1
33 
34 STATIC VOID  *mDmaBuffer;
35 STATIC VOID  *mDmaBufferMapping;
36 STATIC UINTN mDmaBufferBusAddress;
37 
38 STATIC SPIN_LOCK mMailboxLock;
39 
40 STATIC
41 BOOLEAN
42 DrainMailbox (
43   VOID
44   )
45 {
46   INTN    Tries;
47   UINT32  Val;
48 
49   //
50   // Get rid of stale response data in the mailbox
51   //
52   Tries = 0;
53   do {
54     Val = MmioRead32 (BCM2836_MBOX_BASE_ADDRESS + BCM2836_MBOX_STATUS_OFFSET);
55     if (Val & (1U << BCM2836_MBOX_STATUS_EMPTY)) {
56       return TRUE;
57     }
58     ArmDataSynchronizationBarrier ();
59     MmioRead32 (BCM2836_MBOX_BASE_ADDRESS + BCM2836_MBOX_READ_OFFSET);
60   } while (++Tries < RPI_MBOX_MAX_TRIES);
61 
62   return FALSE;
63 }
64 
65 STATIC
66 BOOLEAN
67 MailboxWaitForStatusCleared (
68   IN  UINTN   StatusMask
69   )
70 {
71   INTN    Tries;
72   UINT32  Val;
73 
74   //
75   // Get rid of stale response data in the mailbox
76   //
77   Tries = 0;
78   do {
79     Val = MmioRead32 (BCM2836_MBOX_BASE_ADDRESS + BCM2836_MBOX_STATUS_OFFSET);
80     if ((Val & StatusMask) == 0) {
81       return TRUE;
82     }
83     ArmDataSynchronizationBarrier ();
84   } while (++Tries < RPI_MBOX_MAX_TRIES);
85 
86   return FALSE;
87 }
88 
89 STATIC
90 EFI_STATUS
91 MailboxTransaction (
92   IN    UINTN   Length,
93   IN    UINTN   Channel,
94   OUT   UINT32  *Result
95   )
96 {
97   if (Channel >= BCM2836_MBOX_NUM_CHANNELS) {
98     return EFI_INVALID_PARAMETER;
99   }
100 
101   //
102   // Get rid of stale response data in the mailbox
103   //
104   if (!DrainMailbox ()) {
105     DEBUG ((DEBUG_ERROR, "%a: timeout waiting for mailbox to drain\n",
106       __FUNCTION__));
107     return EFI_TIMEOUT;
108   }
109 
110   //
111   // Wait for the 'output register full' bit to become clear
112   //
113   if (!MailboxWaitForStatusCleared (1U << BCM2836_MBOX_STATUS_FULL)) {
114     DEBUG ((DEBUG_ERROR, "%a: timeout waiting for outbox to become empty\n",
115       __FUNCTION__));
116     return EFI_TIMEOUT;
117   }
118 
119   ArmDataSynchronizationBarrier ();
120 
121   //
122   // Start the mailbox transaction
123   //
124   MmioWrite32 (BCM2836_MBOX_BASE_ADDRESS + BCM2836_MBOX_WRITE_OFFSET,
125     (UINT32)((UINTN)mDmaBufferBusAddress | Channel));
126 
127   ArmDataSynchronizationBarrier ();
128 
129   //
130   // Wait for the 'input register empty' bit to clear
131   //
132   if (!MailboxWaitForStatusCleared (1U << BCM2836_MBOX_STATUS_EMPTY)) {
133     DEBUG ((DEBUG_ERROR, "%a: timeout waiting for inbox to become full\n",
134       __FUNCTION__));
135     return EFI_TIMEOUT;
136   }
137 
138   //
139   // Read back the result
140   //
141   ArmDataSynchronizationBarrier ();
142   *Result = MmioRead32 (BCM2836_MBOX_BASE_ADDRESS + BCM2836_MBOX_READ_OFFSET);
143   ArmDataSynchronizationBarrier ();
144 
145   return EFI_SUCCESS;
146 }
147 
148 #pragma pack(1)
149 typedef struct {
150   UINT32    BufferSize;
151   UINT32    Response;
152 } RPI_FW_BUFFER_HEAD;
153 
154 typedef struct {
155   UINT32    TagId;
156   UINT32    TagSize;
157   UINT32    TagValueSize;
158 } RPI_FW_TAG_HEAD;
159 
160 typedef struct {
161   UINT32                    DeviceId;
162   UINT32                    PowerState;
163 } RPI_FW_POWER_STATE_TAG;
164 
165 typedef struct {
166   RPI_FW_BUFFER_HEAD        BufferHead;
167   RPI_FW_TAG_HEAD           TagHead;
168   RPI_FW_POWER_STATE_TAG    TagBody;
169   UINT32                    EndTag;
170 } RPI_FW_SET_POWER_STATE_CMD;
171 #pragma pack()
172 
173 STATIC
174 EFI_STATUS
175 EFIAPI
176 RpiFirmwareSetPowerState (
177   IN  UINT32    DeviceId,
178   IN  BOOLEAN   PowerState,
179   IN  BOOLEAN   Wait
180   )
181 {
182   RPI_FW_SET_POWER_STATE_CMD  *Cmd;
183   EFI_STATUS                  Status;
184   UINT32                      Result;
185 
186   if (!AcquireSpinLockOrFail (&mMailboxLock)) {
187     DEBUG ((DEBUG_ERROR, "%a: failed to acquire spinlock\n", __FUNCTION__));
188     return EFI_DEVICE_ERROR;
189   }
190 
191   Cmd = mDmaBuffer;
192   ZeroMem (Cmd, sizeof (*Cmd));
193 
194   Cmd->BufferHead.BufferSize  = sizeof (*Cmd);
195   Cmd->BufferHead.Response    = 0;
196   Cmd->TagHead.TagId          = RPI_MBOX_SET_POWER_STATE;
197   Cmd->TagHead.TagSize        = sizeof (Cmd->TagBody);
198   Cmd->TagHead.TagValueSize   = 0;
199   Cmd->TagBody.DeviceId       = DeviceId;
200   Cmd->TagBody.PowerState     = (PowerState ? RPI_MBOX_POWER_STATE_ENABLE : 0) |
201                                 (Wait ? RPI_MBOX_POWER_STATE_WAIT : 0);
202   Cmd->EndTag                 = 0;
203 
204   Status = MailboxTransaction (Cmd->BufferHead.BufferSize, RPI_MBOX_VC_CHANNEL, &Result);
205 
206   ReleaseSpinLock (&mMailboxLock);
207 
208   if (EFI_ERROR (Status) ||
209       Cmd->BufferHead.Response != RPI_MBOX_RESP_SUCCESS) {
210     DEBUG ((DEBUG_ERROR,
211       "%a: mailbox transaction error: Status == %r, Response == 0x%x\n",
212       __FUNCTION__, Status, Cmd->BufferHead.Response));
213     Status = EFI_DEVICE_ERROR;
214   }
215 
216   if (!EFI_ERROR (Status) &&
217       PowerState ^ (Cmd->TagBody.PowerState & RPI_MBOX_POWER_STATE_ENABLE)) {
218     DEBUG ((DEBUG_ERROR, "%a: failed to %sable power for device %d\n",
219       __FUNCTION__, PowerState ? "en" : "dis", DeviceId));
220     Status = EFI_DEVICE_ERROR;
221   }
222 
223   return Status;
224 }
225 
226 #pragma pack()
227 typedef struct {
228   UINT32                    Base;
229   UINT32                    Size;
230 } RPI_FW_ARM_MEMORY_TAG;
231 
232 typedef struct {
233   RPI_FW_BUFFER_HEAD        BufferHead;
234   RPI_FW_TAG_HEAD           TagHead;
235   RPI_FW_ARM_MEMORY_TAG     TagBody;
236   UINT32                    EndTag;
237 } RPI_FW_GET_ARM_MEMORY_CMD;
238 #pragma pack()
239 
240 STATIC
241 EFI_STATUS
242 EFIAPI
243 RpiFirmwareGetArmMemory (
244   OUT   UINT32 *Base,
245   OUT   UINT32 *Size
246   )
247 {
248   RPI_FW_GET_ARM_MEMORY_CMD   *Cmd;
249   EFI_STATUS                  Status;
250   UINT32                      Result;
251 
252   if (!AcquireSpinLockOrFail (&mMailboxLock)) {
253     DEBUG ((DEBUG_ERROR, "%a: failed to acquire spinlock\n", __FUNCTION__));
254     return EFI_DEVICE_ERROR;
255   }
256 
257   Cmd = mDmaBuffer;
258   ZeroMem (Cmd, sizeof (*Cmd));
259 
260   Cmd->BufferHead.BufferSize  = sizeof (*Cmd);
261   Cmd->BufferHead.Response    = 0;
262   Cmd->TagHead.TagId          = RPI_MBOX_GET_ARM_MEMSIZE;
263   Cmd->TagHead.TagSize        = sizeof (Cmd->TagBody);
264   Cmd->TagHead.TagValueSize   = 0;
265   Cmd->EndTag                 = 0;
266 
267   Status = MailboxTransaction (Cmd->BufferHead.BufferSize, RPI_MBOX_VC_CHANNEL, &Result);
268 
269   ReleaseSpinLock (&mMailboxLock);
270 
271   if (EFI_ERROR (Status) ||
272       Cmd->BufferHead.Response != RPI_MBOX_RESP_SUCCESS) {
273     DEBUG ((DEBUG_ERROR,
274       "%a: mailbox transaction error: Status == %r, Response == 0x%x\n",
275       __FUNCTION__, Status, Cmd->BufferHead.Response));
276     return EFI_DEVICE_ERROR;
277   }
278 
279   *Base = Cmd->TagBody.Base;
280   *Size = Cmd->TagBody.Size;
281   return EFI_SUCCESS;
282 }
283 
284 #pragma pack()
285 typedef struct {
286   UINT8                     MacAddress[6];
287   UINT32                    Padding;
288 } RPI_FW_MAC_ADDR_TAG;
289 
290 typedef struct {
291   RPI_FW_BUFFER_HEAD        BufferHead;
292   RPI_FW_TAG_HEAD           TagHead;
293   RPI_FW_MAC_ADDR_TAG       TagBody;
294   UINT32                    EndTag;
295 } RPI_FW_GET_MAC_ADDR_CMD;
296 #pragma pack()
297 
298 STATIC
299 EFI_STATUS
300 EFIAPI
301 RpiFirmwareGetMacAddress (
302   OUT   UINT8   MacAddress[6]
303   )
304 {
305   RPI_FW_GET_MAC_ADDR_CMD     *Cmd;
306   EFI_STATUS                  Status;
307   UINT32                      Result;
308 
309   if (!AcquireSpinLockOrFail (&mMailboxLock)) {
310     DEBUG ((DEBUG_ERROR, "%a: failed to acquire spinlock\n", __FUNCTION__));
311     return EFI_DEVICE_ERROR;
312   }
313 
314   Cmd = mDmaBuffer;
315   ZeroMem (Cmd, sizeof (*Cmd));
316 
317   Cmd->BufferHead.BufferSize  = sizeof (*Cmd);
318   Cmd->BufferHead.Response    = 0;
319   Cmd->TagHead.TagId          = RPI_MBOX_GET_MAC_ADDRESS;
320   Cmd->TagHead.TagSize        = sizeof (Cmd->TagBody);
321   Cmd->TagHead.TagValueSize   = 0;
322   Cmd->EndTag                 = 0;
323 
324   Status = MailboxTransaction (Cmd->BufferHead.BufferSize, RPI_MBOX_VC_CHANNEL, &Result);
325 
326   ReleaseSpinLock (&mMailboxLock);
327 
328   if (EFI_ERROR (Status) ||
329       Cmd->BufferHead.Response != RPI_MBOX_RESP_SUCCESS) {
330     DEBUG ((DEBUG_ERROR,
331       "%a: mailbox transaction error: Status == %r, Response == 0x%x\n",
332       __FUNCTION__, Status, Cmd->BufferHead.Response));
333     return EFI_DEVICE_ERROR;
334   }
335 
336   CopyMem (MacAddress, Cmd->TagBody.MacAddress, sizeof (Cmd->TagBody.MacAddress));
337   return EFI_SUCCESS;
338 }
339 
340 #pragma pack()
341 typedef struct {
342   UINT64                    Serial;
343 } RPI_FW_SERIAL_TAG;
344 
345 typedef struct {
346   RPI_FW_BUFFER_HEAD        BufferHead;
347   RPI_FW_TAG_HEAD           TagHead;
348   RPI_FW_SERIAL_TAG         TagBody;
349   UINT32                    EndTag;
350 } RPI_FW_GET_SERIAL_CMD;
351 #pragma pack()
352 
353 STATIC
354 EFI_STATUS
355 EFIAPI
356 RpiFirmwareGetSerial (
357   OUT   UINT64 *Serial
358   )
359 {
360   RPI_FW_GET_SERIAL_CMD       *Cmd;
361   EFI_STATUS                  Status;
362   UINT32                      Result;
363 
364   if (!AcquireSpinLockOrFail (&mMailboxLock)) {
365     DEBUG ((DEBUG_ERROR, "%a: failed to acquire spinlock\n", __FUNCTION__));
366     return EFI_DEVICE_ERROR;
367   }
368 
369   Cmd = mDmaBuffer;
370   ZeroMem (Cmd, sizeof (*Cmd));
371 
372   Cmd->BufferHead.BufferSize  = sizeof (*Cmd);
373   Cmd->BufferHead.Response    = 0;
374   Cmd->TagHead.TagId          = RPI_MBOX_GET_BOARD_SERIAL;
375   Cmd->TagHead.TagSize        = sizeof (Cmd->TagBody);
376   Cmd->TagHead.TagValueSize   = 0;
377   Cmd->EndTag                 = 0;
378 
379   Status = MailboxTransaction (Cmd->BufferHead.BufferSize, RPI_MBOX_VC_CHANNEL, &Result);
380 
381   ReleaseSpinLock (&mMailboxLock);
382 
383   if (EFI_ERROR (Status) ||
384       Cmd->BufferHead.Response != RPI_MBOX_RESP_SUCCESS) {
385     DEBUG ((DEBUG_ERROR,
386       "%a: mailbox transaction error: Status == %r, Response == 0x%x\n",
387       __FUNCTION__, Status, Cmd->BufferHead.Response));
388     return EFI_DEVICE_ERROR;
389   }
390 
391   *Serial = Cmd->TagBody.Serial;
392   // Some platforms return 0 or 0x0000000010000000 for serial.
393   // For those, try to use the MAC address.
394   if ((*Serial == 0) || ((*Serial & 0xFFFFFFFF0FFFFFFFULL) == 0)) {
395     Status = RpiFirmwareGetMacAddress ((UINT8*) Serial);
396     // Convert to a more user-friendly value
397     *Serial = SwapBytes64 (*Serial << 16);
398   }
399 
400   return Status;
401 }
402 
403 #pragma pack()
404 typedef struct {
405   UINT32                    Model;
406 } RPI_FW_MODEL_TAG;
407 
408 typedef struct {
409   RPI_FW_BUFFER_HEAD        BufferHead;
410   RPI_FW_TAG_HEAD           TagHead;
411   RPI_FW_MODEL_TAG          TagBody;
412   UINT32                    EndTag;
413 } RPI_FW_GET_MODEL_CMD;
414 #pragma pack()
415 
416 STATIC
417 EFI_STATUS
418 EFIAPI
419 RpiFirmwareGetModel (
420   OUT   UINT32 *Model
421   )
422 {
423   RPI_FW_GET_MODEL_CMD       *Cmd;
424   EFI_STATUS                  Status;
425   UINT32                      Result;
426 
427   if (!AcquireSpinLockOrFail (&mMailboxLock)) {
428     DEBUG ((DEBUG_ERROR, "%a: failed to acquire spinlock\n", __FUNCTION__));
429     return EFI_DEVICE_ERROR;
430   }
431 
432   Cmd = mDmaBuffer;
433   ZeroMem (Cmd, sizeof (*Cmd));
434 
435   Cmd->BufferHead.BufferSize  = sizeof (*Cmd);
436   Cmd->BufferHead.Response    = 0;
437   Cmd->TagHead.TagId          = RPI_MBOX_GET_BOARD_MODEL;
438   Cmd->TagHead.TagSize        = sizeof (Cmd->TagBody);
439   Cmd->TagHead.TagValueSize   = 0;
440   Cmd->EndTag                 = 0;
441 
442   Status = MailboxTransaction (Cmd->BufferHead.BufferSize, RPI_MBOX_VC_CHANNEL, &Result);
443 
444   ReleaseSpinLock (&mMailboxLock);
445 
446   if (EFI_ERROR (Status) ||
447       Cmd->BufferHead.Response != RPI_MBOX_RESP_SUCCESS) {
448     DEBUG ((DEBUG_ERROR,
449       "%a: mailbox transaction error: Status == %r, Response == 0x%x\n",
450       __FUNCTION__, Status, Cmd->BufferHead.Response));
451     return EFI_DEVICE_ERROR;
452   }
453 
454   *Model = Cmd->TagBody.Model;
455   return EFI_SUCCESS;
456 }
457 
458 #pragma pack()
459 typedef struct {
460   UINT32                    Revision;
461 } RPI_FW_MODEL_REVISION_TAG;
462 
463 typedef struct {
464   RPI_FW_BUFFER_HEAD        BufferHead;
465   RPI_FW_TAG_HEAD           TagHead;
466   RPI_FW_MODEL_REVISION_TAG TagBody;
467   UINT32                    EndTag;
468 } RPI_FW_GET_REVISION_CMD;
469 #pragma pack()
470 
471 STATIC
472 EFI_STATUS
473 EFIAPI
474 RpiFirmwareGetModelRevision (
475   OUT   UINT32 *Revision
476   )
477 {
478   RPI_FW_GET_REVISION_CMD       *Cmd;
479   EFI_STATUS                    Status;
480   UINT32                        Result;
481 
482   if (!AcquireSpinLockOrFail (&mMailboxLock)) {
483     DEBUG ((DEBUG_ERROR, "%a: failed to acquire spinlock\n", __FUNCTION__));
484     return EFI_DEVICE_ERROR;
485   }
486 
487   Cmd = mDmaBuffer;
488   ZeroMem (Cmd, sizeof (*Cmd));
489 
490   Cmd->BufferHead.BufferSize  = sizeof (*Cmd);
491   Cmd->BufferHead.Response    = 0;
492   Cmd->TagHead.TagId          = RPI_MBOX_GET_BOARD_REVISION;
493   Cmd->TagHead.TagSize        = sizeof (Cmd->TagBody);
494   Cmd->TagHead.TagValueSize   = 0;
495   Cmd->EndTag                 = 0;
496 
497   Status = MailboxTransaction (Cmd->BufferHead.BufferSize, RPI_MBOX_VC_CHANNEL, &Result);
498 
499   ReleaseSpinLock (&mMailboxLock);
500 
501   if (EFI_ERROR (Status) ||
502       Cmd->BufferHead.Response != RPI_MBOX_RESP_SUCCESS) {
503     DEBUG ((DEBUG_ERROR,
504       "%a: mailbox transaction error: Status == %r, Response == 0x%x\n",
505       __FUNCTION__, Status, Cmd->BufferHead.Response));
506     return EFI_DEVICE_ERROR;
507   }
508 
509   *Revision = Cmd->TagBody.Revision;
510   return EFI_SUCCESS;
511 }
512 
513 STATIC
514 EFI_STATUS
515 EFIAPI
516 RpiFirmwareGetFirmwareRevision (
517   OUT   UINT32 *Revision
518   )
519 {
520   RPI_FW_GET_REVISION_CMD       *Cmd;
521   EFI_STATUS                    Status;
522   UINT32                        Result;
523 
524   if (!AcquireSpinLockOrFail (&mMailboxLock)) {
525     DEBUG ((DEBUG_ERROR, "%a: failed to acquire spinlock\n", __FUNCTION__));
526     return EFI_DEVICE_ERROR;
527   }
528 
529   Cmd = mDmaBuffer;
530   ZeroMem (Cmd, sizeof (*Cmd));
531 
532   Cmd->BufferHead.BufferSize  = sizeof (*Cmd);
533   Cmd->BufferHead.Response    = 0;
534   Cmd->TagHead.TagId          = RPI_MBOX_GET_REVISION;
535   Cmd->TagHead.TagSize        = sizeof (Cmd->TagBody);
536   Cmd->TagHead.TagValueSize   = 0;
537   Cmd->EndTag                 = 0;
538 
539   Status = MailboxTransaction (Cmd->BufferHead.BufferSize, RPI_MBOX_VC_CHANNEL, &Result);
540 
541   ReleaseSpinLock (&mMailboxLock);
542 
543   if (EFI_ERROR (Status) ||
544       Cmd->BufferHead.Response != RPI_MBOX_RESP_SUCCESS) {
545     DEBUG ((DEBUG_ERROR,
546       "%a: mailbox transaction error: Status == %r, Response == 0x%x\n",
547       __FUNCTION__, Status, Cmd->BufferHead.Response));
548     return EFI_DEVICE_ERROR;
549   }
550 
551   *Revision = Cmd->TagBody.Revision;
552   return EFI_SUCCESS;
553 }
554 
555 STATIC
556 CHAR8*
557 EFIAPI
558 RpiFirmwareGetModelName (
559   IN INTN ModelId
560   )
561 {
562   UINT32  Revision;
563 
564   // If a negative ModelId is passed, detect it.
565   if ((ModelId < 0) && (RpiFirmwareGetModelRevision (&Revision) == EFI_SUCCESS)) {
566     ModelId = (Revision >> 4) & 0xFF;
567   }
568 
569   switch (ModelId) {
570   // www.raspberrypi.org/documentation/hardware/raspberrypi/revision-codes/README.md
571   case 0x00:
572     return "Raspberry Pi Model A";
573   case 0x01:
574     return "Raspberry Pi Model B";
575   case 0x02:
576     return "Raspberry Pi Model A+";
577   case 0x03:
578     return "Raspberry Pi Model B+";
579   case 0x04:
580     return "Raspberry Pi 2 Model B";
581   case 0x06:
582     return "Raspberry Pi Compute Module 1";
583   case 0x08:
584     return "Raspberry Pi 3 Model B";
585   case 0x09:
586     return "Raspberry Pi Zero";
587   case 0x0A:
588     return "Raspberry Pi Compute Module 3";
589   case 0x0C:
590     return "Raspberry Pi Zero W";
591   case 0x0D:
592     return "Raspberry Pi 3 Model B+";
593   case 0x0E:
594     return "Raspberry Pi 3 Model A+";
595   case 0x10:
596     return "Raspberry Pi Compute Module 3+";
597   case 0x11:
598     return "Raspberry Pi 4 Model B";
599   case 0x13:
600     return "Raspberry Pi 400";
601   case 0x14:
602     return "Raspberry Pi Compute Module 4";
603   default:
604     return "Unknown Raspberry Pi Model";
605   }
606 }
607 
608 STATIC
609 EFI_STATUS
610 EFIAPI
611 RPiFirmwareGetModelInstalledMB (
612   OUT   UINT32 *InstalledMB
613   )
614 {
615   EFI_STATUS Status;
616   UINT32     Revision;
617 
618   Status = RpiFirmwareGetModelRevision(&Revision);
619   if (EFI_ERROR(Status)) {
620     DEBUG ((DEBUG_ERROR, "%a: Could not get the board revision: Status == %r\n",
621       __FUNCTION__, Status));
622     return EFI_DEVICE_ERROR;
623   }
624 
625   //
626   // www.raspberrypi.org/documentation/hardware/raspberrypi/revision-codes/README.md
627   // Bits [20-22] indicate the amount of memory starting with 256MB (000b)
628   // and doubling in size for each value (001b = 512 MB, 010b = 1GB, etc.)
629   //
630   *InstalledMB = 256 << ((Revision >> 20) & 0x07);
631   return EFI_SUCCESS;
632 }
633 
634 STATIC
635 EFI_STATUS
636 EFIAPI
637 RPiFirmwareGetModelFamily (
638   OUT   UINT32 *ModelFamily
639   )
640 {
641   EFI_STATUS                  Status;
642   UINT32                      Revision;
643   UINT32                      ModelId;
644 
645   Status = RpiFirmwareGetModelRevision(&Revision);
646   if (EFI_ERROR(Status)) {
647     DEBUG ((DEBUG_ERROR,
648       "%a: Could not get the board revision: Status == %r\n",
649       __FUNCTION__, Status));
650     return EFI_DEVICE_ERROR;
651   } else {
652     ModelId = (Revision >> 4) & 0xFF;
653   }
654 
655   switch (ModelId) {
656   // www.raspberrypi.org/documentation/hardware/raspberrypi/revision-codes/README.md
657   case 0x00:          // Raspberry Pi Model A
658   case 0x01:          // Raspberry Pi Model B
659   case 0x02:          // Raspberry Pi Model A+
660   case 0x03:          // Raspberry Pi Model B+
661   case 0x06:          // Raspberry Pi Compute Module 1
662   case 0x09:          // Raspberry Pi Zero
663   case 0x0C:          // Raspberry Pi Zero W
664       *ModelFamily = 1;
665       break;
666   case 0x04:          // Raspberry Pi 2 Model B
667       *ModelFamily = 2;
668       break;
669   case 0x08:          // Raspberry Pi 3 Model B
670   case 0x0A:          // Raspberry Pi Compute Module 3
671   case 0x0D:          // Raspberry Pi 3 Model B+
672   case 0x0E:          // Raspberry Pi 3 Model A+
673   case 0x10:          // Raspberry Pi Compute Module 3+
674       *ModelFamily = 3;
675       break;
676   case 0x11:          // Raspberry Pi 4 Model B
677   case 0x13:          // Raspberry Pi 400
678   case 0x14:          // Raspberry Pi Computer Module 4
679       *ModelFamily = 4;
680       break;
681   default:
682       *ModelFamily = 0;
683       break;
684   }
685 
686   if (*ModelFamily == 0) {
687     DEBUG ((DEBUG_ERROR,
688       "%a: Unknown Raspberry Pi model family : ModelId == 0x%x\n",
689       __FUNCTION__, ModelId));
690     return EFI_UNSUPPORTED;
691     }
692 
693   return EFI_SUCCESS;
694 }
695 
696 STATIC
697 CHAR8*
698 EFIAPI
699 RpiFirmwareGetManufacturerName (
700   IN INTN ManufacturerId
701   )
702 {
703   UINT32  Revision;
704 
705   // If a negative ModelId is passed, detect it.
706   if ((ManufacturerId < 0) && (RpiFirmwareGetModelRevision (&Revision) == EFI_SUCCESS)) {
707     ManufacturerId = (Revision >> 16) & 0x0F;
708   }
709 
710   switch (ManufacturerId) {
711   // www.raspberrypi.org/documentation/hardware/raspberrypi/revision-codes/README.md
712   case 0x00:
713     return "Sony UK";
714   case 0x01:
715     return "Egoman";
716   case 0x02:
717   case 0x04:
718     return "Embest";
719   case 0x03:
720     return "Sony Japan";
721   case 0x05:
722     return "Stadium";
723   default:
724     return "Unknown Manufacturer";
725   }
726 }
727 
728 STATIC
729 CHAR8*
730 EFIAPI
731 RpiFirmwareGetCpuName (
732   IN INTN CpuId
733   )
734 {
735   UINT32  Revision;
736 
737   // If a negative CpuId is passed, detect it.
738   if ((CpuId < 0) && (RpiFirmwareGetModelRevision (&Revision) == EFI_SUCCESS)) {
739     CpuId = (Revision >> 12) & 0x0F;
740   }
741 
742   switch (CpuId) {
743   // www.raspberrypi.org/documentation/hardware/raspberrypi/revision-codes/README.md
744   case 0x00:
745     return "BCM2835 (ARM11)";
746   case 0x01:
747     return "BCM2836 (ARM Cortex-A7)";
748   case 0x02:
749     return "BCM2837 (ARM Cortex-A53)";
750   case 0x03:
751     return "BCM2711 (ARM Cortex-A72)";
752   default:
753     return "Unknown CPU Model";
754   }
755 }
756 
757 #pragma pack()
758 typedef struct {
759   UINT32 Width;
760   UINT32 Height;
761 } RPI_FW_FB_SIZE_TAG;
762 
763 typedef struct {
764   RPI_FW_BUFFER_HEAD        BufferHead;
765   RPI_FW_TAG_HEAD           TagHead;
766   RPI_FW_FB_SIZE_TAG        TagBody;
767   UINT32                    EndTag;
768 } RPI_FW_GET_FB_SIZE_CMD;
769 
770 typedef struct {
771   UINT32 Depth;
772 } RPI_FW_FB_DEPTH_TAG;
773 
774 typedef struct {
775   UINT32 Pitch;
776 } RPI_FW_FB_PITCH_TAG;
777 
778 typedef struct {
779   UINT32 AlignmentBase;
780   UINT32 Size;
781 } RPI_FW_FB_ALLOC_TAG;
782 
783 typedef struct {
784   RPI_FW_BUFFER_HEAD        BufferHead;
785   RPI_FW_TAG_HEAD           FreeFbTag;
786   UINT32                    EndTag;
787 } RPI_FW_FREE_FB_CMD;
788 
789 typedef struct {
790   RPI_FW_BUFFER_HEAD        BufferHead;
791   RPI_FW_TAG_HEAD           PhysSizeTag;
792   RPI_FW_FB_SIZE_TAG        PhysSize;
793   RPI_FW_TAG_HEAD           VirtSizeTag;
794   RPI_FW_FB_SIZE_TAG        VirtSize;
795   RPI_FW_TAG_HEAD           DepthTag;
796   RPI_FW_FB_DEPTH_TAG       Depth;
797   RPI_FW_TAG_HEAD           AllocFbTag;
798   RPI_FW_FB_ALLOC_TAG       AllocFb;
799   RPI_FW_TAG_HEAD           PitchTag;
800   RPI_FW_FB_PITCH_TAG       Pitch;
801   UINT32                    EndTag;
802 } RPI_FW_INIT_FB_CMD;
803 #pragma pack()
804 
805 STATIC
806 EFI_STATUS
807 EFIAPI
808 RpiFirmwareGetFbSize (
809   OUT   UINT32 *Width,
810   OUT   UINT32 *Height
811   )
812 {
813   RPI_FW_GET_FB_SIZE_CMD     *Cmd;
814   EFI_STATUS                  Status;
815   UINT32                      Result;
816 
817   if (!AcquireSpinLockOrFail (&mMailboxLock)) {
818     DEBUG ((DEBUG_ERROR, "%a: failed to acquire spinlock\n", __FUNCTION__));
819     return EFI_DEVICE_ERROR;
820   }
821 
822   Cmd = mDmaBuffer;
823   ZeroMem (Cmd, sizeof (*Cmd));
824 
825   Cmd->BufferHead.BufferSize  = sizeof (*Cmd);
826   Cmd->BufferHead.Response    = 0;
827   Cmd->TagHead.TagId          = RPI_MBOX_GET_FB_GEOMETRY;
828   Cmd->TagHead.TagSize        = sizeof (Cmd->TagBody);
829   Cmd->TagHead.TagValueSize   = 0;
830   Cmd->EndTag                 = 0;
831 
832   Status = MailboxTransaction (Cmd->BufferHead.BufferSize, RPI_MBOX_VC_CHANNEL, &Result);
833 
834   ReleaseSpinLock (&mMailboxLock);
835 
836   if (EFI_ERROR (Status) ||
837       Cmd->BufferHead.Response != RPI_MBOX_RESP_SUCCESS) {
838     DEBUG ((DEBUG_ERROR,
839       "%a: mailbox  transaction error: Status == %r, Response == 0x%x\n",
840       __FUNCTION__, Status, Cmd->BufferHead.Response));
841     return EFI_DEVICE_ERROR;
842   }
843 
844   *Width = Cmd->TagBody.Width;
845   *Height = Cmd->TagBody.Height;
846   return EFI_SUCCESS;
847 }
848 
849 STATIC
850 EFI_STATUS
851 EFIAPI
852 RpiFirmwareFreeFb (VOID)
853 {
854   RPI_FW_FREE_FB_CMD *Cmd;
855   EFI_STATUS         Status;
856   UINT32             Result;
857 
858   if (!AcquireSpinLockOrFail (&mMailboxLock)) {
859     DEBUG ((DEBUG_ERROR, "%a: failed to acquire spinlock\n", __FUNCTION__));
860     return EFI_DEVICE_ERROR;
861   }
862 
863   Cmd = mDmaBuffer;
864   ZeroMem (Cmd, sizeof (*Cmd));
865 
866   Cmd->BufferHead.BufferSize   = sizeof (*Cmd);
867   Cmd->BufferHead.Response     = 0;
868 
869   Cmd->FreeFbTag.TagId         = RPI_MBOX_FREE_FB;
870   Cmd->FreeFbTag.TagSize       = 0;
871   Cmd->FreeFbTag.TagValueSize  = 0;
872   Cmd->EndTag                  = 0;
873 
874   Status = MailboxTransaction (Cmd->BufferHead.BufferSize, RPI_MBOX_VC_CHANNEL, &Result);
875   ReleaseSpinLock (&mMailboxLock);
876 
877   if (EFI_ERROR (Status) ||
878       Cmd->BufferHead.Response != RPI_MBOX_RESP_SUCCESS) {
879     DEBUG ((DEBUG_ERROR,
880       "%a: mailbox transaction error: Status == %r, Response == 0x%x\n",
881       __FUNCTION__, Status, Cmd->BufferHead.Response));
882     return EFI_DEVICE_ERROR;
883   }
884 
885   return EFI_SUCCESS;
886 }
887 
888 STATIC
889 EFI_STATUS
890 EFIAPI
891 RpiFirmwareAllocFb (
892   IN  UINT32 Width,
893   IN  UINT32 Height,
894   IN  UINT32 Depth,
895   OUT EFI_PHYSICAL_ADDRESS *FbBase,
896   OUT UINTN *FbSize,
897   OUT UINTN *Pitch
898   )
899 {
900   RPI_FW_INIT_FB_CMD *Cmd;
901   EFI_STATUS         Status;
902   UINT32             Result;
903 
904   ASSERT (FbSize != NULL);
905   ASSERT (FbBase != NULL);
906 
907   if (!AcquireSpinLockOrFail (&mMailboxLock)) {
908     DEBUG ((DEBUG_ERROR, "%a: failed to acquire spinlock\n", __FUNCTION__));
909     return EFI_DEVICE_ERROR;
910   }
911 
912   Cmd = mDmaBuffer;
913   ZeroMem (Cmd, sizeof (*Cmd));
914 
915   Cmd->BufferHead.BufferSize  = sizeof (*Cmd);
916   Cmd->BufferHead.Response    = 0;
917 
918   Cmd->PhysSizeTag.TagId      = RPI_MBOX_SET_FB_PGEOM;
919   Cmd->PhysSizeTag.TagSize    = sizeof (Cmd->PhysSize);
920   Cmd->PhysSize.Width         = Width;
921   Cmd->PhysSize.Height        = Height;
922   Cmd->VirtSizeTag.TagId      = RPI_MBOX_SET_FB_VGEOM;
923   Cmd->VirtSizeTag.TagSize    = sizeof (Cmd->VirtSize);
924   Cmd->VirtSize.Width         = Width;
925   Cmd->VirtSize.Height        = Height;
926   Cmd->DepthTag.TagId         = RPI_MBOX_SET_FB_DEPTH;
927   Cmd->DepthTag.TagSize       = sizeof (Cmd->Depth);
928   Cmd->Depth.Depth            = Depth;
929   Cmd->AllocFbTag.TagId       = RPI_MBOX_ALLOC_FB;
930   Cmd->AllocFbTag.TagSize     = sizeof (Cmd->AllocFb);
931   Cmd->AllocFb.AlignmentBase  = 32;
932   Cmd->PitchTag.TagId         = RPI_MBOX_GET_FB_LINELENGTH;
933   Cmd->PitchTag.TagSize       = sizeof (Cmd->Pitch);
934   Cmd->EndTag                 = 0;
935 
936   Status = MailboxTransaction (Cmd->BufferHead.BufferSize, RPI_MBOX_VC_CHANNEL, &Result);
937 
938   ReleaseSpinLock (&mMailboxLock);
939 
940   if (EFI_ERROR (Status) ||
941       Cmd->BufferHead.Response != RPI_MBOX_RESP_SUCCESS) {
942     DEBUG ((DEBUG_ERROR,
943       "%a: mailbox transaction error: Status == %r, Response == 0x%x\n",
944       __FUNCTION__, Status, Cmd->BufferHead.Response));
945     return EFI_DEVICE_ERROR;
946   }
947 
948   *Pitch = Cmd->Pitch.Pitch;
949   *FbBase = Cmd->AllocFb.AlignmentBase - BCM2836_DMA_DEVICE_OFFSET;
950   *FbSize = Cmd->AllocFb.Size;
951   return EFI_SUCCESS;
952 }
953 
954 #pragma pack()
955 typedef struct {
956   RPI_FW_BUFFER_HEAD        BufferHead;
957   RPI_FW_TAG_HEAD           TagHead;
958   UINT8                     CommandLine[0];
959 } RPI_FW_GET_COMMAND_LINE_CMD;
960 #pragma pack()
961 
962 STATIC
963 EFI_STATUS
964 EFIAPI
965 RpiFirmwareGetCommmandLine (
966   IN  UINTN               BufferSize,
967   OUT CHAR8               CommandLine[]
968   )
969 {
970   RPI_FW_GET_COMMAND_LINE_CMD  *Cmd;
971   EFI_STATUS                    Status;
972   UINT32                        Result;
973 
974   if ((BufferSize % sizeof (UINT32)) != 0) {
975     DEBUG ((DEBUG_ERROR, "%a: BufferSize must be a multiple of 4\n",
976       __FUNCTION__));
977     return EFI_INVALID_PARAMETER;
978   }
979 
980   if (sizeof (*Cmd) + BufferSize > EFI_PAGES_TO_SIZE (NUM_PAGES)) {
981     DEBUG ((DEBUG_ERROR, "%a: BufferSize exceeds size of DMA buffer\n",
982       __FUNCTION__));
983     return EFI_OUT_OF_RESOURCES;
984   }
985 
986   if (!AcquireSpinLockOrFail (&mMailboxLock)) {
987     DEBUG ((DEBUG_ERROR, "%a: failed to acquire spinlock\n", __FUNCTION__));
988     return EFI_DEVICE_ERROR;
989   }
990 
991   Cmd = mDmaBuffer;
992   ZeroMem (Cmd, sizeof (*Cmd) + BufferSize + sizeof (UINT32));
993 
994   Cmd->BufferHead.BufferSize  = sizeof (*Cmd) + BufferSize + sizeof (UINT32);
995   Cmd->BufferHead.Response    = 0;
996   Cmd->TagHead.TagId          = RPI_MBOX_GET_COMMAND_LINE;
997   Cmd->TagHead.TagSize        = BufferSize;
998   Cmd->TagHead.TagValueSize   = 0;
999 
1000   Status = MailboxTransaction (Cmd->BufferHead.BufferSize, RPI_MBOX_VC_CHANNEL, &Result);
1001 
1002   ReleaseSpinLock (&mMailboxLock);
1003 
1004   if (EFI_ERROR (Status) ||
1005       Cmd->BufferHead.Response != RPI_MBOX_RESP_SUCCESS) {
1006     DEBUG ((DEBUG_ERROR,
1007       "%a: mailbox transaction error: Status == %r, Response == 0x%x\n",
1008       __FUNCTION__, Status, Cmd->BufferHead.Response));
1009     return EFI_DEVICE_ERROR;
1010   }
1011 
1012   Cmd->TagHead.TagValueSize &= ~RPI_MBOX_VALUE_SIZE_RESPONSE_MASK;
1013   if (Cmd->TagHead.TagValueSize >= BufferSize &&
1014       Cmd->CommandLine[Cmd->TagHead.TagValueSize - 1] != '\0') {
1015     DEBUG ((DEBUG_ERROR, "%a: insufficient buffer size\n", __FUNCTION__));
1016     return EFI_OUT_OF_RESOURCES;
1017   }
1018 
1019   CopyMem (CommandLine, Cmd->CommandLine, Cmd->TagHead.TagValueSize);
1020 
1021   if (Cmd->TagHead.TagValueSize == 0 ||
1022       CommandLine[Cmd->TagHead.TagValueSize - 1] != '\0') {
1023     //
1024     // Add a NUL terminator if required.
1025     //
1026     CommandLine[Cmd->TagHead.TagValueSize] = '\0';
1027   }
1028 
1029   return EFI_SUCCESS;
1030 }
1031 
1032 #pragma pack()
1033 typedef struct {
1034   UINT32                    ClockId;
1035   UINT32                    ClockRate;
1036   UINT32                    SkipTurbo;
1037 } RPI_FW_SET_CLOCK_RATE_TAG;
1038 
1039 typedef struct {
1040   RPI_FW_BUFFER_HEAD        BufferHead;
1041   RPI_FW_TAG_HEAD           TagHead;
1042   RPI_FW_SET_CLOCK_RATE_TAG TagBody;
1043   UINT32                    EndTag;
1044 } RPI_FW_SET_CLOCK_RATE_CMD;
1045 #pragma pack()
1046 
1047 STATIC
1048 EFI_STATUS
1049 EFIAPI
1050 RpiFirmwareSetClockRate (
1051   IN  UINT32  ClockId,
1052   IN  UINT32  ClockRate,
1053   IN  BOOLEAN SkipTurbo
1054   )
1055 {
1056   RPI_FW_SET_CLOCK_RATE_CMD   *Cmd;
1057   EFI_STATUS                  Status;
1058   UINT32                      Result;
1059 
1060   if (!AcquireSpinLockOrFail (&mMailboxLock)) {
1061     DEBUG ((DEBUG_ERROR, "%a: failed to acquire spinlock\n", __FUNCTION__));
1062     return EFI_DEVICE_ERROR;
1063   }
1064 
1065   Cmd = mDmaBuffer;
1066   ZeroMem (Cmd, sizeof (*Cmd));
1067 
1068   Cmd->BufferHead.BufferSize  = sizeof (*Cmd);
1069   Cmd->BufferHead.Response    = 0;
1070   Cmd->TagHead.TagId          = RPI_MBOX_SET_CLOCK_RATE;
1071   Cmd->TagHead.TagSize        = sizeof (Cmd->TagBody);
1072   Cmd->TagHead.TagValueSize   = 0;
1073   Cmd->TagBody.ClockId        = ClockId;
1074   Cmd->TagBody.ClockRate      = ClockRate;
1075   Cmd->TagBody.SkipTurbo      = SkipTurbo ? 1 : 0;
1076   Cmd->EndTag                 = 0;
1077 
1078   Status = MailboxTransaction (Cmd->BufferHead.BufferSize, RPI_MBOX_VC_CHANNEL, &Result);
1079 
1080   ReleaseSpinLock (&mMailboxLock);
1081 
1082   if (EFI_ERROR (Status) ||
1083       Cmd->BufferHead.Response != RPI_MBOX_RESP_SUCCESS) {
1084     DEBUG ((DEBUG_ERROR,
1085       "%a: mailbox transaction error: Status == %r, Response == 0x%x\n",
1086       __FUNCTION__, Status, Cmd->BufferHead.Response));
1087     return EFI_DEVICE_ERROR;
1088   }
1089 
1090   return EFI_SUCCESS;
1091 }
1092 
1093 #pragma pack()
1094 typedef struct {
1095   UINT32                    ClockId;
1096   UINT32                    ClockRate;
1097 } RPI_FW_CLOCK_RATE_TAG;
1098 
1099 typedef struct {
1100   RPI_FW_BUFFER_HEAD        BufferHead;
1101   RPI_FW_TAG_HEAD           TagHead;
1102   RPI_FW_CLOCK_RATE_TAG     TagBody;
1103   UINT32                    EndTag;
1104 } RPI_FW_GET_CLOCK_RATE_CMD;
1105 #pragma pack()
1106 
1107 STATIC
1108 EFI_STATUS
1109 RpiFirmwareGetClockRate (
1110   IN  UINT32 ClockId,
1111   IN  UINT32 ClockKind,
1112   OUT UINT32 *ClockRate
1113   )
1114 {
1115   RPI_FW_GET_CLOCK_RATE_CMD   *Cmd;
1116   EFI_STATUS                  Status;
1117   UINT32                      Result;
1118 
1119   if (!AcquireSpinLockOrFail (&mMailboxLock)) {
1120     DEBUG ((DEBUG_ERROR, "%a: failed to acquire spinlock\n", __FUNCTION__));
1121     return EFI_DEVICE_ERROR;
1122   }
1123 
1124   Cmd = mDmaBuffer;
1125   ZeroMem (Cmd, sizeof (*Cmd));
1126 
1127   Cmd->BufferHead.BufferSize  = sizeof (*Cmd);
1128   Cmd->BufferHead.Response    = 0;
1129   Cmd->TagHead.TagId          = ClockKind;
1130   Cmd->TagHead.TagSize        = sizeof (Cmd->TagBody);
1131   Cmd->TagHead.TagValueSize   = 0;
1132   Cmd->TagBody.ClockId        = ClockId;
1133   Cmd->EndTag                 = 0;
1134 
1135   Status = MailboxTransaction (Cmd->BufferHead.BufferSize, RPI_MBOX_VC_CHANNEL, &Result);
1136 
1137   ReleaseSpinLock (&mMailboxLock);
1138 
1139   if (EFI_ERROR (Status) ||
1140       Cmd->BufferHead.Response != RPI_MBOX_RESP_SUCCESS) {
1141     DEBUG ((DEBUG_ERROR,
1142       "%a: mailbox transaction error: Status == %r, Response == 0x%x\n",
1143       __FUNCTION__, Status, Cmd->BufferHead.Response));
1144     return EFI_DEVICE_ERROR;
1145   }
1146 
1147   *ClockRate = Cmd->TagBody.ClockRate;
1148   return EFI_SUCCESS;
1149 }
1150 
1151 STATIC
1152 EFI_STATUS
1153 EFIAPI
1154 RpiFirmwareGetCurrentClockState (
1155   IN  UINT32    ClockId,
1156   OUT UINT32    *ClockState
1157   )
1158 {
1159   return RpiFirmwareGetClockRate (ClockId, RPI_MBOX_GET_CLOCK_STATE, ClockState);
1160 }
1161 
1162 STATIC
1163 EFI_STATUS
1164 EFIAPI
1165 RpiFirmwareGetCurrentClockRate (
1166   IN  UINT32    ClockId,
1167   OUT UINT32    *ClockRate
1168   )
1169 {
1170   return RpiFirmwareGetClockRate (ClockId, RPI_MBOX_GET_CLOCK_RATE, ClockRate);
1171 }
1172 
1173 STATIC
1174 EFI_STATUS
1175 EFIAPI
1176 RpiFirmwareGetMaxClockRate (
1177   IN  UINT32    ClockId,
1178   OUT UINT32    *ClockRate
1179   )
1180 {
1181   return RpiFirmwareGetClockRate (ClockId, RPI_MBOX_GET_MAX_CLOCK_RATE, ClockRate);
1182 }
1183 
1184 STATIC
1185 EFI_STATUS
1186 EFIAPI
1187 RpiFirmwareGetMinClockRate (
1188   IN  UINT32    ClockId,
1189   OUT UINT32    *ClockRate
1190   )
1191 {
1192   return RpiFirmwareGetClockRate (ClockId, RPI_MBOX_GET_MIN_CLOCK_RATE, ClockRate);
1193 }
1194 
1195 #pragma pack()
1196 typedef struct {
1197   UINT32                    ClockId;
1198   UINT32                    ClockState;
1199 } RPI_FW_GET_CLOCK_STATE_TAG;
1200 
1201 typedef struct {
1202   RPI_FW_BUFFER_HEAD         BufferHead;
1203   RPI_FW_TAG_HEAD            TagHead;
1204   RPI_FW_GET_CLOCK_STATE_TAG TagBody;
1205   UINT32                     EndTag;
1206 } RPI_FW_SET_CLOCK_STATE_CMD;
1207 #pragma pack()
1208 
1209 STATIC
1210 EFI_STATUS
1211 RpiFirmwareSetClockState (
1212   IN  UINT32 ClockId,
1213   IN  UINT32 ClockState
1214   )
1215 {
1216   RPI_FW_SET_CLOCK_STATE_CMD  *Cmd;
1217   EFI_STATUS                  Status;
1218   UINT32                      Result;
1219 
1220   if (!AcquireSpinLockOrFail (&mMailboxLock)) {
1221     DEBUG ((DEBUG_ERROR, "%a: failed to acquire spinlock\n", __FUNCTION__));
1222     return EFI_DEVICE_ERROR;
1223   }
1224 
1225   Cmd = mDmaBuffer;
1226   ZeroMem (Cmd, sizeof (*Cmd));
1227 
1228   Cmd->BufferHead.BufferSize  = sizeof (*Cmd);
1229   Cmd->BufferHead.Response    = 0;
1230   Cmd->TagHead.TagId          = RPI_MBOX_SET_CLOCK_STATE;
1231   Cmd->TagHead.TagSize        = sizeof (Cmd->TagBody);
1232   Cmd->TagHead.TagValueSize   = 0;
1233   Cmd->TagBody.ClockId        = ClockId;
1234   Cmd->TagBody.ClockState     = ClockState;
1235   Cmd->EndTag                 = 0;
1236 
1237   Status = MailboxTransaction (Cmd->BufferHead.BufferSize, RPI_MBOX_VC_CHANNEL, &Result);
1238 
1239   ReleaseSpinLock (&mMailboxLock);
1240 
1241   if (EFI_ERROR (Status) ||
1242       Cmd->BufferHead.Response != RPI_MBOX_RESP_SUCCESS) {
1243     DEBUG ((DEBUG_ERROR,
1244       "%a: mailbox transaction error: Status == %r, Response == 0x%x\n",
1245       __FUNCTION__, Status, Cmd->BufferHead.Response));
1246     return EFI_DEVICE_ERROR;
1247   }
1248 
1249   return EFI_SUCCESS;
1250 }
1251 
1252 #pragma pack()
1253 typedef struct {
1254   UINT32 Pin;
1255   UINT32 State;
1256 } RPI_FW_SET_GPIO_TAG;
1257 
1258 typedef struct {
1259   RPI_FW_BUFFER_HEAD        BufferHead;
1260   RPI_FW_TAG_HEAD           TagHead;
1261   RPI_FW_SET_GPIO_TAG       TagBody;
1262   UINT32                    EndTag;
1263 } RPI_FW_SET_GPIO_CMD;
1264 #pragma pack()
1265 
1266 STATIC
1267 VOID
1268 EFIAPI
1269 RpiFirmwareSetGpio (
1270   IN  UINT32  Gpio,
1271   IN  BOOLEAN State
1272   )
1273 {
1274   RPI_FW_SET_GPIO_CMD *Cmd;
1275   EFI_STATUS          Status;
1276   UINT32              Result;
1277 
1278   if (!AcquireSpinLockOrFail (&mMailboxLock)) {
1279     DEBUG ((DEBUG_ERROR, "%a: failed to acquire spinlock\n", __FUNCTION__));
1280     return;
1281   }
1282 
1283   Cmd = mDmaBuffer;
1284   ZeroMem (Cmd, sizeof (*Cmd));
1285 
1286   Cmd->BufferHead.BufferSize  = sizeof (*Cmd);
1287   Cmd->BufferHead.Response    = 0;
1288   Cmd->TagHead.TagId          = RPI_MBOX_SET_GPIO;
1289   Cmd->TagHead.TagSize        = sizeof (Cmd->TagBody);
1290   /*
1291    * There's also a 128 pin offset.
1292    */
1293   Cmd->TagBody.Pin = 128 + Gpio;
1294   Cmd->TagBody.State = State;
1295   Cmd->TagHead.TagValueSize   = 0;
1296   Cmd->EndTag                 = 0;
1297 
1298   Status = MailboxTransaction (Cmd->BufferHead.BufferSize, RPI_MBOX_VC_CHANNEL, &Result);
1299 
1300   ReleaseSpinLock (&mMailboxLock);
1301 
1302   if (EFI_ERROR (Status) ||
1303       Cmd->BufferHead.Response != RPI_MBOX_RESP_SUCCESS) {
1304     DEBUG ((DEBUG_ERROR,
1305       "%a: mailbox  transaction error: Status == %r, Response == 0x%x\n",
1306       __FUNCTION__, Status, Cmd->BufferHead.Response));
1307   }
1308 }
1309 
1310 STATIC
1311 VOID
1312 EFIAPI
1313 RpiFirmwareSetLed (
1314   IN  BOOLEAN On
1315   )
1316 {
1317   RpiFirmwareSetGpio (RPI_EXP_GPIO_LED, On);
1318 }
1319 
1320 #pragma pack()
1321 typedef struct {
1322   UINT32                       DeviceAddress;
1323 } RPI_FW_NOTIFY_XHCI_RESET_TAG;
1324 
1325 typedef struct {
1326   RPI_FW_BUFFER_HEAD           BufferHead;
1327   RPI_FW_TAG_HEAD              TagHead;
1328   RPI_FW_NOTIFY_XHCI_RESET_TAG TagBody;
1329   UINT32                       EndTag;
1330 } RPI_FW_NOTIFY_XHCI_RESET_CMD;
1331 #pragma pack()
1332 
1333 STATIC
1334 EFI_STATUS
1335 EFIAPI
1336 RpiFirmwareNotifyXhciReset (
1337   IN UINTN BusNumber,
1338   IN UINTN DeviceNumber,
1339   IN UINTN FunctionNumber
1340   )
1341 {
1342   RPI_FW_NOTIFY_XHCI_RESET_CMD *Cmd;
1343   EFI_STATUS                   Status;
1344   UINT32                       Result;
1345 
1346   if (!AcquireSpinLockOrFail (&mMailboxLock)) {
1347     DEBUG ((DEBUG_ERROR, "%a: failed to acquire spinlock\n", __FUNCTION__));
1348     return EFI_DEVICE_ERROR;
1349   }
1350 
1351   Cmd = mDmaBuffer;
1352   ZeroMem (Cmd, sizeof (*Cmd));
1353 
1354   Cmd->BufferHead.BufferSize  = sizeof (*Cmd);
1355   Cmd->BufferHead.Response    = 0;
1356   Cmd->TagHead.TagId          = RPI_MBOX_NOTIFY_XHCI_RESET;
1357   Cmd->TagHead.TagSize        = sizeof (Cmd->TagBody);
1358   Cmd->TagHead.TagValueSize   = 0;
1359   Cmd->TagBody.DeviceAddress  = BusNumber << 20 | DeviceNumber << 15 | FunctionNumber << 12;
1360   Cmd->EndTag                 = 0;
1361 
1362   Status = MailboxTransaction (Cmd->BufferHead.BufferSize, RPI_MBOX_VC_CHANNEL, &Result);
1363 
1364   ReleaseSpinLock (&mMailboxLock);
1365 
1366   if (EFI_ERROR (Status) ||
1367       Cmd->BufferHead.Response != RPI_MBOX_RESP_SUCCESS) {
1368     DEBUG ((DEBUG_ERROR,
1369       "%a: mailbox  transaction error: Status == %r, Response == 0x%x\n",
1370       __FUNCTION__, Status, Cmd->BufferHead.Response));
1371   }
1372 
1373   return Status;
1374 }
1375 
1376 #pragma pack()
1377 typedef struct {
1378   UINT32                       Gpio;
1379   UINT32                       Direction;
1380   UINT32                       Polarity;
1381   UINT32                       TermEn;
1382   UINT32                       TermPullUp;
1383 } RPI_FW_GPIO_GET_CFG_TAG;
1384 
1385 typedef struct {
1386   RPI_FW_BUFFER_HEAD           BufferHead;
1387   RPI_FW_TAG_HEAD              TagHead;
1388   RPI_FW_GPIO_GET_CFG_TAG      TagBody;
1389   UINT32                       EndTag;
1390 } RPI_FW_NOTIFY_GPIO_GET_CFG_CMD;
1391 #pragma pack()
1392 
1393 
1394 STATIC
1395 EFI_STATUS
1396 EFIAPI
1397 RpiFirmwareNotifyGpioGetCfg (
1398   IN UINTN  Gpio,
1399   IN UINT32 *Polarity
1400   )
1401 {
1402   RPI_FW_NOTIFY_GPIO_GET_CFG_CMD *Cmd;
1403   EFI_STATUS                   Status;
1404   UINT32                       Result;
1405 
1406   if (!AcquireSpinLockOrFail (&mMailboxLock)) {
1407     DEBUG ((DEBUG_ERROR, "%a: failed to acquire spinlock\n", __FUNCTION__));
1408     return EFI_DEVICE_ERROR;
1409   }
1410 
1411   Cmd = mDmaBuffer;
1412   ZeroMem (Cmd, sizeof (*Cmd));
1413 
1414   Cmd->BufferHead.BufferSize  = sizeof (*Cmd);
1415   Cmd->BufferHead.Response    = 0;
1416   Cmd->TagHead.TagId          = RPI_MBOX_GET_GPIO_CONFIG;
1417   Cmd->TagHead.TagSize        = sizeof (Cmd->TagBody);
1418   Cmd->TagBody.Gpio = 128 + Gpio;
1419 
1420   Cmd->TagHead.TagValueSize   = 0;
1421   Cmd->EndTag                 = 0;
1422 
1423   Status = MailboxTransaction (Cmd->BufferHead.BufferSize, RPI_MBOX_VC_CHANNEL, &Result);
1424 
1425   *Polarity = Cmd->TagBody.Polarity;
1426 
1427   ReleaseSpinLock (&mMailboxLock);
1428 
1429   if (EFI_ERROR (Status) ||
1430       Cmd->BufferHead.Response != RPI_MBOX_RESP_SUCCESS) {
1431     DEBUG ((DEBUG_ERROR,
1432       "%a: mailbox  transaction error: Status == %r, Response == 0x%x\n",
1433       __FUNCTION__, Status, Cmd->BufferHead.Response));
1434   }
1435 
1436   return Status;
1437 }
1438 
1439 
1440 #pragma pack()
1441 typedef struct {
1442   UINT32                       Gpio;
1443   UINT32                       Direction;
1444   UINT32                       Polarity;
1445   UINT32                       TermEn;
1446   UINT32                       TermPullUp;
1447   UINT32                       State;
1448 } RPI_FW_GPIO_SET_CFG_TAG;
1449 
1450 typedef struct {
1451   RPI_FW_BUFFER_HEAD           BufferHead;
1452   RPI_FW_TAG_HEAD              TagHead;
1453   RPI_FW_GPIO_SET_CFG_TAG      TagBody;
1454   UINT32                       EndTag;
1455 } RPI_FW_NOTIFY_GPIO_SET_CFG_CMD;
1456 #pragma pack()
1457 
1458 
1459 STATIC
1460 EFI_STATUS
1461 EFIAPI
1462 RpiFirmwareNotifyGpioSetCfg (
1463   IN UINTN Gpio,
1464   IN UINTN Direction,
1465   IN UINTN State
1466   )
1467 {
1468   RPI_FW_NOTIFY_GPIO_SET_CFG_CMD *Cmd;
1469   EFI_STATUS                   Status;
1470   UINT32                       Result;
1471 
1472   Status = RpiFirmwareNotifyGpioGetCfg (Gpio, &Result);
1473   if (EFI_ERROR (Status)) {
1474 	  DEBUG ((DEBUG_ERROR, "%a: Failed to get GPIO polarity\n", __FUNCTION__));
1475 	  Result = 0; //default polarity
1476   }
1477 
1478 
1479   if (!AcquireSpinLockOrFail (&mMailboxLock)) {
1480     DEBUG ((DEBUG_ERROR, "%a: failed to acquire spinlock\n", __FUNCTION__));
1481     return EFI_DEVICE_ERROR;
1482   }
1483 
1484   Cmd = mDmaBuffer;
1485   ZeroMem (Cmd, sizeof (*Cmd));
1486 
1487   Cmd->BufferHead.BufferSize  = sizeof (*Cmd);
1488   Cmd->BufferHead.Response    = 0;
1489   Cmd->TagHead.TagId          = RPI_MBOX_SET_GPIO_CONFIG;
1490   Cmd->TagHead.TagSize        = sizeof (Cmd->TagBody);
1491 
1492   Cmd->TagBody.Gpio = 128 + Gpio;
1493   Cmd->TagBody.Direction = Direction;
1494   Cmd->TagBody.Polarity = Result;
1495   Cmd->TagBody.TermEn = 0;
1496   Cmd->TagBody.TermPullUp = 0;
1497   Cmd->TagBody.State = State;
1498 
1499   Cmd->TagHead.TagValueSize   = 0;
1500   Cmd->EndTag                 = 0;
1501 
1502   Status = MailboxTransaction (Cmd->BufferHead.BufferSize, RPI_MBOX_VC_CHANNEL, &Result);
1503 
1504   ReleaseSpinLock (&mMailboxLock);
1505 
1506   if (EFI_ERROR (Status) ||
1507       Cmd->BufferHead.Response != RPI_MBOX_RESP_SUCCESS) {
1508     DEBUG ((DEBUG_ERROR,
1509       "%a: mailbox  transaction error: Status == %r, Response == 0x%x\n",
1510       __FUNCTION__, Status, Cmd->BufferHead.Response));
1511   }
1512 
1513   RpiFirmwareSetGpio (Gpio,!State);
1514 
1515 
1516   return Status;
1517 }
1518 
1519 STATIC RASPBERRY_PI_FIRMWARE_PROTOCOL mRpiFirmwareProtocol = {
1520   RpiFirmwareSetPowerState,
1521   RpiFirmwareGetMacAddress,
1522   RpiFirmwareGetCommmandLine,
1523   RpiFirmwareGetCurrentClockRate,
1524   RpiFirmwareGetMaxClockRate,
1525   RpiFirmwareGetMinClockRate,
1526   RpiFirmwareSetClockRate,
1527   RpiFirmwareAllocFb,
1528   RpiFirmwareFreeFb,
1529   RpiFirmwareGetFbSize,
1530   RpiFirmwareSetLed,
1531   RpiFirmwareGetSerial,
1532   RpiFirmwareGetModel,
1533   RpiFirmwareGetModelRevision,
1534   RpiFirmwareGetModelName,
1535   RPiFirmwareGetModelFamily,
1536   RpiFirmwareGetFirmwareRevision,
1537   RpiFirmwareGetManufacturerName,
1538   RpiFirmwareGetCpuName,
1539   RpiFirmwareGetArmMemory,
1540   RPiFirmwareGetModelInstalledMB,
1541   RpiFirmwareNotifyXhciReset,
1542   RpiFirmwareGetCurrentClockState,
1543   RpiFirmwareSetClockState,
1544   RpiFirmwareNotifyGpioSetCfg
1545 };
1546 
1547 /**
1548   Initialize the state information for the CPU Architectural Protocol
1549 
1550   @param  ImageHandle   of the loaded driver
1551   @param  SystemTable   Pointer to the System Table
1552 
1553   @retval EFI_SUCCESS           Protocol registered
1554   @retval EFI_OUT_OF_RESOURCES  Cannot allocate protocol data structure
1555   @retval EFI_DEVICE_ERROR      Hardware problems
1556 
1557 **/
1558 EFI_STATUS
1559 RpiFirmwareDxeInitialize (
1560   IN EFI_HANDLE         ImageHandle,
1561   IN EFI_SYSTEM_TABLE   *SystemTable
1562   )
1563 {
1564   EFI_STATUS      Status;
1565   UINTN           BufferSize;
1566 
1567   //
1568   // We only need one of these
1569   //
1570   ASSERT_PROTOCOL_ALREADY_INSTALLED (NULL, &gRaspberryPiFirmwareProtocolGuid);
1571 
1572   InitializeSpinLock (&mMailboxLock);
1573 
1574   Status = DmaAllocateBuffer (EfiBootServicesData, NUM_PAGES, &mDmaBuffer);
1575   if (EFI_ERROR (Status)) {
1576     DEBUG ((DEBUG_ERROR, "%a: failed to allocate DMA buffer (Status == %r)\n", __FUNCTION__));
1577     return Status;
1578   }
1579 
1580   BufferSize = EFI_PAGES_TO_SIZE (NUM_PAGES);
1581   Status = DmaMap (MapOperationBusMasterCommonBuffer, mDmaBuffer, &BufferSize,
1582              &mDmaBufferBusAddress, &mDmaBufferMapping);
1583   if (EFI_ERROR (Status)) {
1584     DEBUG ((DEBUG_ERROR, "%a: failed to map DMA buffer (Status == %r)\n", __FUNCTION__));
1585     goto FreeBuffer;
1586   }
1587 
1588   //
1589   // The channel index is encoded in the low bits of the bus address,
1590   // so make sure these are cleared.
1591   //
1592   ASSERT (!(mDmaBufferBusAddress & (BCM2836_MBOX_NUM_CHANNELS - 1)));
1593 
1594   Status = gBS->InstallProtocolInterface (&ImageHandle,
1595                   &gRaspberryPiFirmwareProtocolGuid, EFI_NATIVE_INTERFACE,
1596                   &mRpiFirmwareProtocol);
1597   if (EFI_ERROR (Status)) {
1598     DEBUG ((DEBUG_ERROR,
1599       "%a: failed to install RPI firmware protocol (Status == %r)\n",
1600       __FUNCTION__, Status));
1601     goto UnmapBuffer;
1602   }
1603 
1604   return EFI_SUCCESS;
1605 
1606 UnmapBuffer:
1607   DmaUnmap (mDmaBufferMapping);
1608 FreeBuffer:
1609   DmaFreeBuffer (NUM_PAGES, mDmaBuffer);
1610 
1611   return Status;
1612 }
1613