diff options
Diffstat (limited to 'arch/arm/mach-tegra/nvrm/core/ap15/ap15rm_xpc.c')
-rw-r--r-- | arch/arm/mach-tegra/nvrm/core/ap15/ap15rm_xpc.c | 432 |
1 files changed, 432 insertions, 0 deletions
diff --git a/arch/arm/mach-tegra/nvrm/core/ap15/ap15rm_xpc.c b/arch/arm/mach-tegra/nvrm/core/ap15/ap15rm_xpc.c new file mode 100644 index 000000000000..8b92ae4b5933 --- /dev/null +++ b/arch/arm/mach-tegra/nvrm/core/ap15/ap15rm_xpc.c @@ -0,0 +1,432 @@ +/* + * Copyright (c) 2010 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: + * Cross Proc Communication driver </b> + * + * @b Description: Implements the interface to the NvDdk XPC. + * + */ + +#include "nvrm_xpc.h" +#include "nvrm_memmgr.h" +#include "ap15rm_xpc_hw_private.h" +#include "nvrm_hardware_access.h" +#include "nvassert.h" +#include "ap15/ararb_sema.h" +#include "ap15/arictlr_arbgnt.h" +#include "nvrm_avp_shrd_interrupt.h" + +// Minimum sdram offset required so that avp can access the address which is +// passed. +// AVP can not access the 0x0000:0000 to 0x0000:0040 +enum { MIN_SDRAM_OFFSET = 0x100}; + + +//There are only 32 arb semaphores +#define MAX_ARB_NUM 32 + +#define ARBSEMA_REG_READ(pArbSemaVirtAdd, reg) \ + NV_READ32(pArbSemaVirtAdd + (ARB_SEMA_##reg##_0)) + +#define ARBSEMA_REG_WRITE(pArbSemaVirtAdd, reg, data) \ + NV_WRITE32(pArbSemaVirtAdd + (ARB_SEMA_##reg##_0), (data)); + +#define ARBGNT_REG_READ(pArbGntVirtAdd, reg) \ + NV_READ32(pArbGntVirtAdd + (ARBGNT_##reg##_0)) + +#define ARBGNT_REG_WRITE(pArbGntVirtAdd, reg, data) \ + NV_WRITE32(pArbGntVirtAdd + (ARBGNT_##reg##_0), (data)); + +static NvOsInterruptHandle s_arbInterruptHandle = NULL; + +// Combines the Processor Xpc system details. This contains the details of the +// receive/send message queue and messaging system. +typedef struct NvRmPrivXpcMessageRec +{ + NvRmDeviceHandle hDevice; + + // Hw mail box register. + CpuAvpHwMailBoxReg HwMailBoxReg; + +} NvRmPrivXpcMessage; + +typedef struct NvRmPrivXpcArbSemaRec +{ + NvRmDeviceHandle hDevice; + NvU8 *pArbSemaVirtAddr; + NvU8 *pArbGntVirtAddr; + NvOsSemaphoreHandle semaphore[MAX_ARB_NUM]; + NvOsMutexHandle mutex[MAX_ARB_NUM]; + NvOsIntrMutexHandle hIntrMutex; + +} NvRmPrivXpcArbSema; + +static NvRmPrivXpcArbSema s_ArbSema; + +//Forward declarations +static NvError InitArbSemaSystem(NvRmDeviceHandle hDevice); +static void ArbSemaIsr(void *args); +NvU32 GetArbIdFromRmModuleId(NvRmModuleID modId); +/** + * Initialize the cpu avp hw mail box address and map the hw register address + * to virtual address. + * Thread Safety: Caller responsibility + */ +static NvError +InitializeCpuAvpHwMailBoxRegister(NvRmPrivXpcMessageHandle hXpcMessage) +{ + NvError e; + NvRmPhysAddr ResourceSemaPhysAddr; + + // Get base address of the hw mail box register. This register is in the set + // of resource semaphore module Id. + NvRmModuleGetBaseAddress(hXpcMessage->hDevice, + NVRM_MODULE_ID(NvRmModuleID_ResourceSema, 0), + &ResourceSemaPhysAddr, &hXpcMessage->HwMailBoxReg.BankSize); + + // Map the base address to the virtual address. + hXpcMessage->HwMailBoxReg.pHwMailBoxRegBaseVirtAddr = NULL; + NV_CHECK_ERROR(NvRmPhysicalMemMap( + ResourceSemaPhysAddr, hXpcMessage->HwMailBoxReg.BankSize, + NVOS_MEM_READ_WRITE, NvOsMemAttribute_Uncached, + (void **)&hXpcMessage->HwMailBoxReg.pHwMailBoxRegBaseVirtAddr)); + + NvRmPrivXpcHwResetOutbox(&hXpcMessage->HwMailBoxReg); + + return NvSuccess; +} + +/** + * DeInitialize the cpu avp hw mail box address and unmap the hw register address + * virtual address. + * Thread Safety: Caller responsibility + */ +static void DeInitializeCpuAvpHwMailBoxRegister(NvRmPrivXpcMessageHandle hXpcMessage) +{ + // Unmap the hw register base virtual address + NvRmPhysicalMemUnmap(hXpcMessage->HwMailBoxReg.pHwMailBoxRegBaseVirtAddr, + hXpcMessage->HwMailBoxReg.BankSize); + hXpcMessage->HwMailBoxReg.pHwMailBoxRegBaseVirtAddr = NULL; +} + +/** + * Create the cpu-avp messaging system. + * This function will call other helper function to create the messaging technique + * used for cpu-avp communication. + * Thread Safety: Caller responsibility + */ +static NvError +CreateCpuAvpMessagingSystem(NvRmPrivXpcMessageHandle hXpcMessage) +{ + NvError Error = NvSuccess; + + Error = InitializeCpuAvpHwMailBoxRegister(hXpcMessage); + +#if NV_IS_AVP + hXpcMessage->HwMailBoxReg.IsCpu = NV_FALSE; +#else + hXpcMessage->HwMailBoxReg.IsCpu = NV_TRUE; +#endif + + // If error found then destroy all the allocation and initialization, + if (Error) + DeInitializeCpuAvpHwMailBoxRegister(hXpcMessage); + + return Error; +} + + +/** + * Destroy the cpu-avp messaging system. + * This function destroy all the allocation/initialization done for creating + * the cpu-avp messaging system. + * Thread Safety: Caller responsibility + */ +static void DestroyCpuAvpMessagingSystem(NvRmPrivXpcMessageHandle hXpcMessage) +{ + // Destroy the cpu-avp hw mail box registers. + DeInitializeCpuAvpHwMailBoxRegister(hXpcMessage); + hXpcMessage->HwMailBoxReg.pHwMailBoxRegBaseVirtAddr = NULL; + hXpcMessage->HwMailBoxReg.BankSize = 0; +} + + +NvError +NvRmPrivXpcCreate( + NvRmDeviceHandle hDevice, + NvRmPrivXpcMessageHandle *phXpcMessage) +{ + NvError Error = NvSuccess; + NvRmPrivXpcMessageHandle hNewXpcMsgHandle = NULL; + + *phXpcMessage = NULL; + + // Allocates the memory for the xpc message handle. + hNewXpcMsgHandle = NvOsAlloc(sizeof(*hNewXpcMsgHandle)); + if (!hNewXpcMsgHandle) + { + return NvError_InsufficientMemory; + } + + // Initialize all the members of the xpc message handle. + hNewXpcMsgHandle->hDevice = hDevice; + hNewXpcMsgHandle->HwMailBoxReg.pHwMailBoxRegBaseVirtAddr = NULL; + hNewXpcMsgHandle->HwMailBoxReg.BankSize = 0; + + // Create the messaging system between the processors. + Error = CreateCpuAvpMessagingSystem(hNewXpcMsgHandle); + + // if error the destroy all allocations done here. + if (Error) + { + NvOsFree(hNewXpcMsgHandle); + hNewXpcMsgHandle = NULL; + } + +#if NV_IS_AVP + Error = InitArbSemaSystem(hDevice); + if (Error) + { + NvOsFree(hNewXpcMsgHandle); + hNewXpcMsgHandle = NULL; + } +#endif + + // Copy the new xpc message handle into the passed parameter. + *phXpcMessage = hNewXpcMsgHandle; + return Error; +} + + +/** + * Destroy the Rm Xpc message handle. + * Thread Safety: It is provided inside the function. + */ +void NvRmPrivXpcDestroy(NvRmPrivXpcMessageHandle hXpcMessage) +{ + // If not a null pointer then destroy. + if (hXpcMessage) + { + // Destroy the messaging system between processor. + DestroyCpuAvpMessagingSystem(hXpcMessage); + + // Free the allocated memory for the xpc message handle. + NvOsFree(hXpcMessage); + } +} + + +// Set the outbound mailbox with the given data. We might have to spin until +// it's safe to send the message. +NvError +NvRmPrivXpcSendMessage(NvRmPrivXpcMessageHandle hXpcMessage, NvU32 data) +{ + NvRmPrivXpcHwSendMessageToTarget(&hXpcMessage->HwMailBoxReg, data); + return NvSuccess; +} + + +// Get the value currently in the inbox register. This read clears the incoming +// interrupt. +NvU32 +NvRmPrivXpcGetMessage(NvRmPrivXpcMessageHandle hXpcMessage) +{ + NvU32 data; + NvRmPrivXpcHwReceiveMessageFromTarget(&hXpcMessage->HwMailBoxReg, &data); + return data; +} + +NvError NvRmXpcInitArbSemaSystem(NvRmDeviceHandle hDevice) +{ +#if NV_IS_AVP + return NvSuccess; +#else + return InitArbSemaSystem(hDevice); +#endif +} + +static NvError InitArbSemaSystem(NvRmDeviceHandle hDevice) +{ + NvOsInterruptHandler ArbSemaHandler; + NvRmPhysAddr ArbSemaBase, ArbGntBase; + NvU32 ArbSemaSize, ArbGntSize; + NvU32 irq; + NvError e; + NvU32 i = 0; + + irq = NvRmGetIrqForLogicalInterrupt( + hDevice, NvRmModuleID_ArbitrationSema, 0); + + ArbSemaHandler = ArbSemaIsr; + + NV_CHECK_ERROR_CLEANUP( + NvRmInterruptRegister(hDevice, 1, &irq, &ArbSemaHandler, + hDevice, &s_arbInterruptHandle, NV_TRUE) + ); + + NvRmModuleGetBaseAddress(hDevice, + NVRM_MODULE_ID(NvRmModuleID_ArbitrationSema, 0), + &ArbSemaBase, &ArbSemaSize); + + NvRmModuleGetBaseAddress(hDevice, + NVRM_MODULE_ID(NvRmPrivModuleID_InterruptArbGnt, 0), + &ArbGntBase, &ArbGntSize); + + NV_CHECK_ERROR_CLEANUP( + NvRmPhysicalMemMap(ArbSemaBase, ArbSemaSize, NVOS_MEM_READ_WRITE, + NvOsMemAttribute_Uncached, (void**)&s_ArbSema.pArbSemaVirtAddr) + ); + + NV_CHECK_ERROR_CLEANUP( + NvRmPhysicalMemMap(ArbGntBase, ArbGntSize, NVOS_MEM_READ_WRITE, + NvOsMemAttribute_Uncached, (void**)&s_ArbSema.pArbGntVirtAddr) + ); + + //Initialize all the semaphores and mutexes + for (i=0;i<MAX_ARB_NUM;i++) + { + NV_CHECK_ERROR_CLEANUP( + NvOsSemaphoreCreate(&s_ArbSema.semaphore[i], 0) + ); + + NV_CHECK_ERROR_CLEANUP( + NvOsMutexCreate(&s_ArbSema.mutex[i]) + ); + } + + NV_CHECK_ERROR_CLEANUP( + NvOsIntrMutexCreate(&s_ArbSema.hIntrMutex) + ); + +fail: + + return e; +} + + +static void ArbSemaIsr(void *args) +{ + NvU32 int_mask, proc_int_enable, arb_gnt, i = 0; + + NvOsIntrMutexLock(s_ArbSema.hIntrMutex); + //Check which arb semaphores have been granted to this processor + arb_gnt = ARBSEMA_REG_READ(s_ArbSema.pArbSemaVirtAddr, SMP_GNT_ST); + + //Figure out which arb semaphores were signalled and then disable them. +#if NV_IS_AVP + proc_int_enable = ARBGNT_REG_READ(s_ArbSema.pArbGntVirtAddr, COP_ENABLE); + int_mask = arb_gnt & proc_int_enable; + ARBGNT_REG_WRITE(s_ArbSema.pArbGntVirtAddr, + COP_ENABLE, (proc_int_enable & ~int_mask)); +#else + proc_int_enable = ARBGNT_REG_READ(s_ArbSema.pArbGntVirtAddr, CPU_ENABLE); + int_mask = arb_gnt & proc_int_enable; + ARBGNT_REG_WRITE(s_ArbSema.pArbGntVirtAddr, + CPU_ENABLE, (proc_int_enable & ~int_mask)); +#endif + + //Signal all the required semaphores + do + { + if (int_mask & 0x1) + { + NvOsSemaphoreSignal(s_ArbSema.semaphore[i]); + } + int_mask >>= 1; + i++; + + } while (int_mask); + + NvOsIntrMutexUnlock(s_ArbSema.hIntrMutex); + NvRmInterruptDone(s_arbInterruptHandle); +} + +NvU32 GetArbIdFromRmModuleId(NvRmModuleID modId) +{ + NvU32 arbId; + + switch(modId) + { + case NvRmModuleID_BseA: + arbId = NvRmArbSema_Bsea; + break; + case NvRmModuleID_Vde: + default: + arbId = NvRmArbSema_Vde; + break; + } + + return arbId; +} + +void NvRmXpcModuleAcquire(NvRmModuleID modId) +{ + NvU32 RequestedSemaNum; + NvU32 reg; + + RequestedSemaNum = GetArbIdFromRmModuleId(modId); + + NvOsMutexLock(s_ArbSema.mutex[RequestedSemaNum]); + NvOsIntrMutexLock(s_ArbSema.hIntrMutex); + + //Try to grab the lock + ARBSEMA_REG_WRITE(s_ArbSema.pArbSemaVirtAddr, SMP_GET, 1 << RequestedSemaNum); + + //Enable arb sema interrupt +#if NV_IS_AVP + reg = ARBGNT_REG_READ(s_ArbSema.pArbGntVirtAddr, COP_ENABLE); + reg |= (1 << RequestedSemaNum); + ARBGNT_REG_WRITE(s_ArbSema.pArbGntVirtAddr, COP_ENABLE, reg); +#else + reg = ARBGNT_REG_READ(s_ArbSema.pArbGntVirtAddr, CPU_ENABLE); + reg |= (1 << RequestedSemaNum); + ARBGNT_REG_WRITE(s_ArbSema.pArbGntVirtAddr, CPU_ENABLE, reg); +#endif + + NvOsIntrMutexUnlock(s_ArbSema.hIntrMutex); + NvOsSemaphoreWait(s_ArbSema.semaphore[RequestedSemaNum]); +} + +void NvRmXpcModuleRelease(NvRmModuleID modId) +{ + NvU32 RequestedSemaNum; + + RequestedSemaNum = GetArbIdFromRmModuleId(modId); + + //Release the lock + ARBSEMA_REG_WRITE(s_ArbSema.pArbSemaVirtAddr, SMP_PUT, 1 << RequestedSemaNum); + + NvOsMutexUnlock(s_ArbSema.mutex[RequestedSemaNum]); +} |