12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157115811591160116111621163116411651166116711681169117011711172117311741175117611771178117911801181118211831184118511861187118811891190119111921193119411951196119711981199120012011202120312041205120612071208120912101211121212131214121512161217121812191220122112221223122412251226122712281229123012311232123312341235123612371238123912401241124212431244124512461247124812491250125112521253125412551256125712581259126012611262126312641265126612671268126912701271127212731274127512761277127812791280128112821283128412851286128712881289129012911292129312941295129612971298129913001301130213031304130513061307130813091310131113121313131413151316131713181319132013211322132313241325132613271328132913301331133213331334133513361337133813391340134113421343134413451346134713481349135013511352135313541355135613571358135913601361136213631364136513661367136813691370137113721373137413751376137713781379138013811382138313841385138613871388138913901391139213931394139513961397139813991400140114021403140414051406140714081409141014111412141314141415141614171418141914201421142214231424142514261427142814291430143114321433143414351436143714381439144014411442144314441445144614471448144914501451145214531454145514561457145814591460146114621463146414651466146714681469147014711472147314741475147614771478147914801481148214831484148514861487148814891490149114921493149414951496149714981499150015011502150315041505150615071508150915101511151215131514151515161517151815191520152115221523152415251526152715281529153015311532153315341535153615371538153915401541154215431544154515461547154815491550155115521553155415551556155715581559156015611562156315641565156615671568156915701571157215731574157515761577157815791580158115821583158415851586158715881589159015911592159315941595159615971598159916001601160216031604160516061607160816091610161116121613161416151616161716181619162016211622162316241625162616271628162916301631163216331634163516361637163816391640164116421643164416451646164716481649 |
- /*++
- Copyright (c) 2015 Minoca Corp.
- This file is licensed under the terms of the GNU General Public License
- version 3. Alternative licensing terms are available. Contact
- info@minocacorp.com for details. See the LICENSE file at the root of this
- project for complete licensing information.
- Module Name:
- sddwc.c
- Abstract:
- This module implements the library functionality for the DesignWare SD/MMC
- device.
- Author:
- Chris Stevens 16-Jul-2015
- Environment:
- Firmware
- --*/
- //
- // ------------------------------------------------------------------- Includes
- //
- #include <uefifw.h>
- #include <dev/sddwc.h>
- //
- // --------------------------------------------------------------------- Macros
- //
- //
- // ---------------------------------------------------------------- Definitions
- //
- //
- // ------------------------------------------------------ Data Type Definitions
- //
- //
- // ----------------------------------------------- Internal Function Prototypes
- //
- EFI_STATUS
- EfipSdDwcInitializeController (
- PEFI_SD_CONTROLLER Controller,
- VOID *Context,
- UINT32 Phase
- );
- EFI_STATUS
- EfipSdDwcResetController (
- PEFI_SD_CONTROLLER Controller,
- VOID *Context,
- UINT32 Flags
- );
- EFI_STATUS
- EfipSdDwcSendCommand (
- PEFI_SD_CONTROLLER Controller,
- VOID *Context,
- PSD_COMMAND Command
- );
- EFI_STATUS
- EfipSdDwcGetSetBusWidth (
- PEFI_SD_CONTROLLER Controller,
- VOID *Context,
- UINT16 *BusWidth,
- BOOLEAN Set
- );
- EFI_STATUS
- EfipSdDwcGetSetClockSpeed (
- PEFI_SD_CONTROLLER Controller,
- VOID *Context,
- UINT32 *ClockSpeed,
- BOOLEAN Set
- );
- EFI_STATUS
- EfipSdDwcReadData (
- PEFI_SD_CONTROLLER Controller,
- VOID *Context,
- VOID *Data,
- UINT32 Size
- );
- EFI_STATUS
- EfipSdDwcWriteData (
- PEFI_SD_CONTROLLER Controller,
- VOID *Context,
- VOID *Data,
- UINT32 Size
- );
- //
- // -------------------------------------------------------------------- Globals
- //
- SD_FUNCTION_TABLE EfiSdDwcFunctionTable = {
- EfipSdDwcInitializeController,
- EfipSdDwcResetController,
- EfipSdDwcSendCommand,
- EfipSdDwcGetSetBusWidth,
- EfipSdDwcGetSetClockSpeed
- };
- //
- // ------------------------------------------------------------------ Functions
- //
- PEFI_SD_DWC_CONTROLLER
- EfiSdDwcCreateController (
- PEFI_SD_DWC_INITIALIZATION_BLOCK Parameters
- )
- /*++
- Routine Description:
- This routine creates a new DesignWare SD controller object.
- Arguments:
- Parameters - Supplies a pointer to the parameters to use when creating the
- controller. This can be stack allocated, as the DesignWare SD device
- won't use this memory after this routine returns.
- Return Value:
- Returns a pointer to the controller structure on success.
- NULL on allocation failure or if a required parameter was not filled in.
- --*/
- {
- PEFI_SD_DWC_CONTROLLER Controller;
- PEFI_SD_CONTROLLER SdController;
- EFI_SD_INITIALIZATION_BLOCK SdParameters;
- EFI_STATUS Status;
- if (Parameters->ControllerBase == NULL) {
- return NULL;
- }
- SdController = NULL;
- Status = EfiAllocatePool(EfiBootServicesData,
- sizeof(EFI_SD_DWC_CONTROLLER),
- (VOID **)&Controller);
- if (EFI_ERROR(Status)) {
- goto CreateControllerEnd;
- }
- EfiSetMem(Controller, sizeof(EFI_SD_DWC_CONTROLLER), 0);
- Controller->ControllerBase = Parameters->ControllerBase;
- Controller->Voltages = Parameters->Voltages;
- Controller->HostCapabilities = Parameters->HostCapabilities;
- Controller->FundamentalClock = Parameters->FundamentalClock;
- if (Parameters->OverrideFunctionTable != NULL) {
- EfiCopyMem(&(Controller->OverrideFunctionTable),
- Parameters->OverrideFunctionTable,
- sizeof(SD_FUNCTION_TABLE));
- }
- Controller->OverrideContext = Parameters->OverrideContext;
- //
- // Forward this call onto the core SD library for creation.
- //
- EfiSetMem(&SdParameters, sizeof(EFI_SD_INITIALIZATION_BLOCK), 0);
- SdParameters.ConsumerContext = Controller;
- SdParameters.OverrideFunctionTable = &EfiSdDwcFunctionTable;
- SdParameters.Voltages = Parameters->Voltages;
- SdParameters.FundamentalClock = Parameters->FundamentalClock;
- SdParameters.HostCapabilities = Parameters->HostCapabilities;
- SdController = EfiSdCreateController(&SdParameters);
- if (SdController == NULL) {
- Status = EFI_OUT_OF_RESOURCES;
- goto CreateControllerEnd;
- }
- Controller->SdController = SdController;
- Status = EFI_SUCCESS;
- CreateControllerEnd:
- if (EFI_ERROR(Status)) {
- if (SdController != NULL) {
- EfiSdDestroyController(SdController);
- }
- if (Controller != NULL) {
- EfiFreePool(Controller);
- Controller = NULL;
- }
- }
- return Controller;
- }
- VOID
- EfiSdDwcDestroyController (
- PEFI_SD_DWC_CONTROLLER Controller
- )
- /*++
- Routine Description:
- This routine destroys a DesignWare SD controller object.
- Arguments:
- Controller - Supplies a pointer to the controller to destroy.
- Return Value:
- None.
- --*/
- {
- EfiSdDestroyController(Controller->SdController);
- EfiFreePool(Controller);
- return;
- }
- EFI_STATUS
- EfiSdDwcInitializeController (
- PEFI_SD_DWC_CONTROLLER Controller,
- BOOLEAN SoftReset
- )
- /*++
- Routine Description:
- This routine resets and initializes the DesignWare SD host controller.
- Arguments:
- Controller - Supplies a pointer to the controller to initialize.
- SoftReset - Supplies a boolean indicating whether or not to perform a soft
- reset on the controller.
- Return Value:
- Status code.
- --*/
- {
- EFI_STATUS Status;
- Status = EfiSdInitializeController(Controller->SdController, SoftReset);
- if (EFI_ERROR(Status)) {
- goto InitializeControllerEnd;
- }
- InitializeControllerEnd:
- return Status;
- }
- EFI_STATUS
- EfiSdDwcBlockIoPolled (
- PEFI_SD_DWC_CONTROLLER Controller,
- UINT64 BlockOffset,
- UINTN BlockCount,
- VOID *Buffer,
- BOOLEAN Write
- )
- /*++
- Routine Description:
- This routine performs a block I/O read or write using the CPU and not
- DMA.
- Arguments:
- Controller - Supplies a pointer to the controller.
- BlockOffset - Supplies the logical block address of the I/O.
- BlockCount - Supplies the number of blocks to read or write.
- Buffer - Supplies the virtual address of the I/O buffer.
- Write - Supplies a boolean indicating if this is a read operation (FALSE)
- or a write operation.
- Return Value:
- Status code.
- --*/
- {
- EFI_STATUS Status;
- Status = EfiSdBlockIoPolled(Controller->SdController,
- BlockOffset,
- BlockCount,
- Buffer,
- Write);
- return Status;
- }
- EFI_STATUS
- EfiSdDwcGetMediaParameters (
- PEFI_SD_DWC_CONTROLLER Controller,
- UINT64 *BlockCount,
- UINT32 *BlockSize
- )
- /*++
- Routine Description:
- This routine returns information about the media card.
- Arguments:
- Controller - Supplies a pointer to the controller.
- BlockCount - Supplies a pointer where the number of blocks in the user
- area of the medium will be returned.
- BlockSize - Supplies a pointer where the block size of the medium will be
- returned.
- Return Value:
- EFI_SUCCESS on success.
- EFI_NO_MEDIA if there is no card in the slot.
- --*/
- {
- EFI_STATUS Status;
- Status = EfiSdGetMediaParameters(Controller->SdController,
- BlockCount,
- BlockSize);
- return Status;
- }
- EFI_STATUS
- EfiSdDwcSetClockSpeed (
- PEFI_SD_DWC_CONTROLLER DwcController,
- UINT32 ClockSpeed
- )
- /*++
- Routine Description:
- This routine sets the controller's clock speed.
- Arguments:
- DwcController - Supplies a pointer to this DesignWare SD controller.
- ClockSpeed - Supplies the desired clock speed in Hertz.
- Return Value:
- Status code.
- --*/
- {
- UINT32 Divisor;
- EFI_STATUS Status;
- UINT64 Time;
- UINT64 Timeout;
- UINT32 Value;
- 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;
- }
- //
- // Get the appropriate divisor without going over the desired clock speed.
- //
- if (ClockSpeed >= DwcController->FundamentalClock) {
- Divisor = 0;
- } else {
- Divisor = 2;
- while (Divisor < SD_DWC_MAX_DIVISOR) {
- if ((DwcController->FundamentalClock / Divisor) <= ClockSpeed) {
- break;
- }
- Divisor += 2;
- }
- Divisor >>= 1;
- }
- SD_DWC_WRITE_REGISTER(DwcController, SdDwcClockDivider, Divisor);
- 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;
- }
- EFI_STATUS
- EfipSdDwcInitializeController (
- PEFI_SD_CONTROLLER Controller,
- VOID *Context,
- UINT32 Phase
- )
- /*++
- Routine Description:
- This routine performs any controller specific initialization steps.
- Arguments:
- Controller - Supplies a pointer to the controller.
- Context - Supplies a context pointer passed to the SD/MMC library upon
- creation of the controller.
- Phase - Supplies the phase of initialization. Phase 0 happens after the
- initial software reset and Phase 1 happens after the bus width has been
- set to 1 and the speed to 400KHz.
- Return Value:
- Status code.
- --*/
- {
- PEFI_SD_DWC_CONTROLLER DwcController;
- UINT32 Mask;
- EFI_STATUS Status;
- UINT32 Value;
- UINT32 Voltage;
- DwcController = (PEFI_SD_DWC_CONTROLLER)Context;
- if (DwcController->OverrideFunctionTable.InitializeController != NULL) {
- Status = DwcController->OverrideFunctionTable.InitializeController(
- Controller,
- DwcController->OverrideContext,
- Phase);
- return Status;
- }
- //
- // Phase 0 is an early initialization phase that happens after the
- // controller has been set. It is used to gather capabilities and set
- // certain parameters in the hardware.
- //
- if (Phase == 0) {
- Mask = SD_DWC_CONTROL_FIFO_RESET | SD_DWC_CONTROL_CONTROLLER_RESET;
- SD_DWC_WRITE_REGISTER(DwcController, SdDwcControl, Mask);
- do {
- Value = SD_DWC_READ_REGISTER(DwcController, SdDwcControl);
- } while ((Value & Mask) != 0);
- //
- // Set the default burst length.
- //
- Value = (SD_DWC_BUS_MODE_BURST_LENGTH_16 <<
- SD_DWC_BUS_MODE_BURST_LENGTH_SHIFT) |
- SD_DWC_BUS_MODE_FIXED_BURST;
- SD_DWC_WRITE_REGISTER(DwcController, SdDwcBusMode, Value);
- //
- // Set the default FIFO threshold.
- //
- SD_DWC_WRITE_REGISTER(DwcController,
- SdDwcFifoThreshold,
- SD_DWC_FIFO_THRESHOLD_DEFAULT);
- //
- // Set the default timeout.
- //
- SD_DWC_WRITE_REGISTER(DwcController,
- SdDwcTimeout,
- SD_DWC_TIMEOUT_DEFAULT);
- //
- // Set the voltages based on the supported values supplied when the
- // controller was created.
- //
- Voltage = SD_DWC_READ_REGISTER(DwcController, SdDwcUhs);
- Voltage &= ~SD_DWC_UHS_VOLTAGE_MASK;
- if ((DwcController->Voltages &
- (SD_VOLTAGE_32_33 | SD_VOLTAGE_33_34)) ==
- (SD_VOLTAGE_32_33 | SD_VOLTAGE_33_34)) {
- Voltage |= SD_DWC_UHS_VOLTAGE_3V3;
- } else if ((DwcController->Voltages &
- (SD_VOLTAGE_165_195 | SD_VOLTAGE_18)) != 0) {
- Voltage |= SD_DWC_UHS_VOLTAGE_1V8;
- } else {
- Status = EFI_DEVICE_ERROR;
- goto InitializeControllerEnd;
- }
- SD_DWC_WRITE_REGISTER(DwcController, SdDwcUhs, Voltage);
- //
- // Phase 1 happens right before the initialization command sequence is
- // about to begin. The clock and bus width have been program and the device
- // is just about read to go.
- //
- } else if (Phase == 1) {
- //
- // Turn on the power.
- //
- SD_DWC_WRITE_REGISTER(DwcController, SdDwcPower, SD_DWC_POWER_ENABLE);
- //
- // Set the interrupt mask, clear any pending state, and enable the
- // interrupts.
- //
- SD_DWC_WRITE_REGISTER(DwcController, SdDwcInterruptMask, 0);
- SD_DWC_WRITE_REGISTER(DwcController,
- SdDwcInterruptStatus,
- SD_DWC_INTERRUPT_STATUS_ALL_MASK);
- Value = SD_DWC_READ_REGISTER(DwcController, SdDwcControl);
- Value |= SD_DWC_CONTROL_INTERRUPT_ENABLE;
- SD_DWC_WRITE_REGISTER(DwcController, SdDwcControl, Value);
- }
- Status = EFI_SUCCESS;
- InitializeControllerEnd:
- return Status;
- }
- EFI_STATUS
- EfipSdDwcResetController (
- PEFI_SD_CONTROLLER Controller,
- VOID *Context,
- UINT32 Flags
- )
- /*++
- Routine Description:
- This routine performs a soft reset of the SD controller.
- Arguments:
- Controller - Supplies a pointer to the controller.
- Context - Supplies a context pointer passed to the SD/MMC library upon
- creation of the controller.
- Flags - Supplies a bitmask of reset flags. See SD_RESET_FLAG_* for
- definitions.
- Return Value:
- Status code.
- --*/
- {
- PEFI_SD_DWC_CONTROLLER DwcController;
- UINT32 ResetMask;
- EFI_STATUS Status;
- UINT64 Time;
- UINT64 Timeout;
- UINT32 Value;
- DwcController = (PEFI_SD_DWC_CONTROLLER)Context;
- if (DwcController->OverrideFunctionTable.ResetController != NULL) {
- Status = DwcController->OverrideFunctionTable.ResetController(
- Controller,
- DwcController->OverrideContext,
- Flags);
- return Status;
- }
- //
- // Always reset the FIFO, but only reset the whole controller if the all
- // flag was specified.
- //
- ResetMask = SD_DWC_CONTROL_FIFO_RESET;
- if ((Flags & SD_RESET_FLAG_ALL) != 0) {
- ResetMask |= SD_DWC_CONTROL_CONTROLLER_RESET;
- }
- SD_DWC_WRITE_REGISTER(DwcController, SdDwcControl, ResetMask);
- Status = EFI_TIMEOUT;
- Timeout = EFI_SD_DWC_CONTROLLER_TIMEOUT;
- Time = 0;
- do {
- Value = SD_DWC_READ_REGISTER(DwcController, SdDwcControl);
- if ((Value & ResetMask) == 0) {
- Status = EFI_SUCCESS;
- break;
- }
- EfiStall(50);
- Time += 50;
- } while (Time <= Timeout);
- if (EFI_ERROR(Status)) {
- return Status;
- }
- return EFI_SUCCESS;
- }
- EFI_STATUS
- EfipSdDwcSendCommand (
- PEFI_SD_CONTROLLER Controller,
- VOID *Context,
- PSD_COMMAND Command
- )
- /*++
- Routine Description:
- This routine sends the given command to the card.
- Arguments:
- Controller - Supplies a pointer to the controller.
- Context - Supplies a context pointer passed to the SD/MMC library upon
- creation of the controller.
- Command - Supplies a pointer to the command parameters.
- Return Value:
- Status code.
- --*/
- {
- UINT32 CommandValue;
- PEFI_SD_DWC_CONTROLLER DwcController;
- UINT32 Flags;
- EFI_STATUS Status;
- UINT64 Time;
- UINT64 Timeout;
- UINT32 Value;
- DwcController = (PEFI_SD_DWC_CONTROLLER)Context;
- if (DwcController->OverrideFunctionTable.SendCommand != NULL) {
- Status = DwcController->OverrideFunctionTable.SendCommand(
- Controller,
- DwcController->OverrideContext,
- Command);
- return Status;
- }
- //
- // Wait for the last command to complete.
- //
- Value = SD_DWC_READ_REGISTER(DwcController, SdDwcStatus);
- if ((Value & SD_DWC_STATUS_FIFO_EMPTY) == 0) {
- Value = SD_DWC_READ_REGISTER(DwcController, SdDwcControl);
- Value |= SD_DWC_CONTROL_FIFO_RESET;
- SD_DWC_WRITE_REGISTER(DwcController, SdDwcControl, Value);
- Timeout = EFI_SD_DWC_CONTROLLER_TIMEOUT;
- Time = 0;
- Status = EFI_TIMEOUT;
- do {
- Value = SD_DWC_READ_REGISTER(DwcController, SdDwcControl);
- if ((Value & SD_DWC_CONTROL_FIFO_RESET) == 0) {
- Status = EFI_SUCCESS;
- break;
- }
- EfiStall(50);
- Time += 50;
- } while (Time <= Timeout);
- if (EFI_ERROR(Status)) {
- goto SendCommandEnd;
- }
- }
- //
- // Clear any old interrupt status.
- //
- SD_DWC_WRITE_REGISTER(DwcController,
- SdDwcInterruptStatus,
- SD_DWC_INTERRUPT_STATUS_ALL_MASK);
- //
- // Set up the response flags.
- //
- Flags = SD_DWC_COMMAND_WAIT_PREVIOUS_DATA_COMPLETE;
- if (Command->Command == SdCommandReset) {
- Flags |= SD_DWC_COMMAND_SEND_INITIALIZATION;
- }
- if ((Command->ResponseType & SD_RESPONSE_PRESENT) != 0) {
- if ((Command->ResponseType & SD_RESPONSE_136_BIT) != 0) {
- Flags |= SD_DWC_COMMAND_LONG_RESPONSE;
- }
- Flags |= SD_DWC_COMMAND_RESPONSE_EXPECTED;
- }
- //
- // Set up the remainder of the command flags.
- //
- if ((Command->ResponseType & SD_RESPONSE_VALID_CRC) != 0) {
- Flags |= SD_DWC_COMMAND_CHECK_RESPONSE_CRC;
- }
- //
- // If there's a data buffer, program the block count.
- //
- if (Command->BufferSize != 0) {
- Flags |= SD_DWC_COMMAND_DATA_EXPECTED;
- if (Command->Write != FALSE) {
- Flags |= SD_DWC_COMMAND_WRITE;
- } else {
- Flags |= SD_DWC_COMMAND_READ;
- }
- //
- // If reading or writing multiple blocks, the block size register
- // should be set to the default block size and the byte count should be
- // a multiple of the block size.
- //
- if ((Command->Command == SdCommandReadMultipleBlocks) ||
- (Command->Command == SdCommandWriteMultipleBlocks)) {
- if ((DwcController->HostCapabilities & SD_MODE_AUTO_CMD12) != 0) {
- Flags |= SD_DWC_COMMAND_SEND_AUTO_STOP;
- }
- SD_DWC_WRITE_REGISTER(DwcController,
- SdDwcBlockSize,
- SD_DWC_BLOCK_SIZE);
- SD_DWC_WRITE_REGISTER(DwcController,
- SdDwcByteCount,
- Command->BufferSize);
- //
- // Otherwise set the block size to total number of bytes to be
- // processed.
- //
- } else {
- SD_DWC_WRITE_REGISTER(DwcController,
- SdDwcBlockSize,
- Command->BufferSize);
- SD_DWC_WRITE_REGISTER(DwcController,
- SdDwcByteCount,
- Command->BufferSize);
- }
- }
- SD_DWC_WRITE_REGISTER(DwcController, SdDwcTimeout, 0xFFFFFFFF);
- //
- // Write the command argument.
- //
- SD_DWC_WRITE_REGISTER(DwcController,
- SdDwcCommandArgument,
- Command->CommandArgument);
- //
- // Set the command and wait for it to be accepted.
- //
- CommandValue = (Command->Command << SD_DWC_COMMAND_INDEX_SHIFT) &
- SD_DWC_COMMAND_INDEX_MASK;
- CommandValue |= SD_DWC_COMMAND_START |
- SD_DWC_COMMAND_USE_HOLD_REGISTER |
- Flags;
- SD_DWC_WRITE_REGISTER(DwcController, SdDwcCommand, CommandValue);
- 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)) {
- goto SendCommandEnd;
- }
- //
- // Check the interrupt status.
- //
- Timeout = EFI_SD_DWC_CONTROLLER_TIMEOUT;
- Time = 0;
- Status = EFI_TIMEOUT;
- do {
- Value = SD_DWC_READ_REGISTER(DwcController, SdDwcInterruptStatus);
- if ((Value & SD_DWC_INTERRUPT_STATUS_COMMAND_DONE) != 0) {
- Status = EFI_SUCCESS;
- break;
- }
- EfiStall(50);
- Time += 50;
- } while (Time <= Timeout);
- if (EFI_ERROR(Status)) {
- goto SendCommandEnd;
- }
- if ((Value & SD_DWC_INTERRUPT_STATUS_ERROR_RESPONSE_TIMEOUT) != 0) {
- SD_DWC_WRITE_REGISTER(DwcController,
- SdDwcInterruptStatus,
- SD_DWC_INTERRUPT_STATUS_ALL_MASK);
- EfipSdDwcResetController(Controller,
- DwcController,
- SD_RESET_FLAG_COMMAND_LINE);
- Status = EFI_TIMEOUT;
- goto SendCommandEnd;
- } else if ((Value & SD_DWC_INTERRUPT_STATUS_COMMAND_ERROR_MASK) != 0) {
- SD_DWC_WRITE_REGISTER(DwcController,
- SdDwcInterruptStatus,
- SD_DWC_INTERRUPT_STATUS_ALL_MASK);
- Status = EFI_DEVICE_ERROR;
- goto SendCommandEnd;
- }
- //
- // Acknowledge the completed command.
- //
- SD_DWC_WRITE_REGISTER(DwcController,
- SdDwcInterruptStatus,
- SD_DWC_INTERRUPT_STATUS_COMMAND_DONE);
- //
- // Get the response if there is one.
- //
- if ((Command->ResponseType & SD_RESPONSE_PRESENT) != 0) {
- if ((Command->ResponseType & SD_RESPONSE_136_BIT) != 0) {
- Command->Response[3] = SD_DWC_READ_REGISTER(DwcController,
- SdDwcResponse0);
- Command->Response[2] = SD_DWC_READ_REGISTER(DwcController,
- SdDwcResponse1);
- Command->Response[1] = SD_DWC_READ_REGISTER(DwcController,
- SdDwcResponse2);
- Command->Response[0] = SD_DWC_READ_REGISTER(DwcController,
- SdDwcResponse3);
- if ((DwcController->HostCapabilities &
- SD_MODE_RESPONSE136_SHIFTED) != 0) {
- Command->Response[0] = (Command->Response[0] << 8) |
- ((Command->Response[1] >> 24) & 0xFF);
- Command->Response[1] = (Command->Response[1] << 8) |
- ((Command->Response[2] >> 24) & 0xFF);
- Command->Response[2] = (Command->Response[2] << 8) |
- ((Command->Response[3] >> 24) & 0xFF);
- Command->Response[3] = Command->Response[3] << 8;
- }
- } else {
- Command->Response[0] = SD_DWC_READ_REGISTER(DwcController,
- SdDwcResponse0);
- }
- }
- //
- // Read/write the data.
- //
- if (Command->BufferSize != 0) {
- if (Command->Write != FALSE) {
- Status = EfipSdDwcWriteData(Controller,
- Context,
- Command->Buffer,
- Command->BufferSize);
- } else {
- Status = EfipSdDwcReadData(Controller,
- Context,
- Command->Buffer,
- Command->BufferSize);
- }
- if (EFI_ERROR(Status)) {
- goto SendCommandEnd;
- }
- }
- Status = EFI_SUCCESS;
- SendCommandEnd:
- return Status;
- }
- EFI_STATUS
- EfipSdDwcGetSetBusWidth (
- PEFI_SD_CONTROLLER Controller,
- VOID *Context,
- UINT16 *BusWidth,
- BOOLEAN Set
- )
- /*++
- Routine Description:
- This routine gets or sets the controller's bus width.
- Arguments:
- Controller - Supplies a pointer to the controller.
- Context - Supplies a context pointer passed to the SD/MMC library upon
- creation of the controller.
- BusWidth - Supplies a pointer that receives bus width information on get
- and contains bus width information on set.
- Set - Supplies a boolean indicating whether the bus width should be queried
- or set.
- Return Value:
- Status code.
- --*/
- {
- PEFI_SD_DWC_CONTROLLER DwcController;
- EFI_STATUS Status;
- UINT32 Value;
- DwcController = (PEFI_SD_DWC_CONTROLLER)Context;
- if (DwcController->OverrideFunctionTable.GetSetBusWidth != NULL) {
- Status = DwcController->OverrideFunctionTable.GetSetBusWidth(
- Controller,
- DwcController->OverrideContext,
- BusWidth,
- Set);
- return Status;
- }
- if (Set != FALSE) {
- switch (*BusWidth) {
- case 1:
- Value = SD_DWC_CARD_TYPE_1_BIT_WIDTH;
- break;
- case 4:
- Value = SD_DWC_CARD_TYPE_4_BIT_WIDTH;
- break;
- case 8:
- Value = SD_DWC_CARD_TYPE_8_BIT_WIDTH;
- break;
- default:
- return EFI_INVALID_PARAMETER;
- }
- SD_DWC_WRITE_REGISTER(DwcController, SdDwcCardType, Value);
- } else {
- Value = SD_DWC_READ_REGISTER(DwcController, SdDwcCardType);
- if ((Value & SD_DWC_CARD_TYPE_8_BIT_WIDTH) != 0) {
- *BusWidth = 8;
- } else if ((Value & SD_DWC_CARD_TYPE_4_BIT_WIDTH) != 0) {
- *BusWidth = 4;
- } else {
- *BusWidth = 1;
- }
- }
- return EFI_SUCCESS;
- }
- EFI_STATUS
- EfipSdDwcGetSetClockSpeed (
- 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_DWC_CONTROLLER DwcController;
- EFI_STATUS Status;
- DwcController = (PEFI_SD_DWC_CONTROLLER)Context;
- if (DwcController->OverrideFunctionTable.GetSetClockSpeed != NULL) {
- Status = DwcController->OverrideFunctionTable.GetSetClockSpeed(
- Controller,
- DwcController->OverrideContext,
- ClockSpeed,
- Set);
- return Status;
- }
- if (DwcController->FundamentalClock == 0) {
- return EFI_INVALID_PARAMETER;
- }
- //
- // 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 EfiSdDwcSetClockSpeed(DwcController, *ClockSpeed);
- }
- //
- // --------------------------------------------------------- Internal Functions
- //
- EFI_STATUS
- EfipSdDwcReadData (
- PEFI_SD_CONTROLLER Controller,
- VOID *Context,
- VOID *Data,
- UINT32 Size
- )
- /*++
- Routine Description:
- This routine reads polled data from the SD controller.
- Arguments:
- Controller - Supplies a pointer to the controller.
- Context - Supplies a context pointer passed to the SD/MMC library upon
- creation of the controller.
- Data - Supplies a pointer to the buffer where the data will be read into.
- Size - Supplies the size in bytes. This must be a multiple of four bytes.
- Return Value:
- Status code.
- --*/
- {
- UINT32 *Buffer32;
- UINT32 BusyMask;
- UINT32 Count;
- UINT32 DataReadyMask;
- BOOLEAN DataTransferOver;
- PEFI_SD_DWC_CONTROLLER DwcController;
- UINT32 Interrupts;
- UINT32 IoIndex;
- EFI_STATUS Status;
- UINT64 Time;
- UINT64 Timeout;
- UINT32 Value;
- DwcController = (PEFI_SD_DWC_CONTROLLER)Context;
- DataTransferOver = FALSE;
- Buffer32 = (UINT32 *)Data;
- Size /= sizeof(UINT32);
- while (Size != 0) {
- //
- // Get the interrupt status register.
- //
- Time = 0;
- Timeout = EFI_SD_DWC_CONTROLLER_TIMEOUT;
- Status = EFI_TIMEOUT;
- do {
- Interrupts = SD_DWC_READ_REGISTER(DwcController,
- SdDwcInterruptStatus);
- if (Interrupts != 0) {
- Status = EFI_SUCCESS;
- break;
- }
- EfiStall(50);
- Time += 50;
- } while (Time <= Timeout);
- if (EFI_ERROR(Status)) {
- return Status;
- }
- //
- // Reset the controller if any error bits are set.
- //
- if ((Interrupts & SD_DWC_INTERRUPT_STATUS_DATA_ERROR_MASK) != 0) {
- EfipSdDwcResetController(Controller,
- Context,
- SD_RESET_FLAG_DATA_LINE);
- return EFI_DEVICE_ERROR;
- }
- //
- // Check for received data status. If data is ready, the status
- // register holds the number of 32-bit elements to be read.
- //
- DataReadyMask = SD_DWC_INTERRUPT_STATUS_RECEIVE_FIFO_DATA_REQUEST;
- if ((Interrupts & DataReadyMask) != 0) {
- Count = SD_DWC_READ_REGISTER(DwcController, SdDwcStatus);
- Count = (Count & SD_DWC_STATUS_FIFO_COUNT_MASK) >>
- SD_DWC_STATUS_FIFO_COUNT_SHIFT;
- for (IoIndex = 0; IoIndex < Count; IoIndex += 1) {
- *Buffer32 = SD_DWC_READ_REGISTER(DwcController, SdDwcFifoBase);
- Buffer32 += 1;
- }
- Size -= Count;
- SD_DWC_WRITE_REGISTER(DwcController,
- SdDwcInterruptStatus,
- DataReadyMask);
- }
- //
- // Check for the transfer over bit. If it is set, then read the rest of
- // the bytes from the FIFO.
- //
- if ((Interrupts & SD_DWC_INTERRUPT_STATUS_DATA_TRANSFER_OVER) != 0) {
- for (IoIndex = 0; IoIndex < Size; IoIndex += 1) {
- *Buffer32 = SD_DWC_READ_REGISTER(DwcController, SdDwcFifoBase);
- Buffer32 += 1;
- }
- SD_DWC_WRITE_REGISTER(DwcController,
- SdDwcInterruptStatus,
- SD_DWC_INTERRUPT_STATUS_DATA_TRANSFER_OVER);
- Size = 0;
- DataTransferOver = TRUE;
- break;
- }
- }
- //
- // If the data transfer over interrupt has not yet been seen, wait for it
- // to be asserted.
- //
- if (DataTransferOver == FALSE) {
- Time = 0;
- Timeout = EFI_SD_DWC_CONTROLLER_TIMEOUT;
- Status = EFI_TIMEOUT;
- do {
- Interrupts = SD_DWC_READ_REGISTER(DwcController,
- SdDwcInterruptStatus);
- if ((Interrupts &
- SD_DWC_INTERRUPT_STATUS_DATA_TRANSFER_OVER) != 0) {
- Status = EFI_SUCCESS;
- break;
- }
- EfiStall(50);
- Time += 50;
- } while (Time <= Timeout);
- if (EFI_ERROR(Status)) {
- return Status;
- }
- SD_DWC_WRITE_REGISTER(DwcController,
- SdDwcInterruptStatus,
- SD_DWC_INTERRUPT_STATUS_DATA_TRANSFER_OVER);
- }
- //
- // Wait until the state machine and data stop being busy.
- //
- Timeout = EFI_SD_DWC_CONTROLLER_TIMEOUT;
- Time = 0;
- Status = EFI_TIMEOUT;
- BusyMask = SD_DWC_STATUS_DATA_STATE_MACHINE_BUSY |
- SD_DWC_STATUS_DATA_BUSY;
- do {
- Value = SD_DWC_READ_REGISTER(DwcController, SdDwcStatus);
- if ((Value & BusyMask) == 0) {
- Status = EFI_SUCCESS;
- break;
- }
- EfiStall(50);
- Time += 50;
- } while (Time <= Timeout);
- if (EFI_ERROR(Status)) {
- return Status;
- }
- return EFI_SUCCESS;
- }
- EFI_STATUS
- EfipSdDwcWriteData (
- PEFI_SD_CONTROLLER Controller,
- VOID *Context,
- VOID *Data,
- UINT32 Size
- )
- /*++
- Routine Description:
- This routine writes polled data to the SD controller.
- Arguments:
- Controller - Supplies a pointer to the controller.
- Context - Supplies a context pointer passed to the SD/MMC library upon
- creation of the controller.
- Data - Supplies a pointer to the buffer containing the data to write.
- Size - Supplies the size in bytes. This must be a multiple of 4 bytes.
- Return Value:
- Status code.
- --*/
- {
- UINT32 *Buffer32;
- UINT32 BusyMask;
- UINT32 Count;
- UINT32 DataRequestMask;
- BOOLEAN DataTransferOver;
- PEFI_SD_DWC_CONTROLLER DwcController;
- UINT32 Interrupts;
- UINT32 IoIndex;
- EFI_STATUS Status;
- UINT64 Time;
- UINT64 Timeout;
- UINT32 Value;
- DwcController = (PEFI_SD_DWC_CONTROLLER)Context;
- DataTransferOver = FALSE;
- Buffer32 = (UINT32 *)Data;
- Size /= sizeof(UINT32);
- while (Size != 0) {
- //
- // Get the interrupt status register.
- //
- Time = 0;
- Timeout = EFI_SD_DWC_CONTROLLER_TIMEOUT;
- Status = EFI_TIMEOUT;
- do {
- Interrupts = SD_DWC_READ_REGISTER(DwcController,
- SdDwcInterruptStatus);
- if (Interrupts != 0) {
- Status = EFI_SUCCESS;
- break;
- }
- EfiStall(50);
- Time += 50;
- } while (Time <= Timeout);
- if (EFI_ERROR(Status)) {
- return Status;
- }
- //
- // Reset the controller if any error bits are set.
- //
- if ((Interrupts & SD_DWC_INTERRUPT_STATUS_DATA_ERROR_MASK) != 0) {
- EfipSdDwcResetController(Controller,
- Context,
- SD_RESET_FLAG_DATA_LINE);
- return EFI_DEVICE_ERROR;
- }
- //
- // If the controller is ready for data to be written, the number of
- // 4-byte elements consumed in the FIFO is stored in the status
- // register. The available bytes is the total FIFO size minus that
- // amount.
- //
- DataRequestMask = SD_DWC_INTERRUPT_STATUS_TRANSMIT_FIFO_DATA_REQUEST;
- if ((Interrupts & DataRequestMask) != 0) {
- Count = SD_DWC_READ_REGISTER(DwcController, SdDwcStatus);
- Count = (Count & SD_DWC_STATUS_FIFO_COUNT_MASK) >>
- SD_DWC_STATUS_FIFO_COUNT_SHIFT;
- Count = (SD_DWC_FIFO_DEPTH / sizeof(UINT32)) - Count;
- for (IoIndex = 0; IoIndex < Count; IoIndex += 1) {
- SD_DWC_WRITE_REGISTER(DwcController, SdDwcFifoBase, *Buffer32);
- Buffer32 += 1;
- }
- Size -= Count;
- SD_DWC_WRITE_REGISTER(DwcController,
- SdDwcInterruptStatus,
- DataRequestMask);
- }
- //
- // Check for the transfer over bit. If it is set, then exit.
- //
- if ((Interrupts & SD_DWC_INTERRUPT_STATUS_DATA_TRANSFER_OVER) != 0) {
- SD_DWC_WRITE_REGISTER(DwcController,
- SdDwcInterruptStatus,
- SD_DWC_INTERRUPT_STATUS_DATA_TRANSFER_OVER);
- Size = 0;
- DataTransferOver = TRUE;
- break;
- }
- }
- //
- // If the data transfer over interrupt has not yet been seen, wait for it
- // to be asserted.
- //
- if (DataTransferOver == FALSE) {
- Timeout = EFI_SD_DWC_CONTROLLER_TIMEOUT;
- Time = 0;
- Status = EFI_TIMEOUT;
- do {
- Interrupts = SD_DWC_READ_REGISTER(DwcController,
- SdDwcInterruptStatus);
- if ((Interrupts &
- SD_DWC_INTERRUPT_STATUS_DATA_TRANSFER_OVER) != 0) {
- Status = EFI_SUCCESS;
- break;
- }
- EfiStall(50);
- Time += 50;
- } while (Time <= Timeout);
- if (EFI_ERROR(Status)) {
- return Status;
- }
- SD_DWC_WRITE_REGISTER(DwcController,
- SdDwcInterruptStatus,
- SD_DWC_INTERRUPT_STATUS_DATA_TRANSFER_OVER);
- }
- //
- // Wait until the state machine and data stop being busy.
- //
- Timeout = EFI_SD_DWC_CONTROLLER_TIMEOUT;
- Time = 0;
- Status = EFI_TIMEOUT;
- BusyMask = SD_DWC_STATUS_DATA_STATE_MACHINE_BUSY |
- SD_DWC_STATUS_DATA_BUSY;
- do {
- Value = SD_DWC_READ_REGISTER(DwcController, SdDwcStatus);
- if ((Value & BusyMask) == 0) {
- Status = EFI_SUCCESS;
- break;
- }
- EfiStall(50);
- Time += 50;
- } while (Time <= Timeout);
- if (EFI_ERROR(Status)) {
- return Status;
- }
- return EFI_SUCCESS;
- }
|