-# $OpenBSD: GENERIC,v 1.33 2016/08/05 19:00:25 kettenis Exp $
+# $OpenBSD: GENERIC,v 1.34 2016/08/05 20:38:17 kettenis Exp $
#
# For further information on compiling OpenBSD kernels, see the config(8)
# man page.
sunxi0 at mainbus?
# Sunxi on-chip devices
-a1xintc* at fdt? # A1x interrupt controller
+sxiintc* at fdt? # A1x interrupt controller
sxipio* at sunxi? # GPIO pins for leds & PHYs
gpio* at sxipio?
sxiccmu* at sunxi? # Clock Control Module/Unit
-# $OpenBSD: RAMDISK,v 1.30 2016/08/05 19:00:25 kettenis Exp $
+# $OpenBSD: RAMDISK,v 1.31 2016/08/05 20:38:17 kettenis Exp $
machine armv7 arm
sunxi0 at mainbus?
# Sunxi on-chip devices
-a1xintc* at fdt? # A1x interrupt controller
+sxiintc* at fdt? # A1x interrupt controller
sxipio* at sunxi? # GPIO pins for leds & PHYs
gpio* at sxipio?
sxiccmu* at sunxi? # Clock Control Module/Unit
+++ /dev/null
-/* $OpenBSD: a1xintc.c,v 1.8 2016/08/05 19:00:25 kettenis Exp $ */
-/*
- * Copyright (c) 2007,2009 Dale Rahn <drahn@openbsd.org>
- * Copyright (c) 2013 Artturi Alm
- *
- * Permission to use, copy, modify, and distribute this software for any
- * purpose with or without fee is hereby granted, provided that the above
- * copyright notice and this permission notice appear in all copies.
- *
- * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
- * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
- * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
- * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
- * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
- * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
- * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
- */
-
-#include <sys/param.h>
-#include <sys/systm.h>
-#include <sys/queue.h>
-#include <sys/malloc.h>
-#include <sys/device.h>
-#include <sys/evcount.h>
-
-#include <machine/bus.h>
-#include <machine/fdt.h>
-
-#include <armv7/armv7/armv7var.h>
-#include <armv7/sunxi/sunxireg.h>
-#include <armv7/sunxi/a1xintc.h>
-
-#include <dev/ofw/openfirm.h>
-#include <dev/ofw/fdt.h>
-
-#ifdef DEBUG_INTC
-#define DPRINTF(x) do { if (a1xintcdebug) printf x; } while (0)
-#define DPRINTFN(n,x) do { if (a1xintcdebug>(n)) printf x; } while (0)
-int a1xintcdebug = 10;
-char *ipl_strtbl[NIPL] = {
- "IPL_NONE",
- "IPL_SOFT",
- "IPL_SOFTCLOCK",
- "IPL_SOFTNET",
- "IPL_SOFTTTY",
- "IPL_BIO|IPL_USB",
- "IPL_NET",
- "IPL_TTY",
- "IPL_VM",
- "IPL_AUDIO",
- "IPL_CLOCK",
- "IPL_STATCLOCK",
- "IPL_SCHED|IPL_HIGH"
-};
-#else
-#define DPRINTF(x)
-#define DPRINTFN(n,x)
-#endif
-
-#define NIRQ 96
-#define NBANKS 3
-#define NIRQPRIOREGS 5
-
-/* registers */
-#define INTC_VECTOR_REG 0x00
-#define INTC_BASE_ADR_REG 0x04
-#define INTC_PROTECTION_REG 0x08
-#define INTC_NMI_CTRL_REG 0x0c
-
-#define INTC_IRQ_PENDING_REG0 0x10
-#define INTC_IRQ_PENDING_REG1 0x14
-#define INTC_IRQ_PENDING_REG2 0x18
-
-#define INTC_SELECT_REG0 0x30
-#define INTC_SELECT_REG1 0x34
-#define INTC_SELECT_REG2 0x38
-
-#define INTC_ENABLE_REG0 0x40
-#define INTC_ENABLE_REG1 0x44
-#define INTC_ENABLE_REG2 0x48
-
-#define INTC_MASK_REG0 0x50
-#define INTC_MASK_REG1 0x54
-#define INTC_MASK_REG2 0x58
-
-#define INTC_RESP_REG0 0x60
-#define INTC_RESP_REG1 0x64
-#define INTC_RESP_REG2 0x68
-
-#define INTC_PRIO_REG0 0x80
-#define INTC_PRIO_REG1 0x84
-#define INTC_PRIO_REG2 0x88
-#define INTC_PRIO_REG3 0x8c
-#define INTC_PRIO_REG4 0x90
-
-#define INTC_IRQ_PENDING_REG(_b) (0x10 + ((_b) * 4))
-#define INTC_FIQ_PENDING_REG(_b) (0x20 + ((_b) * 4))
-#define INTC_SELECT_REG(_b) (0x30 + ((_b) * 4))
-#define INTC_ENABLE_REG(_b) (0x40 + ((_b) * 4))
-#define INTC_MASK_REG(_b) (0x50 + ((_b) * 4))
-#define INTC_RESP_REG(_b) (0x60 + ((_b) * 4))
-#define INTC_PRIO_REG(_b) (0x80 + ((_b) * 4))
-
-#define IRQ2REG32(i) (((i) >> 5) & 0x3)
-#define IRQ2BIT32(i) ((i) & 0x1f)
-
-#define IRQ2REG16(i) (((i) >> 4) & 0x5)
-#define IRQ2BIT16(i) (((i) & 0x0f) * 2)
-
-#define INTC_IRQ_HIPRIO 0x3
-#define INTC_IRQ_ENABLED 0x2
-#define INTC_IRQ_DISABLED 0x1
-#define INTC_IRQ_LOWPRIO 0x0
-#define INTC_PRIOCLEAR(i) (~(INTC_IRQ_HIPRIO << IRQ2BIT16((i))))
-#define INTC_PRIOENABLE(i) (INTC_IRQ_ENABLED << IRQ2BIT16((i)))
-#define INTC_PRIOHI(i) (INTC_IRQ_HIPRIO << IRQ2BIT16((i)))
-
-
-struct intrhand {
- TAILQ_ENTRY(intrhand) ih_list; /* link on intrq list */
- int (*ih_func)(void *); /* handler */
- void *ih_arg; /* arg for handler */
- int ih_ipl; /* IPL_* */
- int ih_irq; /* IRQ number */
- struct evcount ih_count;
- char *ih_name;
-};
-
-struct intrq {
- TAILQ_HEAD(, intrhand) iq_list; /* handler list */
- int iq_irq; /* IRQ to mask while handling */
- int iq_levels; /* IPL_*'s this IRQ has */
- int iq_ist; /* share type */
-};
-
-volatile int a1xsoftint_pending;
-
-struct intrq a1xintc_handler[NIRQ];
-u_int32_t a1xintc_smask[NIPL];
-u_int32_t a1xintc_imask[NBANKS][NIPL];
-struct interrupt_controller a1xintc_ic;
-
-bus_space_tag_t a1xintc_iot;
-bus_space_handle_t a1xintc_ioh;
-int a1xintc_nirq;
-
-int a1xintc_match(struct device *, void *, void *);
-void a1xintc_attach(struct device *, struct device *, void *);
-int a1xintc_spllower(int);
-int a1xintc_splraise(int);
-void a1xintc_setipl(int);
-void a1xintc_calc_masks(void);
-void *a1xintc_intr_establish_fdt(void *, int *, int, int (*)(void *),
- void *, char *);
-
-struct cfattach a1xintc_ca = {
- sizeof (struct device), a1xintc_match, a1xintc_attach
-};
-
-struct cfdriver a1xintc_cd = {
- NULL, "a1xintc", DV_DULL
-};
-
-int a1xintc_attached = 0;
-
-int
-a1xintc_match(struct device *parent, void *match, void *aux)
-{
- struct fdt_attach_args *faa = aux;
-
- return OF_is_compatible(faa->fa_node, "allwinner,sun4i-a10-ic");
-}
-
-void
-a1xintc_attach(struct device *parent, struct device *self, void *aux)
-{
- struct fdt_attach_args *faa = aux;
- int i, j;
-
- a1xintc_iot = faa->fa_iot;
- if (bus_space_map(a1xintc_iot, faa->fa_reg[0].addr,
- faa->fa_reg[0].size, 0, &a1xintc_ioh))
- panic("a1xintc_attach: bus_space_map failed!");
-
- /* disable/mask/clear all interrupts */
- for (i = 0; i < NBANKS; i++) {
- bus_space_write_4(a1xintc_iot, a1xintc_ioh, INTC_ENABLE_REG(i), 0);
- bus_space_write_4(a1xintc_iot, a1xintc_ioh, INTC_MASK_REG(i), 0);
- bus_space_write_4(a1xintc_iot, a1xintc_ioh, INTC_IRQ_PENDING_REG(i),
- 0xffffffff);
- for (j = 0; j < NIPL; j++)
- a1xintc_imask[i][j] = 0;
- }
-
- /* XXX */
- bus_space_write_4(a1xintc_iot, a1xintc_ioh, INTC_PROTECTION_REG, 1);
- bus_space_write_4(a1xintc_iot, a1xintc_ioh, INTC_NMI_CTRL_REG, 0);
-
- for (i = 0; i < NIRQ; i++)
- TAILQ_INIT(&a1xintc_handler[i].iq_list);
-
- a1xintc_calc_masks();
-
- arm_init_smask();
- a1xintc_attached = 1;
-
- /* insert self as interrupt handler */
- arm_set_intr_handler(a1xintc_splraise, a1xintc_spllower, a1xintc_splx,
- a1xintc_setipl,
- a1xintc_intr_establish, a1xintc_intr_disestablish, a1xintc_intr_string,
- a1xintc_irq_handler);
- a1xintc_setipl(IPL_HIGH); /* XXX ??? */
- enable_interrupts(PSR_I);
- printf("\n");
-
- a1xintc_ic.ic_node = faa->fa_node;
- a1xintc_ic.ic_establish = a1xintc_intr_establish_fdt;
- arm_intr_register_fdt(&a1xintc_ic);
-}
-
-void
-a1xintc_calc_masks(void)
-{
- struct cpu_info *ci = curcpu();
- int irq;
- struct intrhand *ih;
- int i;
-
- for (irq = 0; irq < NIRQ; irq++) {
- int max = IPL_NONE;
- int min = IPL_HIGH;
- TAILQ_FOREACH(ih, &a1xintc_handler[irq].iq_list, ih_list) {
- if (ih->ih_ipl > max)
- max = ih->ih_ipl;
- if (ih->ih_ipl < min)
- min = ih->ih_ipl;
- }
-
- a1xintc_handler[irq].iq_irq = max;
-
- if (max == IPL_NONE)
- min = IPL_NONE;
-
-#ifdef DEBUG_INTC
- if (min != IPL_NONE) {
- printf("irq %d to block at %d %d reg %d bit %d\n",
- irq, max, min, IRQ2REG32(irq),
- IRQ2BIT32(irq));
- }
-#endif
- /* Enable interrupts at lower levels, clear -> enable */
- for (i = 0; i < min; i++)
- a1xintc_imask[IRQ2REG32(irq)][i] &=
- ~(1 << IRQ2BIT32(irq));
- for (; i < NIPL; i++)
- a1xintc_imask[IRQ2REG32(irq)][i] |=
- (1 << IRQ2BIT32(irq));
- /* XXX - set enable/disable, priority */
- }
-
- a1xintc_setipl(ci->ci_cpl);
-}
-
-void
-a1xintc_splx(int new)
-{
- struct cpu_info *ci = curcpu();
- a1xintc_setipl(new);
-
- if (ci->ci_ipending & arm_smask[ci->ci_cpl])
- arm_do_pending_intr(ci->ci_cpl);
-}
-
-int
-a1xintc_spllower(int new)
-{
- struct cpu_info *ci = curcpu();
- int old = ci->ci_cpl;
- a1xintc_splx(new);
- return (old);
-}
-
-int
-a1xintc_splraise(int new)
-{
- struct cpu_info *ci = curcpu();
- int old;
- old = ci->ci_cpl;
-
- /*
- * setipl must always be called because there is a race window
- * where the variable is updated before the mask is set
- * an interrupt occurs in that window without the mask always
- * being set, the hardware might not get updated on the next
- * splraise completely messing up spl protection.
- */
- if (old > new)
- new = old;
-
- a1xintc_setipl(new);
-
- return (old);
-}
-
-void
-a1xintc_setipl(int new)
-{
- struct cpu_info *ci = curcpu();
- int i, psw;
-#if 1
- /*
- * XXX not needed, because all interrupts are disabled
- * by default, so touching maskregs has no effect, i hope.
- */
- if (a1xintc_attached == 0) {
- ci->ci_cpl = new;
- return;
- }
-#endif
- psw = disable_interrupts(PSR_I);
- ci->ci_cpl = new;
- for (i = 0; i < NBANKS; i++)
- bus_space_write_4(a1xintc_iot, a1xintc_ioh,
- INTC_MASK_REG(i), a1xintc_imask[i][new]);
- restore_interrupts(psw);
-}
-
-void
-a1xintc_irq_handler(void *frame)
-{
- struct intrhand *ih;
- void *arg;
- uint32_t pr;
- int irq, prio, s;
-
- irq = bus_space_read_4(a1xintc_iot, a1xintc_ioh, INTC_VECTOR_REG) >> 2;
- if (irq == 0)
- return;
-
- prio = a1xintc_handler[irq].iq_irq;
- s = a1xintc_splraise(prio);
- splassert(prio);
-
- pr = bus_space_read_4(a1xintc_iot, a1xintc_ioh,
- INTC_ENABLE_REG(IRQ2REG32(irq)));
- bus_space_write_4(a1xintc_iot, a1xintc_ioh,
- INTC_ENABLE_REG(IRQ2REG32(irq)),
- pr & ~(1 << IRQ2BIT32(irq)));
-
- /* clear pending */
- pr = bus_space_read_4(a1xintc_iot, a1xintc_ioh,
- INTC_IRQ_PENDING_REG(IRQ2REG32(irq)));
- bus_space_write_4(a1xintc_iot, a1xintc_ioh,
- INTC_IRQ_PENDING_REG(IRQ2REG32(irq)),
- pr | (1 << IRQ2BIT32(irq)));
-
- pr = bus_space_read_4(a1xintc_iot, a1xintc_ioh,
- INTC_ENABLE_REG(IRQ2REG32(irq)));
- bus_space_write_4(a1xintc_iot, a1xintc_ioh,
- INTC_ENABLE_REG(IRQ2REG32(irq)),
- pr | (1 << IRQ2BIT32(irq)));
-
- TAILQ_FOREACH(ih, &a1xintc_handler[irq].iq_list, ih_list) {
- if (ih->ih_arg != 0)
- arg = ih->ih_arg;
- else
- arg = frame;
-
- if (ih->ih_func(arg))
- ih->ih_count.ec_count++;
- }
- a1xintc_splx(s);
-}
-
-void *
-a1xintc_intr_establish(int irq, int level, int (*func)(void *),
- void *arg, char *name)
-{
- int psw;
- struct intrhand *ih;
- uint32_t er;
-
- if (irq <= 0 || irq >= NIRQ)
- panic("intr_establish: bogus irq %d %s\n", irq, name);
-
- DPRINTF(("intr_establish: irq %d level %d [%s]\n", irq, level,
- name != NULL ? name : "NULL"));
-
- psw = disable_interrupts(PSR_I);
-
- /* no point in sleeping unless someone can free memory. */
- ih = (struct intrhand *)malloc (sizeof *ih, M_DEVBUF,
- cold ? M_NOWAIT : M_WAITOK);
- if (ih == NULL)
- panic("intr_establish: can't malloc handler info\n");
- ih->ih_func = func;
- ih->ih_arg = arg;
- ih->ih_ipl = level;
- ih->ih_irq = irq;
- ih->ih_name = name;
-
- TAILQ_INSERT_TAIL(&a1xintc_handler[irq].iq_list, ih, ih_list);
-
- if (name != NULL)
- evcount_attach(&ih->ih_count, name, &ih->ih_irq);
-
- er = bus_space_read_4(a1xintc_iot, a1xintc_ioh,
- INTC_ENABLE_REG(IRQ2REG32(irq)));
- bus_space_write_4(a1xintc_iot, a1xintc_ioh,
- INTC_ENABLE_REG(IRQ2REG32(irq)),
- er | (1 << IRQ2BIT32(irq)));
-
- a1xintc_calc_masks();
-
- restore_interrupts(psw);
- return (ih);
-}
-
-void *
-a1xintc_intr_establish_fdt(void *cookie, int *cell, int level,
- int (*func)(void *), void *arg, char *name)
-{
- return a1xintc_intr_establish(cell[0], level, func, arg, name);
-}
-
-void
-a1xintc_intr_disestablish(void *cookie)
-{
- struct intrhand *ih = cookie;
- int irq = ih->ih_irq;
- int psw;
- uint32_t er;
-
- psw = disable_interrupts(PSR_I);
-
- TAILQ_REMOVE(&a1xintc_handler[irq].iq_list, ih, ih_list);
-
- if (ih->ih_name != NULL)
- evcount_detach(&ih->ih_count);
-
- free(ih, M_DEVBUF, 0);
-
- er = bus_space_read_4(a1xintc_iot, a1xintc_ioh,
- INTC_ENABLE_REG(IRQ2REG32(irq)));
- bus_space_write_4(a1xintc_iot, a1xintc_ioh,
- INTC_ENABLE_REG(IRQ2REG32(irq)),
- er & ~(1 << IRQ2BIT32(irq)));
-
- a1xintc_calc_masks();
-
- restore_interrupts(psw);
-}
-
-const char *
-a1xintc_intr_string(void *cookie)
-{
- return "asd?";
-}
+++ /dev/null
-/* $OpenBSD: a1xintc.h,v 1.3 2015/05/19 06:09:35 jsg Exp $ */
-/*
- * Copyright (c) 2007,2009 Dale Rahn <drahn@openbsd.org>
- *
- * Permission to use, copy, modify, and distribute this software for any
- * purpose with or without fee is hereby granted, provided that the above
- * copyright notice and this permission notice appear in all copies.
- *
- * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
- * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
- * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
- * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
- * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
- * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
- * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
- */
-
-#ifndef _A1XINTC_H_
-#define _A1XINTC_H_
-
-#ifndef _LOCORE
-
-#include <arm/armreg.h>
-#include <arm/cpufunc.h>
-#include <machine/intr.h>
-#include <arm/softintr.h>
-
-extern volatile int current_spl_level;
-extern volatile int softint_pending;
-void a1xintc_do_pending(void);
-
-#define SI_TO_IRQBIT(si) (1U<<(si))
-void a1xintc_setipl(int);
-void a1xintc_splx(int);
-int a1xintc_splraise(int);
-int a1xintc_spllower(int);
-void a1xintc_setsoftintr(int);
-
-void a1xintc_irq_handler(void *);
-void *a1xintc_intr_establish(int, int, int (*)(void *), void *, char *);
-void a1xintc_intr_disestablish(void *);
-const char *a1xintc_intr_string(void *);
-
-#endif /* ! _LOCORE */
-
-#endif /* _A1XINTC_H_ */
-
-# $OpenBSD: files.sunxi,v 1.7 2016/08/05 19:00:25 kettenis Exp $
+# $OpenBSD: files.sunxi,v 1.8 2016/08/05 20:38:17 kettenis Exp $
define sunxi {}
device sunxi: sunxi
attach sxipio at sunxi
file arch/armv7/sunxi/sxipio.c sxipio
-device a1xintc
-attach a1xintc at fdt
-file arch/armv7/sunxi/a1xintc.c a1xintc
+device sxiintc
+attach sxiintc at fdt
+file arch/armv7/sunxi/sxiintc.c sxiintc
device sxitimer
attach sxitimer at sunxi
--- /dev/null
+/* $OpenBSD: sxiintc.c,v 1.1 2016/08/05 20:38:17 kettenis Exp $ */
+/*
+ * Copyright (c) 2007,2009 Dale Rahn <drahn@openbsd.org>
+ * Copyright (c) 2013 Artturi Alm
+ *
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+#include <sys/param.h>
+#include <sys/systm.h>
+#include <sys/queue.h>
+#include <sys/malloc.h>
+#include <sys/device.h>
+#include <sys/evcount.h>
+
+#include <machine/bus.h>
+#include <machine/fdt.h>
+
+#include <armv7/armv7/armv7var.h>
+#include <armv7/sunxi/sunxireg.h>
+#include <armv7/sunxi/sxiintc.h>
+
+#include <dev/ofw/openfirm.h>
+#include <dev/ofw/fdt.h>
+
+#ifdef DEBUG_INTC
+#define DPRINTF(x) do { if (sxiintcdebug) printf x; } while (0)
+#define DPRINTFN(n,x) do { if (sxiintcdebug>(n)) printf x; } while (0)
+int sxiintcdebug = 10;
+char *ipl_strtbl[NIPL] = {
+ "IPL_NONE",
+ "IPL_SOFT",
+ "IPL_SOFTCLOCK",
+ "IPL_SOFTNET",
+ "IPL_SOFTTTY",
+ "IPL_BIO|IPL_USB",
+ "IPL_NET",
+ "IPL_TTY",
+ "IPL_VM",
+ "IPL_AUDIO",
+ "IPL_CLOCK",
+ "IPL_STATCLOCK",
+ "IPL_SCHED|IPL_HIGH"
+};
+#else
+#define DPRINTF(x)
+#define DPRINTFN(n,x)
+#endif
+
+#define NIRQ 96
+#define NBANKS 3
+#define NIRQPRIOREGS 5
+
+/* registers */
+#define INTC_VECTOR_REG 0x00
+#define INTC_BASE_ADR_REG 0x04
+#define INTC_PROTECTION_REG 0x08
+#define INTC_NMI_CTRL_REG 0x0c
+
+#define INTC_IRQ_PENDING_REG0 0x10
+#define INTC_IRQ_PENDING_REG1 0x14
+#define INTC_IRQ_PENDING_REG2 0x18
+
+#define INTC_SELECT_REG0 0x30
+#define INTC_SELECT_REG1 0x34
+#define INTC_SELECT_REG2 0x38
+
+#define INTC_ENABLE_REG0 0x40
+#define INTC_ENABLE_REG1 0x44
+#define INTC_ENABLE_REG2 0x48
+
+#define INTC_MASK_REG0 0x50
+#define INTC_MASK_REG1 0x54
+#define INTC_MASK_REG2 0x58
+
+#define INTC_RESP_REG0 0x60
+#define INTC_RESP_REG1 0x64
+#define INTC_RESP_REG2 0x68
+
+#define INTC_PRIO_REG0 0x80
+#define INTC_PRIO_REG1 0x84
+#define INTC_PRIO_REG2 0x88
+#define INTC_PRIO_REG3 0x8c
+#define INTC_PRIO_REG4 0x90
+
+#define INTC_IRQ_PENDING_REG(_b) (0x10 + ((_b) * 4))
+#define INTC_FIQ_PENDING_REG(_b) (0x20 + ((_b) * 4))
+#define INTC_SELECT_REG(_b) (0x30 + ((_b) * 4))
+#define INTC_ENABLE_REG(_b) (0x40 + ((_b) * 4))
+#define INTC_MASK_REG(_b) (0x50 + ((_b) * 4))
+#define INTC_RESP_REG(_b) (0x60 + ((_b) * 4))
+#define INTC_PRIO_REG(_b) (0x80 + ((_b) * 4))
+
+#define IRQ2REG32(i) (((i) >> 5) & 0x3)
+#define IRQ2BIT32(i) ((i) & 0x1f)
+
+#define IRQ2REG16(i) (((i) >> 4) & 0x5)
+#define IRQ2BIT16(i) (((i) & 0x0f) * 2)
+
+#define INTC_IRQ_HIPRIO 0x3
+#define INTC_IRQ_ENABLED 0x2
+#define INTC_IRQ_DISABLED 0x1
+#define INTC_IRQ_LOWPRIO 0x0
+#define INTC_PRIOCLEAR(i) (~(INTC_IRQ_HIPRIO << IRQ2BIT16((i))))
+#define INTC_PRIOENABLE(i) (INTC_IRQ_ENABLED << IRQ2BIT16((i)))
+#define INTC_PRIOHI(i) (INTC_IRQ_HIPRIO << IRQ2BIT16((i)))
+
+
+struct intrhand {
+ TAILQ_ENTRY(intrhand) ih_list; /* link on intrq list */
+ int (*ih_func)(void *); /* handler */
+ void *ih_arg; /* arg for handler */
+ int ih_ipl; /* IPL_* */
+ int ih_irq; /* IRQ number */
+ struct evcount ih_count;
+ char *ih_name;
+};
+
+struct intrq {
+ TAILQ_HEAD(, intrhand) iq_list; /* handler list */
+ int iq_irq; /* IRQ to mask while handling */
+ int iq_levels; /* IPL_*'s this IRQ has */
+ int iq_ist; /* share type */
+};
+
+volatile int a1xsoftint_pending;
+
+struct intrq sxiintc_handler[NIRQ];
+u_int32_t sxiintc_smask[NIPL];
+u_int32_t sxiintc_imask[NBANKS][NIPL];
+struct interrupt_controller sxiintc_ic;
+
+bus_space_tag_t sxiintc_iot;
+bus_space_handle_t sxiintc_ioh;
+int sxiintc_nirq;
+
+int sxiintc_match(struct device *, void *, void *);
+void sxiintc_attach(struct device *, struct device *, void *);
+int sxiintc_spllower(int);
+int sxiintc_splraise(int);
+void sxiintc_setipl(int);
+void sxiintc_calc_masks(void);
+void *sxiintc_intr_establish_fdt(void *, int *, int, int (*)(void *),
+ void *, char *);
+
+struct cfattach sxiintc_ca = {
+ sizeof (struct device), sxiintc_match, sxiintc_attach
+};
+
+struct cfdriver sxiintc_cd = {
+ NULL, "sxiintc", DV_DULL
+};
+
+int sxiintc_attached = 0;
+
+int
+sxiintc_match(struct device *parent, void *match, void *aux)
+{
+ struct fdt_attach_args *faa = aux;
+
+ return OF_is_compatible(faa->fa_node, "allwinner,sun4i-a10-ic");
+}
+
+void
+sxiintc_attach(struct device *parent, struct device *self, void *aux)
+{
+ struct fdt_attach_args *faa = aux;
+ int i, j;
+
+ sxiintc_iot = faa->fa_iot;
+ if (bus_space_map(sxiintc_iot, faa->fa_reg[0].addr,
+ faa->fa_reg[0].size, 0, &sxiintc_ioh))
+ panic("sxiintc_attach: bus_space_map failed!");
+
+ /* disable/mask/clear all interrupts */
+ for (i = 0; i < NBANKS; i++) {
+ bus_space_write_4(sxiintc_iot, sxiintc_ioh, INTC_ENABLE_REG(i), 0);
+ bus_space_write_4(sxiintc_iot, sxiintc_ioh, INTC_MASK_REG(i), 0);
+ bus_space_write_4(sxiintc_iot, sxiintc_ioh, INTC_IRQ_PENDING_REG(i),
+ 0xffffffff);
+ for (j = 0; j < NIPL; j++)
+ sxiintc_imask[i][j] = 0;
+ }
+
+ /* XXX */
+ bus_space_write_4(sxiintc_iot, sxiintc_ioh, INTC_PROTECTION_REG, 1);
+ bus_space_write_4(sxiintc_iot, sxiintc_ioh, INTC_NMI_CTRL_REG, 0);
+
+ for (i = 0; i < NIRQ; i++)
+ TAILQ_INIT(&sxiintc_handler[i].iq_list);
+
+ sxiintc_calc_masks();
+
+ arm_init_smask();
+ sxiintc_attached = 1;
+
+ /* insert self as interrupt handler */
+ arm_set_intr_handler(sxiintc_splraise, sxiintc_spllower, sxiintc_splx,
+ sxiintc_setipl,
+ sxiintc_intr_establish, sxiintc_intr_disestablish, sxiintc_intr_string,
+ sxiintc_irq_handler);
+ sxiintc_setipl(IPL_HIGH); /* XXX ??? */
+ enable_interrupts(PSR_I);
+ printf("\n");
+
+ sxiintc_ic.ic_node = faa->fa_node;
+ sxiintc_ic.ic_establish = sxiintc_intr_establish_fdt;
+ arm_intr_register_fdt(&sxiintc_ic);
+}
+
+void
+sxiintc_calc_masks(void)
+{
+ struct cpu_info *ci = curcpu();
+ int irq;
+ struct intrhand *ih;
+ int i;
+
+ for (irq = 0; irq < NIRQ; irq++) {
+ int max = IPL_NONE;
+ int min = IPL_HIGH;
+ TAILQ_FOREACH(ih, &sxiintc_handler[irq].iq_list, ih_list) {
+ if (ih->ih_ipl > max)
+ max = ih->ih_ipl;
+ if (ih->ih_ipl < min)
+ min = ih->ih_ipl;
+ }
+
+ sxiintc_handler[irq].iq_irq = max;
+
+ if (max == IPL_NONE)
+ min = IPL_NONE;
+
+#ifdef DEBUG_INTC
+ if (min != IPL_NONE) {
+ printf("irq %d to block at %d %d reg %d bit %d\n",
+ irq, max, min, IRQ2REG32(irq),
+ IRQ2BIT32(irq));
+ }
+#endif
+ /* Enable interrupts at lower levels, clear -> enable */
+ for (i = 0; i < min; i++)
+ sxiintc_imask[IRQ2REG32(irq)][i] &=
+ ~(1 << IRQ2BIT32(irq));
+ for (; i < NIPL; i++)
+ sxiintc_imask[IRQ2REG32(irq)][i] |=
+ (1 << IRQ2BIT32(irq));
+ /* XXX - set enable/disable, priority */
+ }
+
+ sxiintc_setipl(ci->ci_cpl);
+}
+
+void
+sxiintc_splx(int new)
+{
+ struct cpu_info *ci = curcpu();
+ sxiintc_setipl(new);
+
+ if (ci->ci_ipending & arm_smask[ci->ci_cpl])
+ arm_do_pending_intr(ci->ci_cpl);
+}
+
+int
+sxiintc_spllower(int new)
+{
+ struct cpu_info *ci = curcpu();
+ int old = ci->ci_cpl;
+ sxiintc_splx(new);
+ return (old);
+}
+
+int
+sxiintc_splraise(int new)
+{
+ struct cpu_info *ci = curcpu();
+ int old;
+ old = ci->ci_cpl;
+
+ /*
+ * setipl must always be called because there is a race window
+ * where the variable is updated before the mask is set
+ * an interrupt occurs in that window without the mask always
+ * being set, the hardware might not get updated on the next
+ * splraise completely messing up spl protection.
+ */
+ if (old > new)
+ new = old;
+
+ sxiintc_setipl(new);
+
+ return (old);
+}
+
+void
+sxiintc_setipl(int new)
+{
+ struct cpu_info *ci = curcpu();
+ int i, psw;
+#if 1
+ /*
+ * XXX not needed, because all interrupts are disabled
+ * by default, so touching maskregs has no effect, i hope.
+ */
+ if (sxiintc_attached == 0) {
+ ci->ci_cpl = new;
+ return;
+ }
+#endif
+ psw = disable_interrupts(PSR_I);
+ ci->ci_cpl = new;
+ for (i = 0; i < NBANKS; i++)
+ bus_space_write_4(sxiintc_iot, sxiintc_ioh,
+ INTC_MASK_REG(i), sxiintc_imask[i][new]);
+ restore_interrupts(psw);
+}
+
+void
+sxiintc_irq_handler(void *frame)
+{
+ struct intrhand *ih;
+ void *arg;
+ uint32_t pr;
+ int irq, prio, s;
+
+ irq = bus_space_read_4(sxiintc_iot, sxiintc_ioh, INTC_VECTOR_REG) >> 2;
+ if (irq == 0)
+ return;
+
+ prio = sxiintc_handler[irq].iq_irq;
+ s = sxiintc_splraise(prio);
+ splassert(prio);
+
+ pr = bus_space_read_4(sxiintc_iot, sxiintc_ioh,
+ INTC_ENABLE_REG(IRQ2REG32(irq)));
+ bus_space_write_4(sxiintc_iot, sxiintc_ioh,
+ INTC_ENABLE_REG(IRQ2REG32(irq)),
+ pr & ~(1 << IRQ2BIT32(irq)));
+
+ /* clear pending */
+ pr = bus_space_read_4(sxiintc_iot, sxiintc_ioh,
+ INTC_IRQ_PENDING_REG(IRQ2REG32(irq)));
+ bus_space_write_4(sxiintc_iot, sxiintc_ioh,
+ INTC_IRQ_PENDING_REG(IRQ2REG32(irq)),
+ pr | (1 << IRQ2BIT32(irq)));
+
+ pr = bus_space_read_4(sxiintc_iot, sxiintc_ioh,
+ INTC_ENABLE_REG(IRQ2REG32(irq)));
+ bus_space_write_4(sxiintc_iot, sxiintc_ioh,
+ INTC_ENABLE_REG(IRQ2REG32(irq)),
+ pr | (1 << IRQ2BIT32(irq)));
+
+ TAILQ_FOREACH(ih, &sxiintc_handler[irq].iq_list, ih_list) {
+ if (ih->ih_arg != 0)
+ arg = ih->ih_arg;
+ else
+ arg = frame;
+
+ if (ih->ih_func(arg))
+ ih->ih_count.ec_count++;
+ }
+ sxiintc_splx(s);
+}
+
+void *
+sxiintc_intr_establish(int irq, int level, int (*func)(void *),
+ void *arg, char *name)
+{
+ int psw;
+ struct intrhand *ih;
+ uint32_t er;
+
+ if (irq <= 0 || irq >= NIRQ)
+ panic("intr_establish: bogus irq %d %s\n", irq, name);
+
+ DPRINTF(("intr_establish: irq %d level %d [%s]\n", irq, level,
+ name != NULL ? name : "NULL"));
+
+ psw = disable_interrupts(PSR_I);
+
+ /* no point in sleeping unless someone can free memory. */
+ ih = (struct intrhand *)malloc (sizeof *ih, M_DEVBUF,
+ cold ? M_NOWAIT : M_WAITOK);
+ if (ih == NULL)
+ panic("intr_establish: can't malloc handler info\n");
+ ih->ih_func = func;
+ ih->ih_arg = arg;
+ ih->ih_ipl = level;
+ ih->ih_irq = irq;
+ ih->ih_name = name;
+
+ TAILQ_INSERT_TAIL(&sxiintc_handler[irq].iq_list, ih, ih_list);
+
+ if (name != NULL)
+ evcount_attach(&ih->ih_count, name, &ih->ih_irq);
+
+ er = bus_space_read_4(sxiintc_iot, sxiintc_ioh,
+ INTC_ENABLE_REG(IRQ2REG32(irq)));
+ bus_space_write_4(sxiintc_iot, sxiintc_ioh,
+ INTC_ENABLE_REG(IRQ2REG32(irq)),
+ er | (1 << IRQ2BIT32(irq)));
+
+ sxiintc_calc_masks();
+
+ restore_interrupts(psw);
+ return (ih);
+}
+
+void *
+sxiintc_intr_establish_fdt(void *cookie, int *cell, int level,
+ int (*func)(void *), void *arg, char *name)
+{
+ return sxiintc_intr_establish(cell[0], level, func, arg, name);
+}
+
+void
+sxiintc_intr_disestablish(void *cookie)
+{
+ struct intrhand *ih = cookie;
+ int irq = ih->ih_irq;
+ int psw;
+ uint32_t er;
+
+ psw = disable_interrupts(PSR_I);
+
+ TAILQ_REMOVE(&sxiintc_handler[irq].iq_list, ih, ih_list);
+
+ if (ih->ih_name != NULL)
+ evcount_detach(&ih->ih_count);
+
+ free(ih, M_DEVBUF, 0);
+
+ er = bus_space_read_4(sxiintc_iot, sxiintc_ioh,
+ INTC_ENABLE_REG(IRQ2REG32(irq)));
+ bus_space_write_4(sxiintc_iot, sxiintc_ioh,
+ INTC_ENABLE_REG(IRQ2REG32(irq)),
+ er & ~(1 << IRQ2BIT32(irq)));
+
+ sxiintc_calc_masks();
+
+ restore_interrupts(psw);
+}
+
+const char *
+sxiintc_intr_string(void *cookie)
+{
+ return "asd?";
+}
--- /dev/null
+/* $OpenBSD: sxiintc.h,v 1.1 2016/08/05 20:38:17 kettenis Exp $ */
+/*
+ * Copyright (c) 2007,2009 Dale Rahn <drahn@openbsd.org>
+ *
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+#ifndef _SXIINTC_H_
+#define _SXIINTC_H_
+
+#ifndef _LOCORE
+
+#include <arm/armreg.h>
+#include <arm/cpufunc.h>
+#include <machine/intr.h>
+#include <arm/softintr.h>
+
+extern volatile int current_spl_level;
+extern volatile int softint_pending;
+void sxiintc_do_pending(void);
+
+#define SI_TO_IRQBIT(si) (1U<<(si))
+void sxiintc_setipl(int);
+void sxiintc_splx(int);
+int sxiintc_splraise(int);
+int sxiintc_spllower(int);
+void sxiintc_setsoftintr(int);
+
+void sxiintc_irq_handler(void *);
+void *sxiintc_intr_establish(int, int, int (*)(void *), void *, char *);
+void sxiintc_intr_disestablish(void *);
+const char *sxiintc_intr_string(void *);
+
+#endif /* ! _LOCORE */
+
+#endif /* _SXIINTC_H_ */
+