diff options
Diffstat (limited to 'arch/arm/mach-tegra/nvrm/core/ap15/ap15rm_interrupt.c')
-rw-r--r-- | arch/arm/mach-tegra/nvrm/core/ap15/ap15rm_interrupt.c | 314 |
1 files changed, 314 insertions, 0 deletions
diff --git a/arch/arm/mach-tegra/nvrm/core/ap15/ap15rm_interrupt.c b/arch/arm/mach-tegra/nvrm/core/ap15/ap15rm_interrupt.c new file mode 100644 index 000000000000..db6c1beb2d66 --- /dev/null +++ b/arch/arm/mach-tegra/nvrm/core/ap15/ap15rm_interrupt.c @@ -0,0 +1,314 @@ +/* + * Copyright (c) 2007-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. + * + */ + +#include "nvos.h" +#include "nvrm_module.h" +#include "nvrm_interrupt.h" +#include "nvrm_processor.h" +#include "nvassert.h" +#include "nvrm_relocation_table.h" +#include "nvrm_chiplib.h" +#include "nvrm_hwintf.h" +#include "nvrm_drf.h" +#include "nvrm_structure.h" +#include "ap15rm_private.h" +#include "ap15/arictlr.h" + +#define NVRM_ENABLE_PRINTF 0 // Module debug: 0=disable, 1=enable + +#if (NV_DEBUG && NVRM_ENABLE_PRINTF) +#define NVRM_INTERRUPT_PRINTF(x) NvOsDebugPrintf x +#else +#define NVRM_INTERRUPT_PRINTF(x) +#endif + +//----------------------------------------------------------------------------- +// Register access macros +//----------------------------------------------------------------------------- + +#define NV_INTR_REGR(rm,inst,reg) NV_REGR(rm, NvRmPrivModuleID_Interrupt, inst, ICTLR_##reg##_0) +#define NV_INTR_REGW(rm,inst,reg,data) NV_REGW(rm, NvRmPrivModuleID_Interrupt, inst, ICTLR_##reg##_0, data) + +#define NV_REGA(rm, aperture, instance, offset) \ + ((volatile void*)((NvUPtr)(((rm)->ModuleTable.ModInst + (rm)->ModuleTable.Modules[(aperture)].Index + (instance))->VirtAddr) + (offset))) + +#define NV_INTR_REG_READ(pIntr, reg) NV_READ32((((NvUPtr)(pIntr)) + ICTLR_##reg##_0)) + +NvRmIntrDecoder gs_Ap15PrimaryDecoder = + /* AP15 Primary interrupt controller */ + {NvRmPrivModuleID_Interrupt, + NVRM_IRQS_PER_INTR_CTLR, 0, {0}, {0}, {0} }; + +NvRmIntrDecoder gs_Ap20PrimaryDecoder = + /* AP20 Primary interrupt controller */ + {NvRmPrivModuleID_ArmPerif, + NVRM_IRQS_PER_INTR_CTLR * 5, 0, {0}, {0}, {0} }; + + +NvRmIntrDecoder *gs_PrimaryDecoder = &gs_Ap15PrimaryDecoder; + +NvRmIntrDecoder gs_SubDecoder[] = +{ + /* Secondary interrupt controllers */ + + /* Secondary interrupt controller for APB DMA */ + {NvRmPrivModuleID_ApbDma, + NVRM_MAX_DMA_CHANNELS, 0, {0}, {0}, {0}}, + + /* GPIO secondary interrupt controller */ + {NvRmPrivModuleID_Gpio, + NVRM_IRQS_PER_GPIO_CTLR, 0, {0}, {0}, {0}}, +}; + + + +static NvU16 +NvRmPrivSubControllerInit( + NvRmDeviceHandle hRmDevice, + NvRmIntrDecoderHandle pDecoder, + NvU16 Irq) +{ + NvRmModuleInstance *inst; // Pointer to the module instance + NvU8 num; // Number of instances/loop index + NvU32 devid; // Hardware device id + NvError e; + + NV_ASSERT( hRmDevice ); + + NV_CHECK_ERROR_CLEANUP( NvRmPrivGetModuleInstance( hRmDevice, + pDecoder->ModuleID, &inst) ); + NV_ASSERT(inst != NULL); + + num = 0; + devid = inst->DeviceId; + /* Get all the instances of that sub-controller */ + while ( devid == inst->DeviceId ) + { + NV_ASSERT( inst->IrqMap != NULL ); + NV_ASSERT( num < NVRM_MAX_INSTANCES); + + /* For modules which are sub-interrupt controllers, IRQ value in the + * IrqMap[0] represents the IRQ of the main interrupt controller. Sub + * IRQs for that controller can be computed from IndexMax and IndexBase + * members */ + inst->IrqMap->IndexMax = pDecoder->SubIrqCount; + inst->IrqMap->IndexBase = Irq; + + pDecoder->MainIrq[num] = inst->IrqMap->Irq[0]; + pDecoder->SubIrqFirst[num] = Irq; + pDecoder->SubIrqLast[num] = Irq + pDecoder->SubIrqCount - 1; + + Irq += pDecoder->SubIrqCount; + inst++; + num++; + } + pDecoder->NumberOfInstances = num; + + return Irq; +fail: + NV_ASSERT(!"Invalid ModuleID or Instance in ap15rm_interrupt"); + return 0; +} + +static +NvU16 NvRmPrivMainControllerInit(NvRmDeviceHandle hRmDevice, + NvRmIntrDecoder *pDecoder) +{ + NvRmModuleInstance *inst; // Pointer to the module instance + NvU32 num = 0; + NvU16 irq = 0; // Primary controller will start with IRQ 0. + NvU16 devid; + NvError e; + + NV_CHECK_ERROR_CLEANUP( + NvRmPrivGetModuleInstance( hRmDevice, pDecoder->ModuleID, &inst) + ); + + NV_ASSERT(inst != NULL); + devid = inst->DeviceId; + + while( devid == inst->DeviceId ) + { + pDecoder->SubIrqFirst[num] = irq; + pDecoder->SubIrqLast[num] = irq + pDecoder->SubIrqCount - 1; + pDecoder->MainIrq[num] = NVRM_IRQ_INVALID; + + irq += pDecoder->SubIrqCount; + num++; + inst++; + } + + pDecoder->NumberOfInstances = num; + return irq; +fail: + NV_ASSERT(!"Invalid ModuleID or Instance in ap15rm_interrupt"); + return 0; +} + +void NvRmPrivInterruptTableInit( NvRmDeviceHandle hRmDevice ) +{ + NvU16 irq; + NvU32 subDecoder; + + NV_ASSERT( hRmDevice ); + + NVRM_CAP_CLEAR(hRmDevice, NvRmCaps_HasFalconInterruptController); + NVRM_CAP_CLEAR(hRmDevice, NvRmCaps_Has128bitInterruptSerializer); + + // WARNING: the falcon interrupt controller is not in simulation! + if( NvRmIsSimulation() == NV_FALSE && hRmDevice->ChipId.Id >= 0x20) + { + NVRM_CAP_SET(hRmDevice, NvRmCaps_HasFalconInterruptController); + + if (hRmDevice->ChipId.Major == 0 + && hRmDevice->ChipId.Netlist != 0 + && hRmDevice->ChipId.Minor != 0 ) + { + /* PALAU has 128-bit interrupt serializer and needs some WARs to + * compensate for the delays in interrupt arrival at interrupt + * controller */ + NVRM_CAP_SET(hRmDevice, NvRmCaps_Has128bitInterruptSerializer); + } + } + + if (!NVRM_IS_CAP_SET(hRmDevice, NvRmCaps_HasFalconInterruptController)) + { + gs_PrimaryDecoder = &gs_Ap15PrimaryDecoder; + } + else + { + gs_PrimaryDecoder = &gs_Ap20PrimaryDecoder; + } + + irq = NvRmPrivMainControllerInit(hRmDevice, gs_PrimaryDecoder); + + subDecoder = NV_ARRAY_SIZE(gs_SubDecoder); + while (subDecoder) + { + subDecoder --; + irq = NvRmPrivSubControllerInit(hRmDevice, + &(gs_SubDecoder[subDecoder]), irq); + } + + hRmDevice->MaxIrqs = irq; + NVRM_INTERRUPT_PRINTF(("MAX IRQs: %d\n", irq)); +} + +NvU32 NvRmGetIrqForLogicalInterrupt( + NvRmDeviceHandle hRmDevice, + NvRmModuleID ModuleID, + NvU32 Index) +{ + NvRmModuleInstance* inst = NULL; // Pointer to module instance + NvRmModuleIrqMap* pIrqMap; // Pointer to module IRQ map + NvU16 irq = 0; + NvError e; + NV_ASSERT( hRmDevice ); + + + NV_CHECK_ERROR_CLEANUP( NvRmPrivGetModuleInstance( hRmDevice, + ModuleID, &inst) ); + if ( inst == NULL || inst->IrqMap == NULL) + { + // NV_ASSERT(!"Illegal call\n"); + // Is this legal? Some clients like NVBL + // is calling this API blindly as they don't know if this module + // supports interrupt or not. I don't know if this good or bad. Why + // would a clinet request IRQ, if they know the underying module + // doesn'tsupport interrupts. + return NVRM_IRQ_INVALID; + } + + pIrqMap = inst->IrqMap; + + /* Check if this the interrupt for this module is routed to secondary + * interrupt controller or to the main controller */ + /* FIXME rename IndexMax and IndexBase variables to SubInterruptCount and + * SubInterruptBase */ + if (pIrqMap->IndexMax == 0) + { + NV_ASSERT (Index < pIrqMap->IrqCount); + NV_ASSERT(pIrqMap->Irq[Index] != NVRM_IRQ_INVALID); + + irq = pIrqMap->Irq[Index]; + } + /* Secondary interrupt controller */ + else + { + // Requesting controller's main interrupt? This is a hack used by the + // OAL to get the main IRQ line for the sub-deocders. OAL builds a list + // of all the main IRQs for the sub-decoders and asserts if someone + // tries to register an interrupt handler for the main IRQ line. + if (Index == 0xFF) + { + NV_ASSERT (pIrqMap->Irq[0] != NVRM_IRQ_INVALID); + irq = pIrqMap->Irq[0]; + } else + { + /* Index cannot be more than the Max IRQs registered by that + * secondary interrupt controller */ + NV_ASSERT( Index < pIrqMap->IndexMax ); + irq = pIrqMap->IndexBase + Index; + } + } + return irq; +fail: + NV_ASSERT(!"Invalid ModuleID or Instance in ap15rm_interrupt"); + return 0; +} + +NvU32 NvRmGetIrqCountForLogicalInterrupt( + NvRmDeviceHandle hRmDevice, + NvRmModuleID ModuleID) +{ + NvRmModuleInstance *inst = NULL; + NvError e; + + NV_ASSERT( hRmDevice ); + + NV_CHECK_ERROR_CLEANUP( NvRmPrivGetModuleInstance( hRmDevice, + ModuleID, &inst) ); + if ( inst == NULL || inst->IrqMap == NULL) + { + // NV_ASSERT(!"Illegal call\n"); + // Is this legal? Some clients like NVBL are calling this API blindly + // as they don't know if this module supports interrupt or not. + // I don't know if this good or bad. Why would a clinet request IRQ, + // if they know the underying module doesn't support interrupts. + return 0; + } + + return inst->IrqMap->IrqCount; +fail: + NV_ASSERT(!"Invalid ModuleID or Instance in ap15rm_interrupt"); + return 0; +} |