📄 lh7a404_vic_driver.c
字号:
/* For VIC1, set all interrupts as IRQ type, disabled, and
cleared */
for (source = VIC_FIRST_VIC1_INTERRUPT;
source <= VIC_LAST_VIC1_INTERRUPT; source++)
{
/* Set all jump addresses to 0x00000000 */
vic_func_ptrs[source] = (PFV) 0x00000000;
/* Set interrupt to disabled */
VIC1->intenclr = VIC_INT_SELECT((UNS_32)(source));
/* Clear any pending software interrupts */
VIC1->swint_clr = VIC_INT_SELECT((UNS_32)(source));
}
/* For VIC2, set all interrupts as IRQ type, disabled, and
cleared */
for (source = VIC_FIRST_VIC2_INTERRUPT;
source <= VIC_LAST_VIC2_INTERRUPT; source++)
{
/* Set all jump addresses to 0x00000000 */
vic_func_ptrs[source] = (PFV) 0x00000000;
/* Set interrupt to disabled */
VIC2->intenclr = VIC_INT_SELECT((UNS_32)(source -
VIC_FIRST_VIC2_INTERRUPT));
/* Clear any pending software interrupts */
VIC2->swint_clr = VIC_INT_SELECT((UNS_32)(source -
VIC_FIRST_VIC2_INTERRUPT));
}
/* All interrupt types are IRQ type */
VIC1->intsel = 0x00000000;
VIC2->intsel = 0x00000000;
/* Clear any pending vectored interrupts */
VIC1->vecaddr = 0x00000000;
VIC2->vecaddr = 0x00000000;
/* Set the default address for IRQs as the default handler */
VIC1->nv_vecaddr = (PFV) &vic1_irq_dispatcher;
VIC2->nv_vecaddr = (PFV) &vic2_irq_dispatcher;
for (idx = 0; idx < 16; idx++)
{
/* Disable all vectored interrupts */
VIC1->vec_cntl[idx] = 0x00000000;
VIC2->vec_cntl[idx] = 0x00000000;
/* Make all the default vectored handlers the default IRQ
handler (safety) until they are correctly initialized */
VIC1->vecaddrs[idx] = (PFV) &vec_irq_handler;
VIC2->vecaddrs[idx] = (PFV) &vec_irq_handler;
}
/* Save user passed vector area pointer */
vecarea = (UNS_32 *) vectbladdr;
/* Put interrupt and exception code at ARM vector area */
vic_int_write_table();
}
/***********************************************************************
*
* Function: vic_install_arm_handler
*
* Purpose: Install an new ARM interrupt or exception handler
*
* Processing:
* If the passed fiq_handler_ptr pointer is not 0x00000000, then
* set the handler jump address for the specific interrupt or
* exception to handler_ptr. Recopy the vector table and vector
* branch instructions to the interrupt and exception area with a
* call to int_write_table.
*
* Parameters:
* handler_id : Must be an enumeration of type VECTOR_T
* handler_ptr : Pointer to new interrupt or exception handler
*
* Outputs: None
*
* Returns: Nothing
*
* Notes:
* For handler_id values of VIC1_IRQ_VEC and VIC2_IRQ_VEC, the
* handler addresses will be updated in the VIC1 and VIC2
* non-vectored address registers. These are used by the main ARM
* IRQ handler to determine the default IRQ jump addresses for
* VIC1 and VIC2.
*
**********************************************************************/
void vic_install_arm_handler(VECTOR_T handler_id,
PFV handler_ptr)
{
/* Update address only if it is not NULL */
if (handler_ptr != (PFV) 0x00000000)
{
switch (handler_id)
{
case RESET_VEC:
vec_reset_handler = (UNS_32) handler_ptr;
cp15_force_cache_coherence(
(UNS_32 *) &vec_reset_handler,
(UNS_32 *) &vec_reset_handler);
break;
case UNDEFINED_INST_VEC:
vec_undefined_handler = (UNS_32) handler_ptr;
cp15_force_cache_coherence(
(UNS_32 *) &vec_undefined_handler,
(UNS_32 *) &vec_undefined_handler);
break;
case SWI_VEC:
vec_swi_handler = (UNS_32) handler_ptr;
cp15_force_cache_coherence(
(UNS_32 *) &vec_swi_handler,
(UNS_32 *) &vec_swi_handler);
break;
case PREFETCH_ABORT_VEC:
vec_prefetch_handler = (UNS_32) handler_ptr;
cp15_force_cache_coherence(
(UNS_32 *) &vec_prefetch_handler,
(UNS_32 *) &vec_prefetch_handler);
break;
case DATA_ABORT_VEC:
vec_abort_handler = (UNS_32) handler_ptr;
cp15_force_cache_coherence(
(UNS_32 *) &vec_abort_handler,
(UNS_32 *) &vec_abort_handler);
break;
case IRQ_VEC:
vec_irq_handler = (UNS_32) handler_ptr;
cp15_force_cache_coherence(
(UNS_32 *) &vec_irq_handler,
(UNS_32 *) &vec_irq_handler);
break;
case FIQ_VEC:
vec_fiq_handler = (UNS_32) handler_ptr;
cp15_force_cache_coherence(
(UNS_32 *) &vec_fiq_handler,
(UNS_32 *) &vec_fiq_handler);
break;
case VIC1_IRQ_VEC:
/* This is the vector that gets called from the first
vectored interrupt controller when not configured as
and FIQ or vectored interrupt */
VIC1->nv_vecaddr = handler_ptr;
break;
case VIC2_IRQ_VEC:
/* This is the vector that gets called from the second
vectored interrupt controller when not configured as
and FIQ or vectored interrupt */
VIC2->nv_vecaddr = handler_ptr;
break;
default:
break;
}
/* Update table in vector area */
vic_int_write_table();
}
}
/***********************************************************************
*
* Function: vic_install_handler
*
* Purpose: Install a function for a specific interrupt
*
* Processing:
* Save the function address for the interrupt source in the
* interrupt function jump table (used for IRQ interrupts only).
* If the interrupt type is VIC_IRQ, then clear the interrupt
* select bit for the interrupt source in the VIC1 or VIC2 select
* register to make it an IRQ interrupt type and return TRUE to the
* caller. If the interrupt type is VIC_FIQ, then set the interrupt
* select bit for the interrupt source in the VIC1 or VIC2 select
* register to make it an FIQ interrupt type and return TRUE to
* the caller. If the interrupt type is VIC_VECTORED, then call
* the vic_check_and_install function to check and install the
* vectored interrupt, using the return status from the function
* as the return status to the caller. If any interrupt type is
* passed, it is invalid and FALSE is returned to the caller.
*
* Parameters:
* source : Interrupt source of type VIC_INT_SOURCE_T
* itype : Must be VIC_IRQ, VIC_FIQ, or VIC_VECTORED
* func_ptr : Pointer to a void function
*
* Outputs: None
*
* Returns: TRUE if the handler installation was good, otherwise FALSE
*
* Notes:
* This function will not install FIQ handlers. This interrupt
* driver design only allows 1 FIQ interrupt. Use the
* vic_install_arm_handler to install the FIQ interrupt, but use
* this function to change the interrupt to an FIQ type.
*
**********************************************************************/
BOOL_32 vic_install_handler(VIC_INT_SOURCE_T source,
VIC_INT_T itype,
PFV func_ptr)
{
BOOL_32 installed = TRUE;
/* Save a copy of the function pointer */
vic_func_ptrs[source] = func_ptr;
if (itype == VIC_IRQ)
{
if ((source >= VIC_FIRST_VIC1_INTERRUPT) &&
(source <= VIC_LAST_VIC1_INTERRUPT))
{
/* Make the interrupt an IRQ type */
VIC1->intsel &= ~VIC_INT_SELECT((UNS_32) source);
}
else
{
/* Make the interrupt an IRQ type */
VIC2->intsel &= ~VIC_INT_SELECT((UNS_32) source -
VIC_FIRST_VIC2_INTERRUPT);
}
}
else if (itype == VIC_FIQ)
{
if ((source >= VIC_FIRST_VIC1_INTERRUPT) &&
(source <= VIC_LAST_VIC1_INTERRUPT))
{
/* Make the interrupt an FIQ type */
VIC1->intsel |= VIC_INT_SELECT((UNS_32) source);
}
else
{
/* Make the interrupt an FIQ type */
VIC2->intsel |= VIC_INT_SELECT((UNS_32) source -
VIC_FIRST_VIC2_INTERRUPT);
}
}
else if (itype == VIC_VECTORED)
{
installed = vic_check_and_install(source, itype, func_ptr);
}
else
{
/* Invalid interrupt type */
installed = FALSE;
}
return installed;
}
/***********************************************************************
*
* Function: vic_int_enable
*
* Purpose: Enable an interrupt
*
* Processing:
* If the interrupt source is in the range of the first VIC, then
* check the value of enable. If enable is TRUE, then enable the
* selected interrupt source by setting the appropriate enable bit
* in the VIC1 interrupt enable register. If enable is FALSE,
* disable the selected interrupt source by setting the appropriate
* disable bit in the VIC1 interrupt disable register. Otherwise
* (if the interrupt source is not in the range of the first VIC),
* perform the same logic to enable or disable the interrupt for
* the second VIC.
*
* Parameters:
* source : Interrupt source of type VIC_INT_SOURCE_T
* enable : Must be TRUE to enable an interrupt or FALSE
*
* Outputs: None
*
* Returns: Nothing
*
* Notes: None
*
**********************************************************************/
void vic_int_enable(VIC_INT_SOURCE_T source,
BOOL_32 enable)
{
if ((source >= VIC_FIRST_VIC1_INTERRUPT) &&
(source <= VIC_LAST_VIC1_INTERRUPT))
{
/* VIC1 interrupt */
if (enable == TRUE)
{
/* Enable the interrupt */
VIC1->inten = VIC_INT_SELECT((UNS_32)(source));
}
else
{
/* Disable the interrupt */
VIC1->intenclr = VIC_INT_SELECT((UNS_32)(source));
}
}
else
{
/* VIC2 interrupt */
if (enable == TRUE)
{
/* Enable the interrupt */
VIC2->inten = VIC_INT_SELECT((UNS_32)(source -
VIC_FIRST_VIC2_INTERRUPT));
}
else
{
/* Disable the interrupt */
VIC2->intenclr = VIC_INT_SELECT((UNS_32)(source -
VIC_FIRST_VIC2_INTERRUPT));
}
}
}
/***********************************************************************
*
* Function: vic_int_pending
*
* Purpose: Check to see if an interrupt is pending
*
* Processing:
* If the interrupt source is in the range of the first VIC, then
* get the pending interrupt status from the IRQ status register
* for VIC1 and mask it with the inverted value of the VIC1
* interrupt select register. Get the pending interrupt status from
* the FIQ status register for VIC1 and mask it with the value of
* the VIC1 interrupt select register. 'OR' the two masked values
* together to get a pending interrupt bitfield of enabled
* interrupts. Mask the 'OR'ed value with the bit fromt the
* interrupt source. If the resulting value is not zero, then
* return TRUE to the caller. Otherwise, return FALSE.
*
* If the interrupt source is in the range of the VIC2, then
* get the pending interrupt status from the IRQ status register
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -