rt-thread-official/bsp/imx6ul/platform/cpu/gic.c

244 lines
6.6 KiB
C

/*
* Copyright (c) 2012, Freescale Semiconductor, Inc.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without modification,
* are permitted provided that the following conditions are met:
*
* o Redistributions of source code must retain the above copyright notice, this list
* of conditions and the following disclaimer.
*
* o 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.
*
* o Neither the name of Freescale Semiconductor, Inc. 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 <assert.h>
#include "gic.h"
#include "gic_registers.h"
#include "cortex_a.h"
////////////////////////////////////////////////////////////////////////////////
// Prototypes
////////////////////////////////////////////////////////////////////////////////
static inline gicd_t * gic_get_gicd(void);
static inline gicc_t * gic_get_gicc(void);
static inline uint32_t irq_get_register_offset(uint32_t irqID);
static inline uint32_t irq_get_bit_offset(uint32_t irqID);
static inline uint32_t irq_get_bit_mask(uint32_t irqID);
////////////////////////////////////////////////////////////////////////////////
// Code
////////////////////////////////////////////////////////////////////////////////
static inline gicd_t * gic_get_gicd(void)
{
uint32_t base = get_arm_private_peripheral_base() + kGICDBaseOffset;
return (gicd_t *)base;
}
static inline gicc_t * gic_get_gicc(void)
{
uint32_t base = get_arm_private_peripheral_base() + kGICCBaseOffset;
return (gicc_t *)base;
}
static inline uint32_t irq_get_register_offset(uint32_t irqID)
{
return irqID / 32;
}
static inline uint32_t irq_get_bit_offset(uint32_t irqID)
{
return irqID & 0x1f;
}
static inline uint32_t irq_get_bit_mask(uint32_t irqID)
{
return 1 << irq_get_bit_offset(irqID);
}
void gic_enable(bool enableIt)
{
gicd_t * gicd = gic_get_gicd();
if (enableIt)
{
// Enable both secure and non-secure.
gicd->CTLR |= kBM_GICD_CTLR_EnableGrp0 | kBM_GICD_CTLR_EnableGrp1;
}
else
{
// Clear the enable bits.
gicd->CTLR &= ~(kBM_GICD_CTLR_EnableGrp0 | kBM_GICD_CTLR_EnableGrp1);
}
}
void gic_set_irq_security(uint32_t irqID, bool isSecure)
{
gicd_t * gicd = gic_get_gicd();
uint32_t reg = irq_get_register_offset(irqID);
uint32_t mask = irq_get_bit_mask(irqID);
uint32_t value = gicd->IGROUPRn[reg];
if (!isSecure)
{
value &= ~mask;
}
else
{
value |= mask;
}
gicd->IGROUPRn[reg] = value;
}
void gic_enable_irq(uint32_t irqID, bool isEnabled)
{
gicd_t * gicd = gic_get_gicd();
uint32_t reg = irq_get_register_offset(irqID);
uint32_t mask = irq_get_bit_mask(irqID);
// Select set-enable or clear-enable register based on enable flag.
if (isEnabled)
{
gicd->ISENABLERn[reg] = mask;
}
else
{
gicd->ICENABLERn[reg] = mask;
}
}
void gic_set_irq_priority(uint32_t ID, uint32_t priority)
{
gicd_t * gicd = gic_get_gicd();
// Update the priority register. The priority registers are byte accessible, and the register
// struct has the priority registers as a byte array, so we can just index directly by the
// interrupt ID.
gicd->IPRIORITYRn[ID] = priority & 0xff;
}
void gic_set_cpu_target(uint32_t irqID, unsigned cpuNumber, bool enableIt)
{
// Make sure the CPU number is valid.
assert(cpuNumber <= 7);
gicd_t * gicd = gic_get_gicd();
uint8_t cpuMask = 1 << cpuNumber;
// Like the priority registers, the target registers are byte accessible, and the register
// struct has the them as a byte array, so we can just index directly by the
// interrupt ID.
if (enableIt)
{
gicd->ITARGETSRn[irqID] |= (cpuMask & 0xff);
}
else
{
gicd->ITARGETSRn[irqID] &= ~(cpuMask & 0xff);
}
}
void gic_send_sgi(uint32_t irqID, uint32_t target_list, uint32_t filter_list)
{
gicd_t * gicd = gic_get_gicd();
gicd->SGIR = (filter_list << kBP_GICD_SGIR_TargetListFilter)
| (target_list << kBP_GICD_SGIR_CPUTargetList)
| (irqID & 0xf);
}
void gic_cpu_enable(bool enableIt)
{
gicc_t * gicc = gic_get_gicc();
if (enableIt)
{
gicc->CTLR |= kBM_GICC_CTLR_EnableS | kBM_GICC_CTLR_EnableNS;
}
else
{
gicc->CTLR &= ~(kBM_GICC_CTLR_EnableS | kBM_GICC_CTLR_EnableNS);
}
}
void gic_set_cpu_priority_mask(uint32_t priority)
{
gicc_t * gicc = gic_get_gicc();
gicc->PMR = priority & 0xff;
}
uint32_t gic_read_irq_ack(void)
{
gicc_t * gicc = gic_get_gicc();
return gicc->IAR;
}
void gic_write_end_of_irq(uint32_t irqID)
{
gicc_t * gicc = gic_get_gicc();
gicc->EOIR = irqID;
}
void gic_init(void)
{
gicd_t * gicd = gic_get_gicd();
// First disable the distributor.
gic_enable(false);
// Clear all pending interrupts.
int i;
for (i = 0; i < 32; ++i)
{
gicd->ICPENDRn[i] = 0xffffffff;
}
// Set all interrupts to secure.
for (i = 0; i < 8; ++i)
{
gicd->IGROUPRn[i] = 0;
}
// Init the GIC CPU interface.
gic_init_cpu();
// Now enable the distributor.
gic_enable(true);
}
void gic_init_cpu(void)
{
// Init the GIC CPU interface.
gic_set_cpu_priority_mask(0xff);
// Disable preemption.
gicc_t * gicc = gic_get_gicc();
gicc->BPR = 7;
// Enable signaling the CPU.
gic_cpu_enable(true);
}
////////////////////////////////////////////////////////////////////////////////
// EOF
////////////////////////////////////////////////////////////////////////////////