123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278 |
- /*++
- Copyright (c) 2015 Minoca Corp. All Rights Reserved
- Module Name:
- smp.c
- Abstract:
- This module implements support routines for the second core on RK3288 SoCs.
- Author:
- Evan Green 10-Jul-2015
- Environment:
- Firmware
- --*/
- //
- // ------------------------------------------------------------------- Includes
- //
- #include <uefifw.h>
- #include "veyronfw.h"
- //
- // ---------------------------------------------------------------- Definitions
- //
- //
- // Define the parking page locations. This is completely arbitrary, but has to
- // match the values in the MADT.
- //
- #define RK32_CPU_PARKING_BASE 0x00080000
- #define RK32_CPU_COUNT 4
- #define RK32_CPU_PARKED_ADDRESS_SIZE 0x1000
- #define RK32_CPU_TOTAL_PARKED_ADDRESS_SIZE \
- (RK32_CPU_COUNT * RK32_CPU_PARKED_ADDRESS_SIZE)
- #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 MADT.
- //
- #define RK32_PROCESSOR_ID_BASE 0x500
- //
- // ------------------------------------------------------ Data Type Definitions
- //
- //
- // ----------------------------------------------- Internal Function Prototypes
- //
- //
- // Internal assembly routines.
- //
- VOID
- EfipRk32SendEvent (
- VOID
- );
- VOID
- EfipRk32ProcessorStartup (
- VOID
- );
- //
- // -------------------------------------------------------------------- Globals
- //
- //
- // Define the variables other cores read to boot.
- //
- volatile UINT32 EfiRk32ProcessorId;
- VOID volatile *EfiRk32ProcessorJumpAddress;
- extern UINT8 EfipRk32ParkingLoop;
- extern UINT8 EfipRk32ParkingLoopEnd;
- //
- // ------------------------------------------------------------------ Functions
- //
- EFI_STATUS
- EfipSmpInitialize (
- VOID
- )
- /*++
- Routine Description:
- This routine initializes and parks the second core on the RK32xx.
- Arguments:
- None.
- Return Value:
- EFI status code.
- --*/
- {
- UINT32 Bit;
- UINT32 CoreMask;
- VOID *Cpu;
- UINTN CpuIndex;
- VOID *Cru;
- EFI_PHYSICAL_ADDRESS ParkedAddress;
- VOID *Pmu;
- UINT32 *Sram;
- EFI_STATUS Status;
- UINT32 Value;
- //
- // Allocate the pages for the firmware parked spaces.
- //
- Cru = (VOID *)RK32_CRU_BASE;
- Pmu = (VOID *)RK32_PMU_BASE;
- ParkedAddress = RK32_CPU_PARKING_BASE;
- Status = EfiAllocatePages(
- AllocateAddress,
- EfiACPIMemoryNVS,
- EFI_SIZE_TO_PAGES(RK32_CPU_TOTAL_PARKED_ADDRESS_SIZE),
- &ParkedAddress);
- if (EFI_ERROR(Status)) {
- return Status;
- }
- EfiSetMem((VOID *)(UINTN)ParkedAddress,
- RK32_CPU_TOTAL_PARKED_ADDRESS_SIZE,
- 0);
- Cpu = (VOID *)(UINTN)ParkedAddress;
- for (CpuIndex = 0; CpuIndex < RK32_CPU_COUNT; CpuIndex += 1) {
- //
- // Write -1 to the processor number location.
- //
- Cpu = (VOID *)((UINTN)ParkedAddress +
- (CpuIndex * RK32_CPU_PARKED_ADDRESS_SIZE));
- EfiWriteRegister32(Cpu, -1);
- //
- // Copy the parking protocol loops into the right places.
- //
- EfiCopyMem(
- Cpu + ARM_PARKING_PROTOCOL_FIRMWARE_OFFSET,
- &EfipRk32ParkingLoop,
- (UINTN)&EfipRk32ParkingLoopEnd - (UINTN)&EfipRk32ParkingLoop);
- }
- EfiCoreInvalidateInstructionCacheRange((VOID *)(UINTN)ParkedAddress,
- RK32_CPU_TOTAL_PARKED_ADDRESS_SIZE);
- //
- // Assert reset on cores 1 through 3 before powering them down.
- //
- CoreMask = RK32_CRU_SOFT_RESET0_CORE1 |
- RK32_CRU_SOFT_RESET0_CORE2 |
- RK32_CRU_SOFT_RESET0_CORE3;
- Value = (CoreMask << RK32_CRU_SOFT_RESET0_PROTECT_SHIFT) | CoreMask;
- EfiWriteRegister32(Cru + Rk32CruSoftReset0, Value);
- //
- // Power down the cores.
- //
- CoreMask = RK32_PMU_POWER_DOWN_CONTROL_A17_1 |
- RK32_PMU_POWER_DOWN_CONTROL_A17_2 |
- RK32_PMU_POWER_DOWN_CONTROL_A17_3;
- Value = EfiReadRegister32(Pmu + Rk32PmuPowerDownControl);
- Value |= CoreMask;
- EfiWriteRegister32(Pmu + Rk32PmuPowerDownControl, Value);
- CoreMask = RK32_PMU_POWER_DOWN_STATUS_A17_1 |
- RK32_PMU_POWER_DOWN_STATUS_A17_2 |
- RK32_PMU_POWER_DOWN_STATUS_A17_3;
- while (TRUE) {
- Value = EfiReadRegister32(Pmu + Rk32PmuPowerDownStatus);
- if ((Value & CoreMask) == CoreMask) {
- break;
- }
- }
- //
- // Start up other cores and send them to their parking places.
- //
- for (CpuIndex = 1; CpuIndex < RK32_CPU_COUNT; CpuIndex += 1) {
- Cpu = (VOID *)((UINTN)ParkedAddress +
- (CpuIndex * RK32_CPU_PARKED_ADDRESS_SIZE));
- EfiRk32ProcessorJumpAddress = Cpu +
- ARM_PARKING_PROTOCOL_FIRMWARE_OFFSET;
- EfiRk32ProcessorId = RK32_PROCESSOR_ID_BASE + CpuIndex;
- //
- // Power up the core by clearing the power down control for the core.
- //
- Value = EfiReadRegister32(Pmu + Rk32PmuPowerDownControl);
- Value &= ~(RK32_PMU_POWER_DOWN_CONTROL_A17_0 << CpuIndex);
- EfiWriteRegister32(Pmu + Rk32PmuPowerDownControl, Value);
- //
- // Take the core out of reset. Deasserting reset means writing a 0,
- // and the reset protect tells the register which bits to listen to.
- //
- Bit = RK32_CRU_SOFT_RESET0_CORE0 << CpuIndex;
- Value = Bit << RK32_CRU_SOFT_RESET0_PROTECT_SHIFT;
- EfiWriteRegister32(Cru + Rk32CruSoftReset0, Value);
- //
- // Wait for the status bit to clear.
- //
- do {
- Value = EfiReadRegister32(Pmu + Rk32PmuPowerDownStatus);
- } while ((Value & (RK32_PMU_POWER_DOWN_STATUS_A17_0 << CpuIndex)) != 0);
- //
- // The other cores are sitting in their own parking loop off in SRAM.
- // bring them out of that and into this parking loop.
- //
- Sram = (UINT32 *)RK32_SRAM_BASE;
- Sram[2] = (UINT32)EfipRk32ProcessorStartup;
- Sram[1] = 0xDEADBEAF;
- //
- // Send an event to wake the core up.
- //
- EfipRk32SendEvent();
- //
- // Wait for the CPU to come to life. For some reason marking the
- // variable as volatile doesn't seem to prevent optimization.
- //
- while (EfiReadRegister32(&EfiRk32ProcessorJumpAddress) != (UINTN)NULL) {
- NOTHING;
- }
- }
- return EFI_SUCCESS;
- }
- //
- // --------------------------------------------------------- Internal Functions
- //
|