summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorGary King <gking@nvidia.com>2009-12-15 13:44:34 -0800
committerGary King <gking@nvidia.com>2009-12-15 18:44:21 -0800
commit1c52ff8cde5a0df237d00311e8553b2d027c7bd9 (patch)
tree19eddc60723598d7b58ad2b0634bc873a038b10a
parentf9bff797dd8f7306078806a2858422960e3826fe (diff)
char/tegra: add DPRAM character device attached to Tegra SNOR interface
adds support for dual-ported RAM devices attached to Tegra's internal SNOR controller interface Change-Id: I7ce65c87c9cdcf6c1625f223ee54ee2cf84f995b
-rw-r--r--arch/arm/mach-tegra/Kconfig3
-rw-r--r--arch/arm/mach-tegra/include/nvsnor_controller.h165
-rw-r--r--arch/arm/mach-tegra/nvddk/Makefile1
-rwxr-xr-xarch/arm/mach-tegra/nvddk/nvsnor_controller.c627
-rw-r--r--drivers/char/Kconfig10
-rw-r--r--drivers/char/Makefile1
-rwxr-xr-xdrivers/char/tegra_dpram.c414
7 files changed, 1221 insertions, 0 deletions
diff --git a/arch/arm/mach-tegra/Kconfig b/arch/arm/mach-tegra/Kconfig
index 1a8c395f46fa..ac2824d57464 100644
--- a/arch/arm/mach-tegra/Kconfig
+++ b/arch/arm/mach-tegra/Kconfig
@@ -76,6 +76,9 @@ config TEGRA_ODM_VIBRATE
Adds a timed output vibrator device node for an NVIDIA Tegra ODM kit
vibrator driver
+config TEGRA_SNOR
+ boolean
+
source "arch/arm/mach-tegra/odm_kit/Kconfig"
endif
diff --git a/arch/arm/mach-tegra/include/nvsnor_controller.h b/arch/arm/mach-tegra/include/nvsnor_controller.h
new file mode 100644
index 000000000000..66d7ee87bea4
--- /dev/null
+++ b/arch/arm/mach-tegra/include/nvsnor_controller.h
@@ -0,0 +1,165 @@
+/*
+ * Copyright (c) 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.
+ *
+ */
+
+#ifndef __NVSNOR_CONTROLLER_H
+#define __NVSNOR_CONTROLLER_H
+
+#include "mach/nvrm_linux.h"
+#include "nvos.h"
+#include "nvassert.h"
+#include "nvodm_query.h"
+
+#include "nvodm_services.h"
+#include "nvodm_query_discovery.h"
+
+#include "ap20/arsnor.h"
+#include "nvrm_hardware_access.h"
+#include "nvrm_power.h"
+#include "nvrm_drf.h"
+#include "nvrm_module.h"
+#include "nvrm_memmgr.h"
+#include "nvrm_interrupt.h"
+
+#define SNOR_CONTROLLER_CHIPSELECT_MAX 8
+
+#define SNOR_DMA_BUFFER_SIZE_BYTE 0x1000 //4KB
+//#define SNOR_DMA_BUFFER_SIZE_BYTE 0x4000 //16KB
+
+
+#define SNOR_READ32(pSnorHwRegsVirtBaseAdd, reg) \
+ NV_READ32((pSnorHwRegsVirtBaseAdd) + ((SNOR_##reg##_0)/4))
+
+#define SNOR_WRITE32(pSnorHwRegsVirtBaseAdd, reg, val) \
+ do \
+ { \
+ NV_WRITE32((((pSnorHwRegsVirtBaseAdd) + ((SNOR_##reg##_0)/4))), (val)); \
+ } while (0)
+
+typedef struct
+{
+ NvRmPhysAddr DeviceBaseAddress;
+ NvU32 DeviceAddressSize;
+ NvU16 *pDeviceBaseVirtAddress;
+ NvU32 DevicePureAddress;
+} ConnectedDeviceIntRegister;
+
+typedef struct
+{
+ NvU32 Config;
+
+ NvU32 Status;
+ NvU32 NorAddressPtr;
+ NvU32 AhbAddrPtr;
+ NvU32 Timing0;
+ NvU32 Timing1;
+ NvU32 MioCfg;
+ NvU32 MioTiming;
+ NvU32 DmaConfig;
+ NvU32 ChipSelectMuxConfig;
+} SnorControllerRegs;
+
+typedef struct
+{
+ NvU32 Muxed_Width;
+ NvU32 Hold_Width;
+ NvU32 ADV_dWidth;
+ NvU32 WE_Width;
+ NvU32 OE_Width;
+ NvU32 Wait_Width;
+
+} SnorControllerTimingRegVals;
+
+
+typedef struct NvSnorRec
+{
+ NvRmDeviceHandle hRmDevice;
+
+ NvU32 OpenCount;
+
+ // Physical Address of the SNOR controller instance
+ NvU32 SnorControllerBaseAdd;
+
+ // Virtual address for the SNOR controller instance
+ NvU32 *pSnorControllerVirtBaseAdd;
+
+ // Size of the SNOR register map
+ NvU32 SnorRegMapSize;
+
+ // Semaphore for registering the client with the power manager.
+ NvOsSemaphoreHandle hRmPowerEventSema;
+
+ // Power client Id.
+ NvU32 RmPowerClientId;
+
+ // Command complete semaphore
+ NvOsSemaphoreHandle hCommandCompleteSema;
+
+ // Interrupt handle
+ NvOsInterruptHandle hIntr;
+ //For SNOR controller's DMA allocation
+ NvRmMemHandle hRmMemory;
+ NvRmPhysAddr DmaBuffPhysAdd;
+ NvU32 *pAhbDmaBuffer;
+ NvU32 Snor_DmaBufSize;
+
+ //Number of devices present
+ NvU32 NumOfDevicesConnected;
+
+ // Tells whether the device is avialble or not.
+ //NvU32 IsDevAvailable[SNOR_CONTROLLER_CHIPSELECT_MAX];
+
+ // Device interface register to access the devices which is controlled by SNOR controller.
+ ConnectedDeviceIntRegister ConnectedDevReg;
+
+ SnorControllerRegs SnorRegs;
+} NvSnor;
+
+typedef struct NvSnorRec *NvSnorHandle;
+
+typedef struct
+{
+ NvRmDeviceHandle hRmDevice;
+ NvSnorHandle hSnor;
+} NvSnorInformation;
+
+
+NvError InitSnorInformation(void);
+void DeinitSnorInformation(void);
+void InitSnorController(NvSnorHandle hSnor, NvU32 DevTypeSNOREn, SnorControllerTimingRegVals TimingRegVals);
+void SetChipSelect(NvSnorHandle hSnor, NvU32 ChipSelId);
+NvError CreateSnorHandle(NvRmDeviceHandle hRmDevice, NvSnorHandle *phSnor);
+void DestroySnorHandle(NvSnorHandle hSnor);
+
+void NvReadViaSNORControllerDMA (NvSnorHandle hSnor, void* SnorAddr, NvU32 word32bit_count);
+void NvWriteViaSNORControllerDMA (NvSnorHandle hSnor, void* SnorAddr, NvU32 word32bit_count);
+
+#endif
diff --git a/arch/arm/mach-tegra/nvddk/Makefile b/arch/arm/mach-tegra/nvddk/Makefile
index 55e177db40ea..bc852f5479af 100644
--- a/arch/arm/mach-tegra/nvddk/Makefile
+++ b/arch/arm/mach-tegra/nvddk/Makefile
@@ -23,3 +23,4 @@ obj-$(CONFIG_SERIAL_TEGRA_DDK) += nvddk_uart.o
obj-$(CONFIG_SERIAL_TEGRA_DDK) += ap15ddk_uart_hw_private.o
obj-$(CONFIG_MMC_TEGRA_SDIO) += nvddk_sdio.o
+obj-$(CONFIG_TEGRA_SNOR) += nvsnor_controller.o
diff --git a/arch/arm/mach-tegra/nvddk/nvsnor_controller.c b/arch/arm/mach-tegra/nvddk/nvsnor_controller.c
new file mode 100755
index 000000000000..7be46872db61
--- /dev/null
+++ b/arch/arm/mach-tegra/nvddk/nvsnor_controller.c
@@ -0,0 +1,627 @@
+/*
+ * arch/arm/mach-tegra/nvddk/nvsnor_controller.c
+ *
+ * DDK-like routines for accessing the SNOR controller
+ *
+ * Copyright (c) 2009, NVIDIA Corporation.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
+ * more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ */
+
+#include <linux/delay.h>
+#include <linux/init.h>
+#include <linux/io.h>
+#include <linux/module.h>
+#include <linux/types.h>
+#include <linux/fs.h>
+#include <linux/kernel.h>
+#include <linux/miscdevice.h>
+#include <linux/mutex.h>
+
+#include "nvsnor_controller.h"
+
+#define SNOR_CS_FOR_DPRAM 4
+#define SNOR_CS_FOR_ONENAND 2
+
+NvSnorInformation *g_pSnorInfo = NULL;
+
+struct mutex snor_operation_lock;
+struct mutex snor_hal_lock;
+
+
+static void SnorISR (void *pArgs)
+{
+ NvSnorHandle hSnor_isr = (NvSnorHandle)pArgs;
+ NvU32 StatusReg;
+
+ StatusReg = SNOR_READ32(hSnor_isr->pSnorControllerVirtBaseAdd, DMA_CFG);
+ if (NV_DRF_VAL(SNOR, DMA_CFG, IS_DMA_DONE, StatusReg))
+ {
+ SNOR_WRITE32(hSnor_isr->pSnorControllerVirtBaseAdd, DMA_CFG, StatusReg);
+ NvOsSemaphoreSignal(hSnor_isr->hCommandCompleteSema);
+ }
+
+ NvRmInterruptDone(hSnor_isr->hIntr);
+}
+
+static NvError RegisterSnorInterrupt(NvSnorHandle hSnor)
+{
+ NvU32 IrqList;
+ NvOsInterruptHandler IntHandle = SnorISR;
+
+ IrqList = NvRmGetIrqForLogicalInterrupt(hSnor->hRmDevice,
+ NVRM_MODULE_ID(NvRmModuleID_SyncNor, 0),
+ 0);
+ return NvRmInterruptRegister(hSnor->hRmDevice, 1, &IrqList, &IntHandle,
+ hSnor, &hSnor->hIntr, NV_TRUE);
+}
+/**
+ * Create the dma buffer memory handle.
+ */
+static NvError
+CreateDmaBufferMemoryHandle(
+ NvRmDeviceHandle hDevice,
+ NvRmMemHandle *phNewMemHandle,
+ NvRmPhysAddr *pNewMemAddr,
+ NvU32 BufferSize)
+{
+ NvError Error = NvSuccess;
+ NvRmMemHandle hNewMemHandle = NULL;
+ static const NvRmHeap HeapProperty[] =
+ {
+ NvRmHeap_ExternalCarveOut,
+ NvRmHeap_External,
+ NvRmHeap_GART,
+ };
+
+ // Initialize the memory handle with NULL
+ *phNewMemHandle = NULL;
+
+ /// Create memory handle
+ Error = NvRmMemHandleCreate(hDevice, &hNewMemHandle, BufferSize);
+
+ // Allocates the memory from the sdram
+ if (!Error)
+ Error = NvRmMemAlloc(hNewMemHandle, HeapProperty,
+ NV_ARRAY_SIZE(HeapProperty), 4, NvOsMemAttribute_Uncached);
+
+ // Pin the memory allocation so that it should not move by memory manager.
+ if (!Error)
+ *pNewMemAddr = NvRmMemPin(hNewMemHandle);
+
+ // If error then free the memory allocation and memory handle.
+ if (Error)
+ {
+ NvRmMemHandleFree(hNewMemHandle);
+ hNewMemHandle = NULL;
+ }
+
+ *phNewMemHandle = hNewMemHandle;
+ return Error;
+}
+
+ /**
+ * Destroy the dma buffer memory handle.
+ */
+static void DestroyDmaBufferMemoryHandle(NvRmMemHandle hMemHandle)
+{
+ // Can accept the null parameter. If it is not null then only destroy.
+ if (hMemHandle)
+ {
+ // Unpin the memory allocation.
+ NvRmMemUnpin(hMemHandle);
+
+ // Free the memory handle.
+ NvRmMemHandleFree(hMemHandle);
+ }
+}
+
+static NvError
+CreateDmaTransferBuffer(
+ NvRmDeviceHandle hRmDevice,
+ NvRmMemHandle *phRmMemory,
+ NvRmPhysAddr *pBuffPhysAddr,
+ void **pBuffPtr,
+ NvU32 BufferSize)
+{
+ NvError Error = NvSuccess;
+ NvRmMemHandle hRmMemory = NULL;
+ NvRmPhysAddr BuffPhysAddr;
+
+ // Reset all the members realted to the dma buffer.
+ BuffPhysAddr = 0;
+
+ *phRmMemory = NULL;
+ *pBuffPtr = (void *)NULL;
+ *pBuffPhysAddr = 0;
+
+ // Create the dma buffer memory for receive and transmit.
+ // It will be double of the OneBufferSize
+ Error = CreateDmaBufferMemoryHandle(hRmDevice, &hRmMemory,
+ &BuffPhysAddr, BufferSize);
+ if (!Error)
+ {
+ // 0 to OneBufferSize-1 is buffer 1 and OneBufferSize to 2*OneBufferSize
+ // is second buffer.
+ Error = NvRmMemMap(hRmMemory, 0, BufferSize,
+ NVOS_MEM_READ_WRITE, pBuffPtr);
+ // If error then free the allocation and reset all changed value.
+ if (Error)
+ {
+ DestroyDmaBufferMemoryHandle(hRmMemory);
+ hRmMemory = NULL;
+ *pBuffPtr = (void *)NULL;
+ return Error;
+ }
+ *phRmMemory = hRmMemory;
+ *pBuffPhysAddr = BuffPhysAddr;
+ }
+ return Error;
+}
+
+/**
+ * Destroy the dma transfer buffer.
+ */
+static void
+DestroyDmaTransferBuffer(
+ NvRmMemHandle hRmMemory,
+ void *pBuffPtr,
+ NvU32 BufferSize)
+{
+ if (hRmMemory)
+ {
+ if (pBuffPtr)
+ NvRmMemUnmap(hRmMemory, pBuffPtr, BufferSize);
+ DestroyDmaBufferMemoryHandle(hRmMemory);
+ }
+}
+
+static NvError SetPowerControl(NvSnorHandle hSnor, NvBool IsEnable)
+{
+ NvError Error = NvError_Success;
+ NvRmModuleID ModuleId;
+
+ ModuleId = NVRM_MODULE_ID(NvRmModuleID_SyncNor, 0);
+ if (IsEnable)
+ {
+ // Enable power for Snor module
+ if (!Error)
+ Error = NvRmPowerVoltageControl(hSnor->hRmDevice, ModuleId,
+ hSnor->RmPowerClientId,
+ NvRmVoltsUnspecified, NvRmVoltsUnspecified,
+ NULL, 0, NULL);
+
+ // Enable the clock.
+ if (!Error)
+ Error = NvRmPowerModuleClockControl(hSnor->hRmDevice, ModuleId,
+ hSnor->RmPowerClientId, NV_TRUE);
+ }
+ else
+ {
+ // Disable the clocks.
+ Error = NvRmPowerModuleClockControl(
+ hSnor->hRmDevice,
+ ModuleId, hSnor->RmPowerClientId,
+ NV_FALSE);
+
+ // Disable the power to the controller.
+ if (!Error)
+ Error = NvRmPowerVoltageControl(
+ hSnor->hRmDevice,
+ ModuleId,
+ hSnor->RmPowerClientId,
+ NvRmVoltsOff,
+ NvRmVoltsOff,
+ NULL,
+ 0,
+ NULL);
+ NV_ASSERT(Error == NvError_Success);
+ }
+ return Error;
+}
+
+NvError InitSnorInformation(void)
+{
+ NvSnorInformation *pSnorInfo;
+
+ if(!g_pSnorInfo)
+ {
+ pSnorInfo = NvOsAlloc(sizeof(*pSnorInfo));
+ if (!pSnorInfo)
+ {
+ //printk("InitSnorInformation InsufficientMemory!!\n");
+ return NvError_InsufficientMemory;
+ }
+ NvOsMemset(pSnorInfo, 0, sizeof(*pSnorInfo));
+
+ pSnorInfo->hRmDevice = s_hRmGlobal;
+ NV_ASSERT(pSnorInfo->hRmDevice);
+
+ pSnorInfo->hSnor = NULL;
+
+
+ if (NvOsAtomicCompareExchange32((NvS32*)&g_pSnorInfo, 0, (NvS32)pSnorInfo)!=0)
+ {
+ NvOsFree(pSnorInfo);
+ return NvError_BadParameter;
+ }
+ }
+ mutex_init(&snor_operation_lock);
+ mutex_init(&snor_hal_lock);
+ return NvError_Success;
+}
+
+void __init tegra_init_snor_controller(void)
+{
+ NvError Error = NvError_Success;
+ Error = InitSnorInformation();
+ printk("tegra_init_snor_controller returnes %x!!\n", Error);
+ NV_ASSERT(Error==NvError_Success);
+
+}
+
+#if 0
+void DeinitSnorInformation(void)
+{
+ if(g_pSnorInfo)
+ {
+ NvOsFree(g_pSnorInfo);
+ }
+}
+#endif
+
+void InitSnorController(NvSnorHandle hSnor, NvU32 DevTypeSNOREn, SnorControllerTimingRegVals TimingRegVals)
+{
+//#define NOR_CONTROLLER_TIMING_SET 1 //TODO Need to check with HW engineer to define timing value of DPRAM device.
+
+ NvU32 SnorConfig = hSnor->SnorRegs.Config;
+#ifdef NOR_CONTROLLER_TIMING_SET
+ NvU32 SnorTiming0 = hSnor->SnorRegs.Timing0;
+ NvU32 SnorTiming1 = hSnor->SnorRegs.Timing1;
+#endif
+
+ // Set device type to NOR. With this type setting, can access DPRAM, too.
+if (DevTypeSNOREn==NV_TRUE)
+ SnorConfig = NV_FLD_SET_DRF_DEF(SNOR, CONFIG, NOR_DEVICE_TYPE, SNOR, SnorConfig);
+else
+ SnorConfig = NV_FLD_SET_DRF_DEF(SNOR, CONFIG, NOR_DEVICE_TYPE, MUXONENAND, SnorConfig);
+
+ SnorConfig = NV_FLD_SET_DRF_DEF(SNOR, CONFIG, WORDWIDE_GMI, NOR16BIT, SnorConfig); //TODO Add configuring the 16/32 bit mode of snor controller.
+ SnorConfig = NV_FLD_SET_DRF_DEF(SNOR, CONFIG, MUXMODE_GMI, AD_MUX, SnorConfig); //TODO Add configuring the mux/nonmux mode.
+
+ SnorConfig = NV_FLD_SET_DRF_DEF(SNOR, CONFIG, DEVICE_MODE, ASYNC, SnorConfig);
+
+
+ //TODO Timing Register Setting. Will be better to query timing from ODM interface.
+ //Need to control SNOR Timing0 Register and SNOR Timing1 Register.
+
+#ifdef NOR_CONTROLLER_TIMING_SET
+ SnorTiming0 = NV_FLD_SET_DRF_NUM(SNOR, TIMING0, MUXED_WIDTH, TimingRegVals.Muxed_Width, SnorTiming0);
+ SnorTiming0 = NV_FLD_SET_DRF_NUM(SNOR, TIMING0, HOLD_WIDTH, TimingRegVals.Hold_Width, SnorTiming0);
+ SnorTiming0 = NV_FLD_SET_DRF_NUM(SNOR, TIMING0, ADV_WIDTH, TimingRegVals.ADV_dWidth, SnorTiming0);
+
+ SnorTiming1 = NV_FLD_SET_DRF_NUM(SNOR, TIMING1, WE_WIDTH, TimingRegVals.WE_Width, SnorTiming1);
+ SnorTiming1 = NV_FLD_SET_DRF_NUM(SNOR, TIMING1, OE_WIDTH, TimingRegVals.OE_Width, SnorTiming1);
+ SnorTiming1 = NV_FLD_SET_DRF_NUM(SNOR, TIMING1, WAIT_WIDTH, TimingRegVals.Wait_Width, SnorTiming1);
+#endif
+
+ hSnor->SnorRegs.Config = SnorConfig;
+ SNOR_WRITE32(hSnor->pSnorControllerVirtBaseAdd, CONFIG, SnorConfig);
+
+#ifdef NOR_CONTROLLER_TIMING_SET
+ hSnor->SnorRegs.Timing0 = SnorTiming0;
+ SNOR_WRITE32(hSnor->pSnorControllerVirtBaseAdd, TIMING0, SnorTiming0);
+ hSnor->SnorRegs.Timing1 = SnorTiming1;
+ SNOR_WRITE32(hSnor->pSnorControllerVirtBaseAdd, TIMING1, SnorTiming1);
+#endif
+ //TODO ... In nvodm_query_pinmux.c, right pinmux for SyncNor need to be defined in NvOdmQueryPinMux.
+}
+
+void SetChipSelect(NvSnorHandle hSnor, NvU32 ChipSelId)
+{
+ NvU32 SnorConfig;
+
+ NV_ASSERT(ChipSelId<SNOR_CONTROLLER_CHIPSELECT_MAX);
+
+ SnorConfig = hSnor->SnorRegs.Config;
+ SnorConfig = NV_FLD_SET_DRF_NUM(SNOR, CONFIG, SNOR_SEL, ChipSelId, SnorConfig);
+
+ hSnor->SnorRegs.Config = SnorConfig;
+ SNOR_WRITE32(hSnor->pSnorControllerVirtBaseAdd, CONFIG, SnorConfig);
+}
+
+NvError CreateSnorHandle(
+ NvRmDeviceHandle hRmDevice,
+ NvSnorHandle *phSnor)
+{
+ NvError Error = NvError_Success;
+ NvSnorHandle HandleSnor;
+ SnorControllerTimingRegVals TimingRegValues = {0x1, 0x1, 0x1, 0x3, 0x3, 0x8};
+
+ HandleSnor = NvOsAlloc(sizeof(HandleSnor));
+ if (!HandleSnor)
+ {
+ return NvError_InsufficientMemory;
+ }
+
+ NV_ASSERT(hRmDevice);
+
+ HandleSnor->hRmDevice = hRmDevice;
+ HandleSnor->OpenCount = 0;
+ HandleSnor->SnorControllerBaseAdd = 0;
+ HandleSnor->pSnorControllerVirtBaseAdd = NULL;
+
+ HandleSnor->SnorRegMapSize=0;
+
+ HandleSnor->hRmPowerEventSema = NULL;
+ HandleSnor->RmPowerClientId = 0;
+ HandleSnor->hCommandCompleteSema = NULL;
+ HandleSnor->hIntr = NULL;
+
+ HandleSnor->ConnectedDevReg.DeviceBaseAddress = 0;
+ HandleSnor->ConnectedDevReg.DeviceAddressSize = 0;
+ HandleSnor->ConnectedDevReg.pDeviceBaseVirtAddress = NULL;
+ HandleSnor->ConnectedDevReg.DevicePureAddress = 0;
+
+ HandleSnor->SnorRegs.Config = NV_RESETVAL(SNOR, CONFIG);
+ HandleSnor->SnorRegs.Status = NV_RESETVAL(SNOR, STA);
+ HandleSnor->SnorRegs.NorAddressPtr = NV_RESETVAL(SNOR, NOR_ADDR_PTR);
+ HandleSnor->SnorRegs.AhbAddrPtr = NV_RESETVAL(SNOR, AHB_ADDR_PTR);
+ HandleSnor->SnorRegs.Timing0 = NV_RESETVAL(SNOR, TIMING0);
+ HandleSnor->SnorRegs.Timing1 = NV_RESETVAL(SNOR, TIMING1);
+ HandleSnor->SnorRegs.MioCfg = NV_RESETVAL(SNOR, MIO_CFG);
+ HandleSnor->SnorRegs.MioTiming = NV_RESETVAL(SNOR, MIO_TIMING0);
+ HandleSnor->SnorRegs.DmaConfig = NV_RESETVAL(SNOR, DMA_CFG);
+ HandleSnor->SnorRegs.ChipSelectMuxConfig = NV_RESETVAL(SNOR, CS_MUX_CFG);
+
+ HandleSnor->Snor_DmaBufSize = SNOR_DMA_BUFFER_SIZE_BYTE;
+
+ // Initialize the base addresses of SNOR controller
+ NvRmModuleGetBaseAddress(hRmDevice, NVRM_MODULE_ID(NvRmModuleID_SyncNor, 0),
+ &HandleSnor->SnorControllerBaseAdd,
+ &HandleSnor->SnorRegMapSize);
+
+ Error = NvRmPhysicalMemMap(HandleSnor->SnorControllerBaseAdd,
+ HandleSnor->SnorRegMapSize,
+ NVOS_MEM_READ_WRITE, NvOsMemAttribute_Uncached,
+ (void **)&(HandleSnor->pSnorControllerVirtBaseAdd));
+
+ if (Error)
+ {
+ printk("SNOR Controller register mapping fails!!\n");
+ goto ErrorEnd;
+ }
+
+
+
+ // Initialize the base addresses of device which is connected to SNOR controller.
+ // For example, NOR device, Dual-port RAM.
+ // Then memory read/write from/to pDeviceBaseVirtAddress will be done through GMI_ADxx lines.
+ NvRmModuleGetBaseAddress(hRmDevice,
+ NVRM_MODULE_ID(NvRmModuleID_Nor, 0),
+ &HandleSnor->ConnectedDevReg.DeviceBaseAddress,
+ &HandleSnor->ConnectedDevReg.DeviceAddressSize);
+
+ printk("During Nor Base Register mapping...the size of DeviceAddressSize: %d (0x%x) !!\n",
+ HandleSnor->ConnectedDevReg.DeviceAddressSize, HandleSnor->ConnectedDevReg.DeviceAddressSize);
+
+
+
+ Error = NvRmPhysicalMemMap(HandleSnor->ConnectedDevReg.DeviceBaseAddress,
+ HandleSnor->ConnectedDevReg.DeviceAddressSize,
+ NVOS_MEM_READ_WRITE, NvOsMemAttribute_Uncached,
+ (void **)&(HandleSnor->ConnectedDevReg.pDeviceBaseVirtAddress));
+
+ if (Error)
+ {
+ printk("Device Base address mapping fails!!\n");
+ goto ErrorEnd;
+ }
+
+
+ // Register as the Rm power client
+ Error = NvOsSemaphoreCreate(&HandleSnor->hRmPowerEventSema, 0);
+ if (!Error)
+ Error = NvRmPowerRegister(HandleSnor->hRmDevice,
+ HandleSnor->hRmPowerEventSema,
+ &HandleSnor->RmPowerClientId);
+
+ if (!Error)
+ Error = SetPowerControl(HandleSnor, NV_TRUE);
+
+ if (!Error)
+ {
+ InitSnorController(HandleSnor, NV_TRUE, TimingRegValues);
+ SetChipSelect(HandleSnor, SNOR_CS_FOR_DPRAM);
+ }
+ // Reset the snor controller.
+ if (!Error)
+ NvRmModuleReset(hRmDevice, NVRM_MODULE_ID(NvRmModuleID_SyncNor, 0));
+
+
+ if (!Error)
+ Error = RegisterSnorInterrupt(HandleSnor);
+
+
+ if (!Error)
+ Error = NvOsSemaphoreCreate(&HandleSnor->hCommandCompleteSema, 0);
+
+ if (!Error)
+ Error = CreateDmaTransferBuffer(HandleSnor->hRmDevice, &HandleSnor->hRmMemory,
+ &HandleSnor->DmaBuffPhysAdd, (void **)&HandleSnor->pAhbDmaBuffer,
+ HandleSnor->Snor_DmaBufSize );
+
+ ErrorEnd:
+ // If error then destroy all the allocation done here.
+ if (Error)
+ {
+ DestroySnorHandle(HandleSnor);
+ HandleSnor = NULL;
+ }
+ *phSnor = HandleSnor;
+ return Error;
+
+}
+
+void DestroySnorHandle(NvSnorHandle hSnor)
+{
+ if (!hSnor)
+ {
+ return;
+ }
+
+ if (hSnor->RmPowerClientId)
+ {
+ SetPowerControl(hSnor, NV_FALSE);
+ // Unregister for the power manager.
+ NvRmPowerUnRegister(hSnor->hRmDevice, hSnor->RmPowerClientId);
+ }
+ if (hSnor->hRmPowerEventSema) NvOsSemaphoreDestroy(hSnor->hRmPowerEventSema);
+
+ if (hSnor->hIntr)
+ {
+ NvRmInterruptUnregister(hSnor->hRmDevice, hSnor->hIntr);
+ hSnor->hIntr = NULL;
+ }
+
+ // Unmap the virtual mapping of the snor controller.
+ if (hSnor->pSnorControllerVirtBaseAdd)
+ NvRmPhysicalMemUnmap(hSnor->pSnorControllerVirtBaseAdd, hSnor->SnorRegMapSize);
+
+ // Unmap the virtual mapping of the Nor interfacing register.
+ if (hSnor->ConnectedDevReg.pDeviceBaseVirtAddress)
+ NvRmPhysicalMemUnmap(hSnor->ConnectedDevReg.pDeviceBaseVirtAddress,
+ hSnor->ConnectedDevReg.DeviceAddressSize);
+ if (hSnor->hCommandCompleteSema) NvOsSemaphoreDestroy(hSnor->hCommandCompleteSema);
+
+ if (hSnor->pAhbDmaBuffer) DestroyDmaTransferBuffer(hSnor->hRmMemory, hSnor->pAhbDmaBuffer,
+ hSnor->Snor_DmaBufSize);
+
+ if (hSnor) NvOsFree(hSnor);
+
+ if (g_pSnorInfo->hSnor->OpenCount) g_pSnorInfo->hSnor->OpenCount=0;
+ if (g_pSnorInfo->hSnor) g_pSnorInfo->hSnor=NULL;
+
+
+}
+
+
+void NvReadViaSNORControllerDMA (NvSnorHandle hSnor, void* SnorAddr, NvU32 word32bit_count)
+{
+ mutex_lock(&snor_hal_lock);
+ //SetChipSelect(hSnor, SNOR_CS_FOR_DPRAM); --> Move to CreateHandle part.
+
+ //DMA READ operation
+ //GO_NOR field of configuration reg is already set in InitSnorController.
+
+ NvU32 NorAddressPtr = hSnor->SnorRegs.NorAddressPtr;
+ NvU32 AhbAddrPtr = hSnor->SnorRegs.AhbAddrPtr;
+ NvU32 DmaConfig = hSnor->SnorRegs.DmaConfig;
+ NvU32 SnorConfig = hSnor->SnorRegs.Config;
+ NvU32 StatusReg = 0;
+
+ NorAddressPtr = NV_FLD_SET_DRF_NUM(SNOR, NOR_ADDR_PTR, SNOR_NOR_ADDR_PTR, (NvU32)SnorAddr, NorAddressPtr);
+ AhbAddrPtr = NV_FLD_SET_DRF_NUM(SNOR, AHB_ADDR_PTR, SNOR_AHB_ADDR_PTR, (NvU32)(hSnor->DmaBuffPhysAdd), AhbAddrPtr);
+
+ SnorConfig = NV_FLD_SET_DRF_DEF(SNOR, CONFIG, GO_NOR, ENABLE, SnorConfig);
+ SnorConfig = NV_FLD_SET_DRF_DEF(SNOR, CONFIG, MST_ENB, ENABLE, SnorConfig);
+
+ hSnor->SnorRegs.NorAddressPtr = NorAddressPtr;
+ SNOR_WRITE32(hSnor->pSnorControllerVirtBaseAdd, NOR_ADDR_PTR, NorAddressPtr);
+
+ hSnor->SnorRegs.AhbAddrPtr = AhbAddrPtr;
+ SNOR_WRITE32(hSnor->pSnorControllerVirtBaseAdd, AHB_ADDR_PTR, AhbAddrPtr);
+
+ DmaConfig = NV_FLD_SET_DRF_DEF(SNOR, DMA_CFG, DMA_GO, ENABLE, DmaConfig);
+ DmaConfig = NV_FLD_SET_DRF_DEF(SNOR, DMA_CFG, DIR, NOR2AHB, DmaConfig);
+
+ DmaConfig = NV_FLD_SET_DRF_DEF(SNOR, DMA_CFG, IE_DMA_DONE, ENABLE, DmaConfig);
+ if ((word32bit_count&0x0007)==0) //This means word counts is 8, 16, 24, ...
+ {
+ DmaConfig = NV_FLD_SET_DRF_DEF(SNOR, DMA_CFG, BURST_SIZE, BS8WORD, DmaConfig);
+ }
+ else if ((word32bit_count&0x0003)==0) //This means word counts is 4, 12, 20, ...
+ {
+ DmaConfig = NV_FLD_SET_DRF_DEF(SNOR, DMA_CFG, BURST_SIZE, BS4WORD, DmaConfig);
+ }
+
+ else DmaConfig = NV_FLD_SET_DRF_DEF(SNOR, DMA_CFG, BURST_SIZE, BS1WORD, DmaConfig);
+
+ DmaConfig = NV_FLD_SET_DRF_NUM(SNOR, DMA_CFG, WORD_COUNT, word32bit_count-1, DmaConfig); //Controller transfer total N+1 words.
+
+ hSnor->SnorRegs.Config = SnorConfig;
+ hSnor->SnorRegs.DmaConfig = DmaConfig;
+
+ SNOR_WRITE32(hSnor->pSnorControllerVirtBaseAdd, CONFIG, SnorConfig);
+ SNOR_WRITE32(hSnor->pSnorControllerVirtBaseAdd, DMA_CFG, DmaConfig);
+
+ NvOsSemaphoreWait(hSnor->hCommandCompleteSema);
+
+ mutex_unlock(&snor_hal_lock);
+}
+
+void NvWriteViaSNORControllerDMA (NvSnorHandle hSnor, void* SnorAddr, NvU32 word32bit_count)
+{
+ mutex_lock(&snor_hal_lock);
+ //SetChipSelect(hSnor, SNOR_CS_FOR_DPRAM); --> Move to CreateHandle part.
+ //
+ //DMA WRITE operation
+ //GO_NOR field of configuration reg is already set in InitSnorController.
+
+ NvU32 NorAddressPtr = hSnor->SnorRegs.NorAddressPtr;
+ NvU32 AhbAddrPtr = hSnor->SnorRegs.AhbAddrPtr;
+ NvU32 DmaConfig = hSnor->SnorRegs.DmaConfig;
+ NvU32 SnorConfig = hSnor->SnorRegs.Config;
+ NvU32 StatusReg = 0;
+
+
+ NorAddressPtr = NV_FLD_SET_DRF_NUM(SNOR, NOR_ADDR_PTR, SNOR_NOR_ADDR_PTR, (NvU32)SnorAddr, NorAddressPtr);
+ AhbAddrPtr = NV_FLD_SET_DRF_NUM(SNOR, AHB_ADDR_PTR, SNOR_AHB_ADDR_PTR, (NvU32)(hSnor->DmaBuffPhysAdd), AhbAddrPtr);
+
+
+ SnorConfig = NV_FLD_SET_DRF_DEF(SNOR, CONFIG, GO_NOR, ENABLE, SnorConfig);
+ SnorConfig = NV_FLD_SET_DRF_DEF(SNOR, CONFIG, MST_ENB, ENABLE, SnorConfig);
+
+ hSnor->SnorRegs.NorAddressPtr = NorAddressPtr;
+ SNOR_WRITE32(hSnor->pSnorControllerVirtBaseAdd, NOR_ADDR_PTR, NorAddressPtr);
+
+ hSnor->SnorRegs.AhbAddrPtr = AhbAddrPtr;
+ SNOR_WRITE32(hSnor->pSnorControllerVirtBaseAdd, AHB_ADDR_PTR, AhbAddrPtr);
+
+
+ DmaConfig = NV_FLD_SET_DRF_DEF(SNOR, DMA_CFG, DMA_GO, ENABLE, DmaConfig);
+ DmaConfig = NV_FLD_SET_DRF_DEF(SNOR, DMA_CFG, DIR, AHB2NOR, DmaConfig);
+ DmaConfig = NV_FLD_SET_DRF_DEF(SNOR, DMA_CFG, IE_DMA_DONE, ENABLE, DmaConfig);
+ if ((word32bit_count&0x0007)==0) //This means word counts is 8, 16, 24, ...
+ {
+ DmaConfig = NV_FLD_SET_DRF_DEF(SNOR, DMA_CFG, BURST_SIZE, BS8WORD, DmaConfig);
+ }
+ else if ((word32bit_count&0x0003)==0) //This means word counts is 4, 12, 20, ...
+ {
+ DmaConfig = NV_FLD_SET_DRF_DEF(SNOR, DMA_CFG, BURST_SIZE, BS4WORD, DmaConfig);
+ }
+ else DmaConfig = NV_FLD_SET_DRF_DEF(SNOR, DMA_CFG, BURST_SIZE, BS1WORD, DmaConfig);
+ DmaConfig = NV_FLD_SET_DRF_NUM(SNOR, DMA_CFG, WORD_COUNT, word32bit_count-1, DmaConfig); //Controller transfer total N+1 words.
+
+ hSnor->SnorRegs.Config = SnorConfig;
+ hSnor->SnorRegs.DmaConfig = DmaConfig;
+
+ SNOR_WRITE32(hSnor->pSnorControllerVirtBaseAdd, CONFIG, SnorConfig);
+ SNOR_WRITE32(hSnor->pSnorControllerVirtBaseAdd, DMA_CFG, DmaConfig);
+
+ NvOsSemaphoreWait(hSnor->hCommandCompleteSema);
+
+ mutex_unlock(&snor_hal_lock);
+}
diff --git a/drivers/char/Kconfig b/drivers/char/Kconfig
index 8230d03b3706..d9405d51b154 100644
--- a/drivers/char/Kconfig
+++ b/drivers/char/Kconfig
@@ -88,6 +88,16 @@ config VT_HW_CONSOLE_BINDING
information. For framebuffer console users, please refer to
<file:Documentation/fb/fbcon.txt>.
+config TEGRA_SNOR_DPRAM
+ bool "Dual-ported RAM on NVIDIA Tegra SNOR interface"
+ depends on ARCH_TEGRA && !ARCH_TEGRA_1x_SOC
+ default n
+ select TEGRA_SNOR
+ help
+ Adds character device support for accessing dual-ported memory
+ devices attached to the SNOR interface on NVIDIA Tegra SoCs.
+
+
config DEVMEM
bool "Memory device driver"
default y
diff --git a/drivers/char/Makefile b/drivers/char/Makefile
index 9f1264860a76..882470f991e3 100644
--- a/drivers/char/Makefile
+++ b/drivers/char/Makefile
@@ -10,6 +10,7 @@ FONTMAPFILE = cp437.uni
obj-y += mem.o random.o tty_io.o n_tty.o tty_ioctl.o tty_ldisc.o tty_buffer.o tty_port.o
obj-$(CONFIG_DEVNVMAP) += nvmap.o
+obj-$(CONFIG_TEGRA_SNOR_DPRAM) += tegra_dpram.o
obj-$(CONFIG_LEGACY_PTYS) += pty.o
obj-$(CONFIG_UNIX98_PTYS) += pty.o
obj-y += misc.o
diff --git a/drivers/char/tegra_dpram.c b/drivers/char/tegra_dpram.c
new file mode 100755
index 000000000000..8a8e2143139d
--- /dev/null
+++ b/drivers/char/tegra_dpram.c
@@ -0,0 +1,414 @@
+/*
+ * drivers/char/tegra_dpram.c
+ *
+ * Support for dual-ported RAM devices attached to the SNOR interface on
+ * NVIDIA Tegra SoCs
+ *
+ * Copyright (c) 2009, NVIDIA Corporation.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
+ * more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ */
+
+#include <linux/delay.h>
+#include <linux/init.h>
+#include <linux/io.h>
+#include <linux/module.h>
+#include <linux/types.h>
+#include <linux/fs.h>
+#include <linux/kernel.h>
+#include <linux/miscdevice.h>
+#include <linux/mutex.h>
+
+#include "nvsnor_controller.h"
+
+#define DRIVER_NAME "tegra_dpram"
+#define DRIVER_DESC "Nvidia Tegra dpram driver to access dual-port RAM by using SNOR controller"
+
+#define NV_DPRAM_DEBUG_PRINT 0
+
+#if NV_DPRAM_DEBUG_PRINT
+#define NV_DPRAM_DBG(fmt,args...) \
+ do { pr_info("("DRIVER_NAME")" fmt, ##args); } while (0)
+#else
+#define NV_DPRAM_DBG(fmt,args...) \
+ do{} while (0);
+#endif
+
+extern NvSnorInformation *g_pSnorInfo;
+extern struct mutex snor_operation_lock;
+
+SnorControllerTimingRegVals TimingRegVals_dpram = {0x1, 0x1, 0x1, 0x3, 0x3, 0x8};
+
+NvBool dpram_poweron(void)
+{
+ NvOdmServicesPmuHandle hPmu;
+ NvU32 i;
+ NvU32 settle_us;
+ NvU64 guid;
+ NvOdmPeripheralConnectivity const *conn;
+
+ /* get the dpram guid */
+ guid = NV_ODM_GUID('d','p','r','a','m','d','e','v');
+
+ /* get the connectivity info */
+ conn = NvOdmPeripheralGetGuid( guid );
+ if (!conn) return NV_FALSE;
+
+ hPmu = NvOdmServicesPmuOpen();
+ if (!hPmu) return NV_FALSE;
+
+ for( i = 0; i < conn->NumAddress; i++ )
+ {
+ if( conn->AddressList[i].Interface == NvOdmIoModule_Vdd )
+ {
+ NvOdmServicesPmuVddRailCapabilities cap;
+
+ /* address is the vdd rail id */
+ NvOdmServicesPmuGetCapabilities( hPmu,
+ conn->AddressList[i].Address, &cap );
+
+ /* set the rail volatage to the recommended */
+ NvOdmServicesPmuSetVoltage( hPmu,
+ conn->AddressList[i].Address, cap.requestMilliVolts,
+ &settle_us );
+
+ /* wait for rail to settle */
+ NvOdmOsWaitUS( settle_us );
+ }
+ }
+
+ NvOdmServicesPmuClose( hPmu );
+ return NV_TRUE;
+}
+
+static ssize_t tegra_dpram_read(struct file *file, char __user *buf, size_t len,
+ loff_t *ppos)
+{
+ NvSnorHandle HandleSnor;
+ NvU32 length;
+ void * final_snorside_addr;
+ NvU32 f_pos_local;
+
+ if (!g_pSnorInfo->hSnor)
+ {
+ printk("tegra_dpram_read fail since g_pSnorInfo->hSnor is zero!!\n");
+ NV_ASSERT(0);
+ return 0;
+ }
+
+ if (len==0) return 0;
+ if ((len%2)==1)
+ {
+ printk("tegra_dpram_read, byte access is not allowed by SNOR controller!!\n");
+ NV_ASSERT(0); //Byte access is limited due to SNOR controller's limitation.
+ return 0;
+ }
+
+
+ if (len%4!=0)
+ {
+ printk("tegra_dpram_read, in case DMA mode, only support read of 4bytes, 8bytes, 12 bytes, 16 bytes, ...!!");
+ printk("SNOR controller's minimum DMA-able data size is a word (32bit.) ...!!\n");
+ NV_ASSERT(0); //only support 4bytes, 8bytes, 12 bytes, 16 bytes in case DMA mode.
+ return 0;
+
+ }
+ mutex_lock(&snor_operation_lock);
+
+ HandleSnor=g_pSnorInfo->hSnor;
+
+ f_pos_local = (NvU32)(HandleSnor->ConnectedDevReg.DevicePureAddress);
+
+
+ if (f_pos_local + (NvU32)len > NvOdmQueryMemSize(NvOdmMemoryType_Dpram))
+ {
+ len = NvOdmQueryMemSize(NvOdmMemoryType_Dpram) - f_pos_local;
+
+ if ((len==0)||((len%2)==1)||((len%4)!=0))
+ {
+ printk("tegra_dpram_read: nothing read or calculated len for remained region do not satisfies condition!!\n");
+ mutex_unlock(&snor_operation_lock);
+ return 0;
+ }
+ }
+
+ final_snorside_addr = (NvU8 *)(HandleSnor->ConnectedDevReg.DeviceBaseAddress)
+ + (NvU32)(f_pos_local);
+
+ if (len<=(HandleSnor->Snor_DmaBufSize))
+ {
+ NvReadViaSNORControllerDMA (HandleSnor, final_snorside_addr, len>>2);
+ NvOsMemcpy((void *)buf, (void *)HandleSnor->pAhbDmaBuffer, len);
+ }
+ else
+ {
+ NvU32 remained_len;
+ NvU32 copy_len;
+ NvU32 i=0;
+ NvU8* buf_backup;
+ copy_len = (HandleSnor->Snor_DmaBufSize);
+ remained_len = len;
+
+
+ buf_backup = (NvU8 *)buf;
+ do
+ {
+ if (i!=0)
+ {
+ final_snorside_addr = (NvU8 *)final_snorside_addr + (HandleSnor->Snor_DmaBufSize);
+ buf = (NvU8 *)buf + (HandleSnor->Snor_DmaBufSize);
+ }
+ NvReadViaSNORControllerDMA (HandleSnor, final_snorside_addr, copy_len>>2);
+ NvOsMemcpy((void *)buf, (void *)HandleSnor->pAhbDmaBuffer, copy_len);
+ remained_len = remained_len - (HandleSnor->Snor_DmaBufSize);
+ copy_len = (copy_len<remained_len)?(copy_len):(remained_len);
+ i++;
+
+ }while(remained_len>0);
+ buf = (NvU8 *)buf_backup;
+ }
+ f_pos_local+=len;
+ HandleSnor->ConnectedDevReg.DevicePureAddress = (NvU32)f_pos_local;
+
+ length=len;
+ mutex_unlock(&snor_operation_lock);
+ return length;
+}
+
+static ssize_t tegra_dpram_write(struct file *file, const char __user *data,
+ size_t len, loff_t *ppos)
+{
+ NvSnorHandle HandleSnor;
+ NvU32 length;
+ void * final_snorside_addr;
+ NvU32 f_pos_local;
+
+ if (!g_pSnorInfo->hSnor)
+ {
+ NV_ASSERT(0);
+ return 0;
+ }
+
+ if (len==0) return 0;
+ if ((len%2)==1)
+ {
+ printk("tegra_dpram_write, byte access is not allowed by SNOR controller!!\n");
+ NV_ASSERT(0); //Byte access is limited due to SNOR controller's limitation.
+ return 0;
+ }
+
+ if (len%4!=0)
+ {
+ printk("tegra_dpram_write, in case DMA mode, only support write of 4bytes, 8bytes, 12 bytes, 16 bytes, ...!!");
+ printk("SNOR controller's minimum DMA-able data size is a word (32bit.) ...!!\n");
+ NV_ASSERT(0); //only support 4bytes, 8bytes, 12 bytes, 16 bytes in case DMA mode.
+ return 0;
+
+ }
+ mutex_lock(&snor_operation_lock);
+
+ HandleSnor=g_pSnorInfo->hSnor;
+
+ f_pos_local = (NvU32)(HandleSnor->ConnectedDevReg.DevicePureAddress);
+
+ if (f_pos_local + (NvU32)len > NvOdmQueryMemSize(NvOdmMemoryType_Dpram))
+ {
+ len = NvOdmQueryMemSize(NvOdmMemoryType_Dpram) - f_pos_local;
+
+ if ((len==0)||((len%2)==1)||((len%4)!=0))
+ {
+ printk("tegra_dpram_write, nothing write or calculated len for remained region do not satisfies condition!!\n");
+ mutex_unlock(&snor_operation_lock);
+ return 0;
+ }
+ }
+
+ final_snorside_addr = (NvU8 *)(HandleSnor->ConnectedDevReg.DeviceBaseAddress)
+ + (NvU32)(f_pos_local);
+
+ {
+ if (len<=(HandleSnor->Snor_DmaBufSize))
+ {
+ NvOsMemcpy((void *)HandleSnor->pAhbDmaBuffer, (void *)data, len);
+ NvWriteViaSNORControllerDMA (HandleSnor, final_snorside_addr, len>>2);
+ }
+ else
+ {
+ NvU32 remained_len;
+ NvU32 copy_len;
+ NvU32 i=0;
+ NvU8* data_backup;
+ copy_len = (HandleSnor->Snor_DmaBufSize);
+ remained_len = len;
+
+
+ data_backup = (NvU8 *)data;
+ do
+ {
+ if (i!=0)
+ {
+ final_snorside_addr = (NvU8 *)final_snorside_addr + (HandleSnor->Snor_DmaBufSize);
+ data = (NvU8 *)data + (HandleSnor->Snor_DmaBufSize);
+ }
+ NvOsMemcpy((void *)HandleSnor->pAhbDmaBuffer, (void *)data, copy_len);
+ NvWriteViaSNORControllerDMA (HandleSnor, final_snorside_addr, copy_len>>2);
+ remained_len = remained_len - (HandleSnor->Snor_DmaBufSize);
+ copy_len = (copy_len<remained_len)?(copy_len):(remained_len);
+ i++;
+
+ }while(remained_len>0);
+ data = (NvU8 *)data_backup;
+ }
+ }
+ f_pos_local+=len;
+ HandleSnor->ConnectedDevReg.DevicePureAddress = (NvU32)f_pos_local;
+
+ length=len;
+ mutex_unlock(&snor_operation_lock);
+ return length;
+}
+
+loff_t tegra_dpram_lseek(struct file *file, loff_t offset, int origin)
+{
+ NvSnorHandle HandleSnor;
+
+ if (!g_pSnorInfo->hSnor)
+ {
+ NV_ASSERT(0);
+ return -EINVAL;
+ }
+
+ if (origin!=SEEK_SET) return -EINVAL; //SEEK_SET is only supported.
+ if (offset<0) return -EINVAL;
+
+ if (offset%4!=0)
+ {
+ printk("tegra_dpram_lseek, in case DMA mode, only support write of 4bytes, 8bytes, 12 bytes, 16 bytes, ...!!");
+ printk("SNOR controller's minimum DMA-able data size is a word (32bit.) ...!!\n");
+ printk("So, offset also needs to be Word boundary ...!!\n");
+ return -EINVAL;
+
+ }
+
+ if (offset>NvOdmQueryMemSize(NvOdmMemoryType_Dpram)) return -EINVAL; //out of space
+ mutex_lock(&snor_operation_lock);
+ HandleSnor=g_pSnorInfo->hSnor;
+ HandleSnor->ConnectedDevReg.DevicePureAddress = (NvU32)offset; //Assume input offset in user mode layer is Byte boundary.
+ mutex_unlock(&snor_operation_lock);
+ return (loff_t)offset;
+
+}
+
+static int
+tegra_dpram_open(struct inode *inode, struct file *file)
+{
+
+ NvError Error = NvError_Success;
+
+ printk("tegra_dpram_open is called!!\n");
+
+ if (g_pSnorInfo->hSnor){
+ if (g_pSnorInfo->hSnor->OpenCount)
+ {
+ printk("tegra_dpram_open : Already opened in other place!!\n");
+ printk("Support one pair of open/close.\n");
+ return 1;
+ }
+ }
+
+ if (NV_FALSE==dpram_poweron())
+ {
+ printk("tegra_dpram_open...DPRAM power rail on fails!!\n");
+ return 1;
+ }
+ Error = CreateSnorHandle(g_pSnorInfo->hRmDevice, &g_pSnorInfo->hSnor);
+
+ if (!Error)
+ {
+ g_pSnorInfo->hSnor->OpenCount++;
+ printk("%d th tegra_dpram_open!!\n", g_pSnorInfo->hSnor->OpenCount);
+ printk("tegra_dpram_open...dpram size is 0x%x Byte\n", NvOdmQueryMemSize(NvOdmMemoryType_Dpram));
+ }
+ else
+ {
+ printk("tegra_dpram_open CreateSnorHandle fails!!\n");
+ return 1;
+ }
+
+ //MOD_INC_USE_COUT; //TODO ... Is this working?
+ return 0;
+}
+
+
+static int
+tegra_dpram_release(struct inode *inode, struct file *file)
+{
+ printk("tegra_dpram_release is called!!\n");
+ if (!g_pSnorInfo->hSnor)
+ {
+ printk("tegra dpram is not opened before, or already closed!!\n");
+ return 1;
+ }
+ if (g_pSnorInfo->hSnor->OpenCount==1)
+ {
+ printk("tegra_dpram_release will do 1)DestorySnorHandle!!\n");
+ DestroySnorHandle(g_pSnorInfo->hSnor);
+ //DeinitSnorInformation();
+ }
+ //MOD_DEC_USE_COUT; //TODO ... Is this working?
+ return 0;
+}
+
+static struct file_operations tegra_dpram_fops = {
+ .owner = THIS_MODULE,
+ .read = tegra_dpram_read,
+ .write = tegra_dpram_write,
+ .open = tegra_dpram_open,
+ .release = tegra_dpram_release,
+ .llseek = tegra_dpram_lseek,
+};
+
+static struct miscdevice tegra_dpram_device =
+{
+ .name = "dpram",
+ .fops = &tegra_dpram_fops,
+ .minor = 0,
+};
+
+static int __init
+tegra_dpram_init(void)
+{
+ int retVal = 0;
+ retVal = misc_register(&tegra_dpram_device);
+
+
+ if (retVal <0) printk("tegra_dpram_init fails!!\n");
+ else printk("tegra_dpram_init succeeds! This is to access Dual-Port RAM by using Tegra SNOR controller interface!!\n");
+
+ return retVal;
+}
+
+static void __exit
+tegra_dpram_exit(void)
+{
+ misc_deregister (&tegra_dpram_device);
+}
+
+module_init(tegra_dpram_init);
+module_exit(tegra_dpram_exit);
+
+MODULE_LICENSE("GPL");
+MODULE_DESCRIPTION(DRIVER_DESC);
+