| Index: arch/arm/mach-tegra/nv/include/nvrm_interrupt.h
|
| diff --git a/arch/arm/mach-tegra/nv/include/nvrm_interrupt.h b/arch/arm/mach-tegra/nv/include/nvrm_interrupt.h
|
| new file mode 100644
|
| index 0000000000000000000000000000000000000000..ad06f78b1c8b509922f161af9dbd79efbb3db6ca
|
| --- /dev/null
|
| +++ b/arch/arm/mach-tegra/nv/include/nvrm_interrupt.h
|
| @@ -0,0 +1,271 @@
|
| +/*
|
| + * 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 INCLUDED_nvrm_interrupt_H
|
| +#define INCLUDED_nvrm_interrupt_H
|
| +
|
| +
|
| +#if defined(__cplusplus)
|
| +extern "C"
|
| +{
|
| +#endif
|
| +
|
| +#include "nvrm_module.h"
|
| +#include "nvrm_init.h"
|
| +
|
| +#include "nvos.h"
|
| +
|
| +/** @file
|
| + * @brief <b>NVIDIA Driver Development Kit:
|
| + * Resource Manager %Interrupt API</b>
|
| + *
|
| + * @b Description: Declares the interrupt API for use by NvDDK modules.
|
| + */
|
| +
|
| +/**
|
| + * @defgroup nvrm_interrupt RM Interrupt Management Services
|
| + *
|
| + * @ingroup nvddk_rm
|
| + * @{
|
| + *
|
| + * IRQ Numbers
|
| + * -----------
|
| + * In most cases, we are using the CPU's legacy interrupt support, rather than
|
| + * the new MPCore interrupt controller. This means that we only have one ISR
|
| + * shared between all of the devices in our chip. To determine which device is
|
| + * interrupting us, we have to read some registers. We assign each interrupt
|
| + * source an "IRQ number". IRQ numbers are OS-independent and HW-dependent (a
|
| + * given device may have a different IRQ number from chip to chip).
|
| + *
|
| + * It is arbitrary how far we decode interrupts as part of determining the IRQ
|
| + * number. Normally we might assign one IRQ number to each interrupt line that
|
| + * feeds into the main interrupt controller (typically one per device in the
|
| + * chip), but we can decode further if we want. For example, there are several
|
| + * GPIO controllers, each of which controls 32 GPIO lines. The GPIO controller
|
| + * interrupt line is constructed by OR'ing together the interrupt lines for each
|
| + * of the 32 GPIO pins. If we want, we can assign each GPIO controller 32
|
| + * separate IRQ numbers, one per GPIO line; this simply means we have to sub-
|
| + * decode the interrupts a little further inside the ISR.
|
| + *
|
| + * The main advantage of doing this sub-decoding is that only a single driver is
|
| + * allowed to hook each interrupt source -- if multiple drivers both want to
|
| + * register interrupt handlers for the same interrupt source, the drivers will
|
| + * fight with one another trying to handle the same interrupt, so this is an
|
| + * error. At the same time, it's entirely plausible that out of a group of 32
|
| + * GPIO pins, multiple different drivers care about different groups of those
|
| + * pins. In the absence of sub-decoding, we would have to implement a "GPIO
|
| + * driver" whose sole purpose was to allow those other drivers to register for
|
| + * GPIO notifications, and then use driver-to-driver signaling to indicate when
|
| + * a pin has transitioned state. This is an extra level of overhead compared
|
| + * to if drivers are allowed to directly hook the interrupts for the pins they
|
| + * care about.
|
| + *
|
| + * Because IRQ numbers change from chip to chip, you must ask the RM for the IRQ
|
| + * number of the device when you want to hook its interrupt. This can be
|
| + * accomplished using the NvRmGetIrqForLogicalInterrupt() API. You pass it an
|
| + * [NvRmModuleID, Index] pair telling it what device you are interested in, and
|
| + * which sub-interrupt within that device. Often Index is just zero (many
|
| + * devices only have one IRQ number). For GPIO it might by the pin number
|
| + * within the GPIO controller. For UART, you might (entirely hypothetically --
|
| + * there is no requirement that you do this) have Index=0 for the receive
|
| + * interrupt and Index=1 for the send interrupt.
|
| + *
|
| + * Hooking an Interrupt
|
| + * --------------------
|
| + * Once you have the IRQ number(s), you can hook the interrupt(s) by calling
|
| + * NvRmInterruptRegister(). At driver shutdown, you can unhook the interrupt(s)
|
| + * by calling NvRmInterruptUnregister().
|
| + *
|
| + * NvRmInterruptRegister takes a list of IRQs and a list of callback functions to be
|
| + * called when the corresponding interrupt has fired. The callback functions
|
| + * will be passed an extra "void *context" parameter, typically a pointer to
|
| + * your private driver structure that keeps track of the state of your device.
|
| + * For example, the NAND driver might pass the NvDdkNandHandle as the context
|
| + * param.
|
| + *
|
| + * Drivers that care about more than one IRQ should call NvRmInterruptRegister only
|
| + * once. Calling NvRmInterruptRegister twice (each time with a single IRQ number)
|
| + * may consume more system resources than calling NvRmInterruptRegister once with
|
| + * a list of 2 IRQ numbers and 2 callbacks.
|
| + *
|
| + * Rules for Interrupt Handlers
|
| + * ----------------------------
|
| + * We assume that all interrupt handlers (i.e. the callbacks passed to
|
| + * NvRmInterruptRegister) are "fast": that is, any complex processing that cannot
|
| + * complete in a tightly bounded amount of time, such as polling registers to
|
| + * wait for the HW to complete some processing, is not done in the ISR proper.
|
| + * Instead, the ISR would signal a semaphore, clear the interrupt, and pass off
|
| + * the rest of the work to another thread.
|
| + *
|
| + * To be more precise about this, we expect all interrupt handlers to follow
|
| + * these rules:
|
| + * - They may only call a subset of NvOs functions. The exact subset is
|
| + * documented in nvos.h.
|
| + * - No floating-point. (We don't want to have to save and restore the
|
| + * floating point registers on an interrupt.)
|
| + * - They should use as little stack space as possible. They certainly should
|
| + * not use any recursive algorithms, for example. (For example, if they need
|
| + * to look up a node in a red-black tree, they must use an iterative version
|
| + * of the tree search rather than recursion.) Straw man: 256B maximum?
|
| + * - Any control flow structure that involves looping (like a "for" or "while"
|
| + * statement) must be guaranteed to terminate within a clearly understood
|
| + * time limit. We don't have a strict upper bound, but if it takes
|
| + * milliseconds, it's out of the question.
|
| + * - The callback function _must_ clear the cause of the interrupt. Upon
|
| + * returning from the callback the interrupt will be automatically re-enabled.
|
| + * If the cause is not cleared the system will be stuck in an infinite loop
|
| + * taking interrupts.
|
| + */
|
| +
|
| +/**
|
| + * A Logical Interrupt is a tuple that includes the class of interrupts
|
| + * (i.e., a module), an instance of that module, and the specific interrupt
|
| + * within that instance (an index). This is an abstraction for the
|
| + * actual interrupt bits implemented on the SOC.
|
| + */
|
| +
|
| +typedef struct NvRmLogicalIntrRec
|
| +{
|
| +
|
| + /**
|
| + * Interrupt index within the current instance of specified Module.
|
| + * This identifies a specific interrupt. This is an enumerated index
|
| + * and not a bit-mask.
|
| + */
|
| + NvU8 Index;
|
| +
|
| + /**
|
| + * The SOC hardware controller class identifier
|
| + */
|
| + NvRmModuleID ModuleID;
|
| +} NvRmLogicalIntr;
|
| +
|
| +/**
|
| + * Translate a given logical interrupt to its corresponding IRQ number.
|
| + *
|
| + * @param hRmDevice The RM device handle
|
| + * @param ModuleID The module of interest
|
| + * @param Index Zero-based interrupt index within the module
|
| + *
|
| + * @return The IRQ number.
|
| + */
|
| +
|
| + NvU32 NvRmGetIrqForLogicalInterrupt(
|
| + NvRmDeviceHandle hRmDevice,
|
| + NvRmModuleID ModuleID,
|
| + NvU32 Index );
|
| +
|
| +/**
|
| + * Retrieve the number of IRQs associated with a particular module instance.
|
| + *
|
| + * @param hRmDevice The RM device handle
|
| + * @param ModuleID The module of interest
|
| + *
|
| + * @return The number of IRQs.
|
| + */
|
| +
|
| + NvU32 NvRmGetIrqCountForLogicalInterrupt(
|
| + NvRmDeviceHandle hRmDevice,
|
| + NvRmModuleID ModuleID );
|
| +
|
| +/*
|
| + * Register the interrupt with the given interrupt handler.
|
| + *
|
| + * Assert encountered in debug mode if irq number is not valid.
|
| + *
|
| + * @see NvRmInterruptEnable()
|
| + *
|
| + * @param hRmDevice The RM device handle.
|
| + * @param IrqListSize size of the IrqList passed in for registering the irq
|
| + * handlers for each irq number.
|
| + * @param pIrqList Array of IRQ numbers for which interupt handlers to be
|
| + * registerd.
|
| + * @param pIrqHandlerList array intrupt routine to be called when interrupt
|
| + * occures.
|
| + * @param context pointer to the registrer's context handle
|
| + * @param handle handle to the registered interrupts. This handle is used by for
|
| + * unregistering the interrupt.
|
| + * @param InterruptEnable If true, immediately enable interrupt. Otherwise
|
| + * enable interrupt only after calling NvRmInterruptEnable().
|
| + *
|
| + * @retval "NvError_IrqRegistrationFailed" if interupt is already registred.
|
| + * @retval "NvSuccess" if registration is successfull.
|
| + */
|
| +NvError
|
| +NvRmInterruptRegister(
|
| + NvRmDeviceHandle hRmDevice,
|
| + NvU32 IrqListSize,
|
| + const NvU32 *pIrqList,
|
| + const NvOsInterruptHandler *pIrqHandlerList,
|
| + void *context,
|
| + NvOsInterruptHandle *handle,
|
| + NvBool InterruptEnable);
|
| +
|
| +/**
|
| + * Un-registers the interrupt handler from the associated interrupt handle which
|
| + * is returned by the NvRmInterruptRegister API.
|
| + *
|
| + * @param handle Handle returned when the interrupt is registered.
|
| + */
|
| +void
|
| +NvRmInterruptUnregister(
|
| + NvRmDeviceHandle hRmDevice,
|
| + NvOsInterruptHandle handle);
|
| +
|
| +/**
|
| + * Enable the interrupt handler from the associated interrupt handle which
|
| + * is returned by the NvRmInterruptRegister API.
|
| + *
|
| + * @param handle Handle returned when the interrupt is registered.
|
| + *
|
| + * @retval "NvError_BadParameter" if handle is not valid
|
| + * @retval "NvError_InsufficientMemory" if interupt enable failed.
|
| + * @retval "NvSuccess" if registration is successfull.
|
| + */
|
| +NvError
|
| +NvRmInterruptEnable(
|
| + NvRmDeviceHandle hRmDevice,
|
| + NvOsInterruptHandle handle);
|
| +
|
| +/**
|
| + * Called by the interrupt callaback to re-enable the interrupt.
|
| + */
|
| +
|
| +void
|
| +NvRmInterruptDone( NvOsInterruptHandle handle );
|
| +
|
| +
|
| +#if defined(__cplusplus)
|
| +}
|
| +#endif
|
| +
|
| +#endif
|
|
|