public inbox for devel@edk2.groups.io
 help / color / mirror / Atom feed
* [edk2-devel] [PATCH 0/7] RaspberryPi: SPI Variables, again
@ 2024-01-11  0:04 Jeremy Linton
  2024-01-11  0:04 ` [edk2-devel] [PATCH 1/7] Platform/RaspberryPi: Move GPIO/SPI/I2C to SSDT Jeremy Linton
                   ` (6 more replies)
  0 siblings, 7 replies; 8+ messages in thread
From: Jeremy Linton @ 2024-01-11  0:04 UTC (permalink / raw)
  To: devel; +Cc: ardb+tianocore, quic_llindhol, Jeremy Linton

There is a 512KB SPI flash EEPROM on the RPi4, which is used to hold
the early boot firmware. Versions of this this firmware which predate
the network recovery have 160-300+KB unused, which is a perfect place
to drop a UEFI variable store.

This code scans the region and makes the decision at runtime if there
is sufficient space available and falls back to updating the SD/USB
firmware image if not. This behavior is now enabled/disabled at
compile time with -DSPI_VARIABLES=1/0

This is a rehash of a previous set I posted from a few years back, and
I'm largely re-posting it because its still useful for people who are
willing to back that firmware down to gain the functionality, as well
as fixing a crash caused by the variable store code garbage collecting
the storage region when it starts to get full

Beyond providing some example SPI programming on the platform, it also
moves I2C/SPI/GPIO devices which are debatably usable on Linux in
ACPI mode into its own SSDT.

Jeremy Linton (7):
  Platform/RaspberryPi: Move GPIO/SPI/I2C to SSDT
  Platform/RaspberryPi: Add menu item to enable/disable GPIO
  Platform/RaspberryPi: Add constants for controlling SPI
  Platform/RaspberryPi: Add mailbox cmd to control audio amp
  Platform/RaspberryPi: Add SPI/GPIO to memory map
  Platform/RaspberryPi: Allow pin function selection at runtime
  Platform/RaspberryPi: Add SPI flash variable store.

 .../RaspberryPi/AcpiTables/AcpiTables.inf     |   1 +
 Platform/RaspberryPi/AcpiTables/Dsdt.asl      |   7 -
 Platform/RaspberryPi/AcpiTables/GpuDevs.asl   | 126 ----
 Platform/RaspberryPi/AcpiTables/SsdtGpio.asl  | 159 +++++
 .../RaspberryPi/Drivers/ConfigDxe/ConfigDxe.c |  37 +
 .../Drivers/ConfigDxe/ConfigDxe.inf           |   1 +
 .../Drivers/ConfigDxe/ConfigDxeHii.uni        |   5 +
 .../Drivers/ConfigDxe/ConfigDxeHii.vfr        |  15 +
 .../Drivers/RpiFirmwareDxe/RpiFirmwareDxe.c   |  60 +-
 .../Drivers/VarBlockServiceDxe/FvbInfo.c      |   8 +-
 .../VarBlockServiceDxe/VarBlockService.c      | 669 +++++++++++++++++-
 .../VarBlockServiceDxe/VarBlockService.h      |  10 +
 .../VarBlockServiceDxe/VarBlockServiceDxe.c   |  69 +-
 .../VarBlockServiceDxe/VarBlockServiceDxe.inf |   7 +
 Platform/RaspberryPi/Include/ConfigVars.h     |   4 +
 .../Include/IndustryStandard/RpiMbox.h        |   1 +
 .../Include/Protocol/RpiFirmware.h            |   7 +
 Platform/RaspberryPi/RPi3/RPi3.dsc            |   6 +
 Platform/RaspberryPi/RPi4/RPi4.dsc            |  12 +-
 Platform/RaspberryPi/RaspberryPi.dec          |   1 +
 .../Include/IndustryStandard/Bcm2836.h        |  34 +
 .../Bcm283x/Include/Library/GpioLib.h         |   6 +
 .../Bcm283x/Library/GpioLib/GpioLib.c         |  16 +-
 23 files changed, 1100 insertions(+), 161 deletions(-)
 create mode 100644 Platform/RaspberryPi/AcpiTables/SsdtGpio.asl

-- 
2.43.0



-=-=-=-=-=-=-=-=-=-=-=-
Groups.io Links: You receive all messages sent to this group.
View/Reply Online (#113549): https://edk2.groups.io/g/devel/message/113549
Mute This Topic: https://groups.io/mt/103653085/7686176
Group Owner: devel+owner@edk2.groups.io
Unsubscribe: https://edk2.groups.io/g/devel/unsub [rebecca@openfw.io]
-=-=-=-=-=-=-=-=-=-=-=-



^ permalink raw reply	[flat|nested] 8+ messages in thread

* [edk2-devel] [PATCH 1/7] Platform/RaspberryPi: Move GPIO/SPI/I2C to SSDT
  2024-01-11  0:04 [edk2-devel] [PATCH 0/7] RaspberryPi: SPI Variables, again Jeremy Linton
@ 2024-01-11  0:04 ` Jeremy Linton
  2024-01-11  0:04 ` [edk2-devel] [PATCH 2/7] Platform/RaspberryPi: Add menu item to enable/disable GPIO Jeremy Linton
                   ` (5 subsequent siblings)
  6 siblings, 0 replies; 8+ messages in thread
From: Jeremy Linton @ 2024-01-11  0:04 UTC (permalink / raw)
  To: devel; +Cc: ardb+tianocore, quic_llindhol, Jeremy Linton

The UEFI firmware uses the GPIO port for the fan and
real soon now the runtime SPI variable store. As such
we need to be able to either isolate those devices from
the OS or we risk clashing with OS's that reconfigure
the GPIO pins. Ideally we would just rip this out
and use _DSM() or just individual device power
on/off methods to adjust the GPIO pins when needed.

For now, lets leave it since windows at least knows
about it. In the future we will decide whether the
firmware is controlling something (SPI!) based on
whether the user has enabled the GPIO block.

Signed-off-by: Jeremy Linton <jeremy.linton@arm.com>
---
 .../RaspberryPi/AcpiTables/AcpiTables.inf     |   1 +
 Platform/RaspberryPi/AcpiTables/Dsdt.asl      |   7 -
 Platform/RaspberryPi/AcpiTables/GpuDevs.asl   | 126 --------------
 Platform/RaspberryPi/AcpiTables/SsdtGpio.asl  | 159 ++++++++++++++++++
 .../RaspberryPi/Drivers/ConfigDxe/ConfigDxe.c |   6 +
 5 files changed, 166 insertions(+), 133 deletions(-)
 create mode 100644 Platform/RaspberryPi/AcpiTables/SsdtGpio.asl

diff --git a/Platform/RaspberryPi/AcpiTables/AcpiTables.inf b/Platform/RaspberryPi/AcpiTables/AcpiTables.inf
index da2a6db85f..3894d00565 100644
--- a/Platform/RaspberryPi/AcpiTables/AcpiTables.inf
+++ b/Platform/RaspberryPi/AcpiTables/AcpiTables.inf
@@ -40,6 +40,7 @@
   SsdtThermal.asl
   Xhci.asl
   Pci.asl
+  SsdtGpio.asl
 
 [Packages]
   ArmPkg/ArmPkg.dec
diff --git a/Platform/RaspberryPi/AcpiTables/Dsdt.asl b/Platform/RaspberryPi/AcpiTables/Dsdt.asl
index b594d50bdf..08acc81d57 100644
--- a/Platform/RaspberryPi/AcpiTables/Dsdt.asl
+++ b/Platform/RaspberryPi/AcpiTables/Dsdt.asl
@@ -21,13 +21,6 @@
 
 #include "AcpiTables.h"
 
-#define BCM_ALT0 0x4
-#define BCM_ALT1 0x5
-#define BCM_ALT2 0x6
-#define BCM_ALT3 0x7
-#define BCM_ALT4 0x3
-#define BCM_ALT5 0x2
-
 //
 // The ASL compiler does not support argument arithmetic in functions
 // like QWordMemory (). So we need to instantiate dummy qword regions
diff --git a/Platform/RaspberryPi/AcpiTables/GpuDevs.asl b/Platform/RaspberryPi/AcpiTables/GpuDevs.asl
index 9750dc25c0..3399f0fc9a 100644
--- a/Platform/RaspberryPi/AcpiTables/GpuDevs.asl
+++ b/Platform/RaspberryPi/AcpiTables/GpuDevs.asl
@@ -203,56 +203,6 @@ Device (VCSM)
   }
 }
 
-// Description: GPIO
-Device (GPI0)
-{
-  Name (_HID, "BCM2845")
-  Name (_CID, "BCM2845")
-  Name (_UID, 0x0)
-  Name (_CCA, 0x0)
-  Method (_STA)
-  {
-    Return(0xf)
-  }
-  Name (RBUF, ResourceTemplate ()
-  {
-    MEMORY32FIXED (ReadWrite, 0, GPIO_LENGTH, RMEM)
-    Interrupt (ResourceConsumer, Level, ActiveHigh, Shared)
-    {
-      BCM2386_GPIO_INTERRUPT0, BCM2386_GPIO_INTERRUPT1,
-      BCM2386_GPIO_INTERRUPT2, BCM2386_GPIO_INTERRUPT3
-    }
-  })
-  Method (_CRS, 0x0, Serialized)
-  {
-    MEMORY32SETBASE (RBUF, RMEM, RBAS, GPIO_OFFSET)
-    Return (^RBUF)
-  }
-}
-
-// Description: I2C
-Device (I2C1)
-{
-  Name (_HID, "BCM2841")
-  Name (_CID, "BCM2841")
-  Name (_UID, 0x1)
-  Name (_CCA, 0x0)
-  Method (_STA)
-  {
-    Return(0xf)
-  }
-  Name (RBUF, ResourceTemplate ()
-  {
-    MEMORY32FIXED (ReadWrite, 0, BCM2836_I2C1_LENGTH, RMEM)
-    Interrupt (ResourceConsumer, Level, ActiveHigh, Shared) { BCM2836_I2C1_INTERRUPT }
-    PinFunction (Exclusive, PullUp, BCM_ALT0, "\\_SB.GDV0.GPI0", 0, ResourceConsumer, , ) { 2, 3 }
-  })
-  Method (_CRS, 0x0, Serialized)
-  {
-    MEMORY32SETBASE (RBUF, RMEM, RBAS, BCM2836_I2C1_OFFSET)
-    Return (^RBUF)
-  }
-}
 
 // I2C2 is the HDMI DDC connection
 Device (I2C2)
@@ -278,81 +228,6 @@ Device (I2C2)
   }
 }
 
-// SPI
-Device (SPI0)
-{
-  Name (_HID, "BCM2838")
-  Name (_CID, "BCM2838")
-  Name (_UID, 0x0)
-  Name (_CCA, 0x0)
-  Method (_STA)
-  {
-    Return (0xf)
-  }
-  Name (RBUF, ResourceTemplate ()
-  {
-    MEMORY32FIXED (ReadWrite, 0, BCM2836_SPI0_LENGTH, RMEM)
-    Interrupt (ResourceConsumer, Level, ActiveHigh, Shared) { BCM2836_SPI0_INTERRUPT }
-    PinFunction (Exclusive, PullDown, BCM_ALT0, "\\_SB.GDV0.GPI0", 0, ResourceConsumer, , ) { 9, 10, 11 } // MISO, MOSI, SCLK
-    PinFunction (Exclusive, PullUp, BCM_ALT0, "\\_SB.GDV0.GPI0", 0, ResourceConsumer, , ) { 8 } // CE0
-    PinFunction (Exclusive, PullUp, BCM_ALT0, "\\_SB.GDV0.GPI0", 0, ResourceConsumer, , ) { 7 } // CE1
-  })
-
-  Method (_CRS, 0x0, Serialized)
-  {
-    MEMORY32SETBASE (RBUF, RMEM, RBAS, BCM2836_SPI0_OFFSET)
-    Return (^RBUF)
-  }
-}
-
-Device (SPI1)
-{
-  Name (_HID, "BCM2839")
-  Name (_CID, "BCM2839")
-  Name (_UID, 0x1)
-  Name (_CCA, 0x0)
-  Name (_DEP, Package() { \_SB.GDV0.RPIQ })
-  Method (_STA)
-  {
-    Return (0xf)
-  }
-  Name (RBUF, ResourceTemplate ()
-  {
-    MEMORY32FIXED (ReadWrite, 0, BCM2836_SPI1_LENGTH, RMEM)
-    Interrupt (ResourceConsumer, Level, ActiveHigh, Shared,) { BCM2836_SPI1_INTERRUPT }
-    PinFunction (Exclusive, PullDown, BCM_ALT4, "\\_SB.GDV0.GPI0", 0, ResourceConsumer, , ) { 19, 20, 21 } // MISO, MOSI, SCLK
-    PinFunction (Exclusive, PullDown, BCM_ALT4, "\\_SB.GDV0.GPI0", 0, ResourceConsumer, , ) { 16 } // CE2
-  })
-
-  Method (_CRS, 0x0, Serialized)
-  {
-    MEMORY32SETBASE (RBUF, RMEM, RBAS, BCM2836_SPI1_OFFSET)
-    Return (^RBUF)
-  }
-}
-
-// SPI2 has no pins on GPIO header
-// Device (SPI2)
-// {
-//   Name (_HID, "BCM2839")
-//   Name (_CID, "BCM2839")
-//   Name (_UID, 0x2)
-//   Name (_CCA, 0x0)
-//   Name (_DEP, Package() { \_SB.GDV0.RPIQ })
-//   Method (_STA)
-//   {
-//     Return (0xf)     // Disabled
-//   }
-//   Method (_CRS, 0x0, Serialized)
-//   {
-//     Name (RBUF, ResourceTemplate ()
-//     {
-//       MEMORY32FIXED (ReadWrite, BCM2836_SPI2_BASE_ADDRESS, BCM2836_SPI2_LENGTH, RMEM)
-//       Interrupt (ResourceConsumer, Level, ActiveHigh, Shared,) { BCM2836_SPI2_INTERRUPT }
-//     })
-//     Return (RBUF)
-//   }
-// }
 
 // PWM Driver
 Device (PWM0)
@@ -393,5 +268,4 @@ Device (PWM0)
 }
 
 include ("Uart.asl")
-include ("Rhpx.asl")
 include ("Sdhc.asl")
diff --git a/Platform/RaspberryPi/AcpiTables/SsdtGpio.asl b/Platform/RaspberryPi/AcpiTables/SsdtGpio.asl
new file mode 100644
index 0000000000..38e8a54a8f
--- /dev/null
+++ b/Platform/RaspberryPi/AcpiTables/SsdtGpio.asl
@@ -0,0 +1,159 @@
+/** @file
+ *
+ *  Secondary System Description Table (SSDT) for the GPIO port
+ *
+ *  Copyright (c) 2021, Arm Ltd. All rights reserved.
+ *
+ *  SPDX-License-Identifier: BSD-2-Clause-Patent
+ *
+ **/
+
+#include <IndustryStandard/Acpi.h>
+#include <IndustryStandard/Bcm2711.h>
+#include <IndustryStandard/Bcm2836.h>
+#include <IndustryStandard/Bcm2836Gpio.h>
+
+#include "AcpiTables.h"
+
+#define BCM_ALT0 0x4
+#define BCM_ALT1 0x5
+#define BCM_ALT2 0x6
+#define BCM_ALT3 0x7
+#define BCM_ALT4 0x3
+#define BCM_ALT5 0x2
+
+DefinitionBlock (__FILE__, "SSDT", 5, "RPIFDN", "RPI3GPIO", 2)
+{
+  External (\_SB_.GDV0, DeviceObj)
+  External (\_SB_.GDV0.RPIQ, DeviceObj)
+  Scope (\_SB_.GDV0)
+  {
+    include ("Rhpx.asl")
+
+    // Description: GPIO
+    Device (GPI0)
+    {
+      Name (_HID, "BCM2845")
+      Name (_CID, "BCM2845")
+      Name (_UID, 0x0)
+      Name (_CCA, 0x0)
+      Method (_STA)
+      {
+        Return(0xf)
+      }
+      Name (RBUF, ResourceTemplate ()
+      {
+        MEMORY32FIXED (ReadWrite, 0, GPIO_LENGTH, RMEM)
+        Interrupt (ResourceConsumer, Level, ActiveHigh, Shared)
+        {
+          BCM2386_GPIO_INTERRUPT0, BCM2386_GPIO_INTERRUPT1,
+          BCM2386_GPIO_INTERRUPT2, BCM2386_GPIO_INTERRUPT3
+        }
+      })
+      Method (_CRS, 0x0, Serialized)
+      {
+        MEMORY32SETBASE (RBUF, RMEM, RBAS, GPIO_OFFSET)
+        Return (^RBUF)
+      }
+    }
+
+    // SPI
+    Device (SPI0)
+    {
+      Name (_HID, "BCM2838")
+      Name (_CID, "BCM2838")
+      Name (_UID, 0x0)
+      Name (_CCA, 0x0)
+      Method (_STA)
+      {
+        Return (0xf)
+      }
+      Name (RBUF, ResourceTemplate ()
+      {
+        MEMORY32FIXED (ReadWrite, 0, BCM2836_SPI0_LENGTH, RMEM)
+        Interrupt (ResourceConsumer, Level, ActiveHigh, Shared) { BCM2836_SPI0_INTERRUPT }
+        PinFunction (Exclusive, PullDown, BCM_ALT0, "\\_SB.GDV0.GPI0", 0, ResourceConsumer, , ) { 9, 10, 11 } // MISO, MOSI, SCLK
+        PinFunction (Exclusive, PullUp, BCM_ALT0, "\\_SB.GDV0.GPI0", 0, ResourceConsumer, , ) { 8 } // CE0
+        PinFunction (Exclusive, PullUp, BCM_ALT0, "\\_SB.GDV0.GPI0", 0, ResourceConsumer, , ) { 7 } // CE1
+      })
+
+      Method (_CRS, 0x0, Serialized)
+      {
+        MEMORY32SETBASE (RBUF, RMEM, RBAS, BCM2836_SPI0_OFFSET)
+        Return (^RBUF)
+      }
+    }
+
+    Device (SPI1)
+    {
+      Name (_HID, "BCM2839")
+      Name (_CID, "BCM2839")
+      Name (_UID, 0x1)
+      Name (_CCA, 0x0)
+      Name (_DEP, Package() { \_SB.GDV0.RPIQ })
+      Method (_STA)
+      {
+        Return (0xf)
+      }
+      Name (RBUF, ResourceTemplate ()
+      {
+        MEMORY32FIXED (ReadWrite, 0, BCM2836_SPI1_LENGTH, RMEM)
+        Interrupt (ResourceConsumer, Level, ActiveHigh, Shared,) { BCM2836_SPI1_INTERRUPT }
+        PinFunction (Exclusive, PullDown, BCM_ALT4, "\\_SB_.GDV0.GPI0", 0, ResourceConsumer, , ) { 19, 20, 21 } // MISO, MOSI, SCLK
+        PinFunction (Exclusive, PullDown, BCM_ALT4, "\\_SB_.GDV0.GPI0", 0, ResourceConsumer, , ) { 16 } // CE2
+      })
+
+      Method (_CRS, 0x0, Serialized)
+      {
+        MEMORY32SETBASE (RBUF, RMEM, RBAS, BCM2836_SPI1_OFFSET)
+        Return (^RBUF)
+      }
+    }
+
+  // SPI2 has no pins on GPIO header
+  // Device (SPI2)
+  // {
+  //   Name (_HID, "BCM2839")
+  //   Name (_CID, "BCM2839")
+  //   Name (_UID, 0x2)
+  //   Name (_CCA, 0x0)
+  //   Name (_DEP, Package() { \_SB.GDV0.RPIQ })
+  //   Method (_STA)
+  //   {
+  //     Return (0xf)     // Disabled
+  //   }
+  //   Method (_CRS, 0x0, Serialized)
+  //   {
+  //     Name (RBUF, ResourceTemplate ()
+  //     {
+  //       MEMORY32FIXED (ReadWrite, BCM2836_SPI2_BASE_ADDRESS, BCM2836_SPI2_LENGTH, RMEM)
+  //       Interrupt (ResourceConsumer, Level, ActiveHigh, Shared,) { BCM2836_SPI2_INTERRUPT }
+  //     })
+  //     Return (RBUF)
+  //   }
+  // }
+
+    Device (I2C1)
+    {
+      Name (_HID, "BCM2841")
+      Name (_CID, "BCM2841")
+      Name (_UID, 0x1)
+      Name (_CCA, 0x0)
+      Method (_STA)
+      {
+        Return(0xf)
+      }
+      Name (RBUF, ResourceTemplate ()
+      {
+        MEMORY32FIXED (ReadWrite, 0, BCM2836_I2C1_LENGTH, RMEM)
+        Interrupt (ResourceConsumer, Level, ActiveHigh, Shared) { BCM2836_I2C1_INTERRUPT }
+        PinFunction (Exclusive, PullUp, BCM_ALT0, "\\_SB_.GDV0.GPI0", 0, ResourceConsumer, , ) { 2, 3 }
+      })
+      Method (_CRS, 0x0, Serialized)
+      {
+        MEMORY32SETBASE (RBUF, RMEM, RBAS, BCM2836_I2C1_OFFSET)
+        Return (^RBUF)
+      }
+    }
+  }
+}
diff --git a/Platform/RaspberryPi/Drivers/ConfigDxe/ConfigDxe.c b/Platform/RaspberryPi/Drivers/ConfigDxe/ConfigDxe.c
index 2484787982..dd01e9a8dc 100644
--- a/Platform/RaspberryPi/Drivers/ConfigDxe/ConfigDxe.c
+++ b/Platform/RaspberryPi/Drivers/ConfigDxe/ConfigDxe.c
@@ -840,6 +840,12 @@ STATIC CONST NAMESPACE_TABLES SdtTables[] = {
     NULL
   },
 #endif
+  {
+    SIGNATURE_64 ('R', 'P', 'I', '3', 'G', 'P', 'I', 'O'),
+    0,
+    0,
+    NULL
+  },
   { // DSDT
     SIGNATURE_64 ('R', 'P', 'I', 0, 0, 0, 0, 0),
     0,
-- 
2.43.0



-=-=-=-=-=-=-=-=-=-=-=-
Groups.io Links: You receive all messages sent to this group.
View/Reply Online (#113550): https://edk2.groups.io/g/devel/message/113550
Mute This Topic: https://groups.io/mt/103653086/7686176
Group Owner: devel+owner@edk2.groups.io
Unsubscribe: https://edk2.groups.io/g/devel/unsub [rebecca@openfw.io]
-=-=-=-=-=-=-=-=-=-=-=-



^ permalink raw reply related	[flat|nested] 8+ messages in thread

* [edk2-devel] [PATCH 2/7] Platform/RaspberryPi: Add menu item to enable/disable GPIO
  2024-01-11  0:04 [edk2-devel] [PATCH 0/7] RaspberryPi: SPI Variables, again Jeremy Linton
  2024-01-11  0:04 ` [edk2-devel] [PATCH 1/7] Platform/RaspberryPi: Move GPIO/SPI/I2C to SSDT Jeremy Linton
@ 2024-01-11  0:04 ` Jeremy Linton
  2024-01-11  0:04 ` [edk2-devel] [PATCH 3/7] Platform/RaspberryPi: Add constants for controlling SPI Jeremy Linton
                   ` (4 subsequent siblings)
  6 siblings, 0 replies; 8+ messages in thread
From: Jeremy Linton @ 2024-01-11  0:04 UTC (permalink / raw)
  To: devel; +Cc: ardb+tianocore, quic_llindhol, Jeremy Linton

Now that the GPIO devices are in their own SSDT lets add
a menu item for the rpi4 to enable/disable it. For the
rpi3 the SSDT is always exported.

Signed-off-by: Jeremy Linton <jeremy.linton@arm.com>
---
 .../RaspberryPi/Drivers/ConfigDxe/ConfigDxe.c   | 17 ++++++++++++++++-
 .../RaspberryPi/Drivers/ConfigDxe/ConfigDxe.inf |  1 +
 .../Drivers/ConfigDxe/ConfigDxeHii.uni          |  5 +++++
 .../Drivers/ConfigDxe/ConfigDxeHii.vfr          | 15 +++++++++++++++
 Platform/RaspberryPi/Include/ConfigVars.h       |  4 ++++
 Platform/RaspberryPi/RPi3/RPi3.dsc              |  6 ++++++
 Platform/RaspberryPi/RPi4/RPi4.dsc              |  7 +++++++
 Platform/RaspberryPi/RaspberryPi.dec            |  1 +
 8 files changed, 55 insertions(+), 1 deletion(-)

diff --git a/Platform/RaspberryPi/Drivers/ConfigDxe/ConfigDxe.c b/Platform/RaspberryPi/Drivers/ConfigDxe/ConfigDxe.c
index dd01e9a8dc..151f3cd801 100644
--- a/Platform/RaspberryPi/Drivers/ConfigDxe/ConfigDxe.c
+++ b/Platform/RaspberryPi/Drivers/ConfigDxe/ConfigDxe.c
@@ -309,12 +309,27 @@ SetupVariables (
       }
 
     }
+
+    Size = sizeof (UINT32);
+    Status = gRT->GetVariable (L"EnableGpio",
+                               &gConfigDxeFormSetGuid,
+                               NULL, &Size, &Var32);
+    if (EFI_ERROR (Status)) {
+      Status = PcdSet32S (PcdEnableGpio, PcdGet32 (PcdEnableGpio));
+      ASSERT_EFI_ERROR (Status);
+    }
+
   } else {
     /*
      * Disable PCIe and XHCI
      */
     Status = PcdSet32S (PcdXhciPci, 0);
     ASSERT_EFI_ERROR (Status);
+    /*
+     * Enable GPIO
+     */
+    Status = PcdSet32S (PcdEnableGpio, 1);
+    ASSERT_EFI_ERROR (Status);
   }
 
   Size = sizeof (AssetTagVar);
@@ -842,7 +857,7 @@ STATIC CONST NAMESPACE_TABLES SdtTables[] = {
 #endif
   {
     SIGNATURE_64 ('R', 'P', 'I', '3', 'G', 'P', 'I', 'O'),
-    0,
+    PcdToken (PcdEnableGpio),
     0,
     NULL
   },
diff --git a/Platform/RaspberryPi/Drivers/ConfigDxe/ConfigDxe.inf b/Platform/RaspberryPi/Drivers/ConfigDxe/ConfigDxe.inf
index 475e645537..e422e5ba5c 100644
--- a/Platform/RaspberryPi/Drivers/ConfigDxe/ConfigDxe.inf
+++ b/Platform/RaspberryPi/Drivers/ConfigDxe/ConfigDxe.inf
@@ -97,6 +97,7 @@
   gRaspberryPiTokenSpaceGuid.PcdXhciPci
   gRaspberryPiTokenSpaceGuid.PcdMiniUartClockRate
   gRaspberryPiTokenSpaceGuid.PcdXhciReload
+  gRaspberryPiTokenSpaceGuid.PcdEnableGpio
 
 [Depex]
   gPcdProtocolGuid AND gRaspberryPiFirmwareProtocolGuid
diff --git a/Platform/RaspberryPi/Drivers/ConfigDxe/ConfigDxeHii.uni b/Platform/RaspberryPi/Drivers/ConfigDxe/ConfigDxeHii.uni
index 8130638876..fb06d46a61 100644
--- a/Platform/RaspberryPi/Drivers/ConfigDxe/ConfigDxeHii.uni
+++ b/Platform/RaspberryPi/Drivers/ConfigDxe/ConfigDxeHii.uni
@@ -67,6 +67,11 @@
 #string STR_ADVANCED_XHCIRELOAD_DISABLE #language en-US "Disabled"
 #string STR_ADVANCED_XHCIRELOAD_RELOAD  #language en-US "Reload"
 
+#string STR_ADVANCED_ENABLEGPIO_PROMPT  #language en-US "Export GPIO devices to OS"
+#string STR_ADVANCED_ENABLEGPIO_HELP    #language en-US "OS can see the GPIO device and some low level SPI and I2C interfaces. Enabling this option will disable runtime variable support."
+#string STR_ADVANCED_ENABLEGPIO_DISABLE #language en-US "Disabled"
+#string STR_ADVANCED_ENABLEGPIO_ENABLE  #language en-US "Enable"
+
 #string STR_ADVANCED_ASSET_TAG_PROMPT #language en-US "Asset Tag"
 #string STR_ADVANCED_ASSET_TAG_HELP   #language en-US "Set the system Asset Tag"
 
diff --git a/Platform/RaspberryPi/Drivers/ConfigDxe/ConfigDxeHii.vfr b/Platform/RaspberryPi/Drivers/ConfigDxe/ConfigDxeHii.vfr
index f13b70711d..04eb0a15a2 100644
--- a/Platform/RaspberryPi/Drivers/ConfigDxe/ConfigDxeHii.vfr
+++ b/Platform/RaspberryPi/Drivers/ConfigDxe/ConfigDxeHii.vfr
@@ -66,6 +66,11 @@ formset
       name  = XhciReload,
       guid  = CONFIGDXE_FORM_SET_GUID;
 
+    efivarstore ADVANCED_ENABLEGPIO_VARSTORE_DATA,
+      attribute = EFI_VARIABLE_BOOTSERVICE_ACCESS | EFI_VARIABLE_RUNTIME_ACCESS | EFI_VARIABLE_NON_VOLATILE,
+      name  = EnableGpio,
+      guid  = CONFIGDXE_FORM_SET_GUID;
+
     efivarstore SYSTEM_TABLE_MODE_VARSTORE_DATA,
       attribute = EFI_VARIABLE_BOOTSERVICE_ACCESS | EFI_VARIABLE_RUNTIME_ACCESS | EFI_VARIABLE_NON_VOLATILE,
       name  = SystemTableMode,
@@ -244,6 +249,16 @@ formset
             endoneof;
           endif;
         endif;
+
+        grayoutif ideqval SystemTableMode.Mode == SYSTEM_TABLE_MODE_DT;
+          oneof varid = EnableGpio.Value,
+            prompt      = STRING_TOKEN(STR_ADVANCED_ENABLEGPIO_PROMPT),
+            help        = STRING_TOKEN(STR_ADVANCED_ENABLEGPIO_HELP),
+            flags       = NUMERIC_SIZE_4 | INTERACTIVE | RESET_REQUIRED,
+            option text = STRING_TOKEN(STR_ADVANCED_ENABLEGPIO_DISABLE), value = 0, flags = DEFAULT;
+            option text = STRING_TOKEN(STR_ADVANCED_ENABLEGPIO_ENABLE), value = 1, flags = 0;
+          endoneof;
+        endif;
 #endif
         string varid = AssetTag.AssetTag,
             prompt  = STRING_TOKEN(STR_ADVANCED_ASSET_TAG_PROMPT),
diff --git a/Platform/RaspberryPi/Include/ConfigVars.h b/Platform/RaspberryPi/Include/ConfigVars.h
index a5b32b5284..43a39891d4 100644
--- a/Platform/RaspberryPi/Include/ConfigVars.h
+++ b/Platform/RaspberryPi/Include/ConfigVars.h
@@ -80,6 +80,10 @@ typedef struct {
   UINT32 Value;
 } ADVANCED_XHCIPCI_VARSTORE_DATA;
 
+typedef struct {
+  UINT32 Value;
+} ADVANCED_ENABLEGPIO_VARSTORE_DATA;
+
 typedef struct {
 #define SYSTEM_TABLE_MODE_ACPI 0
 #define SYSTEM_TABLE_MODE_BOTH 1
diff --git a/Platform/RaspberryPi/RPi3/RPi3.dsc b/Platform/RaspberryPi/RPi3/RPi3.dsc
index f5361ab95e..55da7d5870 100644
--- a/Platform/RaspberryPi/RPi3/RPi3.dsc
+++ b/Platform/RaspberryPi/RPi3/RPi3.dsc
@@ -535,6 +535,12 @@
   #
   gRaspberryPiTokenSpaceGuid.PcdXhciReload|L"XhciReload"|gConfigDxeFormSetGuid|0x0|0
 
+  # Export GPIO block to OS
+  #
+  # 1  - Yes (for legacy reasons)
+  #
+  gRaspberryPiTokenSpaceGuid.PcdEnableGpio|L"EnableGpio"|gConfigDxeFormSetGuid|0x0|1
+
   #
   # Common UEFI ones.
   #
diff --git a/Platform/RaspberryPi/RPi4/RPi4.dsc b/Platform/RaspberryPi/RPi4/RPi4.dsc
index 4e91eb9aea..869b88926f 100644
--- a/Platform/RaspberryPi/RPi4/RPi4.dsc
+++ b/Platform/RaspberryPi/RPi4/RPi4.dsc
@@ -554,6 +554,13 @@
   #
   gRaspberryPiTokenSpaceGuid.PcdXhciReload|L"XhciReload"|gConfigDxeFormSetGuid|0x0|0
 
+  # Export GPIO block to OS
+  #
+  # 0  - No
+  # 1  - Yes
+  #
+  gRaspberryPiTokenSpaceGuid.PcdEnableGpio|L"EnableGpio"|gConfigDxeFormSetGuid|0x0|0
+
   #
   # Common UEFI ones.
   #
diff --git a/Platform/RaspberryPi/RaspberryPi.dec b/Platform/RaspberryPi/RaspberryPi.dec
index 6bd16a5ae9..cc56b436cf 100644
--- a/Platform/RaspberryPi/RaspberryPi.dec
+++ b/Platform/RaspberryPi/RaspberryPi.dec
@@ -74,3 +74,4 @@
   gRaspberryPiTokenSpaceGuid.PcdXhciPci|0|UINT32|0x00000022
   gRaspberryPiTokenSpaceGuid.PcdMiniUartClockRate|0|UINT32|0x00000023
   gRaspberryPiTokenSpaceGuid.PcdXhciReload|0|UINT32|0x00000024
+  gRaspberryPiTokenSpaceGuid.PcdEnableGpio|0|UINT32|0x00000025
-- 
2.43.0



-=-=-=-=-=-=-=-=-=-=-=-
Groups.io Links: You receive all messages sent to this group.
View/Reply Online (#113551): https://edk2.groups.io/g/devel/message/113551
Mute This Topic: https://groups.io/mt/103653087/7686176
Group Owner: devel+owner@edk2.groups.io
Unsubscribe: https://edk2.groups.io/g/devel/unsub [rebecca@openfw.io]
-=-=-=-=-=-=-=-=-=-=-=-



^ permalink raw reply related	[flat|nested] 8+ messages in thread

* [edk2-devel] [PATCH 3/7] Platform/RaspberryPi: Add constants for controlling SPI
  2024-01-11  0:04 [edk2-devel] [PATCH 0/7] RaspberryPi: SPI Variables, again Jeremy Linton
  2024-01-11  0:04 ` [edk2-devel] [PATCH 1/7] Platform/RaspberryPi: Move GPIO/SPI/I2C to SSDT Jeremy Linton
  2024-01-11  0:04 ` [edk2-devel] [PATCH 2/7] Platform/RaspberryPi: Add menu item to enable/disable GPIO Jeremy Linton
@ 2024-01-11  0:04 ` Jeremy Linton
  2024-01-11  0:04 ` [edk2-devel] [PATCH 4/7] Platform/RaspberryPi: Add mailbox cmd to control audio amp Jeremy Linton
                   ` (3 subsequent siblings)
  6 siblings, 0 replies; 8+ messages in thread
From: Jeremy Linton @ 2024-01-11  0:04 UTC (permalink / raw)
  To: devel; +Cc: ardb+tianocore, quic_llindhol, Jeremy Linton

Add the #defines needed to access the SPI interface
documented in the BCM2711 Peripheral guide chapter 8.

Signed-off-by: Jeremy Linton <jeremy.linton@arm.com>
---
 .../Include/IndustryStandard/Bcm2836.h        | 34 +++++++++++++++++++
 1 file changed, 34 insertions(+)

diff --git a/Silicon/Broadcom/Bcm283x/Include/IndustryStandard/Bcm2836.h b/Silicon/Broadcom/Bcm283x/Include/IndustryStandard/Bcm2836.h
index a930c64af3..55a446a86c 100644
--- a/Silicon/Broadcom/Bcm283x/Include/IndustryStandard/Bcm2836.h
+++ b/Silicon/Broadcom/Bcm283x/Include/IndustryStandard/Bcm2836.h
@@ -109,6 +109,40 @@
 #define BCM2836_SPI2_LENGTH                                 0x00000040
 #define BCM2836_SPI2_BASE_ADDRESS                           (BCM2836_SOC_REGISTERS + BCM2836_SPI2_OFFSET)
 
+/* SPI register offsets */
+#define BCM2835_SPI_CS                                      0x00
+#define BCM2835_SPI_FIFO                                    0x04
+#define BCM2835_SPI_CLK                                     0x08
+#define BCM2835_SPI_DLEN                                    0x0c
+#define BCM2835_SPI_LTOH                                    0x10
+#define BCM2835_SPI_DC                                      0x14
+
+/* Bitfields in CS */
+#define BCM2835_SPI_CS_LEN_LONG                             0x02000000
+#define BCM2835_SPI_CS_DMA_LEN                              0x01000000
+#define BCM2835_SPI_CS_CSPOL2                               0x00800000
+#define BCM2835_SPI_CS_CSPOL1                               0x00400000
+#define BCM2835_SPI_CS_CSPOL0                               0x00200000
+#define BCM2835_SPI_CS_RXF                                  0x00100000
+#define BCM2835_SPI_CS_RXR                                  0x00080000
+#define BCM2835_SPI_CS_TXD                                  0x00040000
+#define BCM2835_SPI_CS_RXD                                  0x00020000
+#define BCM2835_SPI_CS_DONE                                 0x00010000
+#define BCM2835_SPI_CS_LEN                                  0x00002000
+#define BCM2835_SPI_CS_REN                                  0x00001000
+#define BCM2835_SPI_CS_ADCS                                 0x00000800
+#define BCM2835_SPI_CS_INTR                                 0x00000400
+#define BCM2835_SPI_CS_INTD                                 0x00000200
+#define BCM2835_SPI_CS_DMAEN                                0x00000100
+#define BCM2835_SPI_CS_TA                                   0x00000080
+#define BCM2835_SPI_CS_CSPOL                                0x00000040
+#define BCM2835_SPI_CS_CLEAR_RX                             0x00000020
+#define BCM2835_SPI_CS_CLEAR_TX                             0x00000010
+#define BCM2835_SPI_CS_CPOL                                 0x00000008
+#define BCM2835_SPI_CS_CPHA                                 0x00000004
+#define BCM2835_SPI_CS_CS_10                                0x00000002
+#define BCM2835_SPI_CS_CS_01                                0x00000001
+
 /* dma constants */
 #define BCM2836_DMA0_OFFSET                                 0x00007000
 #define BCM2836_DMA0_BASE_ADDRESS                           (BCM2836_SOC_REGISTERS + BCM2836_DMA0_OFFSET)
-- 
2.43.0



-=-=-=-=-=-=-=-=-=-=-=-
Groups.io Links: You receive all messages sent to this group.
View/Reply Online (#113552): https://edk2.groups.io/g/devel/message/113552
Mute This Topic: https://groups.io/mt/103653088/7686176
Group Owner: devel+owner@edk2.groups.io
Unsubscribe: https://edk2.groups.io/g/devel/unsub [rebecca@openfw.io]
-=-=-=-=-=-=-=-=-=-=-=-



^ permalink raw reply related	[flat|nested] 8+ messages in thread

* [edk2-devel] [PATCH 4/7] Platform/RaspberryPi: Add mailbox cmd to control audio amp
  2024-01-11  0:04 [edk2-devel] [PATCH 0/7] RaspberryPi: SPI Variables, again Jeremy Linton
                   ` (2 preceding siblings ...)
  2024-01-11  0:04 ` [edk2-devel] [PATCH 3/7] Platform/RaspberryPi: Add constants for controlling SPI Jeremy Linton
@ 2024-01-11  0:04 ` Jeremy Linton
  2024-01-11  0:04 ` [edk2-devel] [PATCH 5/7] Platform/RaspberryPi: Add SPI/GPIO to memory map Jeremy Linton
                   ` (2 subsequent siblings)
  6 siblings, 0 replies; 8+ messages in thread
From: Jeremy Linton @ 2024-01-11  0:04 UTC (permalink / raw)
  To: devel; +Cc: ardb+tianocore, quic_llindhol, Jeremy Linton

The lower level firmware can enable/disable a LDO audio
amp, which allows us to mute/unmute audio output while
the firmware is running.

Signed-off-by: Jeremy Linton <jeremy.linton@arm.com>
---
 .../Drivers/RpiFirmwareDxe/RpiFirmwareDxe.c   | 60 ++++++++++++++++++-
 .../Include/IndustryStandard/RpiMbox.h        |  1 +
 .../Include/Protocol/RpiFirmware.h            |  7 +++
 3 files changed, 67 insertions(+), 1 deletion(-)

diff --git a/Platform/RaspberryPi/Drivers/RpiFirmwareDxe/RpiFirmwareDxe.c b/Platform/RaspberryPi/Drivers/RpiFirmwareDxe/RpiFirmwareDxe.c
index 4edec0ad04..ea0ac1eefe 100644
--- a/Platform/RaspberryPi/Drivers/RpiFirmwareDxe/RpiFirmwareDxe.c
+++ b/Platform/RaspberryPi/Drivers/RpiFirmwareDxe/RpiFirmwareDxe.c
@@ -1532,6 +1532,63 @@ RpiFirmwareNotifyGpioSetCfg (
   return Status;
 }
 
+#pragma pack()
+typedef struct {
+  UINT32                       State;
+} RPI_FW_SET_LDO_REG_TAG;
+
+typedef struct {
+  RPI_FW_BUFFER_HEAD           BufferHead;
+  RPI_FW_TAG_HEAD              TagHead;
+  RPI_FW_SET_LDO_REG_TAG       TagBody;
+  UINT32                       EndTag;
+} RPI_FW_SET_LDO_REG_CMD;
+#pragma pack()
+
+
+STATIC
+EFI_STATUS
+EFIAPI
+RpiFirmwareSetLdoRegState (
+  IN UINTN State
+  )
+{
+  RPI_FW_SET_LDO_REG_CMD       *Cmd;
+  EFI_STATUS                   Status;
+  UINT32                       Result;
+
+  if (!AcquireSpinLockOrFail (&mMailboxLock)) {
+    DEBUG ((DEBUG_ERROR, "%a: failed to acquire spinlock\n", __func__));
+    return EFI_DEVICE_ERROR;
+  }
+
+  Cmd = mDmaBuffer;
+  ZeroMem (Cmd, sizeof (*Cmd));
+
+  Cmd->BufferHead.BufferSize  = sizeof (*Cmd);
+  Cmd->BufferHead.Response    = 0;
+  Cmd->TagHead.TagId          = RPI_MBOX_SET_LDO_REGULATOR;
+  Cmd->TagHead.TagSize        = sizeof (Cmd->TagBody);
+  Cmd->TagBody.State          = State;
+
+  Cmd->TagHead.TagValueSize   = 0;
+  Cmd->EndTag                 = 0;
+
+  Status = MailboxTransaction (Cmd->BufferHead.BufferSize, RPI_MBOX_VC_CHANNEL, &Result);
+
+  if (EFI_ERROR (Status) ||
+      Cmd->BufferHead.Response != RPI_MBOX_RESP_SUCCESS) {
+    DEBUG ((DEBUG_ERROR,
+      "%a: mailbox  transaction error: Status == %r, Response == 0x%x\n",
+      __func__, Status, Cmd->BufferHead.Response));
+  }
+
+  ReleaseSpinLock (&mMailboxLock);
+
+  return Status;
+}
+
+
 STATIC RASPBERRY_PI_FIRMWARE_PROTOCOL mRpiFirmwareProtocol = {
   RpiFirmwareSetPowerState,
   RpiFirmwareGetMacAddress,
@@ -1557,7 +1614,8 @@ STATIC RASPBERRY_PI_FIRMWARE_PROTOCOL mRpiFirmwareProtocol = {
   RpiFirmwareNotifyXhciReset,
   RpiFirmwareGetCurrentClockState,
   RpiFirmwareSetClockState,
-  RpiFirmwareNotifyGpioSetCfg
+  RpiFirmwareNotifyGpioSetCfg,
+  RpiFirmwareSetLdoRegState
 };
 
 /**
diff --git a/Platform/RaspberryPi/Include/IndustryStandard/RpiMbox.h b/Platform/RaspberryPi/Include/IndustryStandard/RpiMbox.h
index 551c2b82e5..f36aaafaf8 100644
--- a/Platform/RaspberryPi/Include/IndustryStandard/RpiMbox.h
+++ b/Platform/RaspberryPi/Include/IndustryStandard/RpiMbox.h
@@ -92,6 +92,7 @@
 #define RPI_MBOX_NOTIFY_REBOOT                                0x00030048
 #define RPI_MBOX_GET_POE_HAT_VAL                              0x00030049
 #define RPI_MBOX_SET_POE_HAT_VAL                              0x00030050
+#define RPI_MBOX_SET_LDO_REGULATOR                            0x00030056
 #define RPI_MBOX_NOTIFY_XHCI_RESET                            0x00030058
 
 #define RPI_MBOX_SET_CLOCK_STATE                              0x00038001
diff --git a/Platform/RaspberryPi/Include/Protocol/RpiFirmware.h b/Platform/RaspberryPi/Include/Protocol/RpiFirmware.h
index c48bb6e434..175894e37a 100644
--- a/Platform/RaspberryPi/Include/Protocol/RpiFirmware.h
+++ b/Platform/RaspberryPi/Include/Protocol/RpiFirmware.h
@@ -171,6 +171,12 @@ EFI_STATUS
   UINTN State
   );
 
+typedef
+EFI_STATUS
+(EFIAPI *SET_LDO_REGULATOR) (
+  UINTN State
+  );
+
 typedef struct {
   SET_POWER_STATE        SetPowerState;
   GET_MAC_ADDRESS        GetMacAddress;
@@ -197,6 +203,7 @@ typedef struct {
   GET_CLOCK_STATE        GetClockState;
   SET_CLOCK_STATE        SetClockState;
   GPIO_SET_CFG           SetGpioConfig;
+  SET_LDO_REGULATOR      SetLdoRegState;
 } RASPBERRY_PI_FIRMWARE_PROTOCOL;
 
 extern EFI_GUID gRaspberryPiFirmwareProtocolGuid;
-- 
2.43.0



-=-=-=-=-=-=-=-=-=-=-=-
Groups.io Links: You receive all messages sent to this group.
View/Reply Online (#113553): https://edk2.groups.io/g/devel/message/113553
Mute This Topic: https://groups.io/mt/103653089/7686176
Group Owner: devel+owner@edk2.groups.io
Unsubscribe: https://edk2.groups.io/g/devel/unsub [rebecca@openfw.io]
-=-=-=-=-=-=-=-=-=-=-=-



^ permalink raw reply related	[flat|nested] 8+ messages in thread

* [edk2-devel] [PATCH 5/7] Platform/RaspberryPi: Add SPI/GPIO to memory map
  2024-01-11  0:04 [edk2-devel] [PATCH 0/7] RaspberryPi: SPI Variables, again Jeremy Linton
                   ` (3 preceding siblings ...)
  2024-01-11  0:04 ` [edk2-devel] [PATCH 4/7] Platform/RaspberryPi: Add mailbox cmd to control audio amp Jeremy Linton
@ 2024-01-11  0:04 ` Jeremy Linton
  2024-01-11  0:04 ` [edk2-devel] [PATCH 6/7] Platform/RaspberryPi: Allow pin function selection at runtime Jeremy Linton
  2024-01-11  0:04 ` [edk2-devel] [PATCH 7/7] Platform/RaspberryPi: Add SPI flash variable store Jeremy Linton
  6 siblings, 0 replies; 8+ messages in thread
From: Jeremy Linton @ 2024-01-11  0:04 UTC (permalink / raw)
  To: devel; +Cc: ardb+tianocore, quic_llindhol, Jeremy Linton

A large reason for using the SPI flash on this platform is that
it can be updated without OS interference at rutime. In order for
that to happen we need both the SPI, as well as the GPIO
which is used to change the pinmux from the PWM device to SPI added
to the UEFI memory map as being used by the runtime service.

Signed-off-by: Jeremy Linton <jeremy.linton@arm.com>
---
 .../RaspberryPi/Drivers/ConfigDxe/ConfigDxe.c    | 16 ++++++++++++++++
 1 file changed, 16 insertions(+)

diff --git a/Platform/RaspberryPi/Drivers/ConfigDxe/ConfigDxe.c b/Platform/RaspberryPi/Drivers/ConfigDxe/ConfigDxe.c
index 151f3cd801..377ef438ff 100644
--- a/Platform/RaspberryPi/Drivers/ConfigDxe/ConfigDxe.c
+++ b/Platform/RaspberryPi/Drivers/ConfigDxe/ConfigDxe.c
@@ -504,6 +504,22 @@ ApplyVariables (
     DEBUG ((DEBUG_INFO, "Current CPU speed is %u MHz\n", Rate / FREQ_1_MHZ));
   }
 
+  if (mModelFamily == 4) {
+    Status = gDS->AddMemorySpace (EfiGcdMemoryTypeMemoryMappedIo, BCM2836_SPI0_BASE_ADDRESS,
+                                  SIZE_4KB, EFI_MEMORY_UC | EFI_MEMORY_RUNTIME);
+    ASSERT_EFI_ERROR (Status);
+    Status = gDS->SetMemorySpaceAttributes (BCM2836_SPI0_BASE_ADDRESS,
+                                            SIZE_4KB, EFI_MEMORY_UC|EFI_MEMORY_RUNTIME);
+
+    Status = gDS->AddMemorySpace (EfiGcdMemoryTypeMemoryMappedIo, GPIO_BASE_ADDRESS,
+                                  SIZE_4KB, EFI_MEMORY_UC | EFI_MEMORY_RUNTIME);
+    ASSERT_EFI_ERROR (Status);
+    Status = gDS->SetMemorySpaceAttributes (GPIO_BASE_ADDRESS,
+                                            SIZE_4KB, EFI_MEMORY_UC|EFI_MEMORY_RUNTIME);
+
+    ASSERT_EFI_ERROR (Status);
+  }
+
   if (mModelFamily >= 4 && PcdGet32 (PcdRamMoreThan3GB) != 0 &&
       PcdGet32 (PcdRamLimitTo3GB) == 0) {
     UINT64 SystemMemorySize;
-- 
2.43.0



-=-=-=-=-=-=-=-=-=-=-=-
Groups.io Links: You receive all messages sent to this group.
View/Reply Online (#113554): https://edk2.groups.io/g/devel/message/113554
Mute This Topic: https://groups.io/mt/103653091/7686176
Group Owner: devel+owner@edk2.groups.io
Unsubscribe: https://edk2.groups.io/g/devel/unsub [rebecca@openfw.io]
-=-=-=-=-=-=-=-=-=-=-=-



^ permalink raw reply related	[flat|nested] 8+ messages in thread

* [edk2-devel] [PATCH 6/7] Platform/RaspberryPi: Allow pin function selection at runtime
  2024-01-11  0:04 [edk2-devel] [PATCH 0/7] RaspberryPi: SPI Variables, again Jeremy Linton
                   ` (4 preceding siblings ...)
  2024-01-11  0:04 ` [edk2-devel] [PATCH 5/7] Platform/RaspberryPi: Add SPI/GPIO to memory map Jeremy Linton
@ 2024-01-11  0:04 ` Jeremy Linton
  2024-01-11  0:04 ` [edk2-devel] [PATCH 7/7] Platform/RaspberryPi: Add SPI flash variable store Jeremy Linton
  6 siblings, 0 replies; 8+ messages in thread
From: Jeremy Linton @ 2024-01-11  0:04 UTC (permalink / raw)
  To: devel; +Cc: ardb+tianocore, quic_llindhol, Jeremy Linton

Update GpioLib slightly so that we can change the GPIO pin
muxing at runtime. For the moment only the GpioPinFuncGet/Set()
routines are used at runtime, and only by the Variable service.

Signed-off-by: Jeremy Linton <jeremy.linton@arm.com>
---
 .../Broadcom/Bcm283x/Include/Library/GpioLib.h   |  6 ++++++
 .../Broadcom/Bcm283x/Library/GpioLib/GpioLib.c   | 16 ++++++++++++++--
 2 files changed, 20 insertions(+), 2 deletions(-)

diff --git a/Silicon/Broadcom/Bcm283x/Include/Library/GpioLib.h b/Silicon/Broadcom/Bcm283x/Include/Library/GpioLib.h
index 1f7d2204e0..79765be4fb 100644
--- a/Silicon/Broadcom/Bcm283x/Include/Library/GpioLib.h
+++ b/Silicon/Broadcom/Bcm283x/Include/Library/GpioLib.h
@@ -45,4 +45,10 @@ GpioSetPull (
   IN  UINTN   Pud
 );
 
+VOID
+GpioSetupRuntime (
+  VOID
+);
+
+
 #endif /* __GPIO_LIB__ */
diff --git a/Silicon/Broadcom/Bcm283x/Library/GpioLib/GpioLib.c b/Silicon/Broadcom/Bcm283x/Library/GpioLib/GpioLib.c
index eaf53e5369..fc1f928e6b 100644
--- a/Silicon/Broadcom/Bcm283x/Library/GpioLib/GpioLib.c
+++ b/Silicon/Broadcom/Bcm283x/Library/GpioLib/GpioLib.c
@@ -15,10 +15,22 @@
 #include <Library/DebugLib.h>
 #include <Library/IoLib.h>
 #include <Library/GpioLib.h>
+#include <Library/UefiRuntimeLib.h>
 #include <Library/TimerLib.h>
 #include <IndustryStandard/Bcm2836.h>
 #include <IndustryStandard/Bcm2836Gpio.h>
 
+
+STATIC EFI_PHYSICAL_ADDRESS GpioGfpSel0 = GPIO_GPFSEL0;
+
+VOID
+GpioSetupRuntime (
+  VOID
+  )
+{
+  EfiConvertPointer (0x0, (VOID**)&GpioGfpSel0);
+}
+
 STATIC
 VOID
 GpioFSELModify (
@@ -30,7 +42,7 @@ GpioFSELModify (
   UINT32 Val;
   EFI_PHYSICAL_ADDRESS Reg;
 
-  Reg = RegIndex * sizeof (UINT32) + GPIO_GPFSEL0;
+  Reg = RegIndex * sizeof (UINT32) + GpioGfpSel0;
 
   ASSERT (Reg <= GPIO_GPFSEL5);
   ASSERT ((~ModifyMask & FunctionMask) == 0);
@@ -77,7 +89,7 @@ GpioPinFuncGet (
 
   RegIndex = Pin / 10;
   SelIndex = Pin % 10;
-  Reg = RegIndex * sizeof (UINT32) + GPIO_GPFSEL0;
+  Reg = RegIndex * sizeof (UINT32) + GpioGfpSel0;
 
   Val = MmioRead32 (Reg);
   Val >>= SelIndex * GPIO_FSEL_BITS_PER_PIN;
-- 
2.43.0



-=-=-=-=-=-=-=-=-=-=-=-
Groups.io Links: You receive all messages sent to this group.
View/Reply Online (#113555): https://edk2.groups.io/g/devel/message/113555
Mute This Topic: https://groups.io/mt/103653092/7686176
Group Owner: devel+owner@edk2.groups.io
Unsubscribe: https://edk2.groups.io/g/devel/unsub [rebecca@openfw.io]
-=-=-=-=-=-=-=-=-=-=-=-



^ permalink raw reply related	[flat|nested] 8+ messages in thread

* [edk2-devel] [PATCH 7/7] Platform/RaspberryPi: Add SPI flash variable store.
  2024-01-11  0:04 [edk2-devel] [PATCH 0/7] RaspberryPi: SPI Variables, again Jeremy Linton
                   ` (5 preceding siblings ...)
  2024-01-11  0:04 ` [edk2-devel] [PATCH 6/7] Platform/RaspberryPi: Allow pin function selection at runtime Jeremy Linton
@ 2024-01-11  0:04 ` Jeremy Linton
  6 siblings, 0 replies; 8+ messages in thread
From: Jeremy Linton @ 2024-01-11  0:04 UTC (permalink / raw)
  To: devel; +Cc: ardb+tianocore, quic_llindhol, Jeremy Linton

The RPi4 has a 512KB SPI flash, which depending on RPi
and firmware revision has 300-180K free. We can use this
storage to persist variables when the OS is running or
over firmware upgrades. The problem is that the SPI is pin
mux'ed with the PWM audio, so we want to leave the PWM
configured for OS use. And of course there is the problem
of sharing the GPIO block with OS's that are aware of it.
Hence a previous patch set which moves the GPIO and some of
the low level i2c/etc devices into its own SSDT, and
disables them by default.

This patch, adds a few SPI access functions directly to
the variable store rather than creating another runtime
service since the early boot ordering is critical. These
functions are of the form ReadSpi(), WriteSpi(),
DisableSpiWp(), etc all with Spi in the name. On top of that
a few "Flash" routines are created which provide high level
functions for reading/writing and walking the portion of the
SPI flash we use to clone the variable store region.
Importantly WalkFlashVolume() walks the entire SPI flash
region, which has a simple header structure containing
filename+len for each region of the flash, to return how
much of the capacity is being utilized by the existing
bootloader/etc firmware.

So, if this is a RPi4, and there is sufficient space, and
that space doesn't have a valid varstore header we erase
it and flush the RPI's varstore region to the SPI. Then
we note its starting offset in mFvInstance->FlashOffset.
From then on, writes to the EFI_FW_VOL_BLOCK_DEVICE are
written to both the RAM copy as well as the SPI flash. If
the empty region has a valid header we read the entire
region overtop of the one being passed as part of the RPi's
BL33, and continue as above.

At ready to boot we re-enable the LDO, and then during the
dump vars check, we check for DT or the GPIO being enabled
and disable the runtime SPI updates because we can't be sure
of what the OS might be doing with the GPIO. The dual ACPI
and DT mode, leaves it enabled (if GPIO is disabled) so
care should be taken.

Now, one of the problems here is that with the LDO enabled
any SPI accesses can be heard over the speakers as pops,
buzzes, or scratchy tones. This is happening even without
this patch because TFA and/or the rpi low level firmware
doesn't itself assure the LDO is disabled during resets, so
the early SoC startup is quite noisy. We add to this, but
alongside that a couple fairly trivial TFA patchs, to mute
it before reset, and again assure its off before releasing
to us solve a large part of this problem. That said, this
can now happen during runtime as well. Generally the OS's
aren't doing a lot of variable updates, but when they do
its generally barely noticable clicks since we aren't going
through the long process of muting/unmuting the LDO which
itself causes a pop.

So, this patch fixes a whole bunch of bugs on github that
exist because the variable store isn't persisted. It also
fixes a rather large bug in the existing variable store
code caused by the FaultTolerantWriteDxe erasing the entire
variable store region when it garbage collects during startup.
That latter bug is the result of FvbGetLbaAddress reading
recently erased data from the VolumeHeader before its been
recreated, and results in random UEFI crashes.

Signed-off-by: Jeremy Linton <jeremy.linton@arm.com>
---
 .../Drivers/VarBlockServiceDxe/FvbInfo.c      |   8 +-
 .../VarBlockServiceDxe/VarBlockService.c      | 669 +++++++++++++++++-
 .../VarBlockServiceDxe/VarBlockService.h      |  10 +
 .../VarBlockServiceDxe/VarBlockServiceDxe.c   |  69 +-
 .../VarBlockServiceDxe/VarBlockServiceDxe.inf |   7 +
 Platform/RaspberryPi/RPi4/RPi4.dsc            |   5 +-
 6 files changed, 743 insertions(+), 25 deletions(-)

diff --git a/Platform/RaspberryPi/Drivers/VarBlockServiceDxe/FvbInfo.c b/Platform/RaspberryPi/Drivers/VarBlockServiceDxe/FvbInfo.c
index 0e0c108dba..ee18f327e6 100644
--- a/Platform/RaspberryPi/Drivers/VarBlockServiceDxe/FvbInfo.c
+++ b/Platform/RaspberryPi/Drivers/VarBlockServiceDxe/FvbInfo.c
@@ -11,12 +11,7 @@
 #include <Guid/SystemNvDataGuid.h>
 #include <Library/BaseLib.h>
 #include <Library/PcdLib.h>
-
-typedef struct {
-  UINT64                      FvLength;
-  EFI_FIRMWARE_VOLUME_HEADER  FvbInfo;
-  EFI_FV_BLOCK_MAP_ENTRY      End[1];
-} EFI_FVB_MEDIA_INFO;
+#include "VarBlockService.h"
 
 EFI_FVB_MEDIA_INFO  mPlatformFvbMediaInfo[] = {
   //
@@ -38,6 +33,7 @@ EFI_FVB_MEDIA_INFO  mPlatformFvbMediaInfo[] = {
       FixedPcdGet32 (PcdNvStorageEventLogSize),
       EFI_FVH_SIGNATURE,
       EFI_FVB2_MEMORY_MAPPED |
+        EFI_FVB2_STICKY_WRITE |
         EFI_FVB2_READ_ENABLED_CAP |
         EFI_FVB2_READ_STATUS |
         EFI_FVB2_WRITE_ENABLED_CAP |
diff --git a/Platform/RaspberryPi/Drivers/VarBlockServiceDxe/VarBlockService.c b/Platform/RaspberryPi/Drivers/VarBlockServiceDxe/VarBlockService.c
index 572309439a..3b83d7ead8 100644
--- a/Platform/RaspberryPi/Drivers/VarBlockServiceDxe/VarBlockService.c
+++ b/Platform/RaspberryPi/Drivers/VarBlockServiceDxe/VarBlockService.c
@@ -7,17 +7,28 @@
  *
  **/
 
+#include <Base.h>
+
+#include <IndustryStandard/Bcm2836.h>
+#include <IndustryStandard/Bcm2836Gpio.h>
+
 #include <Protocol/DevicePath.h>
 #include <Protocol/FirmwareVolumeBlock.h>
+#include <Protocol/RpiFirmware.h>
 
 #include <Library/BaseLib.h>
 #include <Library/BaseMemoryLib.h>
 #include <Library/DebugLib.h>
 #include <Library/DevicePathLib.h>
 #include <Library/DxeServicesTableLib.h>
+#include <Library/GpioLib.h>
+#include <Library/IoLib.h>
 #include <Library/MemoryAllocationLib.h>
+#include <Library/TimerLib.h>
 #include <Library/UefiBootServicesTableLib.h>
 
+#include <Guid/VariableFormat.h>
+
 #include "VarBlockService.h"
 
 #define EFI_FVB2_STATUS \
@@ -85,6 +96,470 @@ EFI_FW_VOL_BLOCK_DEVICE mFvbDeviceTemplate = {
   }
 };
 
+/*
+ * This is a derived approximation for the number of BCM2835_SPI_CS
+ * register reads that can be accomplished in 1US on a bcm2711.
+ */
+#define SPI_CS_READS_PER_US 25
+
+STATIC
+VOID
+SpiDelay (
+    IN UINTN micro_sec
+    )
+/*++
+
+  Routine Description:
+     Delay loop based on how fast we can read SPI controller
+     state rather than a hardcoded delay since we are a runtime
+     service.
+
+  Arguments:
+     micro_sec          - Approximate number of micro seconds to delay.
+
+  Returns:
+--*/
+{
+  UINT32 looping;
+  for (looping = 0; looping < micro_sec; looping++) {
+    UINT32 looping2;
+    //
+    // RPi4 does about 25 reg reads per micro second
+    //
+    for (looping2 = 0; looping2 < SPI_CS_READS_PER_US; looping2++) {
+      MmioRead32 (mFvInstance->SpiBase+BCM2835_SPI_CS);
+    }
+  }
+}
+
+STATIC
+INT32
+DoSpiCommand (
+    UINT8 *Buffer,
+    UINTN in_len,
+    UINTN out_len)
+/*++
+
+  Routine Description:
+     Read and/or Write data on the SPI bus. A buffer with
+     data to write/read is passed and this routine then writes
+     out_len data on the SPI bus, and reads in_len data back
+     into the buffer starting at the first location. Obviously
+     this means that the buffer must be greater than the largest
+     of in_len or out_len
+
+  Arguments:
+     in_len      - bytes to read from the SPI to buffer
+     out_len     - bytes to write on the SPI from buffer
+
+  Returns:
+     number of bytes read into buffer.
+--*/
+{
+  int cur_byte;
+  UINT32 ret = 0;
+
+  MmioWrite32 (mFvInstance->SpiBase + BCM2835_SPI_CS, BCM2835_SPI_CS_TA);
+
+  for (cur_byte = 0 ;cur_byte < in_len + out_len; cur_byte++)
+  {
+    int loop = 10000*SPI_CS_READS_PER_US;
+
+    while ((MmioRead32 (mFvInstance->SpiBase + BCM2835_SPI_CS) & BCM2835_SPI_CS_TXD) == 0) {
+      loop--;
+      if (loop == 0) {
+        DEBUG ((DEBUG_ERROR, "Write timeout %X\n", MmioRead32 (mFvInstance->SpiBase+BCM2835_SPI_CS)));
+        ret = -1;
+        break;
+      }
+    }
+
+    if (cur_byte < out_len) {
+      MmioWrite32 (mFvInstance->SpiBase + BCM2835_SPI_FIFO, Buffer[cur_byte]);
+    } else {
+      MmioWrite32 (mFvInstance->SpiBase + BCM2835_SPI_FIFO, 0);
+    }
+
+    loop = 10000 * SPI_CS_READS_PER_US;
+    while ((MmioRead32 (mFvInstance->SpiBase + BCM2835_SPI_CS) & BCM2835_SPI_CS_RXD) == 0) {
+      loop--;
+      if (loop == 0) {
+        DEBUG ((DEBUG_ERROR, "Read timeout %X\n", MmioRead32 (mFvInstance->SpiBase+BCM2835_SPI_CS)));
+        ret = -1;
+        break;
+      }
+    }
+
+    if (cur_byte < out_len) {
+      MmioRead32 (mFvInstance->SpiBase + BCM2835_SPI_FIFO);
+    } else {
+      ret++;
+      Buffer[cur_byte - out_len] = MmioRead32 (mFvInstance->SpiBase + BCM2835_SPI_FIFO);
+    }
+  }
+
+  MmioWrite32 (mFvInstance->SpiBase + BCM2835_SPI_CS, 0);
+
+  SpiDelay (1); //wait for /CS to settle
+
+  return ret;
+}
+
+#if ((RPI_MODEL == 4) && (SPI_VARIABLES))
+STATIC
+INT32
+ReadDeviceId (VOID)
+/*++
+
+  Routine Description:
+     Sends the SPI device identification command then checks to see
+     if its a winbond we recognize, and returns the expected capacity.
+
+  Arguments:
+
+  Returns:
+     Capacity of attached device
+--*/
+{
+  UINT8 Buffer[32];
+  Buffer[0] = 0x9F;
+
+  DoSpiCommand (Buffer, 3, 1);   //EF 30 31 is the winbond W25X40CL on the base rpi4
+  if (Buffer[0] != 0xEF) {
+    DEBUG ((DEBUG_INFO, "ReadDeviceId %02X %02X %02X\n",
+            Buffer[0], Buffer[1], Buffer[2]));
+  }
+  // Lets assume we understand JEDEC type 0x30
+  if (Buffer[1] == 0x30) {
+    // it should be 512K
+    return 1 << Buffer[2]; //not really standard...
+  }
+
+  return 0;
+}
+
+
+STATIC
+INT32
+ReadSpi (
+    UINT32 Addr,
+    UINT8 *Buffer,
+    UINT32 Len)
+/*++
+
+  Routine Description:
+     Reads Len bytes of data at flash Addr into Buffer
+
+  Arguments:
+     Addr    -  Flash device address
+     Buffer  -  Buffer where data is returned, this
+                buffer must be at least 5 bytes long to
+                hold the command.
+     Len     -  Number of bytes to read into Buffer
+
+  Returns:
+     Number of bytes read
+--*/
+{
+  INT32 ret;
+  Buffer[0] = 0x0B; //send read data
+  Buffer[1] = (Addr >> 16) & 0xFF; // address MSB
+  Buffer[2] = (Addr >> 8) & 0xFF;  //
+  Buffer[3] = Addr & 0xFF;         // address LSB
+  Buffer[4] = 0;
+
+  ret = DoSpiCommand (Buffer, Len, 5);
+  return ret;
+}
+
+STATIC
+UINT32
+WalkFlashVolume (VOID)
+/*++
+
+  Routine Description:
+     Walk the RPi's SPI flash volume to determine if there is
+     free space we may consume as the backing store for a UEFI
+     variable store volume. This is fairly safe as the entire volume
+     can be recovered using the Raspberry Pi OS image tool to create
+     an EEPROM update disk. We aren't going to bother to
+     attempt to contain it in their volume format, rather hiding in
+     the free/unclaimed space. If this space is corrupted via an update
+     done outside of our control, we will fallback to the original
+     RPI_EFI.FD variables. AKA we should never really be worse off.
+
+
+  Arguments:
+     None
+
+  Returns:
+     A value that can be assigned to mFvInstance->FlashOffset
+     as the location we may right, otherwise 0.
+--*/
+{
+  UINT32 total_data;
+  UINT32 device_size;
+  UINT8 buffer[32];
+
+  device_size = ReadDeviceId ();
+  // newer write location 00051100
+
+  for (total_data = 0; total_data < device_size; ) {
+    UINT32 len;
+    if (ReadSpi (total_data, buffer, 24) == 24) {
+      len = 0;
+      len += (*(UINT8 *)&buffer[5]) << 16;
+      len += (*(UINT8 *)&buffer[6]) << 8;
+      len += (*(UINT8 *)&buffer[7]);
+
+      // round up to nearest 8 byte align
+      len += 7;
+      len &= 0xFFFFF8;
+
+      buffer[24]=0;
+      DEBUG ((DEBUG_INFO, "%X len=%d filename=%a \n", *(UINT32 *)buffer,
+              len, (char *)&buffer[8]));
+      if (*(UINT32 *)buffer == 0xFFFFFFFF) {
+        break;
+      }
+      total_data += 8 + len;
+    } else {
+      DEBUG ((DEBUG_ERROR, "Didn't get correct amount of data from SPI, abort its use\n"));
+      return 0;
+    }
+  }
+
+  DEBUG ((DEBUG_INFO, "First free sector at %X free space remaining %dK \n", total_data,(device_size-total_data)/1024));
+  if ((device_size - total_data) > SIZE_128KB) {
+    //start at the next 4k page
+    total_data = (total_data + SIZE_4KB) & 0xFFFFE000;
+    DEBUG ((DEBUG_INFO, "Start of Fv at %X\n", total_data));
+  } else {
+    total_data = 0;
+  }
+
+  return total_data;
+}
+
+
+STATIC
+INT32
+FlashRead (
+    UINT32 Addr,
+    UINT8 *Buffer,
+    UINT32 Len)
+/*++
+
+  Routine Description:
+     Reads Len data from variable storage area into Buffer
+
+  Arguments:
+     Addr    -  Offset into variable store region
+     Buffer  -  Buffer where data is returned, this
+                buffer must be at least 5 bytes long to
+                hold the command.
+     Len     -  Number of bytes to read into Buffer
+
+  Returns:
+     Number of bytes read
+--*/
+{
+  return ReadSpi (mFvInstance->FlashOffset + Addr, Buffer, Len);
+}
+#endif
+
+STATIC
+VOID
+DisableSpiWp (VOID)
+/*++
+
+  Routine Description:
+     Sends SPI flash command to disable write protection
+
+  Arguments:
+
+  Returns:
+
+--*/
+{
+  UINT8 Buffer[32];
+  Buffer[0] = 0x06;
+
+  DoSpiCommand (Buffer, 0, 1);
+}
+
+STATIC
+INT32
+ReadSpiStatus (VOID)
+/*++
+
+  Routine Description:
+     Sends SPI get status command
+  Arguments:
+
+  Returns:
+     Status of flash device
+--*/
+{
+  UINT8 Buffer[32];
+  Buffer[0] = 0x05;
+
+  DoSpiCommand (Buffer, 1, 1);
+
+  return Buffer[0];
+}
+
+
+STATIC
+VOID
+WriteSpi (
+    UINT32 Addr,
+    UINT8 *SrcBuffer,
+    UINT32 Len)
+/*++
+
+  Routine Description:
+     Writes Len bytes of SrcBuffer to SPI flash. The max write len is a single
+     256 byte block, but this routine deals with the case where its misaligned
+     across two flash blocks.
+
+  Arguments:
+     Addr       -  Flash device address
+     SrcBuffer  -  Buffer from which data is written to the SPI flash
+     Len        -  Number of bytes to write
+
+  Returns:
+     Nothing
+--*/
+{
+  UINT8 Buffer[280];
+  UINTN loop;
+  int additional = 0;
+
+  if (Len > 256) Len = 256;
+
+  // check if request crosses boundary
+  if (((Addr + Len - 1) & 0xFFFFFF00) != (Addr & 0xFFFFFF00)) {
+    additional = (Addr + Len) & 0xFF;
+    Len -= additional;
+  }
+
+  do {
+
+    DisableSpiWp ();
+
+    while (ReadSpiStatus () != 2) {
+      DEBUG ((DEBUG_INFO, "Spi status %X \n", ReadSpiStatus ()));
+    }
+
+    Buffer[0] = 0x02; //write len
+    Buffer[1] = (Addr >> 16) & 0xFF;
+    Buffer[2] = (Addr >> 8) & 0xFF;
+    Buffer[3] = Addr & 0xFF;
+
+    CopyMem (&Buffer[4], SrcBuffer, Len);
+
+    DoSpiCommand (Buffer, 0, 4+Len);
+
+    loop = Len * 30000 * SPI_CS_READS_PER_US;
+    while (ReadSpiStatus () & 0x3) {
+      loop--;
+      if (loop == 0) {
+        DEBUG ((DEBUG_ERROR, "Write still busy, continue\n"));
+        break;
+      }
+    }
+
+    // deal with second block
+    if (additional) {
+      Addr += Len;
+      SrcBuffer += Len;
+      Len = additional;
+      additional = 0;
+    } else {
+      Len = 0;
+    }
+
+  } while (Len);
+}
+
+
+STATIC
+VOID
+Erase4kSpi (
+    UINT32 Addr)
+/*++
+
+  Routine Description:
+     Erases a complete SPI flash page, which in this
+     case is 4k at the given address.
+
+  Arguments:
+     Addr       -  Flash device address
+
+  Returns:
+     Nothing
+--*/
+{
+  UINT8 Buffer[32];
+  int loop = 300000 * SPI_CS_READS_PER_US;
+
+  DisableSpiWp ();
+
+  Buffer[0] = 0x20; //erase 4k
+  Buffer[1] = (Addr >> 16) & 0xFF;
+  Buffer[2] = (Addr >> 8) & 0xFF;
+  Buffer[3] = Addr & 0xFF;
+
+  DoSpiCommand (Buffer, 0, 4);
+
+  while (ReadSpiStatus () & 0x3) {
+    loop--;
+    if (loop == 0) {
+      DEBUG ((DEBUG_ERROR, "Erase still busy \n"));
+      break;
+    }
+  }
+}
+
+STATIC
+VOID
+FlashWrite (
+  IN     UINTN Address,
+  IN     UINT8 *Buffer,
+  IN     UINTN NumBytes
+  )
+/*++
+
+  Routine Description:
+     Writes Len bytes of SrcBuffer to flash variable storage. This routine breaks
+     the writes into blocks <= 256 bytes, which is the max that can be written with
+     the SPI flash commands we are using.
+
+  Arguments:
+     Address  - Variable store offset
+     Buffer   - data buffer to write
+     NumBytes - bytes in buffer to write
+
+  Returns:
+
+--*/
+{
+  UINTN Off=Address;
+
+  while (NumBytes>0) {
+    int write_bytes = NumBytes;
+    if (write_bytes > 256) {
+      write_bytes = 256;
+    }
+    WriteSpi (mFvInstance->FlashOffset + Off, Buffer, write_bytes);
+
+    Off += write_bytes;
+    Buffer += write_bytes;
+    NumBytes -= write_bytes;
+  }
+}
+
 
 EFI_STATUS
 VarStoreWrite (
@@ -93,8 +568,47 @@ VarStoreWrite (
   IN     UINT8 *Buffer
   )
 {
+
+  if (Address<mFvInstance->FvBase) {
+    return EFI_INVALID_PARAMETER;
+  }
+
   CopyMem ((VOID*)Address, Buffer, *NumBytes);
-  mFvInstance->Dirty = TRUE;
+
+  if (mFvInstance->FlashOffset) {
+    GpioPinFuncSet (40, GPIO_FSEL_ALT4);
+    GpioPinFuncSet (41, GPIO_FSEL_ALT4);
+
+    FlashWrite (Address-mFvInstance->FvBase, Buffer, *NumBytes);
+
+    GpioPinFuncSet (40, GPIO_FSEL_ALT0);
+    GpioPinFuncSet (41, GPIO_FSEL_ALT0);
+  } else {
+    mFvInstance->Dirty = TRUE;
+  }
+
+  return EFI_SUCCESS;
+}
+
+EFI_STATUS
+FlashErase (
+  IN UINTN Address,
+  IN UINTN LbaLength
+  )
+
+{
+  UINTN Off=Address;
+
+  while (LbaLength>0) {
+    int erase_bytes = LbaLength;
+    if (erase_bytes > 4096) {
+      erase_bytes = 4096;
+    }
+    Erase4kSpi (mFvInstance->FlashOffset + Off);
+
+    Off += erase_bytes;
+    LbaLength -= erase_bytes;
+  }
 
   return EFI_SUCCESS;
 }
@@ -106,8 +620,22 @@ VarStoreErase (
   IN UINTN LbaLength
   )
 {
+  if (Address<mFvInstance->FvBase) {
+    return EFI_INVALID_PARAMETER;
+  }
   SetMem ((VOID*)Address, LbaLength, 0xff);
-  mFvInstance->Dirty = TRUE;
+
+  if (mFvInstance->FlashOffset) {
+    GpioPinFuncSet (40, GPIO_FSEL_ALT4);
+    GpioPinFuncSet (41, GPIO_FSEL_ALT4);
+
+    FlashErase (Address-mFvInstance->FvBase, LbaLength);
+
+    GpioPinFuncSet (40, GPIO_FSEL_ALT0);
+    GpioPinFuncSet (41, GPIO_FSEL_ALT0);
+  } else {
+    mFvInstance->Dirty = TRUE;
+  }
 
   return EFI_SUCCESS;
 }
@@ -151,6 +679,7 @@ FvbGetLbaAddress (
 
 --*/
 {
+
   UINT32 NumBlocks;
   UINT32 BlockLength;
   UINTN Offset;
@@ -166,8 +695,16 @@ FvbGetLbaAddress (
   // Parse the blockmap of the FV to find which map entry the Lba belongs to.
   //
   while (TRUE) {
-    NumBlocks = BlockMap->NumBlocks;
-    BlockLength = BlockMap->Length;
+    if (BlockMap->NumBlocks==0xFFFFFFFF) {
+      NumBlocks = mFvInstance->NumOfBlocks;
+    } else {
+      NumBlocks = BlockMap->NumBlocks;
+    }
+    if (BlockMap->Length==0xFFFFFFFF) {
+      BlockLength = mFvInstance->BlockSize;
+    } else {
+      BlockLength = BlockMap->Length;
+    }
 
     if (NumBlocks == 0 || BlockLength == 0) {
       return EFI_INVALID_PARAMETER;
@@ -199,6 +736,7 @@ FvbGetLbaAddress (
     Offset = Offset + NumBlocks * BlockLength;
     BlockMap++;
   }
+
 }
 
 
@@ -371,6 +909,19 @@ FvbSetVolumeAttributes (
   *AttribPtr = (*AttribPtr) | NewStatus;
   *Attributes = *AttribPtr;
 
+  if (mFvInstance->FlashOffset) {
+    GpioPinFuncSet (40, GPIO_FSEL_ALT4);
+    GpioPinFuncSet (41, GPIO_FSEL_ALT4);
+
+    FlashErase (0, 0x1000);
+    FlashWrite (0, (UINT8*)mFvInstance->VolumeHeader, 0x1000);
+
+    GpioPinFuncSet (40, GPIO_FSEL_ALT0);
+    GpioPinFuncSet (41, GPIO_FSEL_ALT0);
+
+  }
+
+
   return EFI_SUCCESS;
 }
 
@@ -416,12 +967,16 @@ FvbProtocolGetBlockSize (
 
 --*/
 {
-  return FvbGetLbaAddress (
-           Lba,
-           NULL,
-           BlockSize,
-           NumOfBlocks
-         );
+  EFI_STATUS Status;
+
+  Status = FvbGetLbaAddress (
+      Lba,
+      NULL,
+      BlockSize,
+      NumOfBlocks
+      );
+
+  return Status;
 }
 
 
@@ -602,7 +1157,7 @@ FvbProtocolWrite (
   EFI_FVB_ATTRIBUTES_2 Attributes;
   UINTN LbaAddress;
   UINTN LbaLength;
-  EFI_STATUS Status;
+  EFI_STATUS Status = EFI_SUCCESS;
   EFI_STATUS ReturnStatus;
 
   //
@@ -637,6 +1192,7 @@ FvbProtocolWrite (
     return EFI_INVALID_PARAMETER;
   }
 
+  // forces this write to split
   if (LbaLength < (*NumBytes + Offset)) {
     *NumBytes = (UINT32)(LbaLength - Offset);
     Status = EFI_BAD_BUFFER_SIZE;
@@ -789,8 +1345,6 @@ ValidateFvHeader (
     Expected =
       (UINT16)(((UINTN)FwVolHeader->Checksum + 0x10000 - Checksum) & 0xffff);
 
-    DEBUG ((DEBUG_INFO, "FV@%p Checksum is 0x%x, expected 0x%x\n",
-      FwVolHeader, FwVolHeader->Checksum, Expected));
     return EFI_NOT_FOUND;
   }
 
@@ -798,6 +1352,20 @@ ValidateFvHeader (
 }
 
 
+extern EFI_EVENT VirtualAddressChangeEvent;
+
+EFI_STATUS
+EFIAPI
+FvbUnload (
+  IN EFI_HANDLE         ImageHandle
+)
+{
+  gBS->CloseEvent (VirtualAddressChangeEvent);
+  return EFI_SUCCESS;
+}
+
+
+
 EFI_STATUS
 EFIAPI
 FvbInitialize (
@@ -825,6 +1393,7 @@ FvbInitialize (
   UINTN NumOfBlocks;
   RETURN_STATUS PcdStatus;
   UINTN StartOffset;
+  EFI_FIRMWARE_VOLUME_HEADER SpiBuffer[2];
 
   BaseAddress = PcdGet32 (PcdNvStorageVariableBase);
   Length = (FixedPcdGet32 (PcdFlashNvStorageVariableSize) +
@@ -833,6 +1402,7 @@ FvbInitialize (
     FixedPcdGet32 (PcdNvStorageEventLogSize));
   StartOffset = BaseAddress - FixedPcdGet64 (PcdFdBaseAddress);
 
+
   BufferSize = sizeof (EFI_FW_VOL_INSTANCE);
 
   mFvInstance = AllocateRuntimeZeroPool (BufferSize);
@@ -842,11 +1412,78 @@ FvbInitialize (
 
   mFvInstance->FvBase = (UINTN)BaseAddress;
   mFvInstance->FvLength = (UINTN)Length;
-  mFvInstance->Offset = StartOffset;
+  mFvInstance->BlockSize = FixedPcdGet32 (PcdFirmwareBlockSize);
+  mFvInstance->Offset = StartOffset;  // Start offset of RPI_EFI.FD file
   /*
    * Should I parse config.txt instead and find the real name?
    */
   mFvInstance->MappedFile = L"RPI_EFI.FD";
+  /*
+   * SPI Control
+   */
+  mFvInstance->SpiBase = BCM2836_SPI0_BASE_ADDRESS;
+  mFvInstance->FlashOffset = 0;
+  mFvInstance->DisableRuntime = 0;
+
+  ZeroMem (SpiBuffer, sizeof (EFI_FIRMWARE_VOLUME_HEADER) * 2);
+#if ((RPI_MODEL == 4) && (SPI_VARIABLES))
+  /*
+   * On the RPI4 there is a 512KB flash chip
+   * used to store the low level bcm2711 bootstrap code
+   * and the XHCI firmware on newer devices. It has between
+   * ~330K and ~180K available depending on model/version
+   * Possibly less as its consumed for other purposes.
+   * It shares a GPIO pin with the 3.5mm audio port (pwm)
+   * so accessing it causes pops, shzzzz and bzzz
+   * noices that are sometimes audible even without us.
+   * During reboot for example. Newer TFA's will presumably
+   * help us out and disable the audio amp at shutdown
+   * and leave it disabled during startup. That means
+   * that this code can bzzzz if TFA hasn't assured the
+   * audio is off for us.
+   *
+   * Runtime audio pops are audible although barely noticable
+   * in Windows and DT based linux boots. Although the larger
+   * problem is configuring the GPIO pins. As such we disable
+   * runtime persistance if either DT boot mode, or ACPI GPIO
+   * is enabled.
+   */
+
+  GpioPinFuncSet (40, GPIO_FSEL_ALT4);
+  GpioPinFuncSet (41, GPIO_FSEL_ALT4);
+  GpioPinFuncSet (42, GPIO_FSEL_ALT4);
+  GpioPinFuncSet (43, GPIO_FSEL_ALT4);
+  GpioPinFuncSet (44, GPIO_FSEL_ALT4);
+  GpioPinFuncSet (45, GPIO_FSEL_ALT4);
+
+  GpioSetPull (43, GPIO_PULL_DOWN);
+  GpioSetPull (44, GPIO_PULL_DOWN);
+  GpioSetPull (45, GPIO_PULL_DOWN);
+
+  mFvInstance->FlashOffset = WalkFlashVolume ();
+
+  if (mFvInstance->FlashOffset) {
+    if (FlashRead (0, (UINT8*)SpiBuffer, sizeof (EFI_FIRMWARE_VOLUME_HEADER)*2)
+        != sizeof (EFI_FIRMWARE_VOLUME_HEADER) * 2) {
+      DEBUG ((DEBUG_ERROR, "Unable to read data from SPI\n"));
+      mFvInstance->FlashOffset = 0;
+    } else  {
+      Status = ValidateFvHeader (SpiBuffer);
+      if (EFI_ERROR (Status)) {
+        DEBUG ((DEBUG_INFO, "Invalid header on SPI, recreate volume\n"));
+        FlashErase (0, Length);
+        FlashWrite (0, (UINT8*)BaseAddress, Length);
+      }
+
+      // read the entire varstore...
+      if (FlashRead (0, (UINT8*)BaseAddress, Length) != Length) {
+        DEBUG ((DEBUG_ERROR, "Failed to read entire flash region\n"));
+      }
+    }
+  }
+  GpioPinFuncSet (40, GPIO_FSEL_ALT0);
+  GpioPinFuncSet (41, GPIO_FSEL_ALT0);
+#endif
 
   Status = ValidateFvHeader (mFvInstance->VolumeHeader);
   if (!EFI_ERROR (Status)) {
@@ -903,7 +1540,9 @@ FvbInitialize (
   }
 
   //
-  // The total number of blocks in the FV.
+  // The total number of blocks in the FV. This should match:
+  // PcdFlashNvStorageVariableSize + PcdFlashNvStorageFtwWorkingSize +
+  // PcdFlashNvStorageFtwSpareSize + PcdNvStorageEventLogSize / PcdFirmwareBlockSize
   //
   mFvInstance->NumOfBlocks = NumOfBlocks;
 
diff --git a/Platform/RaspberryPi/Drivers/VarBlockServiceDxe/VarBlockService.h b/Platform/RaspberryPi/Drivers/VarBlockServiceDxe/VarBlockService.h
index b65c26453d..1b4f6bd877 100644
--- a/Platform/RaspberryPi/Drivers/VarBlockServiceDxe/VarBlockService.h
+++ b/Platform/RaspberryPi/Drivers/VarBlockServiceDxe/VarBlockService.h
@@ -30,9 +30,13 @@ typedef struct {
   UINTN                      FvLength;
   UINTN                      Offset;
   UINTN                      NumOfBlocks;
+  UINTN                      BlockSize;
   EFI_DEVICE_PATH_PROTOCOL   *Device;
   CHAR16                     *MappedFile;
   BOOLEAN                    Dirty;
+  UINTN                      SpiBase;
+  UINTN                      FlashOffset;
+  UINTN                      DisableRuntime;
 } EFI_FW_VOL_INSTANCE;
 
 extern EFI_FW_VOL_INSTANCE *mFvInstance;
@@ -208,4 +212,10 @@ FileClose (
   IN  EFI_FILE_PROTOCOL *File
   );
 
+typedef struct {
+  UINT64                      FvLength;
+  EFI_FIRMWARE_VOLUME_HEADER  FvbInfo;
+  EFI_FV_BLOCK_MAP_ENTRY      End[1];
+} EFI_FVB_MEDIA_INFO;
+
 #endif
diff --git a/Platform/RaspberryPi/Drivers/VarBlockServiceDxe/VarBlockServiceDxe.c b/Platform/RaspberryPi/Drivers/VarBlockServiceDxe/VarBlockServiceDxe.c
index 4071a3fca4..72ca5fafa2 100644
--- a/Platform/RaspberryPi/Drivers/VarBlockServiceDxe/VarBlockServiceDxe.c
+++ b/Platform/RaspberryPi/Drivers/VarBlockServiceDxe/VarBlockServiceDxe.c
@@ -8,8 +8,10 @@
  *
  **/
 
+#include <Library/GpioLib.h>
+#include <Protocol/RpiFirmware.h>
 #include "VarBlockService.h"
-
+#include "ConfigVars.h"
 //
 // Minimum delay to enact before reset, when variables are dirty (in μs).
 // Needed to ensure that SSD-based USB 3.0 devices have time to flush their
@@ -104,11 +106,18 @@ FvbVirtualAddressChangeEvent (
 
 --*/
 {
+  if (mFvInstance->DisableRuntime) {
+    mFvInstance->FlashOffset = 0; //disable flash writes
+  }
+
+  EfiConvertPointer (0x0, (VOID**)&mFvInstance->SpiBase);
   EfiConvertPointer (0x0, (VOID**)&mFvInstance->FvBase);
   EfiConvertPointer (0x0, (VOID**)&mFvInstance->VolumeHeader);
   EfiConvertPointer (0x0, (VOID**)&mFvInstance);
+  GpioSetupRuntime ();
 }
 
+EFI_EVENT VirtualAddressChangeEvent;
 
 VOID
 InstallVirtualAddressChangeHandler (
@@ -116,7 +125,6 @@ InstallVirtualAddressChangeHandler (
   )
 {
   EFI_STATUS Status;
-  EFI_EVENT VirtualAddressChangeEvent;
 
   Status = gBS->CreateEventEx (
                   EVT_NOTIFY_SIGNAL,
@@ -175,6 +183,16 @@ DumpVars (
 
   if (!mFvInstance->Dirty) {
     DEBUG ((DEBUG_INFO, "Variables not dirty, not dumping!\n"));
+    // if there is a valid SPI flash volume in use, don't delay the reset
+    if (mFvInstance->FlashOffset) {
+      PcdSet32S (PcdPlatformResetDelay, 0);
+    }
+    if ((PcdGet32 (PcdSystemTableMode)  != SYSTEM_TABLE_MODE_ACPI ) ||
+        PcdGet32 (PcdEnableGpio)) {
+      DEBUG ((DEBUG_INFO, "Runtime variable support turned off!\n"));
+      mFvInstance->DisableRuntime = TRUE;
+    }
+
     return;
   }
 
@@ -200,6 +218,24 @@ DumpVars (
   mFvInstance->Dirty = FALSE;
 }
 
+STATIC
+VOID
+EnableAudioLdo (VOID)
+{
+  EFI_STATUS Status;
+  RASPBERRY_PI_FIRMWARE_PROTOCOL *mFwProtocol;
+
+  Status = gBS->LocateProtocol (&gRaspberryPiFirmwareProtocolGuid,
+                                NULL, (VOID**)&mFwProtocol);
+  ASSERT_EFI_ERROR (Status);
+  if (EFI_ERROR (Status)) {
+    return;
+  }
+
+  mFwProtocol->SetLdoRegState (1);
+  ASSERT_EFI_ERROR (Status);
+}
+
 
 VOID
 ReadyToBootHandler (
@@ -230,6 +266,21 @@ ReadyToBootHandler (
   DumpVars (NULL, NULL);
   Status = gBS->CloseEvent (Event);
   ASSERT_EFI_ERROR (Status);
+
+  EnableAudioLdo ();
+}
+
+
+
+VOID
+ExitBootServicesHandler (
+  IN EFI_EVENT Event,
+  IN VOID *Context
+  )
+{
+  if (mFvInstance->DisableRuntime) {
+    mFvInstance->FlashOffset = 0; //disable flash writes
+  }
 }
 
 
@@ -241,6 +292,7 @@ InstallDumpVarEventHandlers (
   EFI_STATUS Status;
   EFI_EVENT ResetEvent;
   EFI_EVENT ReadyToBootEvent;
+  EFI_EVENT ExitBootServicesEvent;
 
   Status = gBS->CreateEventEx (
                   EVT_NOTIFY_SIGNAL,
@@ -261,6 +313,19 @@ InstallDumpVarEventHandlers (
                   &ReadyToBootEvent
                 );
   ASSERT_EFI_ERROR (Status);
+
+  // use exit boot services now too because we can't
+  // depend on address space changes following Ards
+  // removal of the call in linux..
+  Status = gBS->CreateEvent (
+                  EVT_SIGNAL_EXIT_BOOT_SERVICES,
+                  TPL_CALLBACK,
+                  ExitBootServicesHandler,
+                  NULL,
+                  &ExitBootServicesEvent
+                  );
+  ASSERT_EFI_ERROR (Status);
+
 }
 
 
diff --git a/Platform/RaspberryPi/Drivers/VarBlockServiceDxe/VarBlockServiceDxe.inf b/Platform/RaspberryPi/Drivers/VarBlockServiceDxe/VarBlockServiceDxe.inf
index c2edb25bd4..4362dddbca 100644
--- a/Platform/RaspberryPi/Drivers/VarBlockServiceDxe/VarBlockServiceDxe.inf
+++ b/Platform/RaspberryPi/Drivers/VarBlockServiceDxe/VarBlockServiceDxe.inf
@@ -17,6 +17,7 @@
   MODULE_TYPE                    = DXE_RUNTIME_DRIVER
   VERSION_STRING                 = 1.0
   ENTRY_POINT                    = FvbInitialize
+  UNLOAD                         = FvbUnload
 
 #
 # The following information is for reference only and not required by the build
@@ -37,6 +38,7 @@
   MdePkg/MdePkg.dec
   MdeModulePkg/MdeModulePkg.dec
   Platform/RaspberryPi/RaspberryPi.dec
+  Silicon/Broadcom/Bcm283x/Bcm283x.dec
 
 [LibraryClasses]
   BaseLib
@@ -44,6 +46,7 @@
   DebugLib
   DevicePathLib
   DxeServicesTableLib
+  GpioLib
   MemoryAllocationLib
   PcdLib
   UefiBootServicesTableLib
@@ -61,6 +64,7 @@
   gEfiBlockIoProtocolGuid
   gEfiFirmwareVolumeBlockProtocolGuid           # PROTOCOL SOMETIMES_PRODUCED
   gEfiDevicePathProtocolGuid                    # PROTOCOL SOMETIMES_PRODUCED
+  gRaspberryPiFirmwareProtocolGuid              ## CONSUMES
 
 [FixedPcd]
   gEfiMdeModulePkgTokenSpaceGuid.PcdFlashNvStorageVariableSize
@@ -75,12 +79,15 @@
   gArmTokenSpaceGuid.PcdFdSize
 
 [Pcd]
+  gBcm283xTokenSpaceGuid.PcdBcm283xRegistersAddress
   gEfiMdeModulePkgTokenSpaceGuid.PcdFlashNvStorageFtwWorkingBase
   gEfiMdeModulePkgTokenSpaceGuid.PcdFlashNvStorageFtwSpareBase
   gEfiMdeModulePkgTokenSpaceGuid.PcdFlashNvStorageVariableBase
   gRaspberryPiTokenSpaceGuid.PcdNvStorageEventLogBase
   gRaspberryPiTokenSpaceGuid.PcdPlatformResetDelay
   gEfiMdeModulePkgTokenSpaceGuid.PcdFlashNvStorageVariableBase64
+  gRaspberryPiTokenSpaceGuid.PcdSystemTableMode
+  gRaspberryPiTokenSpaceGuid.PcdEnableGpio
 
 [FeaturePcd]
 
diff --git a/Platform/RaspberryPi/RPi4/RPi4.dsc b/Platform/RaspberryPi/RPi4/RPi4.dsc
index 869b88926f..a49b3433ac 100644
--- a/Platform/RaspberryPi/RPi4/RPi4.dsc
+++ b/Platform/RaspberryPi/RPi4/RPi4.dsc
@@ -32,6 +32,7 @@
   DEFINE SECURE_BOOT_ENABLE      = FALSE
   DEFINE INCLUDE_TFTP_COMMAND    = FALSE
   DEFINE DEBUG_PRINT_ERROR_LEVEL = 0x8000004F
+  DEFINE SPI_VARIABLES           = 0
 
 !ifndef TFA_BUILD_ARTIFACTS
   #
@@ -88,7 +89,7 @@
   HiiLib|MdeModulePkg/Library/UefiHiiLib/UefiHiiLib.inf
   UefiHiiServicesLib|MdeModulePkg/Library/UefiHiiServicesLib/UefiHiiServicesLib.inf
   SortLib|MdeModulePkg/Library/UefiSortLib/UefiSortLib.inf
-  ImagePropertiesRecordLib|MdeModulePkg/Library/ImagePropertiesRecordLib/ImagePropertiesRecordLib.inf
+  ImagePropertiesRecordLib|MdeModulePkg/Library/ImagePropertiesRecordLib/ImagePropertiesRecordLib.inf
 
   UefiRuntimeLib|MdePkg/Library/UefiRuntimeLib/UefiRuntimeLib.inf
   OrderedCollectionLib|MdePkg/Library/BaseOrderedCollectionRedBlackTreeLib/BaseOrderedCollectionRedBlackTreeLib.inf
@@ -249,7 +250,7 @@
 ###################################################################################################
 
 [BuildOptions]
-  GCC:*_*_*_CC_FLAGS          = -DRPI_MODEL=4
+  GCC:*_*_*_CC_FLAGS          = -DRPI_MODEL=4 -DSPI_VARIABLES=$(SPI_VARIABLES)
   GCC:*_*_*_PP_FLAGS          = -DRPI_MODEL=4
   GCC:*_*_*_ASLPP_FLAGS       = -DRPI_MODEL=4
   GCC:*_*_*_ASLCC_FLAGS       = -DRPI_MODEL=4
-- 
2.43.0



-=-=-=-=-=-=-=-=-=-=-=-
Groups.io Links: You receive all messages sent to this group.
View/Reply Online (#113556): https://edk2.groups.io/g/devel/message/113556
Mute This Topic: https://groups.io/mt/103653093/7686176
Group Owner: devel+owner@edk2.groups.io
Unsubscribe: https://edk2.groups.io/g/devel/unsub [rebecca@openfw.io]
-=-=-=-=-=-=-=-=-=-=-=-



^ permalink raw reply related	[flat|nested] 8+ messages in thread

end of thread, other threads:[~2024-01-11  0:04 UTC | newest]

Thread overview: 8+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2024-01-11  0:04 [edk2-devel] [PATCH 0/7] RaspberryPi: SPI Variables, again Jeremy Linton
2024-01-11  0:04 ` [edk2-devel] [PATCH 1/7] Platform/RaspberryPi: Move GPIO/SPI/I2C to SSDT Jeremy Linton
2024-01-11  0:04 ` [edk2-devel] [PATCH 2/7] Platform/RaspberryPi: Add menu item to enable/disable GPIO Jeremy Linton
2024-01-11  0:04 ` [edk2-devel] [PATCH 3/7] Platform/RaspberryPi: Add constants for controlling SPI Jeremy Linton
2024-01-11  0:04 ` [edk2-devel] [PATCH 4/7] Platform/RaspberryPi: Add mailbox cmd to control audio amp Jeremy Linton
2024-01-11  0:04 ` [edk2-devel] [PATCH 5/7] Platform/RaspberryPi: Add SPI/GPIO to memory map Jeremy Linton
2024-01-11  0:04 ` [edk2-devel] [PATCH 6/7] Platform/RaspberryPi: Allow pin function selection at runtime Jeremy Linton
2024-01-11  0:04 ` [edk2-devel] [PATCH 7/7] Platform/RaspberryPi: Add SPI flash variable store Jeremy Linton

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox