summaryrefslogtreecommitdiff
path: root/Platform/Marvell/Drivers/Spi/MvSpiDxe.c
diff options
context:
space:
mode:
Diffstat (limited to 'Platform/Marvell/Drivers/Spi/MvSpiDxe.c')
-rwxr-xr-xPlatform/Marvell/Drivers/Spi/MvSpiDxe.c379
1 files changed, 379 insertions, 0 deletions
diff --git a/Platform/Marvell/Drivers/Spi/MvSpiDxe.c b/Platform/Marvell/Drivers/Spi/MvSpiDxe.c
new file mode 100755
index 0000000000..aab20fc9ac
--- /dev/null
+++ b/Platform/Marvell/Drivers/Spi/MvSpiDxe.c
@@ -0,0 +1,379 @@
+/*******************************************************************************
+Copyright (C) 2016 Marvell International Ltd.
+
+Marvell BSD License Option
+
+If you received this File from Marvell, you may opt to use, redistribute and/or
+modify this File under the following licensing terms.
+Redistribution and use in source and binary forms, with or without modification,
+are permitted provided that the following conditions are met:
+
+* Redistributions of source code must retain the above copyright notice,
+ this list of conditions and the following disclaimer.
+
+* Redistributions in binary form must reproduce the above copyright
+ notice, this list of conditions and the following disclaimer in the
+ documentation and/or other materials provided with the distribution.
+
+* Neither the name of Marvell nor the names of its contributors may be
+ used to endorse or promote products derived from this software without
+ specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
+ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
+ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+*******************************************************************************/
+#include "MvSpiDxe.h"
+
+SPI_MASTER *mSpiMasterInstance;
+
+STATIC
+EFI_STATUS
+SpiSetBaudRate (
+ IN UINT32 CpuClock,
+ IN UINT32 MaxFreq
+ )
+{
+ UINT32 Spr, BestSpr, Sppr, BestSppr, ClockDivider, Match, Reg, MinBaudDiff;
+ UINTN SpiRegBase = PcdGet32 (PcdSpiRegBase);
+
+ MinBaudDiff = 0xFFFFFFFF;
+ BestSppr = 0;
+
+ //Spr is in range 1-15 and Sppr in range 0-8
+ for (Spr = 1; Spr <= 15; Spr++) {
+ for (Sppr = 0; Sppr <= 7; Sppr++) {
+ ClockDivider = Spr * (1 << Sppr);
+
+ if ((CpuClock / ClockDivider) > MaxFreq) {
+ continue;
+ }
+
+ if ((CpuClock / ClockDivider) == MaxFreq) {
+ BestSpr = Spr;
+ BestSppr = Sppr;
+ Match = 1;
+ break;
+ }
+
+ if ((MaxFreq - (CpuClock / ClockDivider)) < MinBaudDiff) {
+ MinBaudDiff = (MaxFreq - (CpuClock / ClockDivider));
+ BestSpr = Spr;
+ BestSppr = Sppr;
+ }
+ }
+
+ if (Match == 1) {
+ break;
+ }
+ }
+
+ if (BestSpr == 0) {
+ return (EFI_INVALID_PARAMETER);
+ }
+
+ Reg = MmioRead32 (SpiRegBase + SPI_CONF_REG);
+ Reg &= ~(SPI_SPR_MASK | SPI_SPPR_0_MASK | SPI_SPPR_HI_MASK);
+ Reg |= (BestSpr << SPI_SPR_OFFSET) |
+ ((BestSppr & 0x1) << SPI_SPPR_0_OFFSET) |
+ ((BestSppr >> 1) << SPI_SPPR_HI_OFFSET);
+ MmioWrite32 (SpiRegBase + SPI_CONF_REG, Reg);
+
+ return EFI_SUCCESS;
+}
+
+STATIC
+VOID
+SpiSetCs (
+ UINT8 CsId
+ )
+{
+ UINT32 Reg, SpiRegBase = PcdGet32 (PcdSpiRegBase);
+
+ Reg = MmioRead32 (SpiRegBase + SPI_CTRL_REG);
+ Reg &= ~SPI_CS_NUM_MASK;
+ Reg |= (CsId << SPI_CS_NUM_OFFSET);
+ MmioWrite32 (SpiRegBase + SPI_CTRL_REG, Reg);
+}
+
+STATIC
+VOID
+SpiActivateCs (
+ UINT8 IN CsId
+ )
+{
+ UINT32 Reg, SpiRegBase = PcdGet32 (PcdSpiRegBase);
+
+ SpiSetCs(CsId);
+ Reg = MmioRead32 (SpiRegBase + SPI_CTRL_REG);
+ Reg |= SPI_CS_EN_MASK;
+ MmioWrite32(SpiRegBase + SPI_CTRL_REG, Reg);
+}
+
+STATIC
+VOID
+SpiDeactivateCs (
+ VOID
+ )
+{
+ UINT32 Reg, SpiRegBase = PcdGet32 (PcdSpiRegBase);
+
+ Reg = MmioRead32 (SpiRegBase + SPI_CTRL_REG);
+ Reg &= ~SPI_CS_EN_MASK;
+ MmioWrite32(SpiRegBase + SPI_CTRL_REG, Reg);
+}
+
+STATIC
+VOID
+SpiSetupTransfer (
+ IN MARVELL_SPI_MASTER_PROTOCOL *This,
+ IN SPI_DEVICE *Slave
+ )
+{
+ SPI_MASTER *SpiMaster;
+ UINT32 Reg, SpiRegBase, CoreClock, SpiMaxFreq;
+
+ SpiMaster = SPI_MASTER_FROM_SPI_MASTER_PROTOCOL (This);
+
+ // Initialize values from PCDs
+ SpiRegBase = PcdGet32 (PcdSpiRegBase);
+ CoreClock = PcdGet32 (PcdSpiClockFrequency);
+ SpiMaxFreq = PcdGet32 (PcdSpiMaxFrequency);
+
+ EfiAcquireLock (&SpiMaster->Lock);
+
+ Reg = MmioRead32 (SpiRegBase + SPI_CONF_REG);
+ Reg |= SPI_BYTE_LENGTH;
+ MmioWrite32 (SpiRegBase + SPI_CONF_REG, Reg);
+
+ SpiSetCs(Slave->Cs);
+
+ SpiSetBaudRate (CoreClock, SpiMaxFreq);
+
+ Reg = MmioRead32 (SpiRegBase + SPI_CONF_REG);
+ Reg &= ~(SPI_CPOL_MASK | SPI_CPHA_MASK | SPI_TXLSBF_MASK | SPI_RXLSBF_MASK);
+
+ switch (Slave->Mode) {
+ case SPI_MODE0:
+ break;
+ case SPI_MODE1:
+ Reg |= SPI_CPHA_MASK;
+ break;
+ case SPI_MODE2:
+ Reg |= SPI_CPOL_MASK;
+ break;
+ case SPI_MODE3:
+ Reg |= SPI_CPOL_MASK;
+ Reg |= SPI_CPHA_MASK;
+ break;
+ }
+
+ MmioWrite32 (SpiRegBase + SPI_CONF_REG, Reg);
+
+ EfiReleaseLock (&SpiMaster->Lock);
+}
+
+EFI_STATUS
+EFIAPI
+MvSpiTransfer (
+ IN MARVELL_SPI_MASTER_PROTOCOL *This,
+ IN SPI_DEVICE *Slave,
+ IN UINTN DataByteCount,
+ IN VOID *DataOut,
+ IN VOID *DataIn,
+ IN UINTN Flag
+ )
+{
+ SPI_MASTER *SpiMaster;
+ UINT64 Length;
+ UINT32 Iterator, Reg, SpiRegBase;
+ UINT8 *DataOutPtr = (UINT8 *)DataOut;
+ UINT8 *DataInPtr = (UINT8 *)DataIn;
+ UINT8 DataToSend = 0;
+
+ SpiMaster = SPI_MASTER_FROM_SPI_MASTER_PROTOCOL (This);
+
+ SpiRegBase = PcdGet32 (PcdSpiRegBase);
+
+ Length = 8 * DataByteCount;
+
+ EfiAcquireLock (&SpiMaster->Lock);
+
+ if (Flag & SPI_TRANSFER_BEGIN) {
+ SpiActivateCs (Slave->Cs);
+ }
+
+ // Set 8-bit mode
+ Reg = MmioRead32 (SpiRegBase + SPI_CONF_REG);
+ Reg &= ~SPI_BYTE_LENGTH;
+ MmioWrite32 (SpiRegBase + SPI_CONF_REG, Reg);
+
+ while (Length > 0) {
+ if (DataOut != NULL) {
+ DataToSend = *DataOutPtr & 0xFF;
+ }
+ // Transmit Data
+ MmioWrite32 (SpiRegBase + SPI_INT_CAUSE_REG, 0x0);
+ MmioWrite32 (SpiRegBase + SPI_DATA_OUT_REG, DataToSend);
+ // Wait for memory ready
+ for (Iterator = 0; Iterator < SPI_TIMEOUT; Iterator++) {
+ if (MmioRead32 (SpiRegBase + SPI_INT_CAUSE_REG)) {
+ *DataInPtr = MmioRead32 (SpiRegBase + SPI_DATA_IN_REG);
+
+ if (DataInPtr != NULL) {
+ DataInPtr++;
+ }
+ if (DataOutPtr != NULL) {
+ DataOutPtr++;
+ }
+ Length -= 8;
+ break;
+ }
+ }
+
+ if (Iterator >= SPI_TIMEOUT) {
+ DEBUG ((DEBUG_ERROR, "Timeout\n"));
+ }
+ }
+
+ if (Flag & SPI_TRANSFER_END) {
+ SpiDeactivateCs ();
+ }
+
+ EfiReleaseLock (&SpiMaster->Lock);
+
+ return EFI_SUCCESS;
+}
+
+EFI_STATUS
+EFIAPI
+MvSpiReadWrite (
+ IN MARVELL_SPI_MASTER_PROTOCOL *This,
+ IN SPI_DEVICE *Slave,
+ IN UINT8 *Cmd,
+ IN UINTN CmdSize,
+ IN UINT8 *DataOut,
+ OUT UINT8 *DataIn,
+ IN UINTN DataSize
+ )
+{
+ EFI_STATUS Status;
+
+ Status = MvSpiTransfer (This, Slave, CmdSize, Cmd, NULL, SPI_TRANSFER_BEGIN);
+ if (EFI_ERROR (Status)) {
+ Print (L"Spi Transfer Error\n");
+ return EFI_DEVICE_ERROR;
+ }
+
+ Status = MvSpiTransfer (This, Slave, DataSize, DataOut, DataIn, SPI_TRANSFER_END);
+ if (EFI_ERROR (Status)) {
+ Print (L"Spi Transfer Error\n");
+ return EFI_DEVICE_ERROR;
+ }
+
+ return EFI_SUCCESS;
+}
+
+EFI_STATUS
+EFIAPI
+MvSpiInit (
+ IN MARVELL_SPI_MASTER_PROTOCOL * This
+ )
+{
+
+ return EFI_SUCCESS;
+}
+
+SPI_DEVICE *
+EFIAPI
+MvSpiSetupSlave (
+ IN MARVELL_SPI_MASTER_PROTOCOL *This,
+ IN UINTN Cs,
+ IN SPI_MODE Mode
+ )
+{
+ SPI_DEVICE *Slave;
+
+ Slave = AllocateZeroPool (sizeof(SPI_DEVICE));
+ if (Slave == NULL) {
+ DEBUG((DEBUG_ERROR, "Cannot allocate memory\n"));
+ return NULL;
+ }
+
+ Slave->Cs = Cs;
+ Slave->Mode = Mode;
+
+ SpiSetupTransfer (This, Slave);
+
+ return Slave;
+}
+
+EFI_STATUS
+EFIAPI
+MvSpiFreeSlave (
+ IN SPI_DEVICE *Slave
+ )
+{
+ FreePool (Slave);
+
+ return EFI_SUCCESS;
+}
+
+STATIC
+EFI_STATUS
+SpiMasterInitProtocol (
+ IN MARVELL_SPI_MASTER_PROTOCOL *SpiMasterProtocol
+ )
+{
+
+ SpiMasterProtocol->Init = MvSpiInit;
+ SpiMasterProtocol->SetupDevice = MvSpiSetupSlave;
+ SpiMasterProtocol->FreeDevice = MvSpiFreeSlave;
+ SpiMasterProtocol->Transfer = MvSpiTransfer;
+ SpiMasterProtocol->ReadWrite = MvSpiReadWrite;
+
+ return EFI_SUCCESS;
+}
+
+EFI_STATUS
+EFIAPI
+SpiMasterEntryPoint (
+ IN EFI_HANDLE ImageHandle,
+ IN EFI_SYSTEM_TABLE *SystemTable
+ )
+{
+ EFI_STATUS Status;
+
+ mSpiMasterInstance = AllocateZeroPool (sizeof (SPI_MASTER));
+
+ if (mSpiMasterInstance == NULL) {
+ return EFI_OUT_OF_RESOURCES;
+ }
+
+ EfiInitializeLock (&mSpiMasterInstance->Lock, TPL_NOTIFY);
+
+ SpiMasterInitProtocol (&mSpiMasterInstance->SpiMasterProtocol);
+
+ mSpiMasterInstance->Signature = SPI_MASTER_SIGNATURE;
+
+ Status = gBS->InstallMultipleProtocolInterfaces (
+ &(mSpiMasterInstance->Handle),
+ &gMarvellSpiMasterProtocolGuid,
+ &(mSpiMasterInstance->SpiMasterProtocol),
+ NULL
+ );
+ if (EFI_ERROR (Status)) {
+ FreePool (mSpiMasterInstance);
+ return EFI_DEVICE_ERROR;
+ }
+
+ return EFI_SUCCESS;
+}