summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorLaxman Dewangan <ldewangan@nvidia.com>2010-06-12 14:12:28 +0530
committerGary King <gking@nvidia.com>2010-06-14 11:11:36 -0700
commitdf3a2907764ad602865870e03f606488cda20514 (patch)
tree138902a5639aab351f28028e00e90f518fbd6f56
parent69074ee65d452cae27719559c8fe50c8d1b80e75 (diff)
[ARM/tegra] spi: Adding support for the hw based CS.
It is require to use the hw based CS to meet the timing requirement as: - Minimum CS setup time i.e. time from CS active to first clock. - Maximum CS hold time i.e. CS should be active after last clock. SW based CS can support the above 1 but not 2 because it dpeneds on os load and system performance. To meet the above requirements, it is require to enable the hw based CS. As spi controller support for the hw based CS for the smaller number of packet, enabling this feature. Driver use the sw based CS by default. If client want to use the hw based CS, then it need to enable this through nvodm query NvOdmQuerySpiDeviceInfo table for different CS. For this, client need to set device info as CanUseHwBasedCs = TRUE, CsSetupTimeInClock = xx CsHoldTimeInClock = xx Change-Id: I9e943e0b39f2d75272826cc2ec7687b3434b1c2a Reviewed-on: http://git-master/r/2536 Reviewed-by: Laxman Dewangan <ldewangan@nvidia.com> Tested-by: Laxman Dewangan <ldewangan@nvidia.com> Reviewed-by: Gary King <gking@nvidia.com>
-rw-r--r--arch/arm/mach-tegra/include/nvodm_query.h17
-rw-r--r--arch/arm/mach-tegra/nvrm/io/ap15/ap15rm_slink_hw_private.c10
-rw-r--r--arch/arm/mach-tegra/nvrm/io/ap15/rm_spi_hw_private.c10
-rw-r--r--arch/arm/mach-tegra/nvrm/io/ap15/rm_spi_slink.c29
-rw-r--r--arch/arm/mach-tegra/nvrm/io/ap15/rm_spi_slink_hw_private.h10
-rw-r--r--arch/arm/mach-tegra/nvrm/io/ap20/ap20rm_slink_hw_private.c22
6 files changed, 92 insertions, 6 deletions
diff --git a/arch/arm/mach-tegra/include/nvodm_query.h b/arch/arm/mach-tegra/include/nvodm_query.h
index 7912470fb470..4b31dabb7b9e 100644
--- a/arch/arm/mach-tegra/include/nvodm_query.h
+++ b/arch/arm/mach-tegra/include/nvodm_query.h
@@ -219,6 +219,23 @@ typedef struct
/// If this is NV_TRUE, then this device is an SPI slave.
NvBool IsSlave;
+
+ /// Specifies whether it can use the hw based cs or not.
+ NvBool CanUseHwBasedCs;
+
+ /// Specifies the Chipselect setup time i.e. Time between the CS active
+ /// state transition to to first clock in the transaction.
+ /// This parameter is used when using the hw based CS.
+ /// The value is in terms of the clock tick where the clock freq is
+ /// the interface frequency.
+ NvU32 CsSetupTimeInClock;
+
+ /// Specifies the Chipselect Hold time i.e. Time between the last clock and
+ /// CS state transition from active to inactive.
+ /// This parameter is used when using the hw based CS.
+ /// The value is in terms of the clock tick where the clock freq is
+ /// the interface frequency.
+ NvU32 CsHoldTimeInClock;
} NvOdmQuerySpiDeviceInfo;
/**
diff --git a/arch/arm/mach-tegra/nvrm/io/ap15/ap15rm_slink_hw_private.c b/arch/arm/mach-tegra/nvrm/io/ap15/ap15rm_slink_hw_private.c
index 41c17684a6bc..c57d9cbe6666 100644
--- a/arch/arm/mach-tegra/nvrm/io/ap15/ap15rm_slink_hw_private.c
+++ b/arch/arm/mach-tegra/nvrm/io/ap15/ap15rm_slink_hw_private.c
@@ -254,6 +254,15 @@ SlinkHwSetChipSelectLevelBasedOnPacket(
return NV_TRUE;
}
+static void
+SlinkHwSetCsSetupHoldTime(
+ SerialHwRegisters *pSlinkHwRegs,
+ NvU32 CsSetupTimeInClocks,
+ NvU32 CsHoldTimeInClocks)
+{
+ NV_ASSERT(0);
+}
+
/**
* Write into the transmit fifo register.
* returns the number of words written.
@@ -307,6 +316,7 @@ void NvRmPrivSpiSlinkInitSlinkInterface_v1_0(HwInterface *pSlinkInterface)
pSlinkInterface->HwSetChipSelectDefaultLevelFxn = SlinkHwSetChipSelectDefaultLevelFxn;
pSlinkInterface->HwSetChipSelectLevelFxn = SlinkHwSetChipSelectLevel;
pSlinkInterface->HwSetChipSelectLevelBasedOnPacketFxn = SlinkHwSetChipSelectLevelBasedOnPacket;
+ pSlinkInterface->HwSetCsSetupHoldTime = SlinkHwSetCsSetupHoldTime;
pSlinkInterface->HwWriteInTransmitFifoFxn = SlinkHwWriteInTransmitFifo;
pSlinkInterface->HwReadFromReceiveFifoFxn = SlinkHwReadFromReceiveFifo;
}
diff --git a/arch/arm/mach-tegra/nvrm/io/ap15/rm_spi_hw_private.c b/arch/arm/mach-tegra/nvrm/io/ap15/rm_spi_hw_private.c
index cb7293e1896a..652b25aa3f08 100644
--- a/arch/arm/mach-tegra/nvrm/io/ap15/rm_spi_hw_private.c
+++ b/arch/arm/mach-tegra/nvrm/io/ap15/rm_spi_hw_private.c
@@ -363,6 +363,15 @@ SpiHwSetChipSelectLevelBasedOnPacket(
return NV_TRUE;
}
+static void
+SlinkHwSetCsSetupHoldTime(
+ SerialHwRegisters *pSlinkHwRegs,
+ NvU32 CsSetupTimeInClocks,
+ NvU32 CsHoldTimeInClocks)
+{
+ NV_ASSERT(0);
+}
+
/**
* Set the packet length and packed mode.
*/
@@ -622,6 +631,7 @@ void NvRmPrivSpiSlinkInitSpiInterface(HwInterface *pSpiInterface)
pSpiInterface->HwSetChipSelectDefaultLevelFxn = SpiHwSetChipSelectDefaultLevelFxn;
pSpiInterface->HwSetChipSelectLevelFxn = SpiHwSetChipSelectLevel;
pSpiInterface->HwSetChipSelectLevelBasedOnPacketFxn = SpiHwSetChipSelectLevelBasedOnPacket;
+ pSpiInterface->HwSetCsSetupHoldTime = SlinkHwSetCsSetupHoldTime;
pSpiInterface->HwSetPacketLengthFxn = SpiHwSetPacketLength;
pSpiInterface->HwSetDmaTransferSizeFxn = SpiHwSetDmaTransferSize;
pSpiInterface->HwGetTransferdCountFxn = SpiHwGetTransferdCount;
diff --git a/arch/arm/mach-tegra/nvrm/io/ap15/rm_spi_slink.c b/arch/arm/mach-tegra/nvrm/io/ap15/rm_spi_slink.c
index 26fd65121355..c9220113262f 100644
--- a/arch/arm/mach-tegra/nvrm/io/ap15/rm_spi_slink.c
+++ b/arch/arm/mach-tegra/nvrm/io/ap15/rm_spi_slink.c
@@ -296,10 +296,16 @@ SpiSlinkGetDeviceInfo(
// No device info in odm, so set it on default state.
pDeviceInfo->SignalMode = NvOdmQuerySpiSignalMode_0;
pDeviceInfo->ChipSelectActiveLow = NV_TRUE;
+ pDeviceInfo->CanUseHwBasedCs = NV_FALSE;
+ pDeviceInfo->CsHoldTimeInClock = 0;
+ pDeviceInfo->CsSetupTimeInClock = 0;
return NV_FALSE;
}
pDeviceInfo->SignalMode = pSpiDevInfo->SignalMode;
pDeviceInfo->ChipSelectActiveLow = pSpiDevInfo->ChipSelectActiveLow;
+ pDeviceInfo->CanUseHwBasedCs = pSpiDevInfo->CanUseHwBasedCs;
+ pDeviceInfo->CsHoldTimeInClock = pSpiDevInfo->CsHoldTimeInClock;
+ pDeviceInfo->CsSetupTimeInClock = pSpiDevInfo->CsSetupTimeInClock;
return NV_TRUE;
}
@@ -1302,7 +1308,8 @@ SetChipSelectSignalLevel(
if (hRmSpiSlink->IsMasterMode != hRmSpiSlink->HwRegs.IsMasterMode)
hHwIntf->HwSetFunctionalModeFxn(&hRmSpiSlink->HwRegs, hRmSpiSlink->IsMasterMode);
- if (IsOnlyUseSWCS || (!hRmSpiSlink->HwRegs.IsHwChipSelectSupported))
+ if ((hRmSpiSlink->IsMasterMode) && ((IsOnlyUseSWCS) || (!hRmSpiSlink->HwRegs.IsHwChipSelectSupported) ||
+ (!pDevInfo->CanUseHwBasedCs)))
{
IsHigh = (pDevInfo->ChipSelectActiveLow)? NV_FALSE: NV_TRUE;
hHwIntf->HwSetChipSelectLevelFxn(&hRmSpiSlink->HwRegs, ChipSelectId, IsHigh);
@@ -1777,6 +1784,12 @@ MasterModeReadWriteCpu(
&hRmSpiSlink->HwRegs, hRmSpiSlink->CurrTransferChipSelId,
!hRmSpiSlink->DeviceInfo[hRmSpiSlink->CurrTransferChipSelId].ChipSelectActiveLow,
PacketsRequested, PacketsPerWord, NV_FALSE, NV_FALSE);
+
+ if (!hRmSpiSlink->IsCurrentlySwBasedChipSel)
+ hRmSpiSlink->hHwInterface->HwSetCsSetupHoldTime(&hRmSpiSlink->HwRegs,
+ hRmSpiSlink->DeviceInfo[hRmSpiSlink->CurrTransferChipSelId].CsSetupTimeInClock,
+ hRmSpiSlink->DeviceInfo[hRmSpiSlink->CurrTransferChipSelId].CsHoldTimeInClock);
+
hRmSpiSlink->IsChipSelConfigured = NV_TRUE;
}
@@ -1892,6 +1905,12 @@ static NvError MasterModeReadWriteDma(
&hRmSpiSlink->HwRegs, hRmSpiSlink->CurrTransferChipSelId,
!hRmSpiSlink->DeviceInfo[hRmSpiSlink->CurrTransferChipSelId].ChipSelectActiveLow,
PacketsRequested, PacketsPerWord, NV_TRUE, IsOnlyUseSWCS);
+
+ if (!hRmSpiSlink->IsCurrentlySwBasedChipSel)
+ hRmSpiSlink->hHwInterface->HwSetCsSetupHoldTime(&hRmSpiSlink->HwRegs,
+ hRmSpiSlink->DeviceInfo[hRmSpiSlink->CurrTransferChipSelId].CsSetupTimeInClock,
+ hRmSpiSlink->DeviceInfo[hRmSpiSlink->CurrTransferChipSelId].CsHoldTimeInClock);
+
hRmSpiSlink->IsChipSelConfigured = NV_TRUE;
}
@@ -2408,6 +2427,7 @@ void NvRmSpiMultipleTransactions(
NvRmDmaModuleID DmaModuleId;
NvRmSpiTransactionInfo *pTrans = t;
NvU32 TotalTransByte = 0;
+ NvBool IsOnlySwCs = NV_TRUE;
NV_ASSERT(hRmSpi);
NV_ASSERT((PacketSizeInBits > 0) && (PacketSizeInBits <= 32));
@@ -2461,8 +2481,11 @@ void NvRmSpiMultipleTransactions(
}
if (!Error)
+ {
+ IsOnlySwCs = (NumOfTransactions == 1)? NV_FALSE: NV_TRUE;
Error = SetChipSelectSignalLevel(hRmSpi, ChipSelectId, ClockSpeedInKHz,
- NV_TRUE, NV_TRUE);
+ NV_TRUE, IsOnlySwCs);
+ }
if (Error)
goto cleanup;
@@ -2542,7 +2565,7 @@ void NvRmSpiMultipleTransactions(
}
hRmSpi->CurrentDirection = SerialHwDataFlow_None;
(void)SetChipSelectSignalLevel(hRmSpi, ChipSelectId, ClockSpeedInKHz,
- NV_FALSE, NV_TRUE);
+ NV_FALSE, IsOnlySwCs);
cleanup:
diff --git a/arch/arm/mach-tegra/nvrm/io/ap15/rm_spi_slink_hw_private.h b/arch/arm/mach-tegra/nvrm/io/ap15/rm_spi_slink_hw_private.h
index 3e1d83fdc229..741ebf3dda37 100644
--- a/arch/arm/mach-tegra/nvrm/io/ap15/rm_spi_slink_hw_private.h
+++ b/arch/arm/mach-tegra/nvrm/io/ap15/rm_spi_slink_hw_private.h
@@ -285,8 +285,16 @@ typedef struct
NvBool IsApbDmaBasedTransfer,
NvBool IsOnlyUseSWCS);
+ /**
+ * Set the CS setup and hold time.
+ */
+ void
+ (* HwSetCsSetupHoldTime)(
+ SerialHwRegisters *pHwRegs,
+ NvU32 CsSetupTimeInClocks,
+ NvU32 CsHoldTimeInClocks);
- /**
+ /**
* Set the packet length.
*/
void
diff --git a/arch/arm/mach-tegra/nvrm/io/ap20/ap20rm_slink_hw_private.c b/arch/arm/mach-tegra/nvrm/io/ap20/ap20rm_slink_hw_private.c
index dfee4becc53b..ce87dda381ba 100644
--- a/arch/arm/mach-tegra/nvrm/io/ap20/ap20rm_slink_hw_private.c
+++ b/arch/arm/mach-tegra/nvrm/io/ap20/ap20rm_slink_hw_private.c
@@ -47,8 +47,7 @@
#include "nvos.h"
// Enable the hw based chipselect
-#define ENABLE_HW_BASED_CS 0
-
+#define ENABLE_HW_BASED_CS 1
#define SLINK_REG_READ32(pSlinkHwRegsVirtBaseAdd, reg) \
NV_READ32((pSlinkHwRegsVirtBaseAdd) + ((SLINK_##reg##_0)/4))
#define SLINK_REG_WRITE32(pSlinkHwRegsVirtBaseAdd, reg, val) \
@@ -354,6 +353,24 @@ SlinkHwSetChipSelectLevelBasedOnPacket(
return NV_FALSE;
}
+static void
+SlinkHwSetCsSetupHoldTime(
+ SerialHwRegisters *pSlinkHwRegs,
+ NvU32 CsSetupTimeInClocks,
+ NvU32 CsHoldTimeInClocks)
+{
+ NvU32 CommandReg2 = pSlinkHwRegs->HwRegs.SlinkRegs.Command2;
+ NvU32 SetupTime;
+
+ SetupTime = (CsSetupTimeInClocks +1)/2;
+ SetupTime = (SetupTime > 3)?3: SetupTime;
+ CommandReg2 = NV_FLD_SET_DRF_NUM(SLINK, COMMAND2, SS_SETUP,
+ SetupTime, CommandReg2);
+ pSlinkHwRegs->HwRegs.SlinkRegs.Command2 = CommandReg2;
+ SLINK_REG_WRITE32(pSlinkHwRegs->pRegsBaseAdd, COMMAND2,
+ pSlinkHwRegs->HwRegs.SlinkRegs.Command2);
+}
+
/**
* Write into the transmit fifo register.
* returns the number of words written.
@@ -415,6 +432,7 @@ void NvRmPrivSpiSlinkInitSlinkInterface_v1_1(HwInterface *pSlinkInterface)
pSlinkInterface->HwSetChipSelectDefaultLevelFxn = SlinkHwSetChipSelectDefaultLevel;
pSlinkInterface->HwSetChipSelectLevelFxn = SlinkHwSetChipSelectLevel;
pSlinkInterface->HwSetChipSelectLevelBasedOnPacketFxn = SlinkHwSetChipSelectLevelBasedOnPacket;
+ pSlinkInterface->HwSetCsSetupHoldTime = SlinkHwSetCsSetupHoldTime;
pSlinkInterface->HwWriteInTransmitFifoFxn = SlinkHwWriteInTransmitFifo;
pSlinkInterface->HwReadFromReceiveFifoFxn = SlinkHwReadFromReceiveFifo;
}