summaryrefslogtreecommitdiff
path: root/arch/arm/mach-tegra/nvrm/io/ap20/ap20rm_slink_hw_private.c
diff options
context:
space:
mode:
Diffstat (limited to 'arch/arm/mach-tegra/nvrm/io/ap20/ap20rm_slink_hw_private.c')
-rw-r--r--arch/arm/mach-tegra/nvrm/io/ap20/ap20rm_slink_hw_private.c420
1 files changed, 420 insertions, 0 deletions
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
new file mode 100644
index 000000000000..dfee4becc53b
--- /dev/null
+++ b/arch/arm/mach-tegra/nvrm/io/ap20/ap20rm_slink_hw_private.c
@@ -0,0 +1,420 @@
+/*
+ * Copyright (c) 2008-2009 NVIDIA Corporation.
+ * All rights reserved.
+ *
+ * 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 the NVIDIA Corporation 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 HOLDER 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.
+ *
+ */
+/**
+ * @file
+ * @brief <b>nVIDIA driver Development Kit:
+ * Private functions implementation for the slink Rm driver</b>
+ *
+ * @b Description: Implements the private functions for the slink hw interface.
+ *
+ */
+
+// hardware includes
+#include "ap20/arslink.h"
+#include "../ap15/rm_spi_slink_hw_private.h"
+#include "nvrm_drf.h"
+#include "nvrm_hardware_access.h"
+#include "nvassert.h"
+#include "nvos.h"
+
+// Enable the hw based chipselect
+#define ENABLE_HW_BASED_CS 0
+
+#define SLINK_REG_READ32(pSlinkHwRegsVirtBaseAdd, reg) \
+ NV_READ32((pSlinkHwRegsVirtBaseAdd) + ((SLINK_##reg##_0)/4))
+#define SLINK_REG_WRITE32(pSlinkHwRegsVirtBaseAdd, reg, val) \
+ do { \
+ NV_WRITE32((((pSlinkHwRegsVirtBaseAdd) + ((SLINK_##reg##_0)/4))), (val)); \
+ } while(0)
+
+
+#define MAX_SLINK_FIFO_DEPTH 32
+#define MAX_SLINK_WORD_FOR_HW_CS 128
+#define MAX_SLINK_PACKET_FOR_HW_CS 64*1024
+
+#define ALL_SLINK_STATUS_CLEAR \
+ (NV_DRF_NUM(SLINK, STATUS, RDY, 1) | \
+ NV_DRF_NUM(SLINK, STATUS, RX_UNF, 1) | \
+ NV_DRF_NUM(SLINK, STATUS, TX_UNF, 1) | \
+ NV_DRF_NUM(SLINK, STATUS, TX_OVF, 1) | \
+ NV_DRF_NUM(SLINK, STATUS, RX_OVF, 1))
+
+static void
+SlinkHwSetSignalMode(
+ SerialHwRegisters *pSlinkHwRegs,
+ NvOdmQuerySpiSignalMode SignalMode);
+
+/**
+ * Initialize the slink register.
+ */
+static void
+SlinkHwRegisterInitialize(
+ NvU32 SlinkInstanceId,
+ SerialHwRegisters *pSlinkHwRegs)
+{
+ NvU32 CommandReg1;
+ NvU32 CommandReg2;
+ pSlinkHwRegs->InstanceId = SlinkInstanceId;
+ pSlinkHwRegs->pRegsBaseAdd = NULL;
+ pSlinkHwRegs->RegBankSize = 0;
+ pSlinkHwRegs->HwTxFifoAdd = SLINK_TX_FIFO_0;
+ pSlinkHwRegs->HwRxFifoAdd = SLINK_RX_FIFO_0;
+ pSlinkHwRegs->IsPackedMode = NV_FALSE;
+ pSlinkHwRegs->PacketLength = 1;
+ pSlinkHwRegs->CurrSignalMode = NvOdmQuerySpiSignalMode_Invalid;
+ pSlinkHwRegs->MaxWordTransfer = MAX_SLINK_FIFO_DEPTH;
+ pSlinkHwRegs->IsLsbFirst = NV_FALSE;
+ pSlinkHwRegs->IsMasterMode = NV_TRUE;
+ pSlinkHwRegs->IsNonWordAlignedPackModeSupported = NV_TRUE;
+ pSlinkHwRegs->IsHwChipSelectSupported = NV_TRUE;
+
+ CommandReg1 = NV_RESETVAL(SLINK, COMMAND);
+ CommandReg2 = NV_RESETVAL(SLINK, COMMAND2);
+
+ // Do not toggle the CS between each packet.
+ CommandReg2 = NV_FLD_SET_DRF_DEF(SLINK, COMMAND2, CS_ACTIVE_BETWEEN, HIGH,
+ CommandReg2);
+
+ CommandReg1 = NV_FLD_SET_DRF_DEF(SLINK, COMMAND, M_S, MASTER, CommandReg1);
+
+ if (pSlinkHwRegs->IsIdleDataOutHigh)
+ CommandReg1 = NV_FLD_SET_DRF_DEF(SLINK, COMMAND, IDLE_SDA, DRIVE_HIGH, CommandReg1);
+ else
+ CommandReg1 = NV_FLD_SET_DRF_DEF(SLINK, COMMAND, IDLE_SDA, DRIVE_LOW, CommandReg1);
+
+ pSlinkHwRegs->HwRegs.SlinkRegs.Command1 = CommandReg1;
+ pSlinkHwRegs->HwRegs.SlinkRegs.Command2 = CommandReg2;
+ pSlinkHwRegs->HwRegs.SlinkRegs.Status = NV_RESETVAL(SLINK, STATUS);
+ pSlinkHwRegs->HwRegs.SlinkRegs.DmaControl = NV_RESETVAL(SLINK, DMA_CTL);
+}
+
+/**
+ * Set the signal mode of communication whether this is the mode 0, 1, 2 or 3.
+ */
+static void
+SlinkHwSetSignalMode(
+ SerialHwRegisters *pSlinkHwRegs,
+ NvOdmQuerySpiSignalMode SignalMode)
+{
+ NvU32 CommandReg = pSlinkHwRegs->HwRegs.SlinkRegs.Command1;
+ switch (SignalMode)
+ {
+ case NvOdmQuerySpiSignalMode_0:
+ CommandReg = NV_FLD_SET_DRF_DEF(SLINK, COMMAND, IDLE_SCLK,
+ DRIVE_LOW, CommandReg);
+ CommandReg = NV_FLD_SET_DRF_DEF(SLINK, COMMAND, CK_SDA, FIRST_CLK_EDGE,
+ CommandReg);
+ break;
+
+ case NvOdmQuerySpiSignalMode_1:
+ CommandReg = NV_FLD_SET_DRF_DEF(SLINK, COMMAND, IDLE_SCLK,
+ DRIVE_LOW, CommandReg);
+ CommandReg = NV_FLD_SET_DRF_DEF(SLINK, COMMAND, CK_SDA, SECOND_CLK_EDGE,
+ CommandReg);
+ break;
+
+ case NvOdmQuerySpiSignalMode_2:
+ CommandReg = NV_FLD_SET_DRF_DEF(SLINK, COMMAND, IDLE_SCLK,
+ DRIVE_HIGH, CommandReg);
+ CommandReg = NV_FLD_SET_DRF_DEF(SLINK, COMMAND, CK_SDA, FIRST_CLK_EDGE,
+ CommandReg);
+ break;
+ case NvOdmQuerySpiSignalMode_3:
+ CommandReg = NV_FLD_SET_DRF_DEF(SLINK, COMMAND, IDLE_SCLK,
+ DRIVE_HIGH, CommandReg);
+ CommandReg = NV_FLD_SET_DRF_DEF(SLINK, COMMAND, CK_SDA, SECOND_CLK_EDGE,
+ CommandReg);
+ break;
+ default:
+ NV_ASSERT(!"Invalid SignalMode");
+
+ }
+ pSlinkHwRegs->HwRegs.SlinkRegs.Command1 = CommandReg;
+ SLINK_REG_WRITE32(pSlinkHwRegs->pRegsBaseAdd, COMMAND, CommandReg);
+ pSlinkHwRegs->CurrSignalMode = SignalMode;
+}
+
+/**
+ * Set the chip select polarity bit in the command register.
+ */
+static NvU32
+SetPolarityBits(
+ NvU32 ChipSelectId,
+ NvBool IsHigh,
+ NvU32 Command1)
+{
+ NvU32 CSPolVal = (IsHigh)?0:1;
+ NvU32 CommandReg1 = Command1;
+ switch (ChipSelectId)
+ {
+ case 0:
+ CommandReg1 = NV_FLD_SET_DRF_NUM(SLINK, COMMAND, CS_POLARITY0,
+ CSPolVal, CommandReg1);
+ break;
+
+ case 1:
+ CommandReg1 = NV_FLD_SET_DRF_NUM(SLINK, COMMAND, CS_POLARITY1,
+ CSPolVal, CommandReg1);
+ break;
+
+ case 2:
+ CommandReg1 = NV_FLD_SET_DRF_NUM(SLINK, COMMAND, CS_POLARITY2,
+ CSPolVal, CommandReg1);
+ break;
+
+ case 3:
+ CommandReg1 = NV_FLD_SET_DRF_NUM(SLINK, COMMAND, CS_POLARITY3,
+ CSPolVal, CommandReg1);
+ break;
+
+ default:
+ NV_ASSERT(!"Invalid ChipSelectId");
+ }
+ return CommandReg1;
+}
+
+/**
+ * Set the chip select numbers in the command register.
+ */
+static NvU32
+SetCSNumber(
+ NvU32 ChipSelectId,
+ NvU32 Command2)
+{
+ NvU32 CommandReg2 = Command2;
+ switch (ChipSelectId)
+ {
+ case 0:
+ CommandReg2 = NV_FLD_SET_DRF_DEF(SLINK, COMMAND2, SS_EN, CS0, CommandReg2);
+ break;
+
+ case 1:
+ CommandReg2 = NV_FLD_SET_DRF_DEF(SLINK, COMMAND2, SS_EN, CS1, CommandReg2);
+ break;
+
+ case 2:
+ CommandReg2 = NV_FLD_SET_DRF_DEF(SLINK, COMMAND2, SS_EN, CS2, CommandReg2);
+ break;
+
+ case 3:
+ CommandReg2 = NV_FLD_SET_DRF_DEF(SLINK, COMMAND2, SS_EN, CS3, CommandReg2);
+ break;
+
+ default:
+ NV_ASSERT(!"Invalid ChipSelectId");
+ }
+ return CommandReg2;
+}
+
+/**
+ * Set the chip select signal level to be default based on device during the
+ * initialization.
+ */
+static void
+SlinkHwSetChipSelectDefaultLevel(
+ SerialHwRegisters *pSlinkHwRegs,
+ NvU32 ChipSelectId,
+ NvBool IsHigh)
+{
+ NvU32 CommandReg1;
+ CommandReg1 = SetPolarityBits(ChipSelectId, IsHigh,
+ pSlinkHwRegs->HwRegs.SlinkRegs.Command1);
+ pSlinkHwRegs->HwRegs.SlinkRegs.Command1 = CommandReg1;
+ SLINK_REG_WRITE32(pSlinkHwRegs->pRegsBaseAdd, COMMAND, CommandReg1);
+}
+
+/**
+ * Set the chip select signal level.
+ */
+static void
+SlinkHwSetChipSelectLevel(
+ SerialHwRegisters *pSlinkHwRegs,
+ NvU32 ChipSelectId,
+ NvBool IsHigh)
+{
+ NvU32 CommandReg1;
+ NvU32 CommandReg2;
+
+ // Select SW based CS
+ CommandReg1 = SetPolarityBits(ChipSelectId, IsHigh,
+ pSlinkHwRegs->HwRegs.SlinkRegs.Command1);
+ CommandReg1 = NV_FLD_SET_DRF_DEF(SLINK, COMMAND, CS_SW, SOFT, CommandReg1);
+
+ pSlinkHwRegs->HwRegs.SlinkRegs.Command1 = CommandReg1;
+ SLINK_REG_WRITE32(pSlinkHwRegs->pRegsBaseAdd, COMMAND, CommandReg1);
+
+
+ CommandReg2 = SetCSNumber(ChipSelectId, pSlinkHwRegs->HwRegs.SlinkRegs.Command2);
+ pSlinkHwRegs->HwRegs.SlinkRegs.Command2 = CommandReg2;
+ SLINK_REG_WRITE32(pSlinkHwRegs->pRegsBaseAdd, COMMAND2,
+ pSlinkHwRegs->HwRegs.SlinkRegs.Command2);
+}
+/**
+ * Set the chip select signal level based on the transfer size.
+ * it can use the hw based CS or SW based CS based on transfer size and
+ * cpu/apb dma based transfer.
+ * Return NV_TRUE if the SW based chipselection is used otherwise return
+ * NV_FALSE;
+ */
+static NvBool
+SlinkHwSetChipSelectLevelBasedOnPacket(
+ SerialHwRegisters *pSlinkHwRegs,
+ NvU32 ChipSelectId,
+ NvBool IsHigh,
+ NvU32 PacketRequested,
+ NvU32 PacketPerWord,
+ NvBool IsApbDmaBasedTransfer,
+ NvBool IsOnlyUseSWCS)
+{
+ NvU32 MaxWordReq;
+ NvU32 CommandReg1;
+ NvU32 CommandReg2;
+ NvU32 RefillCount = 0;
+#if ENABLE_HW_BASED_CS
+ NvBool UseSWBaseCS = IsOnlyUseSWCS;
+#else
+ NvBool UseSWBaseCS = NV_TRUE;
+#endif
+
+ if (!UseSWBaseCS)
+ {
+ if (IsApbDmaBasedTransfer)
+ {
+ UseSWBaseCS = (PacketRequested <= MAX_SLINK_PACKET_FOR_HW_CS)?
+ NV_FALSE: NV_TRUE;
+ }
+ else
+ {
+ MaxWordReq = (PacketRequested + PacketPerWord -1)/PacketPerWord;
+ NV_ASSERT(MaxWordReq);
+ if (MaxWordReq <= MAX_SLINK_WORD_FOR_HW_CS)
+ {
+ RefillCount = (MaxWordReq)/MAX_SLINK_FIFO_DEPTH;
+ UseSWBaseCS = NV_FALSE;
+ }
+ else
+ {
+ UseSWBaseCS = NV_TRUE;
+ }
+ }
+ }
+ if (UseSWBaseCS)
+ {
+ SlinkHwSetChipSelectLevel(pSlinkHwRegs, ChipSelectId, IsHigh);
+ return NV_TRUE;
+ }
+
+ // Select HW based chipselect.
+ CommandReg1 = NV_FLD_SET_DRF_DEF(SLINK, COMMAND, CS_SW, HARD,
+ pSlinkHwRegs->HwRegs.SlinkRegs.Command1);
+
+ CommandReg2 = SetCSNumber(ChipSelectId,
+ pSlinkHwRegs->HwRegs.SlinkRegs.Command2);
+ if (!IsApbDmaBasedTransfer)
+ CommandReg2 = NV_FLD_SET_DRF_NUM(SLINK, COMMAND2, FIFO_REFILLS,
+ RefillCount, CommandReg2);
+
+ pSlinkHwRegs->HwRegs.SlinkRegs.Command1 = CommandReg1;
+ SLINK_REG_WRITE32(pSlinkHwRegs->pRegsBaseAdd, COMMAND,
+ pSlinkHwRegs->HwRegs.SlinkRegs.Command1);
+
+ pSlinkHwRegs->HwRegs.SlinkRegs.Command2 = CommandReg2;
+ SLINK_REG_WRITE32(pSlinkHwRegs->pRegsBaseAdd, COMMAND2,
+ pSlinkHwRegs->HwRegs.SlinkRegs.Command2);
+
+ return NV_FALSE;
+}
+
+/**
+ * Write into the transmit fifo register.
+ * returns the number of words written.
+ */
+static NvU32
+SlinkHwWriteInTransmitFifo(
+ SerialHwRegisters *pSlinkHwRegs,
+ NvU32 *pTxBuff,
+ NvU32 WordRequested)
+{
+ NvU32 WordWritten = 0;
+ NvU32 WordsRemaining;
+ NvU32 SlinkFifoEmptyCountReg = SLINK_REG_READ32(pSlinkHwRegs->pRegsBaseAdd, STATUS2);
+ SlinkFifoEmptyCountReg = NV_DRF_VAL(SLINK, STATUS2, TX_FIFO_EMPTY_COUNT, SlinkFifoEmptyCountReg);
+ WordsRemaining = NV_MIN(WordRequested, SlinkFifoEmptyCountReg);
+ WordWritten = WordsRemaining;
+ while (WordsRemaining)
+ {
+ SLINK_REG_WRITE32(pSlinkHwRegs->pRegsBaseAdd, TX_FIFO, *pTxBuff);
+ pTxBuff++;
+ WordsRemaining--;
+ }
+ return WordWritten;
+}
+
+/**
+ * Read the data from the receive fifo.
+ * Returns the number of words it read.
+ */
+static NvU32
+SlinkHwReadFromReceiveFifo(
+ SerialHwRegisters *pSlinkHwRegs,
+ NvU32 *pRxBuff,
+ NvU32 WordRequested)
+{
+ NvU32 WordsRemaining;
+ NvU32 SlinkFifoFullCountReg = SLINK_REG_READ32(pSlinkHwRegs->pRegsBaseAdd, STATUS2);
+ NvU32 WordsRead;
+
+ SlinkFifoFullCountReg = NV_DRF_VAL(SLINK, STATUS2, RX_FIFO_FULL_COUNT, SlinkFifoFullCountReg);
+ WordsRemaining = NV_MIN(WordRequested, SlinkFifoFullCountReg);
+ WordsRead = WordsRemaining;
+ while (WordsRemaining)
+ {
+ *pRxBuff = SLINK_REG_READ32(pSlinkHwRegs->pRegsBaseAdd, RX_FIFO);
+ pRxBuff++;
+ WordsRemaining--;
+ }
+ return WordsRead;
+}
+
+/**
+ * Initialize the slink intterface for the hw access.
+ */
+void NvRmPrivSpiSlinkInitSlinkInterface_v1_1(HwInterface *pSlinkInterface)
+{
+ pSlinkInterface->HwRegisterInitializeFxn = SlinkHwRegisterInitialize;
+ pSlinkInterface->HwSetSignalModeFxn = SlinkHwSetSignalMode;
+ pSlinkInterface->HwSetChipSelectDefaultLevelFxn = SlinkHwSetChipSelectDefaultLevel;
+ pSlinkInterface->HwSetChipSelectLevelFxn = SlinkHwSetChipSelectLevel;
+ pSlinkInterface->HwSetChipSelectLevelBasedOnPacketFxn = SlinkHwSetChipSelectLevelBasedOnPacket;
+ pSlinkInterface->HwWriteInTransmitFifoFxn = SlinkHwWriteInTransmitFifo;
+ pSlinkInterface->HwReadFromReceiveFifoFxn = SlinkHwReadFromReceiveFifo;
+}