1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195 |
- /*++
- Copyright (c) 2015 Minoca Corp. All Rights Reserved
- Module Name:
- sd.c
- Abstract:
- This module implements RK3288 SD support in UEFI.
- Author:
- Chris Stevens 14-Jul-2015
- Environment:
- Firmware
- --*/
- //
- // ------------------------------------------------------------------- Includes
- //
- #include <uefifw.h>
- #include <dev/sddwc.h>
- #include <minoca/uefi/protocol/blockio.h>
- #include "veyronfw.h"
- //
- // --------------------------------------------------------------------- Macros
- //
- //
- // This macro returns a pointer to the disk I/O data given a pointer to the
- // block I/O protocol instance.
- //
- #define EFI_SD_RK32_FROM_THIS(_BlockIo) \
- (EFI_SD_RK32_CONTEXT *)((VOID *)(_BlockIo) - \
- ((VOID *)(&(((EFI_SD_RK32_CONTEXT *)0)->BlockIo))))
- //
- // These macros read and write SD controller registers.
- //
- #define SD_RK32_READ_REGISTER(_Device, _Register) \
- EfiReadRegister32((_Device)->ControllerBase + (_Register))
- #define SD_RK32_WRITE_REGISTER(_Device, _Register, _Value) \
- EfiWriteRegister32((_Device)->ControllerBase + (_Register), (_Value))
- //
- // ---------------------------------------------------------------- Definitions
- //
- #define EFI_SD_RK32_MAGIC 0x6B526453 // 'kRdS'
- #define EFI_SD_RK32_BLOCK_IO_DEVICE_PATH_GUID \
- { \
- 0xCF31FAC5, 0xC24E, 0x11D2, \
- {0x85, 0xF3, 0x00, 0xA0, 0xC9, 0x3E, 0xA7, 0x39} \
- }
- //
- // Define the amount of time to wait in microseconds for the controller to
- // respond.
- //
- #define EFI_SD_RK32_TIMEOUT 1000000
- //
- // Define the speed of the SD fundamental clock. This is based on the general
- // PLL, which is set up by the previous loader to be 594MHz.
- //
- #define EFI_SD_RK32_CLOCK_SPEED 594000000
- //
- // ------------------------------------------------------ Data Type Definitions
- //
- /*++
- Structure Description:
- This structure describes the SD RK32 device context.
- Members:
- Magic - Stores the magic constand EFI_SD_RK32_MAGIC.
- Handle - Stores the handle to the block I/O device.
- DevicePath - Stores a pointer to the device path.
- Controller - Stores an pointer to the controller structure.
- ControllerBase - Stores a pointer to the virtual address of the HSMMC
- registers.
- FundamentalClock - Stores the fundamental clock for the HSMMC device in
- Hertz.
- MediaPresent - Stores a boolean indicating whether or not there is a card
- in the slot.
- BlockSize - Stores the cached block size of the media.
- BlockCount - Stores the cached block count of the media.
- BlockIo - Stores the block I/O protocol.
- Media - Stores the block I/O media information.
- --*/
- typedef struct _EFI_SD_RK32_CONTEXT {
- UINT32 Magic;
- EFI_HANDLE Handle;
- EFI_DEVICE_PATH_PROTOCOL *DevicePath;
- PEFI_SD_DWC_CONTROLLER Controller;
- VOID *ControllerBase;
- UINT32 FundamentalClock;
- BOOLEAN MediaPresent;
- UINT32 BlockSize;
- UINT64 BlockCount;
- EFI_BLOCK_IO_PROTOCOL BlockIo;
- EFI_BLOCK_IO_MEDIA Media;
- } EFI_SD_RK32_CONTEXT, *PEFI_SD_RK32_CONTEXT;
- /*++
- Structure Description:
- This structure defines the SD RK32 block I/O device path.
- Members:
- DevicePath - Stores the standard vendor-specific device path.
- ControllerBase - Stores the controller number.
- --*/
- typedef struct _EFI_SD_RK32_BLOCK_IO_DEVICE_PATH {
- VENDOR_DEVICE_PATH DevicePath;
- UINT32 ControllerBase;
- } EFI_SD_RK32_BLOCK_IO_DEVICE_PATH, *PEFI_SD_RK32_BLOCK_IO_DEVICE_PATH;
- /*++
- Structure Description:
- This structure defines the RK32 SD block I/O device path.
- Members:
- Disk - Stores the disk device path node.
- End - Stores the end device path node.
- --*/
- typedef struct _EFI_SD_RK32_DEVICE_PATH {
- EFI_SD_RK32_BLOCK_IO_DEVICE_PATH Disk;
- EFI_DEVICE_PATH_PROTOCOL End;
- } PACKED EFI_SD_RK32_DEVICE_PATH, *PEFI_SD_RK32_DEVICE_PATH;
- //
- // ----------------------------------------------- Internal Function Prototypes
- //
- EFI_STATUS
- EfipVeyronEnumerateSdController (
- UINT32 ControllerBase,
- BOOLEAN RemovableMedia
- );
- EFIAPI
- EFI_STATUS
- EfipSdRk32Reset (
- EFI_BLOCK_IO_PROTOCOL *This,
- BOOLEAN ExtendedVerification
- );
- EFIAPI
- EFI_STATUS
- EfipSdRk32ReadBlocks (
- EFI_BLOCK_IO_PROTOCOL *This,
- UINT32 MediaId,
- EFI_LBA Lba,
- UINTN BufferSize,
- VOID *Buffer
- );
- EFIAPI
- EFI_STATUS
- EfipSdRk32WriteBlocks (
- EFI_BLOCK_IO_PROTOCOL *This,
- UINT32 MediaId,
- EFI_LBA Lba,
- UINTN BufferSize,
- VOID *Buffer
- );
- EFIAPI
- EFI_STATUS
- EfipSdRk32FlushBlocks (
- EFI_BLOCK_IO_PROTOCOL *This
- );
- EFI_STATUS
- EfipSdRk32GetFundamentalClock (
- PEFI_SD_RK32_CONTEXT Device,
- UINT32 *FundamentalClock
- );
- EFI_STATUS
- EfipSdRk32HardResetController (
- PEFI_SD_RK32_CONTEXT Device
- );
- EFI_STATUS
- EfipSdRk32GetSetClockSpeed (
- PEFI_SD_CONTROLLER Controller,
- VOID *Context,
- UINT32 *ClockSpeed,
- BOOLEAN Set
- );
- EFI_STATUS
- EfipSdRk32SetClockSpeed (
- PEFI_SD_RK32_CONTEXT Disk,
- UINT32 ClockSpeed
- );
- //
- // -------------------------------------------------------------------- Globals
- //
- //
- // Define the private data template.
- //
- EFI_SD_RK32_CONTEXT EfiSdRk32DiskTemplate = {
- EFI_SD_RK32_MAGIC,
- NULL,
- NULL,
- NULL,
- NULL,
- 0,
- FALSE,
- 0,
- 0,
- {
- EFI_BLOCK_IO_PROTOCOL_REVISION3,
- NULL,
- EfipSdRk32Reset,
- EfipSdRk32ReadBlocks,
- EfipSdRk32WriteBlocks,
- EfipSdRk32FlushBlocks
- }
- };
- //
- // Define the device path template.
- //
- EFI_SD_RK32_DEVICE_PATH EfiSdRk32DevicePathTemplate = {
- {
- {
- {
- HARDWARE_DEVICE_PATH,
- HW_VENDOR_DP,
- sizeof(EFI_SD_RK32_BLOCK_IO_DEVICE_PATH)
- },
- EFI_SD_RK32_BLOCK_IO_DEVICE_PATH_GUID,
- },
- 0xFFFFFFFF
- },
- {
- END_DEVICE_PATH_TYPE,
- END_ENTIRE_DEVICE_PATH_SUBTYPE,
- END_DEVICE_PATH_LENGTH
- }
- };
- SD_FUNCTION_TABLE EfiSdRk32FunctionTable = {
- NULL,
- NULL,
- NULL,
- NULL,
- EfipSdRk32GetSetClockSpeed
- };
- //
- // ------------------------------------------------------------------ Functions
- //
- EFI_STATUS
- EfipVeyronEnumerateSd (
- VOID
- )
- /*++
- Routine Description:
- This routine enumerates the SD card on the Veyron SoC.
- Arguments:
- None.
- Return Value:
- EFI status code.
- --*/
- {
- EFI_STATUS Status;
- Status = EfipVeyronEnumerateSdController(RK32_SD_BASE, TRUE);
- if (EFI_ERROR(Status)) {
- return Status;
- }
- //
- // Only enumerate eMMC if the firmware was not loaded from SD. Enumerating
- // eMMC will cause NV variables to be loaded from there, which will specify
- // a BootOrder of eMMC first. The user likely didn't go to all the trouble
- // of booting via SD only to have this firmware launch the eMMC boot option.
- //
- if (EfiBootedViaSd == FALSE) {
- Status = EfipVeyronEnumerateSdController(RK32_EMMC_BASE, FALSE);
- }
- return Status;
- }
- //
- // --------------------------------------------------------- Internal Functions
- //
- EFI_STATUS
- EfipVeyronEnumerateSdController (
- UINT32 ControllerBase,
- BOOLEAN RemovableMedia
- )
- /*++
- Routine Description:
- This routine enumerates the an SD or eMMC controller on the Veyron.
- Arguments:
- ControllerBase - Supplies the physical address of the controller to
- enumerate.
- RemovableMedia - Supplies a boolean whether or not the controller is
- connected to removable media.
- Return Value:
- EFI status code.
- --*/
- {
- UINT64 BlockCount;
- UINT32 BlockSize;
- PEFI_SD_RK32_DEVICE_PATH DevicePath;
- PEFI_SD_RK32_CONTEXT Disk;
- EFI_SD_DWC_INITIALIZATION_BLOCK SdDwcParameters;
- EFI_STATUS Status;
- //
- // Allocate and initialize the context structure.
- //
- Status = EfiAllocatePool(EfiBootServicesData,
- sizeof(EFI_SD_RK32_CONTEXT),
- (VOID **)&Disk);
- if (EFI_ERROR(Status)) {
- return Status;
- }
- EfiCopyMem(Disk, &EfiSdRk32DiskTemplate, sizeof(EFI_SD_RK32_CONTEXT));
- Disk->Handle = NULL;
- Disk->ControllerBase = (VOID *)(UINTN)ControllerBase;
- Disk->BlockIo.Media = &(Disk->Media);
- Disk->Media.RemovableMedia = RemovableMedia;
- //
- // Create the device path.
- //
- Status = EfiAllocatePool(EfiBootServicesData,
- sizeof(EFI_SD_RK32_DEVICE_PATH),
- (VOID **)&DevicePath);
- if (EFI_ERROR(Status)) {
- goto VeyronEnumerateSdControllerEnd;
- }
- EfiCopyMem(DevicePath,
- &EfiSdRk32DevicePathTemplate,
- sizeof(EFI_SD_RK32_DEVICE_PATH));
- DevicePath->Disk.ControllerBase = ControllerBase;
- DevicePath->Disk.DevicePath.Guid.Data4[0] += RemovableMedia;
- Disk->DevicePath = (EFI_DEVICE_PATH_PROTOCOL *)DevicePath;
- Status = EfipSdRk32GetFundamentalClock(Disk, &(Disk->FundamentalClock));
- if (EFI_ERROR(Status)) {
- goto VeyronEnumerateSdControllerEnd;
- }
- //
- // Create the SD controller.
- //
- EfiSetMem(&SdDwcParameters, sizeof(EFI_SD_DWC_INITIALIZATION_BLOCK), 0);
- SdDwcParameters.ControllerBase = Disk->ControllerBase;
- SdDwcParameters.Voltages = SD_VOLTAGE_32_33 | SD_VOLTAGE_33_34;
- SdDwcParameters.HostCapabilities = SD_MODE_4BIT |
- SD_MODE_HIGH_SPEED |
- SD_MODE_AUTO_CMD12;
- SdDwcParameters.FundamentalClock = Disk->FundamentalClock;
- SdDwcParameters.OverrideFunctionTable = &EfiSdRk32FunctionTable;
- SdDwcParameters.OverrideContext = Disk;
- Disk->Controller = EfiSdDwcCreateController(&SdDwcParameters);
- if (Disk->Controller == NULL) {
- Status = EFI_OUT_OF_RESOURCES;
- goto VeyronEnumerateSdControllerEnd;
- }
- //
- // Reset the controller.
- //
- Status = EfipSdRk32HardResetController(Disk);
- if (EFI_ERROR(Status)) {
- goto VeyronEnumerateSdControllerEnd;
- }
- //
- // Perform some initialization to see if the card is there.
- //
- Status = EfiSdDwcInitializeController(Disk->Controller, FALSE);
- if (!EFI_ERROR(Status)) {
- Status = EfiSdDwcGetMediaParameters(Disk->Controller,
- &BlockCount,
- &BlockSize);
- if (!EFI_ERROR(Status)) {
- Disk->MediaPresent = TRUE;
- Disk->BlockSize = BlockSize;
- Disk->BlockCount = BlockCount;
- Disk->Media.MediaPresent = TRUE;
- Disk->Media.BlockSize = BlockSize;
- Disk->Media.LastBlock = BlockCount - 1;
- }
- }
- Status = EfiInstallMultipleProtocolInterfaces(&(Disk->Handle),
- &EfiDevicePathProtocolGuid,
- Disk->DevicePath,
- &EfiBlockIoProtocolGuid,
- &(Disk->BlockIo),
- NULL);
- VeyronEnumerateSdControllerEnd:
- if (EFI_ERROR(Status)) {
- if (Disk != NULL) {
- if (Disk->DevicePath != NULL) {
- EfiFreePool(DevicePath);
- }
- if (Disk->Controller != NULL) {
- EfiSdDwcDestroyController(Disk->Controller);
- }
- EfiFreePool(Disk);
- }
- }
- return Status;
- }
- EFIAPI
- EFI_STATUS
- EfipSdRk32Reset (
- EFI_BLOCK_IO_PROTOCOL *This,
- BOOLEAN ExtendedVerification
- )
- /*++
- Routine Description:
- This routine resets the block device.
- Arguments:
- This - Supplies a pointer to the protocol instance.
- ExtendedVerification - Supplies a boolean indicating whether or not the
- driver should perform diagnostics on reset.
- Return Value:
- EFI_SUCCESS on success.
- EFI_DEVICE_ERROR if the device had an error and could not complete the
- request.
- --*/
- {
- PEFI_SD_RK32_CONTEXT Disk;
- EFI_STATUS Status;
- Disk = EFI_SD_RK32_FROM_THIS(This);
- Status = EfiSdDwcInitializeController(Disk->Controller, TRUE);
- if (EFI_ERROR(Status)) {
- Disk->MediaPresent = FALSE;
- Disk->Media.MediaPresent = FALSE;
- } else {
- Disk->Media.MediaId += 1;
- Disk->Media.MediaPresent = TRUE;
- Disk->MediaPresent = TRUE;
- }
- return Status;
- }
- EFIAPI
- EFI_STATUS
- EfipSdRk32ReadBlocks (
- EFI_BLOCK_IO_PROTOCOL *This,
- UINT32 MediaId,
- EFI_LBA Lba,
- UINTN BufferSize,
- VOID *Buffer
- )
- /*++
- Routine Description:
- This routine performs a block I/O read from the device.
- Arguments:
- This - Supplies a pointer to the protocol instance.
- MediaId - Supplies the media identifier, which changes each time the media
- is replaced.
- Lba - Supplies the logical block address of the read.
- BufferSize - Supplies the size of the buffer in bytes.
- Buffer - Supplies the buffer where the read data will be returned.
- Return Value:
- EFI_SUCCESS on success.
- EFI_DEVICE_ERROR if the device had an error and could not complete the
- request.
- EFI_NO_MEDIA if there is no media in the device.
- EFI_MEDIA_CHANGED if the media ID does not match the current device.
- EFI_BAD_BUFFER_SIZE if the buffer was not a multiple of the device block
- size.
- EFI_INVALID_PARAMETER if the read request contains LBAs that are not valid,
- or the buffer is not properly aligned.
- --*/
- {
- PEFI_SD_RK32_CONTEXT Disk;
- EFI_STATUS Status;
- Disk = EFI_SD_RK32_FROM_THIS(This);
- if (MediaId != Disk->Media.MediaId) {
- return EFI_MEDIA_CHANGED;
- }
- if ((Disk->MediaPresent == FALSE) || (Disk->BlockSize == 0)) {
- return EFI_NO_MEDIA;
- }
- Status = EfiSdDwcBlockIoPolled(Disk->Controller,
- Lba,
- BufferSize / Disk->BlockSize,
- Buffer,
- FALSE);
- return Status;
- }
- EFIAPI
- EFI_STATUS
- EfipSdRk32WriteBlocks (
- EFI_BLOCK_IO_PROTOCOL *This,
- UINT32 MediaId,
- EFI_LBA Lba,
- UINTN BufferSize,
- VOID *Buffer
- )
- /*++
- Routine Description:
- This routine performs a block I/O write to the device.
- Arguments:
- This - Supplies a pointer to the protocol instance.
- MediaId - Supplies the media identifier, which changes each time the media
- is replaced.
- Lba - Supplies the logical block address of the write.
- BufferSize - Supplies the size of the buffer in bytes.
- Buffer - Supplies the buffer containing the data to write.
- Return Value:
- EFI_SUCCESS on success.
- EFI_WRITE_PROTECTED if the device cannot be written to.
- EFI_DEVICE_ERROR if the device had an error and could not complete the
- request.
- EFI_NO_MEDIA if there is no media in the device.
- EFI_MEDIA_CHANGED if the media ID does not match the current device.
- EFI_BAD_BUFFER_SIZE if the buffer was not a multiple of the device block
- size.
- EFI_INVALID_PARAMETER if the read request contains LBAs that are not valid,
- or the buffer is not properly aligned.
- --*/
- {
- PEFI_SD_RK32_CONTEXT Disk;
- EFI_STATUS Status;
- Disk = EFI_SD_RK32_FROM_THIS(This);
- if (MediaId != Disk->Media.MediaId) {
- return EFI_MEDIA_CHANGED;
- }
- if ((Disk->MediaPresent == FALSE) || (Disk->BlockSize == 0)) {
- return EFI_NO_MEDIA;
- }
- Status = EfiSdDwcBlockIoPolled(Disk->Controller,
- Lba,
- BufferSize / Disk->BlockSize,
- Buffer,
- TRUE);
- return Status;
- }
- EFIAPI
- EFI_STATUS
- EfipSdRk32FlushBlocks (
- EFI_BLOCK_IO_PROTOCOL *This
- )
- /*++
- Routine Description:
- This routine flushes the block device.
- Arguments:
- This - Supplies a pointer to the protocol instance.
- Return Value:
- EFI_SUCCESS on success.
- EFI_DEVICE_ERROR if the device had an error and could not complete the
- request.
- EFI_NO_MEDIA if there is no media in the device.
- --*/
- {
- return EFI_SUCCESS;
- }
- EFI_STATUS
- EfipSdRk32GetFundamentalClock (
- PEFI_SD_RK32_CONTEXT Device,
- UINT32 *FundamentalClock
- )
- /*++
- Routine Description:
- This routine gets the fundamental clock frequency to use for the SD
- controller.
- Arguments:
- Device - Supplies a pointer to this SD RK32 device.
- FundamentalClock - Supplies a pointer that receives the frequency of the
- fundamental clock, in Hertz.
- Return Value:
- Status code.
- --*/
- {
- *FundamentalClock = EFI_SD_RK32_CLOCK_SPEED;
- return EFI_SUCCESS;
- }
- EFI_STATUS
- EfipSdRk32HardResetController (
- PEFI_SD_RK32_CONTEXT Device
- )
- /*++
- Routine Description:
- This routine resets the DesignWare SD controller and card.
- Arguments:
- Device - Supplies a pointer to this SD RK32 device.
- Return Value:
- Status code.
- --*/
- {
- UINT32 ResetMask;
- EFI_STATUS Status;
- UINT64 Time;
- UINT64 Timeout;
- UINT32 Value;
- //
- // First perform a hardware reset on the SD card.
- //
- SD_RK32_WRITE_REGISTER(Device, SdDwcPower, SD_DWC_POWER_DISABLE);
- SD_RK32_WRITE_REGISTER(Device, SdDwcResetN, SD_DWC_RESET_ENABLE);
- EfiStall(5000);
- SD_RK32_WRITE_REGISTER(Device, SdDwcPower, SD_DWC_POWER_ENABLE);
- SD_RK32_WRITE_REGISTER(Device, SdDwcResetN, 0);
- EfiStall(1000);
- //
- // Perform a complete controller reset and wait for it to complete.
- //
- ResetMask = SD_DWC_CONTROL_FIFO_RESET |
- SD_DWC_CONTROL_CONTROLLER_RESET;
- SD_RK32_WRITE_REGISTER(Device, SdDwcControl, ResetMask);
- Status = EFI_TIMEOUT;
- Timeout = EFI_SD_RK32_TIMEOUT;
- Time = 0;
- do {
- Value = SD_RK32_READ_REGISTER(Device, SdDwcControl);
- if ((Value & ResetMask) == 0) {
- Status = EFI_SUCCESS;
- break;
- }
- EfiStall(50);
- Time += 50;
- } while (Time <= Timeout);
- if (EFI_ERROR(Status)) {
- return Status;
- }
- //
- // Clear interrupts.
- //
- SD_RK32_WRITE_REGISTER(Device,
- SdDwcInterruptStatus,
- SD_DWC_INTERRUPT_STATUS_ALL_MASK);
- //
- // Set 3v3 volts in the UHS register.
- //
- SD_RK32_WRITE_REGISTER(Device, SdDwcUhs, SD_DWC_UHS_VOLTAGE_3V3);
- //
- // Set the clock to 400kHz in preparation for sending CMD0 with the
- // initialization bit set.
- //
- Status = EfipSdRk32SetClockSpeed(Device, 400000);
- if (EFI_ERROR(Status)) {
- return Status;
- }
- //
- // Reset the card by sending the CMD0 reset command with the initialization
- // bit set.
- //
- Value = SD_DWC_COMMAND_START |
- SD_DWC_COMMAND_USE_HOLD_REGISTER |
- SD_DWC_COMMAND_SEND_INITIALIZATION;
- SD_RK32_WRITE_REGISTER(Device, SdDwcCommand, Value);
- //
- // Wait for the command to complete.
- //
- Status = EFI_TIMEOUT;
- Timeout = EFI_SD_RK32_TIMEOUT;
- Time = 0;
- do {
- Value = SD_RK32_READ_REGISTER(Device, SdDwcCommand);
- if ((Value & SD_DWC_COMMAND_START) == 0) {
- Status = EFI_SUCCESS;
- break;
- }
- EfiStall(50);
- Time += 50;
- } while (Time <= Timeout);
- if (EFI_ERROR(Status)) {
- return Status;
- }
- Timeout = EFI_SD_RK32_TIMEOUT;
- Time = 0;
- Status = EFI_TIMEOUT;
- do {
- Value = SD_RK32_READ_REGISTER(Device, SdDwcInterruptStatus);
- if (Value != 0) {
- if ((Value & SD_DWC_INTERRUPT_STATUS_COMMAND_DONE) != 0) {
- Status = EFI_SUCCESS;
- } else if ((Value &
- SD_DWC_INTERRUPT_STATUS_ERROR_RESPONSE_TIMEOUT) != 0) {
- Status = EFI_NO_MEDIA;
- } else {
- Status = EFI_DEVICE_ERROR;
- }
- SD_RK32_WRITE_REGISTER(Device, SdDwcInterruptStatus, Value);
- break;
- }
- EfiStall(50);
- Time += 50;
- } while (Time <= Timeout);
- if (EFI_ERROR(Status)) {
- return Status;
- }
- return EFI_SUCCESS;
- }
- EFI_STATUS
- EfipSdRk32GetSetClockSpeed (
- PEFI_SD_CONTROLLER Controller,
- VOID *Context,
- UINT32 *ClockSpeed,
- BOOLEAN Set
- )
- /*++
- Routine Description:
- This routine gets or sets the controller's clock speed.
- Arguments:
- Controller - Supplies a pointer to the controller.
- Context - Supplies a context pointer passed to the SD/MMC library upon
- creation of the controller.
- ClockSpeed - Supplies a pointer that receives the current clock speed on
- get and contains the desired clock speed on set.
- Set - Supplies a boolean indicating whether the bus width should be queried
- or set.
- Return Value:
- Status code.
- --*/
- {
- PEFI_SD_RK32_CONTEXT Disk;
- Disk = Context;
- //
- // Getting the clock speed is not implemented as the divisor math might not
- // work out precisely in reverse.
- //
- if (Set == FALSE) {
- return EFI_UNSUPPORTED;
- }
- return EfipSdRk32SetClockSpeed(Disk, *ClockSpeed);
- }
- EFI_STATUS
- EfipSdRk32SetClockSpeed (
- PEFI_SD_RK32_CONTEXT Disk,
- UINT32 ClockSpeed
- )
- /*++
- Routine Description:
- This routine sets the controller's clock speed.
- Arguments:
- Disk - Supplies a pointer to the disk context.
- ClockSpeed - Supplies the desired clock speed in Hertz.
- Return Value:
- Status code.
- --*/
- {
- UINT32 Divisor;
- PEFI_SD_DWC_CONTROLLER DwcController;
- UINT32 InputClock;
- EFI_STATUS Status;
- UINT64 Time;
- UINT64 Timeout;
- UINT32 Value;
- DwcController = Disk->Controller;
- if (DwcController->FundamentalClock == 0) {
- return EFI_INVALID_PARAMETER;
- }
- //
- // Wait for the card to not be busy.
- //
- Timeout = EFI_SD_DWC_CONTROLLER_TIMEOUT;
- Time = 0;
- Status = EFI_TIMEOUT;
- do {
- Value = SD_DWC_READ_REGISTER(DwcController, SdDwcStatus);
- if ((Value & SD_DWC_STATUS_DATA_BUSY) == 0) {
- Status = EFI_SUCCESS;
- break;
- }
- EfiStall(50);
- Time += 50;
- } while (Time <= Timeout);
- if (EFI_ERROR(Status)) {
- return Status;
- }
- //
- // Disable all clocks.
- //
- SD_DWC_WRITE_REGISTER(DwcController, SdDwcClockEnable, 0);
- //
- // Send the command to indicate that the clock enable register is being
- // updated.
- //
- Value = SD_DWC_COMMAND_START |
- SD_DWC_COMMAND_UPDATE_CLOCK_REGISTERS |
- SD_DWC_COMMAND_WAIT_PREVIOUS_DATA_COMPLETE;
- SD_DWC_WRITE_REGISTER(DwcController, SdDwcCommand, Value);
- Timeout = EFI_SD_DWC_CONTROLLER_TIMEOUT;
- Time = 0;
- Status = EFI_TIMEOUT;
- do {
- Value = SD_DWC_READ_REGISTER(DwcController, SdDwcCommand);
- if ((Value & SD_DWC_COMMAND_START) == 0) {
- Status = EFI_SUCCESS;
- break;
- }
- EfiStall(50);
- Time += 50;
- } while (Time <= Timeout);
- if (EFI_ERROR(Status)) {
- return Status;
- }
- //
- // Use the 24MHz clock if a really slow speed is desired.
- //
- InputClock = DwcController->FundamentalClock;
- if (ClockSpeed < (InputClock / (RK32_CRU_MAX_MMC_DIVISOR + 1))) {
- //
- // Select the raw 24MHz source, and set the DesignWare divider to 1 to
- // divide by 2.
- //
- InputClock = RK32_SDMMC_FREQUENCY_24MHZ / 2;
- SD_DWC_WRITE_REGISTER(DwcController, SdDwcClockDivider, 1);
- Value = (RK32_CRU_CLOCK_SELECT_24MHZ <<
- RK32_CRU_CLOCK_SELECT_CLOCK_SHIFT);
- //
- // Use the general PLL.
- //
- } else {
- SD_DWC_WRITE_REGISTER(DwcController, SdDwcClockDivider, 0);
- Value = (RK32_CRU_CLOCK_SELECT_GENERAL_PLL <<
- RK32_CRU_CLOCK_SELECT_CLOCK_SHIFT);
- }
- Divisor = InputClock / ClockSpeed;
- if (InputClock / Divisor > ClockSpeed) {
- Divisor += 1;
- }
- //
- // Bits 16 and up must be set for the write to take effect. This is also
- // why read-modify-write is not needed.
- //
- Value |= (RK32_CRU_CLOCK_SELECT_CLOCK_MASK |
- RK32_CRU_CLOCK_SELECT_DIVIDER_MASK) <<
- RK32_CRU_CLOCK_SELECT_PROTECT_SHIFT;
- Value |= Divisor;
- if (Disk->ControllerBase == (VOID *)RK32_SD_BASE) {
- RK32_WRITE_CRU(Rk32CruClockSelect11, Value);
- } else if (Disk->ControllerBase == (VOID *)RK32_EMMC_BASE) {
- Value <<= RK32_CRU_CLOCK_SELECT12_EMMC_DIVIDER_SHIFT;
- RK32_WRITE_CRU(Rk32CruClockSelect12, Value);
- } else {
- return EFI_UNSUPPORTED;
- }
- SD_DWC_WRITE_REGISTER(DwcController,
- SdDwcClockSource,
- SD_DWC_CLOCK_SOURCE_DIVIDER_0);
- //
- // Send the command to indicate that the clock source and divider are is
- // being updated.
- //
- Value = SD_DWC_COMMAND_START |
- SD_DWC_COMMAND_UPDATE_CLOCK_REGISTERS |
- SD_DWC_COMMAND_WAIT_PREVIOUS_DATA_COMPLETE;
- SD_DWC_WRITE_REGISTER(DwcController, SdDwcCommand, Value);
- Timeout = EFI_SD_DWC_CONTROLLER_TIMEOUT;
- Time = 0;
- Status = EFI_TIMEOUT;
- do {
- Value = SD_DWC_READ_REGISTER(DwcController, SdDwcCommand);
- if ((Value & SD_DWC_COMMAND_START) == 0) {
- Status = EFI_SUCCESS;
- break;
- }
- EfiStall(50);
- Time += 50;
- } while (Time <= Timeout);
- if (EFI_ERROR(Status)) {
- return Status;
- }
- //
- // Enable the clocks in lower power mode.
- //
- SD_DWC_WRITE_REGISTER(DwcController,
- SdDwcClockEnable,
- (SD_DWC_CLOCK_ENABLE_LOW_POWER |
- SD_DWC_CLOCK_ENABLE_ON));
- //
- // Send the command to indicate that the clock is enable register being
- // updated.
- //
- Value = SD_DWC_COMMAND_START |
- SD_DWC_COMMAND_UPDATE_CLOCK_REGISTERS |
- SD_DWC_COMMAND_WAIT_PREVIOUS_DATA_COMPLETE;
- SD_DWC_WRITE_REGISTER(DwcController, SdDwcCommand, Value);
- Timeout = EFI_SD_DWC_CONTROLLER_TIMEOUT;
- Time = 0;
- Status = EFI_TIMEOUT;
- do {
- Value = SD_DWC_READ_REGISTER(DwcController, SdDwcCommand);
- if ((Value & SD_DWC_COMMAND_START) == 0) {
- Status = EFI_SUCCESS;
- break;
- }
- EfiStall(50);
- Time += 50;
- } while (Time <= Timeout);
- if (EFI_ERROR(Status)) {
- return Status;
- }
- return EFI_SUCCESS;
- }
|