Skip to content

Commit

Permalink
PIC: Add ARM GICv2/v3, and V2M, ITS support.
Browse files Browse the repository at this point in the history
GIC (Generic Interrupt Controller) is the ARMv7/v8 PIC.
V2M is the PCI MSI/MSI-X for GICv2.
ITS is the PCI MSI/MSI-X for GICv3/v4.

Signed-off-by: GuEe-GUI <[email protected]>
  • Loading branch information
GuEe-GUI committed Jun 11, 2024
1 parent 25f9d04 commit 65158cc
Show file tree
Hide file tree
Showing 11 changed files with 4,441 additions and 0 deletions.
17 changes: 17 additions & 0 deletions components/drivers/include/dt-bindings/size.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
/*
* Copyright (c) 2006-2022, RT-Thread Development Team
*
* SPDX-License-Identifier: Apache-2.0
*/

#ifndef __DT_BINDINGS_SIZE_H__
#define __DT_BINDINGS_SIZE_H__

#define SIZE_KB 1024
#define SIZE_MB (1024 * SIZE_KB)
#define SIZE_GB (1024 * SIZE_MB)

#define SIZE_ALIGN(size, align) (((size) + (align) - 1) & ~((align) - 1))
#define SIZE_ALIGN_DOWN(size, align) ((size) & ~((align) - 1))

#endif /* __DT_BINDINGS_SIZE_H__ */
32 changes: 32 additions & 0 deletions components/drivers/pic/Kconfig
Original file line number Diff line number Diff line change
Expand Up @@ -9,3 +9,35 @@ config MAX_HANDLERS
depends on RT_USING_PIC
range 1 2147483647
default 256

config RT_PIC_ARM_GIC
bool "ARM GICv2/v1"
depends on RT_USING_PIC
depends on RT_USING_OFW
default n

config RT_PIC_ARM_GIC_V2M
bool "ARM GIC V2M" if RT_PIC_ARM_GIC && RT_PCI_MSI
depends on RT_USING_OFW
select RT_USING_ADT_BITMAP
default n

config RT_PIC_ARM_GIC_V3
bool "ARM GICv3"
depends on RT_USING_PIC
depends on RT_USING_OFW
default n

config RT_PIC_ARM_GIC_V3_ITS
bool "ARM GICv3 ITS (Interrupt Translation Service)" if RT_PIC_ARM_GIC_V3 && RT_PCI_MSI
depends on RT_USING_OFW
select RT_USING_ADT_REF
select RT_USING_ADT_BITMAP
default n

config RT_PIC_ARM_GIC_MAX_NR
int
depends on RT_USING_PIC
depends on RT_PIC_ARM_GIC
default 2 if SOC_REALVIEW
default 1
15 changes: 15 additions & 0 deletions components/drivers/pic/SConscript
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,21 @@ CPPPATH = [cwd + '/../include']

src = ['pic.c']

if GetDepend(['RT_PIC_ARM_GIC']) or GetDepend(['RT_PIC_ARM_GIC_V3']):
src += ['pic-gic-common.c']

if GetDepend(['RT_PIC_ARM_GIC']):
src += ['pic-gicv2.c']

if GetDepend(['RT_PIC_ARM_GIC_V2M']):
src += ['pic-gicv2m.c']

if GetDepend(['RT_PIC_ARM_GIC_V3']):
src += ['pic-gicv3.c']

if GetDepend(['RT_PIC_ARM_GIC_V3_ITS']):
src += ['pic-gicv3-its.c']

group = DefineGroup('DeviceDrivers', src, depend = [''], CPPPATH = CPPPATH)

Return('group')
183 changes: 183 additions & 0 deletions components/drivers/pic/pic-gic-common.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,183 @@
/*
* Copyright (c) 2006-2023, RT-Thread Development Team
*
* SPDX-License-Identifier: Apache-2.0
*
* Change Logs:
* Date Author Notes
* 2023-01-30 GuEe-GUI first version
*/

#include <rthw.h>
#include <rtthread.h>

#define DBG_TAG "pic.gic*"
#define DBG_LVL DBG_INFO
#include <rtdbg.h>

#include <drivers/pic.h>

#include "pic-gicv2.h"
#include "pic-gic-common.h"

void gic_common_init_quirk_ofw(const struct rt_ofw_node *ic_np, const struct gic_quirk *quirks, void *data)
{
for (; quirks->desc; ++quirks)
{
if (!quirks->compatible || !rt_ofw_node_is_compatible(ic_np, quirks->compatible))
{
continue;
}

RT_ASSERT(quirks->init != RT_NULL);

if (!quirks->init(data))
{
LOG_I("Enable workaround for %s", quirks->desc);
}
}
}

void gic_common_init_quirk_hw(rt_uint32_t iidr, const struct gic_quirk *quirks, void *data)
{
for (; quirks->desc; ++quirks)
{
if (quirks->compatible)
{
continue;
}

if (quirks->iidr == (iidr & quirks->iidr_mask))
{
RT_ASSERT(quirks->init != RT_NULL);

if (!quirks->init(data))
{
LOG_I("Enable workaround for %s", quirks->desc);
}
}
}
}

void gic_common_sgi_config(void *base, void *data, int irq_base)
{
#ifdef RT_USING_SMP
if (irq_base < 2)
{
struct rt_pic_irq *pirq;

#define DECLARE_GIC_IPI(ipi, hwirq) \
rt_pic_config_ipi(data, ipi, hwirq); \
pirq = rt_pic_find_ipi(data, ipi); \
pirq->mode = RT_IRQ_MODE_EDGE_RISING; \

DECLARE_GIC_IPI(RT_SCHEDULE_IPI, 0);
DECLARE_GIC_IPI(RT_STOP_IPI, 1);

#undef DECLARE_GIC_IPI
}
#endif /* RT_USING_SMP */
}

rt_err_t gic_common_configure_irq(void *base, int irq, rt_uint32_t mode, void (*sync_access)(void *), void *data)
{
rt_err_t err = RT_EOK;
rt_ubase_t level;
rt_uint32_t val, oldval;
rt_uint32_t confoff = (irq / 16) * 4;
rt_uint32_t confmask = 0x2 << ((irq % 16) * 2);
static struct rt_spinlock ic_lock = { 0 };

level = rt_spin_lock_irqsave(&ic_lock);

val = oldval = HWREG32(base + confoff);

if (mode & RT_IRQ_MODE_LEVEL_MASK)
{
/* Level-sensitive */
val &= ~confmask;
}
else if (mode & RT_IRQ_MODE_EDGE_BOTH)
{
/* Edge-triggered */
val |= confmask;
}

if (val != oldval)
{
HWREG32(base + confoff) = val;

if (HWREG32(base + confoff) != val)
{
err = -RT_EINVAL;
}
if (sync_access)
{
sync_access(data);
}
}

rt_spin_unlock_irqrestore(&ic_lock, level);

return err;
}

void gic_common_dist_config(void *base, int max_irqs, void (*sync_access)(void *), void *data)
{
rt_uint32_t i;

/* Set all global interrupts to be level triggered, active low. */
for (i = 32; i < max_irqs; i += 16)
{
HWREG32(base + GIC_DIST_CONFIG + i / 4) = GICD_INT_ACTLOW_LVLTRIG;
}

/* Set priority on all global interrupts. */
for (i = 32; i < max_irqs; i += 4)
{
HWREG32(base + GIC_DIST_PRI + i * 4 / 4) = GICD_INT_DEF_PRI_X4;
}

/* Disable all SPIs. */
for (i = 32; i < max_irqs; i += 32)
{
HWREG32(base + GIC_DIST_ACTIVE_CLEAR + i / 8) = GICD_INT_EN_CLR_X32;
HWREG32(base + GIC_DIST_ENABLE_CLEAR + i / 8) = GICD_INT_EN_CLR_X32;
}

if (sync_access)
{
sync_access(data);
}
}

void gic_common_cpu_config(void *base, int nr, void (*sync_access)(void *), void *data)
{
rt_uint32_t i;

/* Disable all SGIs, PPIs. */
for (i = 0; i < nr; i += 32)
{
HWREG32(base + GIC_DIST_ACTIVE_CLEAR + i / 8) = GICD_INT_EN_CLR_X32;
HWREG32(base + GIC_DIST_ENABLE_CLEAR + i / 8) = GICD_INT_EN_CLR_X32;
}

/* Set priority on all PPI and SGI. */
for (i = 0; i < nr; i += 4)
{
HWREG32(base + GIC_DIST_PRI + i * 4 / 4) = GICD_INT_DEF_PRI_X4;
}

if (sync_access)
{
sync_access(data);
}
}

void gic_fill_ppi_affinity(bitmap_t *affinity)
{
for (int cpuid = 0; cpuid < RT_CPUS_NR; ++cpuid)
{
RT_IRQ_AFFINITY_SET(affinity, cpuid);
}
}
59 changes: 59 additions & 0 deletions components/drivers/pic/pic-gic-common.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,59 @@
/*
* Copyright (c) 2006-2023, RT-Thread Development Team
*
* SPDX-License-Identifier: Apache-2.0
*
* Change Logs:
* Date Author Notes
* 2023-01-30 GuEe-GUI first version
*/

#ifndef __IRQ_GIC_COMMON_H__
#define __IRQ_GIC_COMMON_H__

#include <rtdef.h>

#ifdef RT_PCI_MSI
#include <drivers/pci_msi.h>
#endif
#include <drivers/ofw.h>

#define GIC_SGI_NR 16

#define GICD_INT_DEF_PRI 0xa0U
#define GICD_INT_DEF_PRI_X4 \
( \
(GICD_INT_DEF_PRI << 24) | \
(GICD_INT_DEF_PRI << 16) | \
(GICD_INT_DEF_PRI << 8) | \
GICD_INT_DEF_PRI \
)

struct gic_quirk
{
const char *desc;
const char *compatible;
rt_err_t (*init)(void *data);

rt_uint32_t iidr;
rt_uint32_t iidr_mask;
};

void gic_common_init_quirk_ofw(const struct rt_ofw_node *ic_np, const struct gic_quirk *quirks, void *data);
void gic_common_init_quirk_hw(rt_uint32_t iidr, const struct gic_quirk *quirks, void *data);

void gic_common_sgi_config(void *base, void *data, int irq_base);
rt_err_t gic_common_configure_irq(void *base, int irq, rt_uint32_t mode, void (*sync_access)(void *), void *data);
void gic_common_dist_config(void *base, int max_irqs, void (*sync_access)(void *), void *data);
void gic_common_cpu_config(void *base, int nr, void (*sync_access)(void *), void *data);

void gic_fill_ppi_affinity(bitmap_t *affinity);

#ifdef RT_PIC_ARM_GIC_V2M
rt_err_t gicv2m_ofw_probe(struct rt_ofw_node *ic_np, const struct rt_ofw_node_id *id);
#endif
#ifdef RT_PIC_ARM_GIC_V3_ITS
rt_err_t gicv3_its_ofw_probe(struct rt_ofw_node *ic_np, const struct rt_ofw_node_id *id);
#endif

#endif /* __IRQ_GIC_COMMON_H__ */
Loading

0 comments on commit 65158cc

Please sign in to comment.