123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599 |
- /*++
- Copyright (c) 2015 Minoca Corp. All Rights Reserved
- Module Name:
- main.c
- Abstract:
- This module implements the entry point for the UEFI firmware running on top
- of the Raspberry Pi 2.
- Author:
- Chris Stevens 19-Mar-2015
- Environment:
- Firmware
- --*/
- //
- // ------------------------------------------------------------------- Includes
- //
- #include <minoca/lib/types.h>
- #include <minoca/fw/acpitabs.h>
- #include <minoca/soc/b2709os.h>
- #include <uefifw.h>
- #include "rpi2fw.h"
- //
- // ---------------------------------------------------------------- Definitions
- //
- #define FIRMWARE_IMAGE_NAME "rpi2fw.elf"
- //
- // Define the core timer's crystal clock frequency: 19.2 MHz.
- //
- #define BCM2836_CORE_TIMER_CRYSTAL_CLOCK_FREQUENCY 19200000
- //
- // Define the maximum pre-scaler value.
- //
- #define BCM2836_CORE_TIMER_MAX_PRE_SCALER 0x80000000
- //
- // ------------------------------------------------------ Data Type Definitions
- //
- /*++
- Structure Description:
- 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.
- ArmClockRate - Stores a message setting the ARM core's clock rate.
- EndTag - Stores the tag to denote the end of the mailbox message.
- --*/
- typedef struct _EFI_BCM2709_SET_CLOCK_RATE {
- BCM2709_MAILBOX_HEADER Header;
- BCM2709_MAILBOX_SET_CLOCK_RATE ArmClockRate;
- UINT32 EndTag;
- } EFI_BCM2709_SET_CLOCK_RATE, *PEFI_BCM2709_SET_CLOCK_RATE;
- //
- // ----------------------------------------------- Internal Function Prototypes
- //
- EFI_STATUS
- EfipBcm2836InitializeUart (
- VOID
- );
- EFI_STATUS
- EfipBcm2836InitializeArmClock (
- VOID
- );
- EFI_STATUS
- EfipBcm2836InitializeApbClock (
- VOID
- );
- EFI_STATUS
- EfipBcm2836InitializeCoreTimerClock (
- VOID
- );
- UINT32
- EfipBcm2836GetGtFrequency (
- VOID
- );
- //
- // -------------------------------------------------------------------- Globals
- //
- //
- // Variables defined in the linker script that mark the start and end of the
- // image.
- //
- extern INT8 _end;
- extern INT8 __executable_start;
- //
- // Store a template to set the Raspberry Pi 2's ARM clock frequency.
- //
- EFI_BCM2709_SET_CLOCK_RATE EfiRpi2SetClockTemplate = {
- {
- sizeof(EFI_BCM2709_SET_CLOCK_RATE),
- 0
- },
- {
- {
- BCM2709_MAILBOX_TAG_SET_CLOCK_RATE,
- sizeof(UINT32) * 3,
- sizeof(UINT32) * 3
- },
- BCM2709_MAILBOX_CLOCK_ID_ARM,
- 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
- },
- 0
- };
- //
- // ------------------------------------------------------------------ Functions
- //
- VOID
- EfiRpi2Main (
- VOID *TopOfStack,
- UINTN StackSize
- )
- /*++
- Routine Description:
- This routine is the C entry point for the firmware.
- Arguments:
- TopOfStack - Supplies the top of the stack that has been set up for the
- loader.
- StackSize - Supplies the total size of the stack set up for the loader, in
- bytes.
- Return Value:
- This routine does not return.
- --*/
- {
- 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.
- //
- FirmwareSize = (UINTN)&_end - (UINTN)&__executable_start;
- EfiCoreMain((VOID *)-1,
- &__executable_start,
- FirmwareSize,
- FIRMWARE_IMAGE_NAME,
- TopOfStack - StackSize,
- StackSize);
- return;
- }
- EFI_STATUS
- EfiPlatformInitialize (
- UINT32 Phase
- )
- /*++
- Routine Description:
- This routine performs platform-specific firmware initialization.
- 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. Phase two happens right before boot, after all platform
- devices have been enumerated.
- Return Value:
- EFI status code.
- --*/
- {
- EFI_STATUS Status;
- Status = EFI_SUCCESS;
- if (Phase == 0) {
- Status = EfipBcm2709Initialize((VOID *)BCM2836_BASE);
- if (EFI_ERROR(Status)) {
- goto PlatformInitializeEnd;
- }
- Status = EfipBcm2836SmpInitialize(0);
- if (EFI_ERROR(Status)) {
- goto PlatformInitializeEnd;
- }
- } else if (Phase == 1) {
- Status = EfipBcm2836InitializeArmClock();
- if (EFI_ERROR(Status)) {
- goto PlatformInitializeEnd;
- }
- Status = EfipBcm2709UsbInitialize();
- if (EFI_ERROR(Status)) {
- goto PlatformInitializeEnd;
- }
- Status = EfipBcm2836SmpInitialize(1);
- if (EFI_ERROR(Status)) {
- goto PlatformInitializeEnd;
- }
- Status = EfipRpi2CreateSmbiosTables();
- if (EFI_ERROR(Status)) {
- goto PlatformInitializeEnd;
- }
- } else if (Phase == 2) {
- Status = EfipBcm2836SmpInitialize(2);
- if (EFI_ERROR(Status)) {
- goto PlatformInitializeEnd;
- }
- Status = EfipBcm2836InitializeApbClock();
- if (EFI_ERROR(Status)) {
- goto PlatformInitializeEnd;
- }
- Status = EfipBcm2836InitializeCoreTimerClock();
- if (EFI_ERROR(Status)) {
- goto PlatformInitializeEnd;
- }
- }
- PlatformInitializeEnd:
- return Status;
- }
- EFI_STATUS
- EfiPlatformEnumerateDevices (
- VOID
- )
- /*++
- Routine Description:
- This routine enumerates and connects any builtin devices the platform
- contains.
- Arguments:
- None.
- Return Value:
- EFI status code.
- --*/
- {
- EFI_STATUS Status;
- Status = EfipBcm2709EnumerateSd();
- if (EFI_ERROR(Status)) {
- return Status;
- }
- EfipBcm2709EnumerateVideo();
- EfipBcm2709EnumerateSerial();
- Status = EfipEnumerateRamDisks();
- if (EFI_ERROR(Status)) {
- return Status;
- }
- return EFI_SUCCESS;
- }
- //
- // --------------------------------------------------------- Internal Functions
- //
- EFI_STATUS
- EfipBcm2836InitializeUart (
- VOID
- )
- /*++
- Routine Description:
- 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:
- None.
- Return Value:
- 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));
- SetClockRate.ArmClockRate.Rate = GetClockRate.ClockRate.Rate;
- Status = EfipBcm2709MailboxSendCommand(BCM2709_MAILBOX_PROPERTIES_CHANNEL,
- &SetClockRate,
- sizeof(EFI_BCM2709_SET_CLOCK_RATE),
- TRUE);
- return Status;
- }
- EFI_STATUS
- EfipBcm2836InitializeApbClock (
- 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;
- }
- EFI_STATUS
- EfipBcm2836InitializeCoreTimerClock (
- VOID
- )
- /*++
- Routine Description:
- This routine initializes the ARM core's timer clock. This backs the ARM
- Generic Timer.
- Arguments:
- None.
- Return Value:
- EFI status code.
- --*/
- {
- UINT32 Divider;
- UINT32 Frequency;
- UINT32 PreScaler;
- UINT32 TimerControl;
- //
- // Use the 19.2 MHz crystal clock to back the ARM Generic Timer.
- //
- TimerControl = BCM2836_CORE_TIMER_CONTROL_INCREMENT_BY_1 |
- BCM2836_CORE_TIMER_CONTROL_CRYSTAL_CLOCK;
- EfiWriteRegister32((VOID*)BCM2836_CORE_TIMER_CONTROL, TimerControl);
- //
- // Get the programmed frequency and try to match the pre-scaler so the
- // clock runs at the targeted frequency.
- //
- Frequency = EfipBcm2836GetGtFrequency();
- if (Frequency > BCM2836_CORE_TIMER_CRYSTAL_CLOCK_FREQUENCY) {
- return EFI_UNSUPPORTED;
- }
- //
- // The frequency is obtained by dividing 19.2 MHz by the divider. The
- // divider is obtained by dividing 2^31 by the pre-scaler. Determine the
- // appropriate pre-scaler for the frequency.
- //
- Divider = BCM2836_CORE_TIMER_CRYSTAL_CLOCK_FREQUENCY / Frequency;
- PreScaler = BCM2836_CORE_TIMER_MAX_PRE_SCALER / Divider;
- EfiWriteRegister32((VOID*)BCM2836_CORE_TIMER_PRE_SCALER, PreScaler);
- return EFI_SUCCESS;
- }
|