Browse Source

Updated UEFI firmware to support Raspberry Pi 3.

This change allows the Raspberry Pi 2 image (rpi2.img) to boot the Raspberry
Pi 3 in 32-bit mode. The major differences between the RPI2 and RPI3 in
32-bit mode are that the UART is not assigned GPIO pins 14 and 15 at boot,
the max APB clock rate is 400 MHz, and the MPIDR values start at 0 for the
cores rather than 0xF00.

This change also upgrades the Raspberry Pi firmware blobs for all versions
of the Raspberry Pi.
Chris Stevens 8 years ago
parent
commit
b1c9ba80c2

+ 2 - 1
apps/setup/config/rpi.txt

@@ -36,7 +36,8 @@ RpiFirmwareBlobFiles = [
     "config.txt",
     "start.elf",
     "fixup.dat",
-    "bootcode.bin"
+    "bootcode.bin",
+    "LICENCE.broadcom"
 ];
 
 //

+ 2 - 1
apps/setup/config/rpi2.txt

@@ -36,7 +36,8 @@ RpiFirmwareFiles = [
     "config.txt",
     "start.elf",
     "fixup.dat",
-    "bootcode.bin"
+    "bootcode.bin",
+    "LICENCE.broadcom"
 ];
 
 //

+ 1 - 0
include/minoca/kernel/arm.h

@@ -162,6 +162,7 @@ Author:
 #define ARM_MODE_IRQ    0x00000012
 #define ARM_MODE_SVC    0x00000013
 #define ARM_MODE_ABORT  0x00000017
+#define ARM_MODE_HYP    0x0000001A
 #define ARM_MODE_UNDEF  0x0000001B
 #define ARM_MODE_SYSTEM 0x0000001F
 #define ARM_MODE_MASK   0x0000001F

+ 1 - 0
include/minoca/kernel/arm.inc

@@ -63,6 +63,7 @@ Environment:
 #define ARM_MODE_IRQ    0x00000012
 #define ARM_MODE_SVC    0x00000013
 #define ARM_MODE_ABORT  0x00000017
+#define ARM_MODE_HYP    0x0000001A
 #define ARM_MODE_UNDEF  0x0000001B
 #define ARM_MODE_SYSTEM 0x0000001F
 #define ARM_MODE_MASK   0x0000001F

+ 81 - 1
include/minoca/soc/bcm2709.h

@@ -45,6 +45,7 @@ Author:
 #define BCM2709_MAILBOX_OFFSET      0x0000B880
 #define BCM2709_PRM_OFFSET          0x00100000
 #define BCM2709_PRM_SIZE            0x1000
+#define BCM2709_GPIO_OFFSET         0x00200000
 #define BCM2709_UART_OFFSET         0x00201000
 #define BCM2709_EMMC_OFFSET         0x00300000
 
@@ -335,6 +336,49 @@ Author:
 
 #define BCM2709_PRM_WATCHDOG_RESET_TICKS 10
 
+//
+// Define the GPIO function select values.
+//
+
+#define BCM2709_GPIO_FUNCTION_SELECT_INPUT  0x0
+#define BCM2709_GPIO_FUNCTION_SELECT_OUTPUT 0x1
+#define BCM2709_GPIO_FUNCTION_SELECT_ALT_0  0x4
+#define BCM2709_GPIO_FUNCTION_SELECT_ALT_1  0x5
+#define BCM2709_GPIO_FUNCTION_SELECT_ALT_2  0x6
+#define BCM2709_GPIO_FUNCTION_SELECT_ALT_3  0x7
+#define BCM2709_GPIO_FUNCTION_SELECT_ALT_4  0x3
+#define BCM2709_GPIO_FUNCTION_SELECT_ALT_5  0x2
+
+#define BCM2709_GPIO_FUNCTION_SELECT_MASK   0x7
+
+//
+// Define the number of pins accounted for by each function select register,
+// the bit width for each pin, and the byte width of each select register.
+//
+
+#define BCM2709_GPIO_FUNCTION_SELECT_PIN_COUNT 10
+#define BCM2709_GPIO_FUNCTION_SELECT_PIN_BIT_WIDTH 3
+#define BCM2709_GPIO_FUNCTION_SELECT_REGISTER_BYTE_WIDTH 0x4
+
+//
+// Define the default UART transmit and receive pins.
+//
+
+#define BCM2709_GPIO_TRANSMIT_PIN 14
+#define BCM2709_GPIO_RECEIVE_PIN 15
+
+//
+// Define the maximum GPIO pin.
+//
+
+#define BCM2709_GPIO_PIN_MAX 54
+
+//
+// Define the mask used to convert VC bus addresses to ARM core addresses.
+//
+
+#define BCM2709_ARM_PHYSICAL_ADDRESS_MASK ~(0xC0000000)
+
 //
 // BCM2835 specific definitions
 //
@@ -510,7 +554,7 @@ typedef enum _BCM2709_SYSTEM_TIMER_REGISTER {
 //
 
 typedef enum _BCM2709_MAILBOX_REGISTER {
-    Bcm2709MailboxRead   = 0x0,
+    Bcm2709MailboxRead   = 0x00,
     Bcm2709MailboxPeak   = 0x10,
     Bcm2709MailboxSender = 0x14,
     Bcm2709MailboxStatus = 0x18,
@@ -528,6 +572,42 @@ typedef enum _BCM2709_PRM_REGISTER {
     Bcm2709PrmWatchdog     = 0x24,
 } BCM2709_PRM_REGISTER, *PBCM2709_PRM_REGISTER;
 
+//
+// Define the offsets to the GPIO registers, in bytes.
+//
+
+typedef enum _BCM2709_GPIO_REGISTER {
+    Bcm2709GpioSelect0                     = 0x00,
+    Bcm2709GpioSelect1                     = 0x04,
+    Bcm2709GpioSelect2                     = 0x08,
+    Bcm2709GpioSelect3                     = 0x0C,
+    Bcm2709GpioSelect4                     = 0x10,
+    Bcm2709GpioSelect5                     = 0x14,
+    Bcm2709GpioPinOutputSet0               = 0x1C,
+    Bcm2709GpioPinOutputSet1               = 0x20,
+    Bcm2709GpioPinOutputClear0             = 0x28,
+    Bcm2709GpioPinOutputClear1             = 0x2C,
+    Bcm2709GpioPinLevel0                   = 0x34,
+    Bcm2709GpioPinLevel1                   = 0x38,
+    Bcm2709GpioPinEventDetectStatus0       = 0x40,
+    Bcm2709GpioPinEventDetectStatus1       = 0x44,
+    Bcm2709GpioPinRisingEdgeDetectEnable0  = 0x4C,
+    Bcm2709GpioPinRisingEdgeDetectEnable1  = 0x50,
+    Bcm2709GpioPinFallingEdgeDetectEnable0 = 0x58,
+    Bcm2709GpioPinFallingEdgeDetectEnable1 = 0x5C,
+    Bcm2709GpioPinHighDetectEnable0        = 0x64,
+    Bcm2709GpioPinHighDetectEnable1        = 0x68,
+    Bcm2709GpioPinLowDetectEnable0         = 0x70,
+    Bcm2709GpioPinLowDetectEnable1         = 0x74,
+    Bcm2709GpioPinAsyncRisingEdgeDetect0   = 0x7C,
+    Bcm2709GpioPinAsyncRisingEdgeDetect1   = 0x80,
+    Bcm2709GpioPinAsyncFallingEdgeDetect0  = 0x88,
+    Bcm2709GpioPinAsyncFallingEdgeDetect1  = 0x8C,
+    Bcm2709GpioPinPullUpDownEnable         = 0x94,
+    Bcm2709GpioPinPullUpDownEnableClock0   = 0x98,
+    Bcm2709GpioPinPullUpDownEnableClock1   = 0x9C,
+} BCM2709_GPIO_REGISTER, *PBCM2709_GPIO_REGISTER;
+
 //
 // -------------------------------------------------------------------- Globals
 //

+ 1 - 0
uefi/core/Makefile

@@ -29,6 +29,7 @@ BINARYTYPE = library
 INCLUDES += $(SRCROOT)/os/uefi/include;
 
 OBJS = acpi.o     \
+       acpitabs.o \
        basepe.o   \
        bdsboot.o  \
        bdscon.o   \

+ 86 - 94
uefi/core/acpi.c

@@ -129,7 +129,6 @@ EfipReallocateAcpiTableBuffer (
     VOID
     );
 
-EFIAPI
 EFI_STATUS
 EfipAcpiPublishTables (
     VOID
@@ -140,13 +139,6 @@ EfipAcpiChecksumCommonTables (
     VOID
     );
 
-VOID
-EfipAcpiChecksumTable (
-    VOID *Buffer,
-    UINTN Size,
-    UINTN ChecksumOffset
-    );
-
 //
 // -------------------------------------------------------------------- Globals
 //
@@ -241,9 +233,9 @@ Return Value:
 
             ASSERT(Size >= TableSize);
 
-            EfipAcpiChecksumTable(CurrentTable,
-                                  TableSize,
-                                  OFFSET_OF(DESCRIPTION_HEADER, Checksum));
+            EfiAcpiChecksumTable(CurrentTable,
+                                 TableSize,
+                                 OFFSET_OF(DESCRIPTION_HEADER, Checksum));
 
             Status = EfiAcpiInstallTable(CurrentTable, TableSize, &TableHandle);
             EfiFreePool(CurrentTable);
@@ -362,6 +354,53 @@ Return Value:
     return EFI_SUCCESS;
 }
 
+EFIAPI
+VOID
+EfiAcpiChecksumTable (
+    VOID *Buffer,
+    UINTN Size,
+    UINTN ChecksumOffset
+    )
+
+/*++
+
+Routine Description:
+
+    This routine checksums an ACPI table.
+
+Arguments:
+
+    Buffer - Supplies a pointer to the table to checksum.
+
+    Size - Supplies the size of the table in bytes.
+
+    ChecksumOffset - Supplies the offset of the 8 bit checksum field.
+
+Return Value:
+
+    None.
+
+--*/
+
+{
+
+    UINT8 *Pointer;
+    UINT8 Sum;
+
+    Sum = 0;
+    Pointer = Buffer;
+    Pointer[ChecksumOffset] = 0;
+    while (Size != 0) {
+        Sum = (UINT8)(Sum + *Pointer);
+        Pointer += 1;
+        Size -= 1;
+    }
+
+    Pointer = Buffer;
+    Pointer[ChecksumOffset] = (UINT8)(0xFF - Sum + 1);
+    return;
+}
+
 //
 // --------------------------------------------------------- Internal Functions
 //
@@ -850,9 +889,9 @@ Return Value:
                                        EfiAcpiContext.Fadt->Header.OemRevision;
 
         if (Checksum != FALSE) {
-            EfipAcpiChecksumTable(TableEntry->Table,
-                                  TableEntry->Table->Length,
-                                  OFFSET_OF(DESCRIPTION_HEADER, Checksum));
+            EfiAcpiChecksumTable(TableEntry->Table,
+                                 TableEntry->Table->Length,
+                                 OFFSET_OF(DESCRIPTION_HEADER, Checksum));
         }
 
         break;
@@ -886,9 +925,9 @@ Return Value:
             // Checksum the FADT.
             //
 
-            EfipAcpiChecksumTable(EfiAcpiContext.Fadt,
-                                  EfiAcpiContext.Fadt->Header.Length,
-                                  OFFSET_OF(DESCRIPTION_HEADER, Checksum));
+            EfiAcpiChecksumTable(EfiAcpiContext.Fadt,
+                                 EfiAcpiContext.Fadt->Header.Length,
+                                 OFFSET_OF(DESCRIPTION_HEADER, Checksum));
         }
 
         break;
@@ -919,9 +958,9 @@ Return Value:
             // Checksum the FADT.
             //
 
-            EfipAcpiChecksumTable(EfiAcpiContext.Fadt,
-                                  EfiAcpiContext.Fadt->Header.Length,
-                                  OFFSET_OF(DESCRIPTION_HEADER, Checksum));
+            EfiAcpiChecksumTable(EfiAcpiContext.Fadt,
+                                 EfiAcpiContext.Fadt->Header.Length,
+                                 OFFSET_OF(DESCRIPTION_HEADER, Checksum));
         }
 
         break;
@@ -932,9 +971,9 @@ Return Value:
 
     default:
         if (Checksum != FALSE) {
-            EfipAcpiChecksumTable(TableEntry->Table,
-                                  TableEntry->Table->Length,
-                                  OFFSET_OF(DESCRIPTION_HEADER, Checksum));
+            EfiAcpiChecksumTable(TableEntry->Table,
+                                 TableEntry->Table->Length,
+                                 OFFSET_OF(DESCRIPTION_HEADER, Checksum));
         }
 
         break;
@@ -1086,9 +1125,9 @@ Return Value:
                       sizeof(UINT64),
                       0);
 
-            EfipAcpiChecksumTable(EfiAcpiContext.Fadt,
-                                  EfiAcpiContext.Fadt->Header.Length,
-                                  OFFSET_OF(DESCRIPTION_HEADER, Checksum));
+            EfiAcpiChecksumTable(EfiAcpiContext.Fadt,
+                                 EfiAcpiContext.Fadt->Header.Length,
+                                 OFFSET_OF(DESCRIPTION_HEADER, Checksum));
         }
 
         break;
@@ -1098,9 +1137,9 @@ Return Value:
         if (EfiAcpiContext.Fadt != NULL) {
             EfiAcpiContext.Fadt->DsdtAddress = 0;
             EfiSetMem(&(EfiAcpiContext.Fadt->XDsdt), sizeof(UINT64), 0);
-            EfipAcpiChecksumTable(EfiAcpiContext.Fadt,
-                                  EfiAcpiContext.Fadt->Header.Length,
-                                  OFFSET_OF(DESCRIPTION_HEADER, Checksum));
+            EfiAcpiChecksumTable(EfiAcpiContext.Fadt,
+                                 EfiAcpiContext.Fadt->Header.Length,
+                                 OFFSET_OF(DESCRIPTION_HEADER, Checksum));
         }
 
         break;
@@ -1205,14 +1244,14 @@ Return Value:
         }
     }
 
-    EfipAcpiChecksumTable(Rsdt,
-                          Rsdt->Length,
-                          OFFSET_OF(DESCRIPTION_HEADER, Checksum));
+    EfiAcpiChecksumTable(Rsdt,
+                         Rsdt->Length,
+                         OFFSET_OF(DESCRIPTION_HEADER, Checksum));
 
     if (Xsdt != NULL) {
-        EfipAcpiChecksumTable(Xsdt,
-                              Xsdt->Length,
-                              OFFSET_OF(DESCRIPTION_HEADER, Checksum));
+        EfiAcpiChecksumTable(Xsdt,
+                             Xsdt->Length,
+                             OFFSET_OF(DESCRIPTION_HEADER, Checksum));
     }
 
     *TableCount -= 1;
@@ -1369,7 +1408,6 @@ Return Value:
     return EFI_SUCCESS;
 }
 
-EFIAPI
 EFI_STATUS
 EfipAcpiPublishTables (
     VOID
@@ -1447,68 +1485,22 @@ Return Value:
     UINTN Offset;
 
     Offset = OFFSET_OF(DESCRIPTION_HEADER, Checksum);
-    EfipAcpiChecksumTable(EfiAcpiContext.Rsdp,
-                          OFFSET_OF(RSDP, Length),
-                          OFFSET_OF(RSDP, Checksum));
+    EfiAcpiChecksumTable(EfiAcpiContext.Rsdp,
+                         OFFSET_OF(RSDP, Length),
+                         OFFSET_OF(RSDP, Checksum));
 
-    EfipAcpiChecksumTable(EfiAcpiContext.Rsdp,
-                          sizeof(RSDP),
-                          OFFSET_OF(RSDP, ExtendedChecksum));
+    EfiAcpiChecksumTable(EfiAcpiContext.Rsdp,
+                         sizeof(RSDP),
+                         OFFSET_OF(RSDP, ExtendedChecksum));
 
-    EfipAcpiChecksumTable(EfiAcpiContext.Rsdt,
-                          EfiAcpiContext.Rsdt->Header.Length,
-                          Offset);
+    EfiAcpiChecksumTable(EfiAcpiContext.Rsdt,
+                         EfiAcpiContext.Rsdt->Header.Length,
+                         Offset);
 
-    EfipAcpiChecksumTable(EfiAcpiContext.Xsdt,
-                          EfiAcpiContext.Xsdt->Header.Length,
-                          Offset);
-
-    return;
-}
-
-VOID
-EfipAcpiChecksumTable (
-    VOID *Buffer,
-    UINTN Size,
-    UINTN ChecksumOffset
-    )
-
-/*++
-
-Routine Description:
-
-    This routine checksums an ACPI table.
-
-Arguments:
-
-    Buffer - Supplies a pointer to the table to checksum.
-
-    Size - Supplies the size of the table in bytes.
+    EfiAcpiChecksumTable(EfiAcpiContext.Xsdt,
+                         EfiAcpiContext.Xsdt->Header.Length,
+                         Offset);
 
-    ChecksumOffset - Supplies the offset of the 8 bit checksum field.
-
-Return Value:
-
-    None.
-
---*/
-
-{
-
-    UINT8 *Pointer;
-    UINT8 Sum;
-
-    Sum = 0;
-    Pointer = Buffer;
-    Pointer[ChecksumOffset] = 0;
-    while (Size != 0) {
-        Sum = (UINT8)(Sum + *Pointer);
-        Pointer += 1;
-        Size -= 1;
-    }
-
-    Pointer = Buffer;
-    Pointer[ChecksumOffset] = (UINT8)(0xFF - Sum + 1);
     return;
 }
 

+ 188 - 0
uefi/core/acpitabs.c

@@ -0,0 +1,188 @@
+/*++
+
+Copyright (c) 2016 Minoca Corp. All Rights Reserved
+
+Module Name:
+
+    acpitabs.c
+
+Abstract:
+
+    This module implements support for getting ACPI tables from the EFI system
+    table.
+
+Author:
+
+    Chris Stevens 3-May-2016
+
+Environment:
+
+    Firmware
+
+--*/
+
+//
+// ------------------------------------------------------------------- Includes
+//
+
+#include "ueficore.h"
+#include <minoca/fw/acpitabs.h>
+
+//
+// ---------------------------------------------------------------- Definitions
+//
+
+//
+// ------------------------------------------------------ Data Type Definitions
+//
+
+//
+// ----------------------------------------------- Internal Function Prototypes
+//
+
+PRSDP
+EfipGetRsdp (
+    VOID
+    );
+
+//
+// -------------------------------------------------------------------- Globals
+//
+
+//
+// ------------------------------------------------------------------ Functions
+//
+
+EFIAPI
+VOID *
+EfiGetAcpiTable (
+    UINT32 Signature,
+    VOID *PreviousTable
+    )
+
+/*++
+
+Routine Description:
+
+    This routine attempts to find an ACPI description table with the given
+    signature. This routine does not validate the checksum of the table.
+
+Arguments:
+
+    Signature - Supplies the signature of the desired table.
+
+    PreviousTable - Supplies an optional pointer to the table to start the
+        search from.
+
+Return Value:
+
+    Returns a pointer to the beginning of the header to the table if the table
+    was found, or NULL if the table could not be located.
+
+--*/
+
+{
+
+    PRSDP Rsdp;
+    PRSDT Rsdt;
+    UINTN RsdtIndex;
+    PULONG RsdtTableEntry;
+    PDESCRIPTION_HEADER Table;
+    UINTN TableCount;
+    UINTN TableIndex;
+
+    Rsdp = EfipGetRsdp();
+    if (Rsdp == NULL) {
+        return NULL;
+    }
+
+    Rsdt = (PRSDT)(Rsdp->RsdtAddress);
+    if (Rsdt == NULL) {
+        return NULL;
+    }
+
+    TableCount = (Rsdt->Header.Length - sizeof(DESCRIPTION_HEADER)) /
+                 sizeof(UINT32);
+
+    RsdtTableEntry = (PULONG)&(Rsdt->Entries);
+
+    //
+    // Search the list of pointers, but do it backwards. This runs on the
+    // assumption that if there are two tables in the firmware, the later one
+    // is the better one.
+    //
+
+    for (TableIndex = 0; TableIndex < TableCount; TableIndex += 1) {
+        RsdtIndex = TableCount - TableIndex - 1;
+        Table = (PDESCRIPTION_HEADER)(UINTN)(RsdtTableEntry[RsdtIndex]);
+        if (Table == NULL) {
+            continue;
+        }
+
+        if (PreviousTable != NULL) {
+            if (Table == PreviousTable) {
+                PreviousTable = NULL;
+            }
+
+            continue;
+        }
+
+        if (Table->Signature == Signature) {
+            return Table;
+        }
+    }
+
+    return NULL;
+}
+
+//
+// --------------------------------------------------------- Internal Functions
+//
+
+PRSDP
+EfipGetRsdp (
+    VOID
+    )
+
+/*++
+
+Routine Description:
+
+    This routine attempts to find the RSDP in the EFI system table.
+
+Arguments:
+
+    None.
+
+Return Value:
+
+    Returns a pointer to the RSDP on success.
+
+    NULL on failure.
+
+--*/
+
+{
+
+    BOOLEAN Match;
+    EFI_CONFIGURATION_TABLE *Table;
+    UINTN TableCount;
+    UINTN TableIndex;
+
+    TableCount = EfiSystemTable->NumberOfTableEntries;
+    for (TableIndex = 0; TableIndex < TableCount; TableIndex += 1) {
+        Table = &(EfiSystemTable->ConfigurationTable[TableIndex]);
+        Match = EfiCoreCompareGuids(&(Table->VendorGuid), &EfiAcpiTableGuid);
+        if (Match != FALSE) {
+            return Table->VendorTable;
+        }
+
+        Match = EfiCoreCompareGuids(&(Table->VendorGuid), &EfiAcpiTable1Guid);
+        if (Match != FALSE) {
+            return Table->VendorTable;
+        }
+    }
+
+    return NULL;
+}
+

+ 1 - 0
uefi/core/build.ck

@@ -25,6 +25,7 @@ Environment:
 function build() {
     base_sources = [
         "acpi.c",
+        "acpitabs.c",
         "basepe.c",
         "bdsboot.c",
         "bdscon.c",

+ 6 - 0
uefi/core/init.c

@@ -581,6 +581,12 @@ Return Value:
         goto InitializeEnd;
     }
 
+    Step += 1;
+    EfiStatus = EfiPlatformInitialize(2);
+    if (EFI_ERROR(EfiStatus)) {
+        goto InitializeEnd;
+    }
+
     //
     // Let's get the time, just for kicks.
     //

+ 1 - 0
uefi/core/ueficore.h

@@ -1375,3 +1375,4 @@ Return Value:
     EFI status code.
 
 --*/
+

+ 2 - 1
uefi/dev/bcm2709/Makefile

@@ -26,7 +26,8 @@ BINARY = bcm2709.a
 
 BINARYTYPE = library
 
-OBJS = init.o     \
+OBJS = gpio.o     \
+       init.o     \
        intr.o     \
        mailbox.o  \
        memmap.o   \

+ 1 - 0
uefi/dev/bcm2709/build.ck

@@ -22,6 +22,7 @@ Environment:
 
 function build() {
     sources = [
+        "gpio.c",
         "init.c",
         "intr.c",
         "mailbox.c",

+ 125 - 0
uefi/dev/bcm2709/gpio.c

@@ -0,0 +1,125 @@
+/*++
+
+Copyright (c) 2016 Minoca Corp. All Rights Reserved
+
+Module Name:
+
+    gpio.c
+
+Abstract:
+
+    This module implements platform GPIO support for the BCM2709 SoC family.
+
+Author:
+
+    Chris Stevens 3-May-2016
+
+Environment:
+
+    Firmware
+
+--*/
+
+//
+// ------------------------------------------------------------------- Includes
+//
+
+#include <uefifw.h>
+#include <dev/bcm2709.h>
+
+//
+// --------------------------------------------------------------------- Macros
+//
+
+//
+// This macro reads from a BCM2709 GPIO register.
+//
+
+#define READ_GPIO_REGISTER(_Register) \
+    EfiReadRegister32(BCM2709_GPIO_BASE + (_Register))
+
+//
+// This macro writes to a BCM2709 GPIO register.
+//
+
+#define WRITE_GPIO_REGISTER(_Register, _Value) \
+    EfiWriteRegister32(BCM2709_GPIO_BASE + (_Register), (_Value))
+
+//
+// ---------------------------------------------------------------- Definitions
+//
+
+//
+// ------------------------------------------------------ Data Type Definitions
+//
+
+//
+// ----------------------------------------------- Internal Function Prototypes
+//
+
+//
+// -------------------------------------------------------------------- Globals
+//
+
+//
+// ------------------------------------------------------------------ Functions
+//
+
+EFI_STATUS
+EfipBcm2709GpioFunctionSelect (
+    UINT32 Pin,
+    UINT32 Mode
+    )
+
+/*++
+
+Routine Description:
+
+    This routine sets the given mode for the pin's function select.
+
+Arguments:
+
+    Pin - Supplies the GPIO pin whose function select to modify.
+
+    Mode - Supplies the function select mode to set.
+
+Return Value:
+
+    EFI status code.
+
+--*/
+
+{
+
+    UINT32 Register;
+    UINT32 Shift;
+    UINT32 Value;
+
+    if (EfiBcm2709Initialized == FALSE) {
+        return EFI_NOT_READY;
+    }
+
+    if ((Pin >= BCM2709_GPIO_PIN_MAX) ||
+        (Mode > BCM2709_GPIO_FUNCTION_SELECT_MASK)) {
+
+        return EFI_INVALID_PARAMETER;
+    }
+
+    Register = (Pin / BCM2709_GPIO_FUNCTION_SELECT_PIN_COUNT) *
+               BCM2709_GPIO_FUNCTION_SELECT_REGISTER_BYTE_WIDTH;
+
+    Shift = (Pin % BCM2709_GPIO_FUNCTION_SELECT_PIN_COUNT) *
+            BCM2709_GPIO_FUNCTION_SELECT_PIN_BIT_WIDTH;
+
+    Value = READ_GPIO_REGISTER(Register);
+    Value &= ~(BCM2709_GPIO_FUNCTION_SELECT_MASK << Shift);
+    WRITE_GPIO_REGISTER(Register, Value);
+    Value |= (Mode << Shift);
+    WRITE_GPIO_REGISTER(Register, Value);
+    return EFI_SUCCESS;
+}
+
+//
+// --------------------------------------------------------- Internal Functions
+//
+

+ 2 - 2
uefi/dev/bcm2709/timer.c

@@ -39,7 +39,7 @@ Environment:
     EfiReadRegister32(BCM2709_ARM_TIMER_BASE + (_Register))
 
 //
-// This macro writes to an BCM2709 ARM timer.
+// This macro writes to a BCM2709 ARM timer.
 //
 
 #define WRITE_ARM_TIMER_REGISTER(_Register, _Value) \
@@ -53,7 +53,7 @@ Environment:
     EfiReadRegister32(BCM2709_SYSTEM_TIMER_BASE + (_Register))
 
 //
-// This macro writes to an BCM2709 System timer.
+// This macro writes to a BCM2709 System timer.
 //
 
 #define WRITE_SYSTEM_TIMER_REGISTER(_Register, _Value) \

+ 7 - 3
uefi/dev/bcm2709/video.c

@@ -833,9 +833,7 @@ Return Value:
         PixelOrder = BCM2709_MAILBOX_PIXEL_ORDER_RGB;
     }
 
-    if (PixelOrder != InitializeVideo.PixelOrderMessage.PixelOrder) {
-        InitializeVideo.PixelOrderMessage.PixelOrder = PixelOrder;
-    }
+    InitializeVideo.PixelOrderMessage.PixelOrder = PixelOrder;
 
     //
     // Send the initialization command to the BCM2709 mailbox. This is also a
@@ -958,7 +956,13 @@ Return Value:
         goto Bcm2709VideoInitializeEnd;
     }
 
+    //
+    // The video core may return an aliased address out of range for the ARM
+    // core. Shift the base address until it is accessible by the ARM core.
+    //
+
     *FrameBufferBase = InitializeVideo.FrameBufferMessage.FrameBuffer.Base;
+    *FrameBufferBase &= BCM2709_ARM_PHYSICAL_ADDRESS_MASK;
     *FrameBufferSize = InitializeVideo.FrameBufferMessage.FrameBuffer.Size;
     Status = EFI_SUCCESS;
 

+ 48 - 0
uefi/include/dev/bcm2709.h

@@ -41,6 +41,7 @@ Author:
 #define BCM2709_ARM_TIMER_BASE BCM2709_GET_BASE(BCM2709_ARM_TIMER_OFFSET)
 #define BCM2709_MAILBOX_BASE BCM2709_GET_BASE(BCM2709_MAILBOX_OFFSET)
 #define BCM2709_PRM_BASE BCM2709_GET_BASE(BCM2709_PRM_OFFSET)
+#define BCM2709_GPIO_BASE BCM2709_GET_BASE(BCM2709_GPIO_OFFSET)
 #define BCM2709_UART_BASE BCM2709_GET_BASE(BCM2709_UART_OFFSET)
 #define BCM2709_EMMC_BASE BCM2709_GET_BASE(BCM2709_EMMC_OFFSET)
 
@@ -491,6 +492,29 @@ typedef struct _BCM2709_MAILBOX_BOARD_SERIAL_NUMBER {
 
 /*++
 
+Structure Description:
+
+    This structure defines the data necessary to get a BCM2709's clock rate.
+
+Members:
+
+    Header - Stores a header that defines the total size of the messages being
+        sent to and received from the mailbox.
+
+    ClockRate - Stores a message getting the clock rate.
+
+    EndTag - Stores the tag to denote the end of the mailbox message.
+
+--*/
+
+typedef struct _EFI_BCM2709_GET_CLOCK_RATE {
+    BCM2709_MAILBOX_HEADER Header;
+    BCM2709_MAILBOX_GET_CLOCK_RATE ClockRate;
+    UINT32 EndTag;
+} EFI_BCM2709_GET_CLOCK_RATE, *PEFI_BCM2709_GET_CLOCK_RATE;
+
+/*++
+
 Structure Description:
 
     This structure defines a BCM2709 timer.
@@ -882,6 +906,30 @@ Return Value:
 
 --*/
 
+EFI_STATUS
+EfipBcm2709GpioFunctionSelect (
+    UINT32 Pin,
+    UINT32 Mode
+    );
+
+/*++
+
+Routine Description:
+
+    This routine sets the given mode for the pin's function select.
+
+Arguments:
+
+    Pin - Supplies the GPIO pin whose function select to modify.
+
+    Mode - Supplies the function select mode to set.
+
+Return Value:
+
+    EFI status code.
+
+--*/
+
 EFI_STATUS
 EfipBcm2709UsbInitialize (
     VOID

+ 1 - 0
uefi/include/dev/pl110.h

@@ -66,3 +66,4 @@ Return Value:
     EFI status code.
 
 --*/
+

+ 58 - 1
uefi/include/uefifw.h

@@ -402,7 +402,8 @@ Arguments:
     Phase - Supplies the iteration number this routine is being called on.
         Phase zero occurs very early, just after the debugger comes up.
         Phase one occurs a bit later, after timer and interrupt services are
-        initialized.
+        initialized. Phase two happens right before boot, after all platform
+        devices have been enumerated.
 
 Return Value:
 
@@ -982,6 +983,62 @@ Return Value:
 
 --*/
 
+EFIAPI
+VOID
+EfiAcpiChecksumTable (
+    VOID *Buffer,
+    UINTN Size,
+    UINTN ChecksumOffset
+    );
+
+/*++
+
+Routine Description:
+
+    This routine checksums an ACPI table.
+
+Arguments:
+
+    Buffer - Supplies a pointer to the table to checksum.
+
+    Size - Supplies the size of the table in bytes.
+
+    ChecksumOffset - Supplies the offset of the 8 bit checksum field.
+
+Return Value:
+
+    None.
+
+--*/
+
+EFIAPI
+VOID *
+EfiGetAcpiTable (
+    UINT32 Signature,
+    VOID *PreviousTable
+    );
+
+/*++
+
+Routine Description:
+
+    This routine attempts to find an ACPI description table with the given
+    signature. This routine does not validate the checksum of the table.
+
+Arguments:
+
+    Signature - Supplies the signature of the desired table.
+
+    PreviousTable - Supplies an optional pointer to the table to start the
+        search from.
+
+Return Value:
+
+    Returns a pointer to the beginning of the header to the table if the table
+    was found, or NULL if the table could not be located.
+
+--*/
+
 EFIAPI
 EFI_STATUS
 EfiSmbiosAddStructure (

+ 2 - 1
uefi/plat/beagbone/main.c

@@ -143,7 +143,8 @@ Arguments:
     Phase - Supplies the iteration number this routine is being called on.
         Phase zero occurs very early, just after the debugger comes up.
         Phase one occurs a bit later, after timer and interrupt services are
-        initialized.
+        initialized. Phase two happens right before boot, after all platform
+        devices have been enumerated.
 
 Return Value:
 

+ 2 - 1
uefi/plat/bios/main.c

@@ -124,7 +124,8 @@ Arguments:
     Phase - Supplies the iteration number this routine is being called on.
         Phase zero occurs very early, just after the debugger comes up.
         Phase one occurs a bit later, after timer and interrupt services are
-        initialized.
+        initialized. Phase two happens right before boot, after all platform
+        devices have been enumerated.
 
 Return Value:
 

+ 2 - 1
uefi/plat/integcp/main.c

@@ -119,7 +119,8 @@ Arguments:
     Phase - Supplies the iteration number this routine is being called on.
         Phase zero occurs very early, just after the debugger comes up.
         Phase one occurs a bit later, after timer and interrupt services are
-        initialized.
+        initialized. Phase two happens right before boot, after all platform
+        devices have been enumerated.
 
 Return Value:
 

+ 2 - 1
uefi/plat/panda/main.c

@@ -133,7 +133,8 @@ Arguments:
     Phase - Supplies the iteration number this routine is being called on.
         Phase zero occurs very early, just after the debugger comes up.
         Phase one occurs a bit later, after timer and interrupt services are
-        initialized.
+        initialized. Phase two happens right before boot, after all platform
+        devices have been enumerated.
 
 Return Value:
 

+ 2 - 1
uefi/plat/rpi/main.c

@@ -119,7 +119,8 @@ Arguments:
     Phase - Supplies the iteration number this routine is being called on.
         Phase zero occurs very early, just after the debugger comes up.
         Phase one occurs a bit later, after timer and interrupt services are
-        initialized.
+        initialized. Phase two happens right before boot, after all platform
+        devices have been enumerated.
 
 Return Value:
 

+ 81 - 31
uefi/plat/rpi/smbios.c

@@ -37,10 +37,10 @@ Environment:
 
 #define RPI_SMBIOS_BIOS_VENDOR "Minoca Corp"
 
-#define RPI_SMBIOS_SYSTEM_MANUFACTURER "Raspberry Pi"
+#define RPI_SMBIOS_SYSTEM_MANUFACTURER "Raspberry Pi Foundation"
 #define RPI_SMBIOS_SYSTEM_PRODUCT_NAME "Raspberry Pi"
 
-#define RPI_SMBIOS_MODULE_MANUFACTURER "Raspberry Pi"
+#define RPI_SMBIOS_MODULE_MANUFACTURER "Raspberry Pi Foundation"
 #define RPI_SMBIOS_MODULE_PRODUCT "Raspberry Pi"
 
 #define RPI_SMBIOS_PROCESSOR_MANUFACTURER "Broadcom"
@@ -60,7 +60,7 @@ Environment:
 
 Structure Description:
 
-    This structure stores the data necessary to query the BCM2709 video core
+    This structure defines the data necessary to query the BCM2709 video core
     for SMBIOS related information.
 
 Members:
@@ -68,9 +68,6 @@ Members:
     Header - Stores a header that defines the total size of the messages being
         sent to and received from the mailbox.
 
-    ModelMessage - Stores a message indicating that the board's model number is
-        being queried. Contains the model number on return.
-
     RevisionMessage - Stores a message indicating that the board's revision is
         being queried. Contains the revision on return.
 
@@ -88,7 +85,6 @@ Members:
 
 typedef struct _EFI_BCM2709_GET_SMBIOS_INFORMATION {
     BCM2709_MAILBOX_HEADER Header;
-    BCM2709_MAILBOX_BOARD_MODEL ModelMessage;
     BCM2709_MAILBOX_BOARD_REVISION RevisionMessage;
     BCM2709_MAILBOX_BOARD_SERIAL_NUMBER SerialMessage;
     BCM2709_MAILBOX_GET_CLOCK_RATE ArmClockRate;
@@ -96,6 +92,25 @@ typedef struct _EFI_BCM2709_GET_SMBIOS_INFORMATION {
     UINT32 EndTag;
 } EFI_BCM2709_GET_SMBIOS_INFORMATION, *PEFI_BCM2709_GET_SMBIOS_INFORMATION;
 
+/*++
+
+Structure Description:
+
+    This structure defines a Raspberry Pi revision.
+
+Members:
+
+    Revision - Stores the Raspberry Pi revision number.
+
+    Name - Stores the friendly name of the revision.
+
+--*/
+
+typedef struct _RPI_REVISION {
+    UINT32 Revision;
+    CHAR8 *Name;
+} RPI_REVISION, *PRPI_REVISION;
+
 //
 // ----------------------------------------------- Internal Function Prototypes
 //
@@ -239,16 +254,6 @@ EFI_BCM2709_GET_SMBIOS_INFORMATION EfiRpiBoardInformationTemplate = {
         0
     },
 
-    {
-        {
-            BCM2709_MAILBOX_TAG_GET_BOARD_MODEL,
-            sizeof(UINT32),
-            0
-        },
-
-        0
-    },
-
     {
         {
             BCM2709_MAILBOX_TAG_GET_BOARD_REVISION,
@@ -294,6 +299,26 @@ EFI_BCM2709_GET_SMBIOS_INFORMATION EfiRpiBoardInformationTemplate = {
     0
 };
 
+RPI_REVISION EfiRpiRevisions[] = {
+    {0x00000001, "1 Model B (Beta)"},
+    {0x00000002, "1 Model B Rev 1.0"},
+    {0x00000003, "1 Model B Rev 1.0 (ECN0001)"},
+    {0x00000004, "1 Model B Rev 2.0"},
+    {0x00000005, "1 Model B Rev 2.0"},
+    {0x00000006, "1 Model B Rev 2.0"},
+    {0x00000007, "1 Model A Rev 2.0"},
+    {0x00000008, "1 Model A Rev 2.0"},
+    {0x00000009, "1 Model A Rev 2.0"},
+    {0x0000000D, "1 Model B Rev 2.0"},
+    {0x0000000E, "1 Model B Rev 2.0"},
+    {0x0000000F, "1 Model B Rev 2.0"},
+    {0x00000010, "1 Model B+ Rev 1.0"},
+    {0x00000011, "Compute Module Rev 1.0"},
+    {0x00000012, "1 Model A+ Rev 1.0"},
+    {0x00000013, "1 Model B+ Rev 1.2"},
+    {0x00900092, "Zero Rev 1.2"}
+};
+
 //
 // ------------------------------------------------------------------ Functions
 //
@@ -323,10 +348,15 @@ Return Value:
 
     EFI_BCM2709_GET_SMBIOS_INFORMATION BoardInformation;
     UINT32 ExpectedLength;
+    UINT32 Index;
     UINT32 Length;
+    CHAR8 ProductBuffer[64];
+    CHAR8 *ProductName;
+    PRPI_REVISION Revision;
+    UINT32 RevisionCount;
     CHAR8 SerialNumber[17];
     EFI_STATUS Status;
-    CHAR8 Version[28];
+    CHAR8 Version[13];
 
     //
     // Query the BMC2835 mailbox to get version information and a serial number.
@@ -346,14 +376,6 @@ Return Value:
         return Status;
     }
 
-    Length = BoardInformation.ModelMessage.TagHeader.Length;
-    ExpectedLength = sizeof(BCM2709_MAILBOX_BOARD_MODEL) -
-                     sizeof(BCM2709_MAILBOX_TAG);
-
-    if (BCM2709_MAILBOX_CHECK_TAG_LENGTH(Length, ExpectedLength) == FALSE) {
-        return EFI_DEVICE_ERROR;
-    }
-
     Length = BoardInformation.RevisionMessage.TagHeader.Length;
     ExpectedLength = sizeof(BCM2709_MAILBOX_BOARD_REVISION) -
                      sizeof(BCM2709_MAILBOX_TAG);
@@ -412,16 +434,44 @@ Return Value:
                   sizeof(BoardInformation.SerialMessage.SerialNumber));
 
     //
-    // Convert the model and revision to a string.
+    // Convert the revision to a string.
     //
 
     RtlPrintToString(Version,
                      sizeof(Version),
                      CharacterEncodingAscii,
-                     "Model %08X Rev %08X",
-                     BoardInformation.ModelMessage.ModelNumber,
+                     "Rev %08X",
                      BoardInformation.RevisionMessage.Revision);
 
+    //
+    // Generate the product name based on the revision.
+    //
+
+    Revision = NULL;
+    RevisionCount = sizeof(EfiRpiRevisions) / sizeof(EfiRpiRevisions[0]);
+    for (Index = 0; Index < RevisionCount; Index += 1) {
+        if (EfiRpiRevisions[Index].Revision ==
+            BoardInformation.RevisionMessage.Revision) {
+
+            Revision = &(EfiRpiRevisions[Index]);
+            break;
+        }
+    }
+
+    if (Revision == NULL) {
+        ProductName = RPI_SMBIOS_SYSTEM_PRODUCT_NAME;
+
+    } else {
+        RtlPrintToString(ProductBuffer,
+                         sizeof(ProductBuffer),
+                         CharacterEncodingAscii,
+                         "%s %s",
+                         RPI_SMBIOS_SYSTEM_PRODUCT_NAME,
+                         Revision->Name);
+
+        ProductName = ProductBuffer;
+    }
+
     Status = EfiSmbiosAddStructure(&EfiRpiSmbiosBiosInformation,
                                    RPI_SMBIOS_BIOS_VENDOR,
                                    FIRMWARE_VERSION_STRING,
@@ -434,7 +484,7 @@ Return Value:
 
     Status = EfiSmbiosAddStructure(&EfiRpiSmbiosSystemInformation,
                                    RPI_SMBIOS_SYSTEM_MANUFACTURER,
-                                   RPI_SMBIOS_SYSTEM_PRODUCT_NAME,
+                                   ProductName,
                                    Version,
                                    SerialNumber,
                                    NULL);
@@ -445,7 +495,7 @@ Return Value:
 
     Status = EfiSmbiosAddStructure(&EfiRpiSmbiosModuleInformation,
                                    RPI_SMBIOS_MODULE_MANUFACTURER,
-                                   RPI_SMBIOS_MODULE_PRODUCT,
+                                   ProductName,
                                    NULL);
 
     if (EFI_ERROR(Status)) {

+ 3 - 2
uefi/plat/rpi2/armv7/entry.S

@@ -60,8 +60,7 @@ _start:
     ## Disable interrupts and switch to SVC mode.
     ##
 
-    mov     %r2, #(PSR_FLAG_IRQ | ARM_MODE_SVC)
-    msr     CPSR_c, %r2
+    bl      EfipBcm2836SwitchToSvcMode
 
     ##
     ## Flip some essential MMU bits allowing unaligned accesses.
@@ -89,6 +88,7 @@ BssZeroLoop:
     cmp     %r1, %r2
     blt     BssZeroLoop
 
+
     ##
     ## The stack starts at the image base and works downwards.
     ##
@@ -107,3 +107,4 @@ LoopForever:
 
 InitialMmuAndMask: .word ~(MMU_ALIGNMENT_FAULT_ENABLED)
 InitialMmuOrMask: .word MMU_UNALIGNED_ACCESS_ENABLED
+

+ 111 - 3
uefi/plat/rpi2/armv7/smpa.S

@@ -36,6 +36,7 @@ Environment:
 ##
 
 ASSEMBLY_FILE_HEADER
+.arch_extension virt
 
 ##
 ## .globl allows these labels to be visible to the linker.
@@ -76,6 +77,101 @@ FUNCTION EfipBcm2836SendEvent
 
 END_FUNCTION EfipBcm2836SendEvent
 
+##
+## UINT32
+## EfipBcm2836GetMultiprocessorIdRegister (
+##     VOID
+##     )
+##
+
+/*++
+
+Routine Description:
+
+    This routine gets the Multiprocessor ID register (MPIDR).
+
+Arguments:
+
+    None.
+
+Return Value:
+
+    Returns the value of the MPIDR.
+
+--*/
+
+FUNCTION EfipBcm2836GetMultiprocessorIdRegister
+    mrc     p15, 0, %r0, %c0, %c0, 5            @ Get the MPIDR
+    bx      %lr                                 @
+
+END_FUNCTION EfipBcm2836GetMultiprocessorIdRegister
+
+##
+## VOID
+## EfipBcm2836SwitchToSvcMode (
+##     VOID
+##     )
+##
+
+/*++
+
+Routine Description:
+
+    This routine disabled interrupts and switches to SVC mode. It handles the
+    case where the core is in HYP mode, which requires an execution state
+    transition in order to enter SVC mode.
+
+Arguments:
+
+    None.
+
+Return Value:
+
+    None.
+
+--*/
+
+FUNCTION EfipBcm2836SwitchToSvcMode
+
+    ##
+    ## Disable interrupts.
+    ##
+
+    cpsid   i
+
+    ##
+    ## Test to see if the core is in HYP mode. Transitioning from HYP mode to
+    ## SVC mode requires an ERET to switch execution states.
+    ##
+
+    mrs     %r0, CPSR
+    and     %r0, %r0, #ARM_MODE_MASK
+    cmp     %r0, #ARM_MODE_HYP
+    bne     EfipBcm2836SwitchToSvcModeEnd
+
+    ##
+    ## Trasition to SVC mode with the ERET.
+    ##
+
+    msr     ELR_hyp, %lr
+    mrs     %r0, CPSR
+    and     %r0, %r0, #~(ARM_MODE_MASK)
+    orr     %r0, %r0, #ARM_MODE_SVC
+    msr     SPSR_hyp, %r0
+    eret
+
+EfipBcm2836SwitchToSvcModeEnd:
+
+    ##
+    ## The core was not in HYP mode. Switch to SVC mode the easy way.
+    ##
+
+    mov     %r2, #(PSR_FLAG_IRQ | ARM_MODE_SVC)
+    msr     CPSR_c, %r2
+    bx      %lr
+
+END_FUNCTION EfipBcm2836SwitchToSvcMode
+
 ##
 ## VOID
 ## EfipBcm2836ProcessorStartup (
@@ -87,9 +183,9 @@ END_FUNCTION EfipBcm2836SendEvent
 
 Routine Description:
 
-    This routine implements the startup routine for the second CPU on the TI
-    OMAP4. Since this is the very first set of instructions executed on this
-    core there is nothing set up, including a stack.
+    This routine implements the startup routine for the alternate CPUs on the
+    Raspberry Pi 2. Since this is the very first set of instructions executed
+    on this core there is nothing set up, including a stack.
 
 Arguments:
 
@@ -104,6 +200,18 @@ Return Value:
 .arm
 .align 4
 EfipBcm2836ProcessorStartup:
+
+    ##
+    ## Disable interrupts and switch to SVC mode.
+    ##
+
+    bl      EfipBcm2836SwitchToSvcMode
+
+    ##
+    ## Park the core again, waiting until the firmware can allocate a page for
+    ## the final parking location.
+    ##
+
     mov     %r3, #0
     ldr     %r1, =EfiBcm2836ProcessorId     @ Get the processor ID address.
     ldr     %r0, [%r1]                      @ Get the value.

+ 29 - 0
uefi/plat/rpi2/blobs/LICENCE.broadcom

@@ -0,0 +1,29 @@
+Copyright (c) 2006, Broadcom Corporation.
+Copyright (c) 2015, Raspberry Pi (Trading) Ltd
+All rights reserved.
+
+Redistribution.  Redistribution and use in binary form, without
+modification, are permitted provided that the following conditions are
+met:
+
+* This software may only be used for the purposes of developing for,
+  running or using a Raspberry Pi device.
+* Redistributions must reproduce the above copyright notice and the
+  following disclaimer in the documentation and/or other materials
+  provided with the distribution.
+* Neither the name of Broadcom Corporation nor the names of its suppliers
+  may be used to endorse or promote products derived from this software
+  without specific prior written permission.
+
+DISCLAIMER.  THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND
+CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING,
+BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
+FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
+COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
+INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
+BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
+OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR
+TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE
+USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH
+DAMAGE.

+ 7 - 4
uefi/plat/rpi2/blobs/Makefile

@@ -25,10 +25,11 @@ include $(SRCROOT)/os/minoca.mk
 
 BINDIR = $(BINROOT)/rpi
 
-BINFILES = $(BINDIR)/bootcode.bin \
-           $(BINDIR)/config.txt   \
-           $(BINDIR)/fixup.dat    \
-           $(BINDIR)/start.elf    \
+BINFILES = $(BINDIR)/bootcode.bin     \
+           $(BINDIR)/config.txt       \
+           $(BINDIR)/fixup.dat        \
+           $(BINDIR)/start.elf        \
+           $(BINDIR)/LICENCE.broadcom \
 
 all: $(BINFILES)
 
@@ -49,3 +50,5 @@ $(BINDIR)/fixup.dat: fixup.dat
 $(BINDIR)/start.elf: start.elf
 	@cp -pv $< $@
 
+$(BINDIR)/LICENCE.broadcom: LICENCE.broadcom
+	@cp -pv $< $@

BIN
uefi/plat/rpi2/blobs/bootcode.bin


+ 9 - 0
uefi/plat/rpi2/blobs/config.txt

@@ -107,6 +107,15 @@ config_hdmi_boost=4
 
 disable_l2cache=0
 
+#
+# Force the UART to 3 MHz. The Raspberry Pi 3 UART runs at 48 MHz for the
+# Bluetooth module, but it is not yet enabled. Minoca OS uses the UART for
+# debugging and that only needs to be 3 MHz to achieve an 115200 baudrate.
+#
+
+init_uart_clock=3000000
+init_uart_baud=115200
+
 #
 # Set the kernel image and the kernel's start address.
 #

BIN
uefi/plat/rpi2/blobs/fixup.dat


BIN
uefi/plat/rpi2/blobs/start.elf


+ 227 - 37
uefi/plat/rpi2/main.c

@@ -25,6 +25,9 @@ Environment:
 // ------------------------------------------------------------------- Includes
 //
 
+#include <minoca/lib/types.h>
+#include <minoca/fw/acpitabs.h>
+#include <minoca/soc/b2709os.h>
 #include <uefifw.h>
 #include "rpi2fw.h"
 
@@ -34,8 +37,6 @@ Environment:
 
 #define FIRMWARE_IMAGE_NAME "rpi2fw.elf"
 
-#define RPI2_DEFAULT_ARM_FREQUENCY 900000000
-
 //
 // ------------------------------------------------------ Data Type Definitions
 //
@@ -44,27 +45,15 @@ Environment:
 
 Structure Description:
 
-    This structure stores the data necessary to query the BCM2709 video core
-    for SMBIOS related information.
+    This structure defines the data necessary to set the BCM2709's ARM clock
+    rate.
 
 Members:
 
     Header - Stores a header that defines the total size of the messages being
         sent to and received from the mailbox.
 
-    ModelMessage - Stores a message indicating that the board's model number is
-        being queried. Contains the model number on return.
-
-    RevisionMessage - Stores a message indicating that the board's revision is
-        being queried. Contains the revision on return.
-
-    SerialMessage - Stores a messagin indicating that the board's serial number
-        is being queried. Contains the serial number on return.
-
-    ArmClockRate - Stores a message requesting the ARM core's clock rate.
-
-    ArmMaxClockRate - Stores a message requesting the ARM core's maximum clock
-        rate.
+    ArmClockRate - Stores a message setting the ARM core's clock rate.
 
     EndTag - Stores the tag to denote the end of the mailbox message.
 
@@ -81,7 +70,17 @@ typedef struct _EFI_BCM2709_SET_CLOCK_RATE {
 //
 
 EFI_STATUS
-EfipBcm2836ConfigureArmClock (
+EfipBcm2836InitializeUart (
+    VOID
+    );
+
+EFI_STATUS
+EfipBcm2836InitializeArmClock (
+    VOID
+    );
+
+EFI_STATUS
+EfiBcm2836InitializeApbClock (
     VOID
     );
 
@@ -115,7 +114,27 @@ EFI_BCM2709_SET_CLOCK_RATE EfiRpi2SetClockTemplate = {
         },
 
         BCM2709_MAILBOX_CLOCK_ID_ARM,
-        RPI2_DEFAULT_ARM_FREQUENCY,
+        0,
+        0
+    },
+
+    0
+};
+
+EFI_BCM2709_GET_CLOCK_RATE EfiRpi2GetClockTemplate = {
+    {
+        sizeof(EFI_BCM2709_GET_CLOCK_RATE),
+        0
+    },
+
+    {
+        {
+            BCM2709_MAILBOX_TAG_GET_CLOCK_MAX_RATE,
+            sizeof(UINT32) * 2,
+            sizeof(UINT32) * 2
+        },
+
+        BCM2709_MAILBOX_CLOCK_ID_ARM,
         0
     },
 
@@ -155,6 +174,17 @@ Return Value:
 {
 
     UINTN FirmwareSize;
+    EFI_STATUS Status;
+
+    //
+    // Force GPIO pins 14 and 15 to the UART (rather than the mini-UART) before
+    // debugging comes online.
+    //
+
+    Status = EfipBcm2836InitializeUart();
+    if (EFI_ERROR(Status)) {
+        return;
+    }
 
     //
     // Initialize UEFI enough to get into the debugger.
@@ -187,7 +217,8 @@ Arguments:
     Phase - Supplies the iteration number this routine is being called on.
         Phase zero occurs very early, just after the debugger comes up.
         Phase one occurs a bit later, after timer and interrupt services are
-        initialized.
+        initialized. Phase two happens right before boot, after all platform
+        devices have been enumerated.
 
 Return Value:
 
@@ -199,40 +230,53 @@ Return Value:
 
     EFI_STATUS Status;
 
+    Status = EFI_SUCCESS;
     if (Phase == 0) {
         Status = EfipBcm2709Initialize((VOID *)BCM2836_BASE);
         if (EFI_ERROR(Status)) {
-            return Status;
+            goto PlatformInitializeEnd;
         }
 
         Status = EfipBcm2836SmpInitialize(0);
         if (EFI_ERROR(Status)) {
-            return Status;
+            goto PlatformInitializeEnd;
         }
 
     } else if (Phase == 1) {
-        Status = EfipBcm2836ConfigureArmClock();
+        Status = EfipBcm2836InitializeArmClock();
         if (EFI_ERROR(Status)) {
-            return Status;
+            goto PlatformInitializeEnd;
         }
 
         Status = EfipBcm2709UsbInitialize();
         if (EFI_ERROR(Status)) {
-            return Status;
+            goto PlatformInitializeEnd;
         }
 
         Status = EfipBcm2836SmpInitialize(1);
         if (EFI_ERROR(Status)) {
-            return Status;
+            goto PlatformInitializeEnd;
         }
 
         Status = EfipRpi2CreateSmbiosTables();
         if (EFI_ERROR(Status)) {
-            return Status;
+            goto PlatformInitializeEnd;
+        }
+
+    } else if (Phase == 2) {
+        Status = EfipBcm2836SmpInitialize(2);
+        if (EFI_ERROR(Status)) {
+            goto PlatformInitializeEnd;
+        }
+
+        Status = EfiBcm2836InitializeApbClock();
+        if (EFI_ERROR(Status)) {
+            goto PlatformInitializeEnd;
         }
     }
 
-    return EFI_SUCCESS;
+PlatformInitializeEnd:
+    return Status;
 }
 
 EFI_STATUS
@@ -281,7 +325,7 @@ Return Value:
 //
 
 EFI_STATUS
-EfipBcm2836ConfigureArmClock (
+EfipBcm2836InitializeUart (
     VOID
     )
 
@@ -289,8 +333,9 @@ EfipBcm2836ConfigureArmClock (
 
 Routine Description:
 
-    This routine initialized the ARM clock since the firmware initializes it to
-    600Mhz, rather than the 900Mhz max.
+    This routine initializes the PL011 UART making sure that it is exposed on
+    GPIO pins 14 and 15. On some versions of the Raspberry Pi, the mini-UART is
+    exposed on said pins.
 
 Arguments:
 
@@ -298,25 +343,170 @@ Arguments:
 
 Return Value:
 
-    Status code.
+    EFI status code.
 
 --*/
 
 {
 
+    EFI_STATUS Status;
+
+    //
+    // The BCM2709 device must be initialized before using GPIO.
+    //
+
+    Status = EfipBcm2709Initialize((VOID *)BCM2836_BASE);
+    if (EFI_ERROR(Status)) {
+        goto InitializeUartEnd;
+    }
+
+    Status = EfipBcm2709GpioFunctionSelect(BCM2709_GPIO_RECEIVE_PIN,
+                                           BCM2709_GPIO_FUNCTION_SELECT_ALT_0);
+
+    if (EFI_ERROR(Status)) {
+        goto InitializeUartEnd;
+    }
+
+    Status = EfipBcm2709GpioFunctionSelect(BCM2709_GPIO_TRANSMIT_PIN,
+                                           BCM2709_GPIO_FUNCTION_SELECT_ALT_0);
+
+    if (EFI_ERROR(Status)) {
+        goto InitializeUartEnd;
+    }
+
+InitializeUartEnd:
+    return Status;
+}
+
+EFI_STATUS
+EfipBcm2836InitializeArmClock (
+    VOID
+    )
+
+/*++
+
+Routine Description:
+
+    This routine initializes the ARM clock to its maximu supported frequency.
+    The firmware initializes it to less than the maximum (i.e. 600Mhz, rather
+    than the 900Mhz max on the RPI 2).
+
+Arguments:
+
+    None.
+
+Return Value:
+
+    EFI status code.
+
+--*/
+
+{
+
+    EFI_BCM2709_GET_CLOCK_RATE GetClockRate;
     EFI_BCM2709_SET_CLOCK_RATE SetClockRate;
     EFI_STATUS Status;
 
+    //
+    // Get the maximum supported ARM core clock rate from the mailbox.
+    //
+
+    EfiCopyMem(&GetClockRate,
+               &EfiRpi2GetClockTemplate,
+               sizeof(EFI_BCM2709_GET_CLOCK_RATE));
+
+    Status = EfipBcm2709MailboxSendCommand(BCM2709_MAILBOX_PROPERTIES_CHANNEL,
+                                           &GetClockRate,
+                                           sizeof(EFI_BCM2709_GET_CLOCK_RATE),
+                                           FALSE);
+
+    if (EFI_ERROR(Status)) {
+        return Status;
+    }
+
+    //
+    // Set the ARM core clock rate to the maximum.
+    //
+
     EfiCopyMem(&SetClockRate,
                &EfiRpi2SetClockTemplate,
                sizeof(EFI_BCM2709_SET_CLOCK_RATE));
 
-    Status = EfipBcm2709MailboxSendCommand(
-                                        BCM2709_MAILBOX_PROPERTIES_CHANNEL,
-                                        &SetClockRate,
-                                        sizeof(EFI_BCM2709_SET_CLOCK_RATE),
-                                        TRUE);
+    SetClockRate.ArmClockRate.Rate = GetClockRate.ClockRate.Rate;
+    Status = EfipBcm2709MailboxSendCommand(BCM2709_MAILBOX_PROPERTIES_CHANNEL,
+                                           &SetClockRate,
+                                           sizeof(EFI_BCM2709_SET_CLOCK_RATE),
+                                           TRUE);
+
+    return Status;
+}
+
+EFI_STATUS
+EfiBcm2836InitializeApbClock (
+    VOID
+    )
+
+/*++
+
+Routine Description:
+
+    This routine initializes the APB clock. This is the video cores clock and
+    can be configured via config.txt. Initialization simply consists of reading
+    the clock and updating the BCM2 ACPI table if necessary.
+
+Arguments:
+
+    None.
+
+Return Value:
+
+    EFI status code.
+
+--*/
+
+{
+
+    EFI_BCM2709_GET_CLOCK_RATE GetClockRate;
+    EFI_STATUS Status;
+    PBCM2709_TABLE Table;
+
+    //
+    // Get the current video core clock rate from the mailbox.
+    //
+
+    EfiCopyMem(&GetClockRate,
+               &EfiRpi2GetClockTemplate,
+               sizeof(EFI_BCM2709_GET_CLOCK_RATE));
+
+    GetClockRate.ClockRate.TagHeader.Tag = BCM2709_MAILBOX_TAG_GET_CLOCK_RATE;
+    GetClockRate.ClockRate.ClockId = BCM2709_MAILBOX_CLOCK_ID_VIDEO;
+    Status = EfipBcm2709MailboxSendCommand(BCM2709_MAILBOX_PROPERTIES_CHANNEL,
+                                           &GetClockRate,
+                                           sizeof(EFI_BCM2709_GET_CLOCK_RATE),
+                                           FALSE);
+
+    if (EFI_ERROR(Status)) {
+        goto InitializeApbClockEnd;
+    }
+
+    //
+    // Get the Broadcom ACPI table.
+    //
+
+    Table = EfiGetAcpiTable(BCM2709_SIGNATURE, NULL);
+    if (Table == NULL) {
+        Status = EFI_NOT_FOUND;
+        goto InitializeApbClockEnd;
+    }
+
+    if (Table->ApbClockFrequency != GetClockRate.ClockRate.Rate) {
+        Table->ApbClockFrequency = GetClockRate.ClockRate.Rate;
+        EfiAcpiChecksumTable(Table,
+                             Table->Header.Length,
+                             OFFSET_OF(DESCRIPTION_HEADER, Checksum));
+    }
 
+InitializeApbClockEnd:
     return Status;
 }
 

+ 114 - 40
uefi/plat/rpi2/smbios.c

@@ -35,21 +35,26 @@ Environment:
 // ---------------------------------------------------------------- Definitions
 //
 
-#define RPI2_SMBIOS_BIOS_VENDOR "Minoca Corp"
-
-#define RPI2_SMBIOS_SYSTEM_MANUFACTURER "Raspberry Pi 2"
-#define RPI2_SMBIOS_SYSTEM_PRODUCT_NAME "Raspberry Pi 2"
-
-#define RPI2_SMBIOS_MODULE_MANUFACTURER "Raspberry Pi 2"
-#define RPI2_SMBIOS_MODULE_PRODUCT "Raspberry Pi 2"
+//
+// Define the SMBIOS values common between the RPI 2 and RPI 3.
+//
 
+#define RPI2_SMBIOS_BIOS_VENDOR "Minoca Corp"
+#define RPI2_SMBIOS_SYSTEM_MANUFACTURER "Raspberry Pi Foundation"
+#define RPI2_SMBIOS_SYSTEM_PRODUCT_NAME "Raspberry Pi"
+#define RPI2_SMBIOS_MODULE_MANUFACTURER "Raspberry Pi Foundation"
+#define RPI2_SMBIOS_MODULE_PRODUCT "Raspberry Pi"
 #define RPI2_SMBIOS_PROCESSOR_MANUFACTURER "Broadcom"
-#define RPI2_SMBIOS_PROCESSOR_PART "BCM2836"
-#define RPI2_SMBIOS_PROCESSOR_EXTERNAL_CLOCK 250
 #define RPI2_SMBIOS_PROCESSOR_CORE_COUNT 4
-
 #define RPI2_SMBIOS_CACHE_L1_SIZE 32
 
+//
+// Define the SMBIOS values that differ betweent the RPI 2 and RPI3.
+//
+
+#define RPI2_SMBIOS_PROCESSOR_PART "BCM2836"
+#define RPI3_SMBIOS_PROCESSOR_PART "BCM2837"
+
 #define HERTZ_PER_MEGAHERTZ 1000000ULL
 
 //
@@ -60,7 +65,7 @@ Environment:
 
 Structure Description:
 
-    This structure stores the data necessary to query the BCM2709 video core
+    This structure defines the data necessary to query the BCM2709 video core
     for SMBIOS related information.
 
 Members:
@@ -68,9 +73,6 @@ Members:
     Header - Stores a header that defines the total size of the messages being
         sent to and received from the mailbox.
 
-    ModelMessage - Stores a message indicating that the board's model number is
-        being queried. Contains the model number on return.
-
     RevisionMessage - Stores a message indicating that the board's revision is
         being queried. Contains the revision on return.
 
@@ -88,14 +90,36 @@ Members:
 
 typedef struct _EFI_BCM2709_GET_SMBIOS_INFORMATION {
     BCM2709_MAILBOX_HEADER Header;
-    BCM2709_MAILBOX_BOARD_MODEL ModelMessage;
     BCM2709_MAILBOX_BOARD_REVISION RevisionMessage;
     BCM2709_MAILBOX_BOARD_SERIAL_NUMBER SerialMessage;
     BCM2709_MAILBOX_GET_CLOCK_RATE ArmClockRate;
     BCM2709_MAILBOX_GET_CLOCK_RATE ArmMaxClockRate;
+    BCM2709_MAILBOX_GET_CLOCK_RATE ApbClockRate;
     UINT32 EndTag;
 } EFI_BCM2709_GET_SMBIOS_INFORMATION, *PEFI_BCM2709_GET_SMBIOS_INFORMATION;
 
+/*++
+
+Structure Description:
+
+    This structure defines a Raspberry Pi revision.
+
+Members:
+
+    Revision - Stores the Raspberry Pi revision number.
+
+    Name - Stores the friendly name of the revision.
+
+    ProcessorPart - Stores the processor part used by the revision.
+
+--*/
+
+typedef struct _RPI2_REVISION {
+    UINT32 Revision;
+    CHAR8 *Name;
+    CHAR8 *ProcessorPart;
+} RPI2_REVISION, *PRPI2_REVISION;
+
 //
 // ----------------------------------------------- Internal Function Prototypes
 //
@@ -197,7 +221,7 @@ SMBIOS_PROCESSOR_INFORMATION EfiRpi2SmbiosProcessorInformation = {
     0,
     0,
     0,
-    RPI2_SMBIOS_PROCESSOR_EXTERNAL_CLOCK,
+    0,
     0,
     0,
     SMBIOS_PROCESSOR_STATUS_ENABLED,
@@ -239,16 +263,6 @@ EFI_BCM2709_GET_SMBIOS_INFORMATION EfiRpi2BoardInformationTemplate = {
         0
     },
 
-    {
-        {
-            BCM2709_MAILBOX_TAG_GET_BOARD_MODEL,
-            sizeof(UINT32),
-            0
-        },
-
-        0
-    },
-
     {
         {
             BCM2709_MAILBOX_TAG_GET_BOARD_REVISION,
@@ -291,9 +305,27 @@ EFI_BCM2709_GET_SMBIOS_INFORMATION EfiRpi2BoardInformationTemplate = {
         0
     },
 
+    {
+        {
+            BCM2709_MAILBOX_TAG_GET_CLOCK_RATE,
+            sizeof(UINT32) + sizeof(UINT32),
+            sizeof(UINT32)
+        },
+
+        BCM2709_MAILBOX_CLOCK_ID_VIDEO,
+        0
+    },
+
     0
 };
 
+RPI2_REVISION EfiRpi2Revisions[] = {
+    {0x00a01041, "2 Model B Rev 1.1", RPI2_SMBIOS_PROCESSOR_PART},
+    {0x00a21041, "2 Model B Rev 1.1", RPI2_SMBIOS_PROCESSOR_PART},
+    {0x00a02082, "3 Model B Rev 1.2", RPI3_SMBIOS_PROCESSOR_PART},
+    {0x00a22082, "3 Model B Rev 1.2", RPI3_SMBIOS_PROCESSOR_PART},
+};
+
 //
 // ------------------------------------------------------------------ Functions
 //
@@ -323,10 +355,16 @@ Return Value:
 
     EFI_BCM2709_GET_SMBIOS_INFORMATION BoardInformation;
     UINT32 ExpectedLength;
+    UINT32 Index;
     UINT32 Length;
+    CHAR8 *ProcessorPart;
+    CHAR8 ProductBuffer[32];
+    CHAR8 *ProductName;
+    PRPI2_REVISION Revision;
+    UINT32 RevisionCount;
     CHAR8 SerialNumber[17];
     EFI_STATUS Status;
-    CHAR8 Version[28];
+    CHAR8 Version[13];
 
     //
     // Query the BMC2836 mailbox to get version information and a serial number.
@@ -346,14 +384,6 @@ Return Value:
         return Status;
     }
 
-    Length = BoardInformation.ModelMessage.TagHeader.Length;
-    ExpectedLength = sizeof(BCM2709_MAILBOX_BOARD_MODEL) -
-                     sizeof(BCM2709_MAILBOX_TAG);
-
-    if (BCM2709_MAILBOX_CHECK_TAG_LENGTH(Length, ExpectedLength) == FALSE) {
-        return EFI_DEVICE_ERROR;
-    }
-
     Length = BoardInformation.RevisionMessage.TagHeader.Length;
     ExpectedLength = sizeof(BCM2709_MAILBOX_BOARD_REVISION) -
                      sizeof(BCM2709_MAILBOX_TAG);
@@ -386,6 +416,14 @@ Return Value:
         return EFI_DEVICE_ERROR;
     }
 
+    Length = BoardInformation.ApbClockRate.TagHeader.Length;
+    ExpectedLength = sizeof(BCM2709_MAILBOX_GET_CLOCK_RATE) -
+                     sizeof(BCM2709_MAILBOX_TAG);
+
+    if (BCM2709_MAILBOX_CHECK_TAG_LENGTH(Length, ExpectedLength) == FALSE) {
+        return EFI_DEVICE_ERROR;
+    }
+
     //
     // Update the clock information.
     //
@@ -396,6 +434,9 @@ Return Value:
     EfiRpi2SmbiosProcessorInformation.CurrentSpeed =
                       BoardInformation.ArmClockRate.Rate / HERTZ_PER_MEGAHERTZ;
 
+    EfiRpi2SmbiosProcessorInformation.ExternalClock =
+                      BoardInformation.ApbClockRate.Rate / HERTZ_PER_MEGAHERTZ;
+
     //
     // Convert the serial number to a string.
     //
@@ -418,10 +459,38 @@ Return Value:
     RtlPrintToString(Version,
                      sizeof(Version),
                      CharacterEncodingAscii,
-                     "Model %08X Rev %08X",
-                     BoardInformation.ModelMessage.ModelNumber,
+                     "Rev %08X",
                      BoardInformation.RevisionMessage.Revision);
 
+    //
+    // Generate the product name based on the revision.
+    //
+
+    Revision = NULL;
+    RevisionCount = sizeof(EfiRpi2Revisions) / sizeof(EfiRpi2Revisions[0]);
+    for (Index = 0; Index < RevisionCount; Index += 1) {
+        if (EfiRpi2Revisions[Index].Revision ==
+            BoardInformation.RevisionMessage.Revision) {
+
+            Revision = &(EfiRpi2Revisions[Index]);
+            break;
+        }
+    }
+
+    if (Revision == NULL) {
+        ProductName = RPI2_SMBIOS_SYSTEM_PRODUCT_NAME;
+
+    } else {
+        RtlPrintToString(ProductBuffer,
+                         sizeof(ProductBuffer),
+                         CharacterEncodingAscii,
+                         "%s %s",
+                         RPI2_SMBIOS_SYSTEM_PRODUCT_NAME,
+                         Revision->Name);
+
+        ProductName = ProductBuffer;
+    }
+
     Status = EfiSmbiosAddStructure(&EfiRpi2SmbiosBiosInformation,
                                    RPI2_SMBIOS_BIOS_VENDOR,
                                    FIRMWARE_VERSION_STRING,
@@ -434,7 +503,7 @@ Return Value:
 
     Status = EfiSmbiosAddStructure(&EfiRpi2SmbiosSystemInformation,
                                    RPI2_SMBIOS_SYSTEM_MANUFACTURER,
-                                   RPI2_SMBIOS_SYSTEM_PRODUCT_NAME,
+                                   ProductName,
                                    Version,
                                    SerialNumber,
                                    NULL);
@@ -445,7 +514,7 @@ Return Value:
 
     Status = EfiSmbiosAddStructure(&EfiRpi2SmbiosModuleInformation,
                                    RPI2_SMBIOS_MODULE_MANUFACTURER,
-                                   RPI2_SMBIOS_MODULE_PRODUCT,
+                                   ProductName,
                                    NULL);
 
     if (EFI_ERROR(Status)) {
@@ -457,10 +526,15 @@ Return Value:
         return Status;
     }
 
+    ProcessorPart = "";
+    if (Revision != NULL) {
+        ProcessorPart = Revision->ProcessorPart;
+    }
+
     Status = EfiSmbiosAddStructure(&EfiRpi2SmbiosProcessorInformation,
                                    RPI2_SMBIOS_PROCESSOR_MANUFACTURER,
                                    SerialNumber,
-                                   RPI2_SMBIOS_PROCESSOR_PART,
+                                   ProcessorPart,
                                    NULL);
 
     if (EFI_ERROR(Status)) {

+ 105 - 5
uefi/plat/rpi2/smp.c

@@ -25,6 +25,9 @@ Environment:
 // ------------------------------------------------------------------- Includes
 //
 
+#include <minoca/lib/types.h>
+#include <minoca/fw/acpitabs.h>
+#include <minoca/soc/b2709os.h>
 #include <uefifw.h>
 #include "rpi2fw.h"
 
@@ -75,11 +78,10 @@ Environment:
 #define ARM_PARKING_PROTOCOL_FIRMWARE_OFFSET 0x0800
 
 //
-// Define the physical processor ID base. This comes from core 0's MPIDR and
-// must match the values in the BCM2709 ACPI Table.
+// Define which bits of the MPIDR are valid processor ID bits.
 //
 
-#define BCM2836_PROCESSOR_ID_BASE 0xF00
+#define ARM_PROCESSOR_ID_MASK 0x00FFFFFF
 
 //
 // ------------------------------------------------------ Data Type Definitions
@@ -94,11 +96,21 @@ EfipBcm2836ProcessorStartup (
     VOID
     );
 
+UINT32
+EfipBcm2836GetMultiprocessorIdRegister (
+    VOID
+    );
+
 VOID
 EfipBcm2836SendEvent (
     VOID
     );
 
+EFI_STATUS
+EfipBcm2836UpdateAcpi (
+    UINT32 ProcessorIdBase
+    );
+
 //
 // -------------------------------------------------------------------- Globals
 //
@@ -145,12 +157,19 @@ Return Value:
 {
 
     VOID *Cpu[BCM2836_CPU_COUNT];
+    UINT32 IdBase;
     UINT32 Index;
     UINTN Pages;
     EFI_PHYSICAL_ADDRESS ParkedAddress;
     UINTN ParkingLoopSize;
     EFI_STATUS Status;
 
+    //
+    // Get the MPIDR of the current core to determine the base CPU ID.
+    //
+
+    IdBase = EfipBcm2836GetMultiprocessorIdRegister() & ARM_PROCESSOR_ID_MASK;
+
     //
     // Phase 0 initializes all of the cores and then parks the non-boot cores.
     // They are currently parked within page zero, but UEFI memory
@@ -174,7 +193,7 @@ Return Value:
         //
 
         for (Index = 1; Index < BCM2836_CPU_COUNT; Index += 1) {
-            EfiBcm2836ProcessorId = BCM2836_PROCESSOR_ID_BASE + Index;
+            EfiBcm2836ProcessorId = IdBase + Index;
 
             //
             // Poke the CPU to fire it up.
@@ -259,7 +278,7 @@ Return Value:
             EfiBcm2836JumpAddress = Cpu[Index] +
                                     ARM_PARKING_PROTOCOL_FIRMWARE_OFFSET;
 
-            EfiBcm2836ProcessorId = BCM2836_PROCESSOR_ID_BASE + Index;
+            EfiBcm2836ProcessorId = IdBase + Index;
 
             //
             // Send an event to the cores, only the one with the matching ID
@@ -278,6 +297,12 @@ Return Value:
                 NOTHING;
             }
         }
+
+    } else {
+        Status = EfipBcm2836UpdateAcpi(IdBase);
+        if (EFI_ERROR(Status)) {
+            return Status;
+        }
     }
 
     return EFI_SUCCESS;
@@ -287,3 +312,78 @@ Return Value:
 // --------------------------------------------------------- Internal Functions
 //
 
+EFI_STATUS
+EfipBcm2836UpdateAcpi (
+    UINT32 ProcessorIdBase
+    )
+
+/*++
+
+Routine Description:
+
+    This routine updates the BCM2 ACPI table with the current platform's SMP
+    information.
+
+Arguments:
+
+    ProcessorIdBase - Supplies the base ID for the BCM2836's ARM cores.
+
+Return Value:
+
+    EFI status code.
+
+--*/
+
+{
+
+    PBCM2709_CPU_ENTRY CpuEntry;
+    PBCM2709_GENERIC_ENTRY CurrentEntry;
+    UINT32 ProcessorCount;
+    EFI_STATUS Status;
+    PBCM2709_TABLE Table;
+
+    Table = EfiGetAcpiTable(BCM2709_SIGNATURE, NULL);
+    if (Table == NULL) {
+        Status = EFI_NOT_FOUND;
+        goto UpdateAcpiEnd;
+    }
+
+    //
+    // Update the processor ID for each CPU entry in the table. Different
+    // BCM2836 devices have different sets of MPIDR values.
+    //
+
+    ProcessorCount = 0;
+    CurrentEntry = (PBCM2709_GENERIC_ENTRY)(Table + 1);
+    while ((UINTN)CurrentEntry <
+           ((UINTN)Table + Table->Header.Length)) {
+
+        if ((CurrentEntry->Type == Bcm2709EntryTypeCpu) &&
+            (CurrentEntry->Length == sizeof(BCM2709_CPU_ENTRY))) {
+
+            CpuEntry = (PBCM2709_CPU_ENTRY)CurrentEntry;
+            CpuEntry->ProcessorId = ProcessorIdBase + ProcessorCount;
+            ProcessorCount += 1;
+            if (ProcessorCount == BCM2836_CPU_COUNT) {
+                break;
+            }
+        }
+
+        CurrentEntry = (PBCM2709_GENERIC_ENTRY)((PUCHAR)CurrentEntry +
+                                                CurrentEntry->Length);
+    }
+
+    //
+    // Now that the table has been modified, recompute the checksum.
+    //
+
+    EfiAcpiChecksumTable(Table,
+                         Table->Header.Length,
+                         OFFSET_OF(DESCRIPTION_HEADER, Checksum));
+
+    Status = EFI_SUCCESS;
+
+UpdateAcpiEnd:
+    return Status;
+}
+

+ 2 - 1
uefi/plat/veyron/main.c

@@ -154,7 +154,8 @@ Arguments:
     Phase - Supplies the iteration number this routine is being called on.
         Phase zero occurs very early, just after the debugger comes up.
         Phase one occurs a bit later, after timer and interrupt services are
-        initialized.
+        initialized. Phase two happens right before boot, after all platform
+        devices have been enumerated.
 
 Return Value: