summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorLaxman Dewangan <ldewangan@nvidia.com>2010-05-30 23:01:20 +0530
committerGary King <gking@nvidia.com>2010-06-02 09:50:05 -0700
commit59d46e28718323d1214fa3f94b6d811e8e26e7a8 (patch)
tree115441e2767eef592691f6129db8a381a63882d6
parent39e090b49c224778b5b83ac05ec948dffb717f3b (diff)
tegra spi: Adding the 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 Tested on whistler. Change-Id: I4ca799178f032a03ef5c462845db26b0db935d02 Reviewed-on: http://git-master/r/1402 Reviewed-by: Venkata (Muni) Anda <vanda@nvidia.com> Tested-by: Venkata (Muni) Anda <vanda@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 9bc66d4f44a9..68e38607d44d 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..147d6ce7ef1e 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 (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;
}