123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674 |
- /*++
- Copyright (c) 2014 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 RK3288 Veyron.
- Author:
- Evan Green 10-Jul-2015
- Environment:
- Firmware
- --*/
- //
- // ------------------------------------------------------------------- Includes
- //
- #include <uefifw.h>
- #include "veyronfw.h"
- //
- // ---------------------------------------------------------------- Definitions
- //
- #define FIRMWARE_IMAGE_NAME "veyronfw.elf"
- //
- // The I2C PMU defaults to run at 400KHz.
- //
- #define RK32_I2C_PMU_FREQUENCY 400000
- //
- // ------------------------------------------------------ Data Type Definitions
- //
- //
- // ----------------------------------------------- Internal Function Prototypes
- //
- VOID
- EfipVeyronConfigureArmPll (
- VOID
- );
- EFI_STATUS
- EfipVeyronConfigureI2cClock (
- VOID
- );
- VOID
- EfipVeyronConfigureMmcClocks (
- VOID
- );
- //
- // -------------------------------------------------------------------- Globals
- //
- //
- // Variables defined in the linker script that mark the start and end of the
- // image.
- //
- extern INT8 _end;
- extern INT8 __executable_start;
- //
- // Disable the RK3288 watchdog by default. Once it is started, it cannot be
- // stopped. So, it is essentially useless unless a keep-alive method is
- // implemented.
- //
- BOOLEAN EfiDisableWatchdog = TRUE;
- //
- // Define a boolean indicating whether the firmware was loaded via SD or eMMC.
- //
- BOOLEAN EfiBootedViaSd;
- //
- // ------------------------------------------------------------------ Functions
- //
- VOID
- EfiVeyronMain (
- 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;
- //
- // 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;
- if (Phase == 0) {
- if (EfiDisableWatchdog != FALSE) {
- EfiPlatformSetWatchdogTimer(0, 0, 0, NULL);
- }
- EfipVeyronConfigureArmPll();
- EfipVeyronConfigureMmcClocks();
- //
- // Initialize the I2C clock so that the clock frequency querying code
- // does not need to be present in the runtime core.
- //
- Status = EfipVeyronConfigureI2cClock();
- if (EFI_ERROR(Status)) {
- return Status;
- }
- } else if (Phase == 1) {
- EfipVeyronUsbInitialize();
- Status = EfipSmpInitialize();
- if (EFI_ERROR(Status)) {
- return Status;
- }
- Status = EfipVeyronCreateSmbiosTables();
- if (EFI_ERROR(Status)) {
- return Status;
- }
- }
- return EFI_SUCCESS;
- }
- 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 = EfipVeyronEnumerateVideo();
- if (EFI_ERROR(Status)) {
- return Status;
- }
- Status = EfipVeyronEnumerateSd();
- if (EFI_ERROR(Status)) {
- return Status;
- }
- Status = EfipVeyronEnumerateSerial();
- if (EFI_ERROR(Status)) {
- return Status;
- }
- Status = EfipEnumerateRamDisks();
- if (EFI_ERROR(Status)) {
- return Status;
- }
- return EFI_SUCCESS;
- }
- EFI_STATUS
- EfipRk32GetPllClockFrequency (
- RK32_PLL_TYPE PllType,
- UINT32 *Frequency
- )
- /*++
- Routine Description:
- This routine returns the base PLL clock frequency of the given type.
- Arguments:
- PllType - Supplies the type of the PLL clock whose frequency is being
- queried.
- Frequency - Supplies a pointer that receives the PLL clock's frequency in
- Hertz.
- Return Value:
- Status code.
- --*/
- {
- RK32_CRU_REGISTER Configuration0;
- RK32_CRU_REGISTER Configuration1;
- VOID *CruBase;
- UINT32 Mode;
- UINT32 Nf;
- UINT32 No;
- UINT32 Nr;
- UINT32 Value;
- CruBase = (VOID *)RK32_CRU_BASE;
- *Frequency = 0;
- //
- // The CRU mode control register encodes the clock mode for each of the PLL
- // clocks.
- //
- Mode = EfiReadRegister32(CruBase + Rk32CruModeControl);
- switch (PllType) {
- case Rk32PllNew:
- Mode = (Mode & RK32_CRU_MODE_CONTROL_NEW_PLL_MODE_MASK) >>
- RK32_CRU_MODE_CONTROL_NEW_PLL_MODE_SHIFT;
- Configuration0 = Rk32CruNewPllConfiguration0;
- Configuration1 = Rk32CruNewPllConfiguration1;
- break;
- case Rk32PllCodec:
- Mode = (Mode & RK32_CRU_MODE_CONTROL_CODEC_PLL_MODE_MASK) >>
- RK32_CRU_MODE_CONTROL_CODEC_PLL_MODE_SHIFT;
- Configuration0 = Rk32CruCodecPllConfiguration0;
- Configuration1 = Rk32CruCodecPllConfiguration1;
- break;
- case Rk32PllGeneral:
- Mode = (Mode & RK32_CRU_MODE_CONTROL_GENERAL_PLL_MODE_MASK) >>
- RK32_CRU_MODE_CONTROL_GENERAL_PLL_MODE_SHIFT;
- Configuration0 = Rk32CruGeneralPllConfiguration0;
- Configuration1 = Rk32CruGeneralPllConfiguration1;
- break;
- case Rk32PllDdr:
- Mode = (Mode & RK32_CRU_MODE_CONTROL_DDR_PLL_MODE_MASK) >>
- RK32_CRU_MODE_CONTROL_DDR_PLL_MODE_SHIFT;
- Configuration0 = Rk32CruDdrPllConfiguration0;
- Configuration1 = Rk32CruDdrPllConfiguration1;
- break;
- case Rk32PllArm:
- Mode = (Mode & RK32_CRU_MODE_CONTROL_ARM_PLL_MODE_MASK) >>
- RK32_CRU_MODE_CONTROL_ARM_PLL_MODE_SHIFT;
- Configuration0 = Rk32CruArmPllConfiguration0;
- Configuration1 = Rk32CruArmPllConfiguration1;
- break;
- default:
- return EFI_UNSUPPORTED;
- }
- //
- // Calculate the frequency based on the mode.
- //
- if (Mode == RK32_CRU_MODE_CONTROL_SLOW_MODE) {
- *Frequency = RK32_CRU_PLL_SLOW_MODE_FREQUENCY;
- } else if (Mode == RK32_CRU_MODE_CONTROL_NORMAL_MODE) {
- //
- // Calculate the clock speed based on the formula described in
- // section 3.9 of the RK3288 TRM.
- //
- Value = EfiReadRegister32(CruBase + Configuration0);
- No = (Value & RK32_PLL_CONFIGURATION0_OD_MASK) >>
- RK32_PLL_CONFIGURATION0_OD_SHIFT;
- No += 1;
- Nr = (Value & RK32_PLL_CONFIGURATION0_NR_MASK) >>
- RK32_PLL_CONFIGURATION0_NR_SHIFT;
- Nr += 1;
- Value = EfiReadRegister32(CruBase + Configuration1);
- Nf = (Value & RK32_PLL_CONFIGURATION1_NF_MASK) >>
- RK32_PLL_CONFIGURATION1_NF_SHIFT;
- Nf += 1;
- *Frequency = RK32_CRU_PLL_COMPUTE_CLOCK_FREQUENCY(Nf, Nr, No);
- } else if (Mode == RK32_CRU_MODE_CONTROL_DEEP_SLOW_MODE) {
- *Frequency = RK32_CRU_PLL_DEEP_SLOW_MODE_FREQUENCY;
- } else {
- return EFI_DEVICE_ERROR;
- }
- return EFI_SUCCESS;
- }
- //
- // --------------------------------------------------------- Internal Functions
- //
- VOID
- EfipVeyronConfigureArmPll (
- VOID
- )
- /*++
- Routine Description:
- This routine configures the ARM PLL, since the 1800MHz set by the firmware
- actually seems to be too fast to run correctly.
- Arguments:
- None.
- Return Value:
- None.
- --*/
- {
- UINT32 Frequency;
- UINT32 Nf;
- UINT32 No;
- UINT32 Nr;
- UINT32 Value;
- //
- // Put the PLL in slow mode to bypass the PLL while it's being configured.
- //
- Value = (RK32_CRU_MODE_CONTROL_ARM_PLL_MODE_MASK << 16) |
- RK32_CRU_MODE_CONTROL_ARM_PLL_MODE_SLOW;
- RK32_WRITE_CRU(Rk32CruModeControl, Value);
- Frequency = VEYRON_ARM_CPU_HERTZ;
- Nr = 1;
- No = 1;
- Nf = (UINT32)((UINT64)Frequency * Nr * No / VEYRON_OSC_HERTZ);
- //
- // Reset the PLL.
- //
- Value = (RK32_PLL_CONFIGURATION3_RESET << 16) |
- RK32_PLL_CONFIGURATION3_RESET;
- RK32_WRITE_CRU(Rk32CruArmPllConfiguration3, Value);
- //
- // Configure the PLL.
- //
- Value = ((RK32_PLL_CONFIGURATION0_NR_MASK |
- RK32_PLL_CONFIGURATION0_OD_MASK) << 16) |
- ((Nr - 1) << RK32_PLL_CONFIGURATION0_NR_SHIFT) | (No - 1);
- RK32_WRITE_CRU(Rk32CruArmPllConfiguration0, Value);
- Value = (RK32_PLL_CONFIGURATION1_NF_MASK << 16) | (Nf - 1);
- RK32_WRITE_CRU(Rk32CruArmPllConfiguration1, Value);
- Value = (RK32_PLL_CONFIGURATION2_BWADJ_MASK << 16) | ((Nf >> 1) - 1);
- RK32_WRITE_CRU(Rk32CruArmPllConfiguration2, Value);
- EfiStall(10);
- //
- // Clear reset.
- //
- Value = RK32_PLL_CONFIGURATION3_RESET << 16;
- RK32_WRITE_CRU(Rk32CruArmPllConfiguration3, Value);
- //
- // Wait for the PLL to lock itself.
- //
- do {
- Value = RK32_READ_GRF(Rk32GrfSocStatus1);
- } while ((Value & RK32_GRF_SOC_STATUS1_ARM_PLL_LOCK) == 0);
- //
- // Enter normal mode on the PLL.
- //
- Value = (RK32_CRU_MODE_CONTROL_ARM_PLL_MODE_MASK << 16) |
- RK32_CRU_MODE_CONTROL_ARM_PLL_MODE_NORMAL;
- RK32_WRITE_CRU(Rk32CruModeControl, Value);
- return;
- }
- EFI_STATUS
- EfipVeyronConfigureI2cClock (
- VOID
- )
- /*++
- Routine Description:
- This routine configures the I2C clock to 400Khz. This is done outside the
- runtime core to avoid pulling in the clock querying code and divide
- intrinsics.
- Arguments:
- None.
- Return Value:
- Status code.
- --*/
- {
- UINT32 AclkPllFrequency;
- UINT32 BusAclkDivider;
- UINT32 BusAclkDivider1;
- UINT32 BusAclkFrequency;
- UINT32 BusPclkDivider;
- UINT32 BusPclkFrequency;
- UINT32 Divisor;
- UINT32 DivisorHigh;
- UINT32 DivisorLow;
- VOID *I2cPmuBase;
- RK32_PLL_TYPE PllType;
- VOID *PmuBase;
- EFI_STATUS Status;
- UINT32 Value;
- I2cPmuBase = (VOID *)RK32_I2C_PMU_BASE;
- PmuBase = (VOID *)RK32_PMU_BASE;
- EfiWriteRegister32(PmuBase + Rk32PmuIomuxI2c0Sda,
- RK32_PMU_IOMUX_I2C0_SDA_DEFAULT);
- EfiWriteRegister32(PmuBase + Rk32PmuIomuxI2c0Scl,
- RK32_PMU_IOMUX_I2C0_SCL_DEFAULT);
- //
- // Get the frequency of the bus PCLK. The bus's ACLK must first be
- // calculated.
- //
- PllType = Rk32PllCodec;
- Value = EfiReadRegister32((VOID *)RK32_CRU_BASE + Rk32CruClockSelect1);
- if ((Value & RK32_CRU_CLOCK_SELECT1_GENERAL_PLL) != 0) {
- PllType = Rk32PllGeneral;
- }
- Status = EfipRk32GetPllClockFrequency(PllType, &AclkPllFrequency);
- if (EFI_ERROR(Status)) {
- return Status;
- }
- BusAclkDivider = (Value & RK32_CRU_CLOCK_SELECT1_ACLK_DIVIDER_MASK) >>
- RK32_CRU_CLOCK_SELECT1_ACLK_DIVIDER_SHIFT;
- BusAclkDivider += 1;
- BusAclkDivider1 = (Value & RK32_CRU_CLOCK_SELECT1_ACLK_DIVIDER1_MASK) >>
- RK32_CRU_CLOCK_SELECT1_ACLK_DIVIDER1_SHIFT;
- BusAclkDivider1 += 1;
- BusAclkFrequency = AclkPllFrequency / (BusAclkDivider * BusAclkDivider1);
- //
- // Now divide the ACLK by the PCLK's divider to get the PCLK frequency.
- //
- BusPclkDivider = (Value & RK32_CRU_CLOCK_SELECT1_PCLK_DIVIDER_MASK) >>
- RK32_CRU_CLOCK_SELECT1_PCLK_DIVIDER_SHIFT;
- BusPclkDivider += 1;
- BusPclkFrequency = BusAclkFrequency / BusPclkDivider;
- //
- // Set the clock divisor to run at 400Mhz.
- //
- Divisor = (BusPclkFrequency + (8 * RK32_I2C_PMU_FREQUENCY - 1)) /
- (8 * RK32_I2C_PMU_FREQUENCY);
- DivisorHigh = ((Divisor * 3) / 7) - 1;
- DivisorLow = Divisor - DivisorHigh - 2;
- Value = (DivisorHigh << RK32_I2C_CLOCK_DIVISOR_HIGH_SHIFT) &
- RK32_I2C_CLOCK_DIVISOR_HIGH_MASK;
- Value |= (DivisorLow << RK32_I2C_CLOCK_DIVISOR_LOW_SHIFT) &
- RK32_I2C_CLOCK_DIVISOR_LOW_MASK;
- EfiWriteRegister32(I2cPmuBase + Rk32I2cClockDivisor, Value);
- return EFI_SUCCESS;
- }
- VOID
- EfipVeyronConfigureMmcClocks (
- VOID
- )
- /*++
- Routine Description:
- This routine configures the MMC clock.
- Arguments:
- None.
- Return Value:
- Status code.
- --*/
- {
- UINT32 Mask;
- UINT32 Mmc;
- UINT32 Value;
- //
- // To figure out if the firmware was loaded from SD or eMMC, check to see
- // which clock was configured. If SD was configured for high speed, assume
- // boot came from there.
- //
- Mmc = EfiReadRegister32((VOID *)RK32_CRU_BASE + Rk32CruClockSelect11);
- if ((Mmc & RK32_CRU_CLOCK_SELECT11_MMC0_CLOCK_MASK) !=
- (RK32_CRU_CLOCK_SELECT11_MMC0_24MHZ <<
- RK32_CRU_CLOCK_SELECT11_MMC0_CLOCK_SHIFT)) {
- EfiBootedViaSd = TRUE;
- }
- //
- // Set up MMC0 to clock off of the general PLL / 6, which comes out to
- // 99MHz.
- //
- Mmc = (RK32_CRU_CLOCK_SELECT11_MMC0_GENERAL_PLL <<
- RK32_CRU_CLOCK_SELECT11_MMC0_CLOCK_SHIFT) |
- (5 << RK32_CRU_CLOCK_SELECT11_MMC0_DIVIDER_SHIFT);
- Mask = RK32_CRU_CLOCK_SELECT11_MMC0_CLOCK_MASK |
- RK32_CRU_CLOCK_SELECT11_MMC0_DIVIDER_MASK;
- Mmc |= Mask << RK32_CRU_CLOCK_SELECT11_PROTECT_SHIFT;
- EfiWriteRegister32((VOID *)RK32_CRU_BASE + Rk32CruClockSelect11, Mmc);
- //
- // Set up eMMC like the MMC0.
- //
- Mmc = (RK32_CRU_CLOCK_SELECT12_EMMC_GENERAL_PLL <<
- RK32_CRU_CLOCK_SELECT12_EMMC_CLOCK_SHIFT) |
- (5 << RK32_CRU_CLOCK_SELECT12_EMMC_DIVIDER_SHIFT);
- Mask = RK32_CRU_CLOCK_SELECT12_EMMC_CLOCK_MASK |
- RK32_CRU_CLOCK_SELECT12_EMMC_DIVIDER_MASK;
- Mmc |= Mask << RK32_CRU_CLOCK_SELECT12_PROTECT_SHIFT;
- EfiWriteRegister32((VOID *)RK32_CRU_BASE + Rk32CruClockSelect12, Mmc);
- //
- // Reset the SD/MMC.
- //
- Value = RK32_CRU_SOFT_RESET8_MMC0 << RK32_CRU_SOFT_RESET8_PROTECT_SHIFT;
- Value |= RK32_CRU_SOFT_RESET8_MMC0;
- EfiWriteRegister32((VOID *)RK32_CRU_BASE + Rk32CruSoftReset8, Value);
- EfiStall(100);
- Value &= ~RK32_CRU_SOFT_RESET8_MMC0;
- EfiWriteRegister32((VOID *)RK32_CRU_BASE + Rk32CruSoftReset8, Value);
- //
- // Reset the IOMUX to the correct value for SD/MMC.
- //
- Value = RK32_GRF_GPIO6C_IOMUX_VALUE;
- EfiWriteRegister32((VOID *)RK32_GRF_BASE + Rk32GrfGpio6cIomux, Value);
- return;
- }
|