diff options
author | Gary King <gking@nvidia.com> | 2009-12-15 13:44:34 -0800 |
---|---|---|
committer | Gary King <gking@nvidia.com> | 2009-12-15 18:44:21 -0800 |
commit | 1c52ff8cde5a0df237d00311e8553b2d027c7bd9 (patch) | |
tree | 19eddc60723598d7b58ad2b0634bc873a038b10a | |
parent | f9bff797dd8f7306078806a2858422960e3826fe (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/Kconfig | 3 | ||||
-rw-r--r-- | arch/arm/mach-tegra/include/nvsnor_controller.h | 165 | ||||
-rw-r--r-- | arch/arm/mach-tegra/nvddk/Makefile | 1 | ||||
-rwxr-xr-x | arch/arm/mach-tegra/nvddk/nvsnor_controller.c | 627 | ||||
-rw-r--r-- | drivers/char/Kconfig | 10 | ||||
-rw-r--r-- | drivers/char/Makefile | 1 | ||||
-rwxr-xr-x | drivers/char/tegra_dpram.c | 414 |
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); + |