blob: 6c1294cb7b817546601f89f9566d70dc22717703 [file] [log] [blame]
/*
* Copyright 2017, Data61, CSIRO (ABN 41 687 119 230)
*
* SPDX-License-Identifier: BSD-2-Clause
*/
#include <utils/util.h>
#include <platsupport/irq_combiner.h>
#include "../../services.h"
#define NGROUPS 32
struct combiner_gmap {
uint32_t enable_set;
uint32_t enable_clr;
uint32_t status;
uint32_t masked_status;
};
struct irq_combiner_map {
struct combiner_gmap g[NGROUPS / 4];
uint32_t res[32];
uint32_t pending;
};
volatile struct irq_combiner_map *_combiner_regs = NULL;
#define GROUP_INDEX(cirq) (COMBINER_IRQ_GET_GROUP(cirq) >> 2)
#define GROUP_SHIFT(cirq) ((COMBINER_IRQ_GET_GROUP(cirq) & 0x3) * 8)
#define IRQ_SHIFT(cirq) (COMBINER_IRQ_GET_INDEX(cirq))
#define GROUP_INDEX_MASK 0xff
static volatile struct irq_combiner_map*
irq_combiner_get_regs(irq_combiner_t* combiner) {
assert(combiner);
assert(combiner->priv);
return (volatile struct irq_combiner_map*)combiner->priv;
}
static int
exynos_irq_combiner_is_pending(irq_combiner_t* combiner, combiner_irq_t cirq)
{
volatile struct irq_combiner_map* regs;
int gidx, shift;
regs = irq_combiner_get_regs(combiner);
gidx = GROUP_INDEX(cirq);
shift = GROUP_SHIFT(cirq) + IRQ_SHIFT(cirq);
return !!(regs->g[gidx].masked_status & BIT(shift));
}
static int
exynos_irq_combiner_is_enabled(irq_combiner_t* combiner, combiner_irq_t cirq)
{
volatile struct irq_combiner_map* regs;
int gidx, shift;
regs = irq_combiner_get_regs(combiner);
gidx = GROUP_INDEX(cirq);
shift = GROUP_SHIFT(cirq) + IRQ_SHIFT(cirq);
return !!(regs->g[gidx].enable_set & BIT(shift));
}
static int
exynos_irq_combiner_set_enabled(irq_combiner_t* combiner, combiner_irq_t cirq, int v)
{
volatile struct irq_combiner_map* regs;
int gidx, shift;
regs = irq_combiner_get_regs(combiner);
gidx = GROUP_INDEX(cirq);
shift = GROUP_SHIFT(cirq) + IRQ_SHIFT(cirq);
if (v) {
regs->g[gidx].enable_set = BIT(shift);
} else {
regs->g[gidx].enable_clr = BIT(shift);
}
return 0;
}
static uint32_t
exynos_irq_combiner_grp_pending(irq_combiner_t* combiner, int group)
{
volatile struct irq_combiner_map* regs;
combiner_irq_t cirq;
int gidx, shift;
uint32_t v;
regs = irq_combiner_get_regs(combiner);
cirq = COMBINER_IRQ(group, 0);
gidx = GROUP_INDEX(cirq);
shift = GROUP_SHIFT(cirq);
v = regs->g[gidx].masked_status;
return (v >> shift) & GROUP_INDEX_MASK;
}
static int
irq_combiner_init_common(irq_combiner_t* combiner)
{
if (_combiner_regs == NULL) {
return -1;
} else {
/* Initialise the structure */
combiner->priv = (void*)_combiner_regs;
combiner->is_pending = &exynos_irq_combiner_is_pending;
combiner->is_enabled = &exynos_irq_combiner_is_enabled;
combiner->set_enabled = &exynos_irq_combiner_set_enabled;
combiner->grp_pending = &exynos_irq_combiner_grp_pending;
return 0;
}
}
int
exynos_irq_combiner_init(void* base, irq_combiner_t* combiner)
{
if (base) {
_combiner_regs = (volatile struct irq_combiner_map *)base;
}
return irq_combiner_init_common(combiner);
}
int
irq_combiner_init(enum irq_combiner_id id, ps_io_ops_t* io_ops, irq_combiner_t* combiner)
{
/* Map memory */
ZF_LOGD("Mapping device ID %d\n", id);
switch (id) {
case IRQ_COMBINER0:
MAP_IF_NULL(io_ops, EXYNOS_IRQ_COMBINER, _combiner_regs);
break;
default:
return -1;
}
return irq_combiner_init_common(combiner);
}
int
irq_combiner_nirqs(enum irq_combiner_id id)
{
switch (id) {
case IRQ_COMBINER0:
return 32;
default:
return -1;
}
}
int irq_combiner_irq(enum irq_combiner_id id, int group)
{
switch (id) {
case IRQ_COMBINER0:
return group + 32;
default:
return -1;
}
}