Initial support for Raspberry Pi 2/3. All the hard work done by patrick@, I
authorkettenis <kettenis@openbsd.org>
Sun, 7 Aug 2016 17:46:36 +0000 (17:46 +0000)
committerkettenis <kettenis@openbsd.org>
Sun, 7 Aug 2016 17:46:36 +0000 (17:46 +0000)
just cleaned things up a bit.  Any bugs introduced in that process are
entirely mine.

This doesn't work yet.  But when it does, you'll need recent firmware from
the Raspberry Pi Foundation git repository at

  https://github.com/raspberrypi/firmware

The device tree for the Raspberry Pi is somewhat in flux as bits and pieces
to support the Raspberry Pi 2 and 3 are committed to the mainline Linux
kernel.

sys/arch/armv7/armv7/platform.c
sys/arch/armv7/broadcom/bcm2835_dwctwo.c [new file with mode: 0644]
sys/arch/armv7/broadcom/bcm2835_muart.c [new file with mode: 0644]
sys/arch/armv7/broadcom/bcm2836_intr.c [new file with mode: 0644]
sys/arch/armv7/broadcom/files.broadcom [new file with mode: 0644]
sys/arch/armv7/conf/GENERIC
sys/arch/armv7/conf/files.armv7

index f122c1f..b0eb469 100644 (file)
@@ -1,4 +1,4 @@
-/*     $OpenBSD: platform.c,v 1.8 2016/06/08 15:56:29 jsg Exp $        */
+/*     $OpenBSD: platform.c,v 1.9 2016/08/07 17:46:36 kettenis Exp $   */
 /*
  * Copyright (c) 2014 Patrick Wildt <patrick@blueri.se>
  *
@@ -39,6 +39,7 @@ void  imxuart_init_cons(void);
 void   omapuart_init_cons(void);
 void   sxiuart_init_cons(void);
 void   pl011_init_cons(void);
+void   bcmmuart_init_cons(void);
 
 struct armv7_platform *imx_platform_match(void);
 struct armv7_platform *omap_platform_match(void);
@@ -104,6 +105,7 @@ platform_init_cons(void)
        omapuart_init_cons();
        sxiuart_init_cons();
        pl011_init_cons();
+       bcmmuart_init_cons();
 }
 
 void
diff --git a/sys/arch/armv7/broadcom/bcm2835_dwctwo.c b/sys/arch/armv7/broadcom/bcm2835_dwctwo.c
new file mode 100644 (file)
index 0000000..35e2e94
--- /dev/null
@@ -0,0 +1,144 @@
+/*     $OpenBSD: bcm2835_dwctwo.c,v 1.1 2016/08/07 17:46:36 kettenis Exp $     */
+/*
+ * Copyright (c) 2015 Masao Uebayashi <uebayasi@tombiinc.com>
+ *
+ * Permission to use, copy, modify, and/or 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/device.h>
+#include <sys/malloc.h>
+#include <sys/pool.h>
+#include <sys/kthread.h>
+
+#include <machine/intr.h>
+#include <machine/bus.h>
+#include <machine/fdt.h>
+
+#include <dev/ofw/openfirm.h>
+#include <dev/ofw/fdt.h>
+
+#include <dev/usb/usb.h>
+#include <dev/usb/usbdi.h>
+#include <dev/usb/usbdivar.h>
+#include <dev/usb/usb_mem.h>
+#include <dev/usb/usb_quirks.h>
+
+#include <dev/usb/dwc2/dwc2var.h>
+#include <dev/usb/dwc2/dwc2.h>
+#include <dev/usb/dwc2/dwc2_core.h>
+
+struct bcm_dwctwo_softc {
+       struct dwc2_softc       sc_dwc2;
+       struct arm32_bus_dma_tag sc_dmat;
+       struct arm32_dma_range  sc_dmarange[1];
+
+       void                    *sc_ih;
+};
+
+int    bcm_dwctwo_match(struct device *, void *, void *);
+void   bcm_dwctwo_attach(struct device *, struct device *, void *);
+void   bcm_dwctwo_deferred(void *);
+
+const struct cfattach bcmdwctwo_ca = {
+       sizeof(struct bcm_dwctwo_softc), bcm_dwctwo_match, bcm_dwctwo_attach,
+};
+
+struct cfdriver dwctwo_cd = {
+       NULL, "dwctwo", DV_DULL
+};
+
+static struct dwc2_core_params bcm_dwctwo_params = {
+       .otg_cap                        = 0,    /* HNP/SRP capable */
+       .otg_ver                        = 0,    /* 1.3 */
+       .dma_enable                     = 1,
+       .dma_desc_enable                = 0,
+       .speed                          = 0,    /* High Speed */
+       .enable_dynamic_fifo            = 1,
+       .en_multiple_tx_fifo            = 1,
+       .host_rx_fifo_size              = 774,  /* 774 DWORDs */
+       .host_nperio_tx_fifo_size       = 256,  /* 256 DWORDs */
+       .host_perio_tx_fifo_size        = 512,  /* 512 DWORDs */
+       .max_transfer_size              = 65535,
+       .max_packet_count               = 511,
+       .host_channels                  = 8,
+       .phy_type                       = 1,    /* UTMI */
+       .phy_utmi_width                 = 8,    /* 8 bits */
+       .phy_ulpi_ddr                   = 0,    /* Single */
+       .phy_ulpi_ext_vbus              = 0,
+       .i2c_enable                     = 0,
+       .ulpi_fs_ls                     = 0,
+       .host_support_fs_ls_low_power   = 0,
+       .host_ls_low_power_phy_clk      = 0,    /* 48 MHz */
+       .ts_dline                       = 0,
+       .reload_ctl                     = 0,
+       .ahbcfg                         = 0x10,
+       .uframe_sched                   = 1,
+};
+
+int
+bcm_dwctwo_match(struct device *parent, void *match, void *aux)
+{
+       struct fdt_attach_args *faa = (struct fdt_attach_args *)aux;
+
+       return (OF_is_compatible(faa->fa_node, "brcm,bcm2708-usb") ||
+           OF_is_compatible(faa->fa_node, "brcm,bcm2835-usb"));
+}
+
+void
+bcm_dwctwo_attach(struct device *parent, struct device *self, void *aux)
+{
+       struct bcm_dwctwo_softc *sc = (struct bcm_dwctwo_softc *)self;
+       struct fdt_attach_args *faa = aux;
+       extern int physmem;
+
+       printf("\n");
+
+       memcpy(&sc->sc_dmat, faa->fa_dmat, sizeof(sc->sc_dmat));
+       sc->sc_dmarange[0].dr_sysbase = 0;
+       sc->sc_dmarange[0].dr_busbase = 0xC0000000;
+       sc->sc_dmarange[0].dr_len = physmem * PAGE_SIZE;
+       sc->sc_dmat._ranges = sc->sc_dmarange;
+       sc->sc_dmat._nranges = 1;
+
+       sc->sc_dwc2.sc_iot = faa->fa_iot;
+       sc->sc_dwc2.sc_bus.pipe_size = sizeof(struct usbd_pipe);
+       sc->sc_dwc2.sc_bus.dmatag = &sc->sc_dmat;
+       sc->sc_dwc2.sc_params = &bcm_dwctwo_params;
+
+       if (bus_space_map(faa->fa_iot, faa->fa_reg[0].addr,
+           faa->fa_reg[0].size, 0, &sc->sc_dwc2.sc_ioh))
+               panic("%s: bus_space_map failed!", __func__);
+
+       sc->sc_ih = arm_intr_establish_fdt_idx(faa->fa_node, 1, IPL_USB,
+           dwc2_intr, (void *)&sc->sc_dwc2, sc->sc_dwc2.sc_bus.bdev.dv_xname);
+       if (sc->sc_ih == NULL)
+               panic("%s: intr_establish failed!", __func__);
+
+       kthread_create_deferred(bcm_dwctwo_deferred, sc);
+}
+
+void
+bcm_dwctwo_deferred(void *self)
+{
+       struct bcm_dwctwo_softc *sc = (struct bcm_dwctwo_softc *)self;
+       int rc;
+
+       rc = dwc2_init(&sc->sc_dwc2);
+       if (rc != 0)
+               return;
+
+       sc->sc_dwc2.sc_child = config_found(&sc->sc_dwc2.sc_bus.bdev,
+           &sc->sc_dwc2.sc_bus, usbctlprint);
+}
diff --git a/sys/arch/armv7/broadcom/bcm2835_muart.c b/sys/arch/armv7/broadcom/bcm2835_muart.c
new file mode 100644 (file)
index 0000000..8e7e31c
--- /dev/null
@@ -0,0 +1,112 @@
+/* $OpenBSD: bcm2835_muart.c,v 1.1 2016/08/07 17:46:36 kettenis Exp $ */
+/*
+ * Copyright (c) 2016 Patrick Wildt <patrick@blueri.se>
+ *
+ * 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/conf.h>
+#include <sys/device.h>
+#include <sys/tty.h>
+
+#include <machine/intr.h>
+#include <machine/bus.h>
+#include <machine/fdt.h>
+
+#include <armv7/armv7/armv7_machdep.h>
+#include <arm/armv7/armv7var.h>
+
+#include <dev/ic/comvar.h>
+
+#include <dev/ofw/fdt.h>
+#include <dev/ofw/openfirm.h>
+
+int     bcmmuart_match(struct device *, void *, void *);
+void    bcmmuart_attach(struct device *, struct device *, void *);
+
+void    bcmmuart_init_cons(void);
+
+struct cfdriver bcmmuart_cd = {
+       NULL, "bcmmuart", DV_DULL
+};
+
+struct cfattach bcmmuart_ca = {
+       sizeof (struct com_softc), bcmmuart_match, bcmmuart_attach,
+};
+
+int
+bcmmuart_match(struct device *parent, void *self, void *aux)
+{
+       struct fdt_attach_args *faa = aux;
+
+       if (OF_is_compatible(faa->fa_node, "brcm,bcm2835-aux-uart"))
+               return 1;
+
+       return 0;
+}
+
+void
+bcmmuart_attach(struct device *parent, struct device *self, void *aux)
+{
+       struct com_softc *sc = (struct com_softc *)self;
+       struct fdt_attach_args *faa = aux;
+
+       if (faa->fa_nreg < 1)
+               return;
+
+       sc->sc_frequency = 500000000;
+       sc->sc_uarttype = COM_UART_16550;
+
+       if (faa->fa_reg[0].addr == comconsaddr + 0x3f000000) {
+               sc->sc_iobase = comconsaddr;
+               sc->sc_iot = comconsiot;
+               sc->sc_ioh = comconsioh;
+       } else {
+               sc->sc_iot = faa->fa_iot; /* XXX */
+               sc->sc_iobase = faa->fa_reg[0].addr;
+               if (bus_space_map(sc->sc_iot, faa->fa_reg[0].addr,
+                   faa->fa_reg[0].size, 0, &sc->sc_ioh)) {
+                       printf("%s: bus_space_map failed\n", __func__);
+                       return;
+               }
+       }
+
+       com_attach_subr(sc);
+
+       arm_intr_establish_fdt(faa->fa_node, IPL_TTY, comintr, sc,
+           sc->sc_dev.dv_xname);
+
+       extern struct cfdriver com_cd;
+       com_cd.cd_devs = bcmmuart_cd.cd_devs;
+       com_cd.cd_ndevs = bcmmuart_cd.cd_ndevs;
+}
+
+extern int comcnspeed;
+extern int comcnmode;
+
+void
+bcmmuart_init_cons(void)
+{
+       struct fdt_reg reg;
+       void *node;
+
+       if ((node = fdt_find_cons("brcm,bcm2835-aux-uart")) == NULL)
+               return;
+       if (fdt_get_reg(node, 0, &reg))
+               return;
+
+       comcnattach(&armv7_a4x_bs_tag, reg.addr, comcnspeed, 500000000,
+           comcnmode);
+}
diff --git a/sys/arch/armv7/broadcom/bcm2836_intr.c b/sys/arch/armv7/broadcom/bcm2836_intr.c
new file mode 100644 (file)
index 0000000..5fb7d54
--- /dev/null
@@ -0,0 +1,567 @@
+/* $OpenBSD: bcm2836_intr.c,v 1.1 2016/08/07 17:46:36 kettenis Exp $ */
+/*
+ * Copyright (c) 2007,2009 Dale Rahn <drahn@openbsd.org>
+ * Copyright (c) 2015 Patrick Wildt <patrick@blueri.se>
+ *
+ * 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 <arm/cpufunc.h>
+
+#include <dev/ofw/openfirm.h>
+#include <dev/ofw/fdt.h>
+
+/* registers */
+#define        INTC_PENDING_BANK0      0x00
+#define        INTC_PENDING_BANK1      0x04
+#define        INTC_PENDING_BANK2      0x08
+#define        INTC_FIQ_CONTROL        0x0C
+#define        INTC_ENABLE_BANK1       0x10
+#define        INTC_ENABLE_BANK2       0x14
+#define        INTC_ENABLE_BANK0       0x18
+#define        INTC_DISABLE_BANK1      0x1C
+#define        INTC_DISABLE_BANK2      0x20
+#define        INTC_DISABLE_BANK0      0x24
+
+/* arm local */
+#define        ARM_LOCAL_CONTROL               0x00
+#define        ARM_LOCAL_PRESCALER             0x08
+#define         PRESCALER_19_2                 0x80000000 /* 19.2 MHz */
+#define        ARM_LOCAL_INT_TIMER(n)          (0x40 + (n) * 4)
+#define        ARM_LOCAL_INT_MAILBOX(n)        (0x50 + (n) * 4)
+#define        ARM_LOCAL_INT_PENDING(n)        (0x60 + (n) * 4)
+#define         ARM_LOCAL_INT_PENDING_MASK     0x0f
+
+#define        BANK0_START     64
+#define        BANK0_END       (BANK0_START + 32 - 1)
+#define        BANK1_START     0
+#define        BANK1_END       (BANK1_START + 32 - 1)
+#define        BANK2_START     32
+#define        BANK2_END       (BANK2_START + 32 - 1)
+#define        LOCAL_START     96
+#define        LOCAL_END       (LOCAL_START + 32 - 1)
+
+#define        IS_IRQ_BANK0(n) (((n) >= BANK0_START) && ((n) <= BANK0_END))
+#define        IS_IRQ_BANK1(n) (((n) >= BANK1_START) && ((n) <= BANK1_END))
+#define        IS_IRQ_BANK2(n) (((n) >= BANK2_START) && ((n) <= BANK2_END))
+#define        IS_IRQ_LOCAL(n) (((n) >= LOCAL_START) && ((n) <= LOCAL_END))
+#define        IRQ_BANK0(n)    ((n) - BANK0_START)
+#define        IRQ_BANK1(n)    ((n) - BANK1_START)
+#define        IRQ_BANK2(n)    ((n) - BANK2_START)
+#define        IRQ_LOCAL(n)    ((n) - LOCAL_START)
+
+#define        INTC_NIRQ       128
+#define        INTC_NBANK      4
+
+#define INTC_IRQ_TO_REG(i)     (((i) >> 5) & 0x3)
+#define INTC_IRQ_TO_REGi(i)    ((i) & 0x1f)
+
+struct intrhand {
+       TAILQ_ENTRY(intrhand) ih_list;  /* link on intrq list */
+       int (*ih_fun)(void *);          /* handler */
+       void *ih_arg;                   /* arg for handler */
+       int ih_ipl;                     /* IPL_* */
+       int ih_irq;                     /* IRQ number */
+       struct evcount ih_count;        /* interrupt counter */
+       char *ih_name;                  /* device name */
+};
+
+struct intrsource {
+       TAILQ_HEAD(, intrhand) is_list; /* handler list */
+       int is_irq;                     /* IRQ to mask while handling */
+};
+
+struct bcm_intc_softc {
+       struct device            sc_dev;
+       struct intrsource        sc_bcm_intc_handler[INTC_NIRQ];
+       uint32_t                 sc_bcm_intc_imask[INTC_NBANK][NIPL];
+       bus_space_tag_t          sc_iot;
+       bus_space_handle_t       sc_ioh;
+       bus_space_handle_t       sc_lioh;
+       struct interrupt_controller sc_intc;
+       struct interrupt_controller sc_l1_intc;
+};
+struct bcm_intc_softc *bcm_intc;
+
+int     bcm_intc_match(struct device *, void *, void *);
+void    bcm_intc_attach(struct device *, struct device *, void *);
+void    bcm_intc_splx(int new);
+int     bcm_intc_spllower(int new);
+int     bcm_intc_splraise(int new);
+void    bcm_intc_setipl(int new);
+void    bcm_intc_calc_mask(void);
+void   *bcm_intc_intr_establish(int, int, int (*)(void *),
+    void *, char *);
+void   *bcm_intc_intr_establish_fdt(void *, int *, int, int (*)(void *),
+    void *, char *);
+void   *l1_intc_intr_establish_fdt(void *, int *, int, int (*)(void *),
+    void *, char *);
+void    bcm_intc_intr_disestablish(void *);
+const char *bcm_intc_intr_string(void *);
+void    bcm_intc_irq_handler(void *);
+
+struct cfattach        bcmintc_ca = {
+       sizeof (struct bcm_intc_softc), bcm_intc_match, bcm_intc_attach
+};
+
+struct cfdriver bcmintc_cd = {
+       NULL, "bcmintc", DV_DULL
+};
+
+int
+bcm_intc_match(struct device *parent, void *cfdata, void *aux)
+{
+       struct fdt_attach_args *faa = aux;
+
+       if (OF_is_compatible(faa->fa_node, "brcm,bcm2836-armctrl-ic"))
+               return 1;
+
+       return 0;
+}
+
+void
+bcm_intc_attach(struct device *parent, struct device *self, void *aux)
+{
+       struct bcm_intc_softc *sc = (struct bcm_intc_softc *)self;
+       struct fdt_attach_args *faa = aux;
+       int node;
+       int i;
+
+       if (faa->fa_nreg < 1)
+               return;
+
+       bcm_intc = sc;
+
+       sc->sc_iot = faa->fa_iot;
+
+       if (bus_space_map(sc->sc_iot, faa->fa_reg[0].addr,
+           faa->fa_reg[0].size, 0, &sc->sc_ioh))
+               panic("%s: bus_space_map failed!", __func__);
+
+       /*
+        * ARM Local area, because fuck you.
+        *
+        * The original rPi with the BCM2835 does implement the same IC
+        * but with a different IRQ basis. On the BCM2836 there's an
+        * additional area to enable Timer/Mailbox interrupts, which
+        * is not yet exposed in the given DT.
+        */
+       extern struct bus_space armv7_bs_tag;
+       if (bus_space_map(&armv7_bs_tag, 0x40000000, 0x1000, 0,
+           &sc->sc_lioh))
+               panic("%s: bus_space_map failed!", __func__);
+
+       bus_space_write_4(sc->sc_iot, sc->sc_lioh, 0, 0);
+       bus_space_write_4(sc->sc_iot, sc->sc_lioh, 8, 0x80000000);
+
+       printf("\n");
+
+       /* mask all interrupts */
+       bus_space_write_4(sc->sc_iot, sc->sc_ioh, INTC_DISABLE_BANK0,
+           0xffffffff);
+       bus_space_write_4(sc->sc_iot, sc->sc_ioh, INTC_DISABLE_BANK1,
+           0xffffffff);
+       bus_space_write_4(sc->sc_iot, sc->sc_ioh, INTC_DISABLE_BANK2,
+           0xffffffff);
+
+       /* ARM local specific */
+       bus_space_write_4(sc->sc_iot, sc->sc_lioh, ARM_LOCAL_CONTROL, 0);
+       bus_space_write_4(sc->sc_iot, sc->sc_lioh, ARM_LOCAL_PRESCALER,
+           PRESCALER_19_2);
+       for (i = 0; i < 4; i++)
+               bus_space_write_4(sc->sc_iot, sc->sc_lioh,
+                   ARM_LOCAL_INT_TIMER(i), 0);
+       for (i = 0; i < 4; i++)
+               bus_space_write_4(sc->sc_iot, sc->sc_lioh,
+                   ARM_LOCAL_INT_MAILBOX(i), 1);
+
+       for (i = 0; i < INTC_NIRQ; i++) {
+               TAILQ_INIT(&sc->sc_bcm_intc_handler[i].is_list);
+       }
+
+       bcm_intc_calc_mask();
+
+       /* insert self as interrupt handler */
+       arm_set_intr_handler(bcm_intc_splraise, bcm_intc_spllower, bcm_intc_splx,
+           bcm_intc_setipl,
+           bcm_intc_intr_establish, bcm_intc_intr_disestablish, bcm_intc_intr_string,
+           bcm_intc_irq_handler);
+
+       sc->sc_intc.ic_node = faa->fa_node;
+       sc->sc_intc.ic_cookie = sc;
+       sc->sc_intc.ic_establish = bcm_intc_intr_establish_fdt;
+       sc->sc_intc.ic_disestablish = bcm_intc_intr_disestablish;
+       arm_intr_register_fdt(&sc->sc_intc);
+
+       node = OF_finddevice("/soc/local_intc");
+       if (node != -1) {
+               sc->sc_l1_intc.ic_node = node;
+               sc->sc_l1_intc.ic_cookie = sc;
+               sc->sc_l1_intc.ic_establish = l1_intc_intr_establish_fdt;
+               sc->sc_l1_intc.ic_disestablish = bcm_intc_intr_disestablish;
+               arm_intr_register_fdt(&sc->sc_l1_intc);
+       }
+
+       bcm_intc_setipl(IPL_HIGH);  /* XXX ??? */
+       enable_interrupts(PSR_I);
+}
+
+void
+bcm_intc_intr_enable(int irq, int ipl)
+{
+       struct bcm_intc_softc   *sc = bcm_intc;
+
+       if (IS_IRQ_BANK0(irq))
+               sc->sc_bcm_intc_imask[0][ipl] |= (1 << IRQ_BANK0(irq));
+       else if (IS_IRQ_BANK1(irq))
+               sc->sc_bcm_intc_imask[1][ipl] |= (1 << IRQ_BANK1(irq));
+       else if (IS_IRQ_BANK2(irq))
+               sc->sc_bcm_intc_imask[2][ipl] |= (1 << IRQ_BANK2(irq));
+       else if (IS_IRQ_LOCAL(irq))
+               sc->sc_bcm_intc_imask[3][ipl] |= (1 << IRQ_LOCAL(irq));
+       else
+               printf("%s: invalid irq number: %d\n", __func__, irq);
+}
+
+void
+bcm_intc_intr_disable(int irq, int ipl)
+{
+       struct bcm_intc_softc   *sc = bcm_intc;
+
+       if (IS_IRQ_BANK0(irq))
+               sc->sc_bcm_intc_imask[0][ipl] &= ~(1 << IRQ_BANK0(irq));
+       else if (IS_IRQ_BANK1(irq))
+               sc->sc_bcm_intc_imask[1][ipl] &= ~(1 << IRQ_BANK1(irq));
+       else if (IS_IRQ_BANK2(irq))
+               sc->sc_bcm_intc_imask[2][ipl] &= ~(1 << IRQ_BANK2(irq));
+       else if (IS_IRQ_LOCAL(irq))
+               sc->sc_bcm_intc_imask[3][ipl] &= ~(1 << IRQ_LOCAL(irq));
+       else
+               printf("%s: invalid irq number: %d\n", __func__, irq);
+}
+
+void
+bcm_intc_calc_mask(void)
+{
+       struct cpu_info *ci = curcpu();
+       struct bcm_intc_softc *sc = bcm_intc;
+       int irq;
+       struct intrhand *ih;
+       int i;
+
+       for (irq = 0; irq < INTC_NIRQ; irq++) {
+               int max = IPL_NONE;
+               int min = IPL_HIGH;
+               TAILQ_FOREACH(ih, &sc->sc_bcm_intc_handler[irq].is_list,
+                   ih_list) {
+                       if (ih->ih_ipl > max)
+                               max = ih->ih_ipl;
+
+                       if (ih->ih_ipl < min)
+                               min = ih->ih_ipl;
+               }
+
+               sc->sc_bcm_intc_handler[irq].is_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, INTC_IRQ_TO_REG(irq),
+                           INTC_IRQ_TO_REGi(irq));
+               }
+#endif
+               /* Enable interrupts at lower levels, clear -> enable */
+               for (i = 0; i < min; i++)
+                       bcm_intc_intr_enable(irq, i);
+               for (; i <= IPL_HIGH; i++)
+                       bcm_intc_intr_disable(irq, i);
+       }
+       arm_init_smask();
+       bcm_intc_setipl(ci->ci_cpl);
+}
+
+void
+bcm_intc_splx(int new)
+{
+       struct cpu_info *ci = curcpu();
+
+       if (ci->ci_ipending & arm_smask[new])
+               arm_do_pending_intr(new);
+
+       bcm_intc_setipl(new);
+}
+
+int
+bcm_intc_spllower(int new)
+{
+       struct cpu_info *ci = curcpu();
+       int old = ci->ci_cpl;
+       bcm_intc_splx(new);
+       return (old);
+}
+
+int
+bcm_intc_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;
+
+       bcm_intc_setipl(new);
+
+       return (old);
+}
+
+void
+bcm_intc_setipl(int new)
+{
+       struct cpu_info *ci = curcpu();
+       struct bcm_intc_softc *sc = bcm_intc;
+       int i, psw;
+
+       psw = disable_interrupts(PSR_I);
+       ci->ci_cpl = new;
+       bus_space_write_4(sc->sc_iot, sc->sc_ioh, INTC_DISABLE_BANK0,
+           0xffffffff);
+       bus_space_write_4(sc->sc_iot, sc->sc_ioh, INTC_DISABLE_BANK1,
+           0xffffffff);
+       bus_space_write_4(sc->sc_iot, sc->sc_ioh, INTC_DISABLE_BANK2,
+           0xffffffff);
+       bus_space_write_4(sc->sc_iot, sc->sc_ioh, INTC_ENABLE_BANK0,
+           sc->sc_bcm_intc_imask[0][new]);
+       bus_space_write_4(sc->sc_iot, sc->sc_ioh, INTC_ENABLE_BANK1,
+           sc->sc_bcm_intc_imask[1][new]);
+       bus_space_write_4(sc->sc_iot, sc->sc_ioh, INTC_ENABLE_BANK2,
+           sc->sc_bcm_intc_imask[2][new]);
+       /* XXX: SMP */
+       for (i = 0; i < 4; i++)
+               bus_space_write_4(sc->sc_iot, sc->sc_lioh,
+                   ARM_LOCAL_INT_TIMER(i), sc->sc_bcm_intc_imask[3][new]);
+       restore_interrupts(psw);
+}
+
+int
+bcm_intc_get_next_irq(int last_irq)
+{
+       struct bcm_intc_softc *sc = bcm_intc;
+       uint32_t pending;
+       int32_t irq = last_irq + 1;
+
+       /* Sanity check */
+       if (irq < 0)
+               irq = 0;
+
+       /* We need to keep this order. */
+       /* TODO: should we mask last_irq? */
+       if (IS_IRQ_BANK1(irq)) {
+               pending = bus_space_read_4(sc->sc_iot, sc->sc_ioh,
+                   INTC_PENDING_BANK1);
+               if (pending == 0) {
+                       irq = BANK2_START;      /* skip to next bank */
+               } else do {
+                       if (pending & (1 << IRQ_BANK1(irq)))
+                               return irq;
+                       irq++;
+               } while (IS_IRQ_BANK1(irq));
+       }
+       if (IS_IRQ_BANK2(irq)) {
+               pending = bus_space_read_4(sc->sc_iot, sc->sc_ioh,
+                   INTC_PENDING_BANK2);
+               if (pending == 0) {
+                       irq = BANK0_START;      /* skip to next bank */
+               } else do {
+                       if (pending & (1 << IRQ_BANK2(irq)))
+                               return irq;
+                       irq++;
+               } while (IS_IRQ_BANK2(irq));
+       }
+       if (IS_IRQ_BANK0(irq)) {
+               pending = bus_space_read_4(sc->sc_iot, sc->sc_ioh,
+                   INTC_PENDING_BANK0);
+               if (pending == 0) {
+                       irq = LOCAL_START;      /* skip to next bank */
+               } else do {
+                       if (pending & (1 << IRQ_BANK0(irq)))
+                               return irq;
+                       irq++;
+               } while (IS_IRQ_BANK0(irq));
+       }
+       if (IS_IRQ_LOCAL(irq)) {
+               /* XXX: SMP */
+               pending = bus_space_read_4(sc->sc_iot, sc->sc_lioh,
+                   ARM_LOCAL_INT_PENDING(0));
+               pending &= ARM_LOCAL_INT_PENDING_MASK;
+               if (pending != 0) do {
+                       if (pending & (1 << IRQ_LOCAL(irq)))
+                               return irq;
+                       irq++;
+               } while (IS_IRQ_LOCAL(irq));
+       }
+       return (-1);
+}
+
+static void
+bcm_intc_call_handler(int irq, void *frame)
+{
+       struct bcm_intc_softc *sc = bcm_intc;
+       struct intrhand *ih;
+       int pri, s;
+       void *arg;
+
+#ifdef DEBUG_INTC
+       if (irq != 99)
+               printf("irq  %d fired\n", irq);
+       else {
+               static int cnt = 0;
+               if ((cnt++ % 100) == 0) {
+                       printf("irq  %d fired * _100\n", irq);
+                       Debugger();
+               }
+       }
+#endif
+
+       pri = sc->sc_bcm_intc_handler[irq].is_irq;
+       s = bcm_intc_splraise(pri);
+       TAILQ_FOREACH(ih, &sc->sc_bcm_intc_handler[irq].is_list, ih_list) {
+               if (ih->ih_arg != 0)
+                       arg = ih->ih_arg;
+               else
+                       arg = frame;
+
+               if (ih->ih_fun(arg))
+                       ih->ih_count.ec_count++;
+
+       }
+
+       bcm_intc_splx(s);
+}
+
+void
+bcm_intc_irq_handler(void *frame)
+{
+       int irq = -1;
+
+       while ((irq = bcm_intc_get_next_irq(irq)) != -1)
+               bcm_intc_call_handler(irq, frame);
+}
+
+void *
+bcm_intc_intr_establish_fdt(void *cookie, int *cell, int level,
+    int (*func)(void *), void *arg, char *name)
+{
+       struct bcm_intc_softc   *sc = (struct bcm_intc_softc *)cookie;
+       int irq;
+
+       irq = cell[1];
+       if (cell[0] == 0)
+               irq += BANK0_START;
+       else if (cell[0] == 1)
+               irq += BANK1_START;
+       else if (cell[0] == 2)
+               irq += BANK2_START;
+       else if (cell[0] == 3)
+               irq += LOCAL_START;
+       else
+               panic("%s: bogus interrupt type", sc->sc_dev.dv_xname);
+
+       return bcm_intc_intr_establish(irq, level, func, arg, name);
+}
+
+void *
+l1_intc_intr_establish_fdt(void *cookie, int *cell, int level,
+    int (*func)(void *), void *arg, char *name)
+{
+       int irq;
+
+       irq = cell[0] + LOCAL_START;
+       return bcm_intc_intr_establish(irq, level, func, arg, name);
+}
+
+void *
+bcm_intc_intr_establish(int irqno, int level, int (*func)(void *),
+    void *arg, char *name)
+{
+       struct bcm_intc_softc *sc = bcm_intc;
+       struct intrhand *ih;
+       int psw;
+
+       if (irqno < 0 || irqno >= INTC_NIRQ)
+               panic("bcm_intc_intr_establish: bogus irqnumber %d: %s",
+                    irqno, name);
+       psw = disable_interrupts(PSR_I);
+
+       ih = malloc(sizeof *ih, M_DEVBUF, M_WAITOK);
+       ih->ih_fun = func;
+       ih->ih_arg = arg;
+       ih->ih_ipl = level;
+       ih->ih_irq = irqno;
+       ih->ih_name = name;
+
+       TAILQ_INSERT_TAIL(&sc->sc_bcm_intc_handler[irqno].is_list, ih, ih_list);
+
+       if (name != NULL)
+               evcount_attach(&ih->ih_count, name, &ih->ih_irq);
+
+#ifdef DEBUG_INTC
+       printf("%s irq %d level %d [%s]\n", __func__, irqno, level,
+           name);
+#endif
+       bcm_intc_calc_mask();
+
+       restore_interrupts(psw);
+       return (ih);
+}
+
+void
+bcm_intc_intr_disestablish(void *cookie)
+{
+       struct bcm_intc_softc *sc = bcm_intc;
+       struct intrhand *ih = cookie;
+       int irqno = ih->ih_irq;
+       int psw;
+       psw = disable_interrupts(PSR_I);
+       TAILQ_REMOVE(&sc->sc_bcm_intc_handler[irqno].is_list, ih, ih_list);
+       if (ih->ih_name != NULL)
+               evcount_detach(&ih->ih_count);
+       free(ih, M_DEVBUF, 0);
+       restore_interrupts(psw);
+}
+
+const char *
+bcm_intc_intr_string(void *cookie)
+{
+       return "huh?";
+}
diff --git a/sys/arch/armv7/broadcom/files.broadcom b/sys/arch/armv7/broadcom/files.broadcom
new file mode 100644 (file)
index 0000000..e6b4323
--- /dev/null
@@ -0,0 +1,13 @@
+#      $OpenBSD: files.broadcom,v 1.1 2016/08/07 17:46:36 kettenis Exp $
+
+device bcmintc
+attach bcmintc at fdt
+file   arch/armv7/broadcom/bcm2836_intr.c              bcmintc
+
+device bcmmuart
+attach bcmmuart at fdt
+file   arch/armv7/broadcom/bcm2835_muart.c             bcmmuart
+
+include                "dev/usb/dwc2/files.dwc2"
+attach dwctwo at fdt with bcmdwctwo
+file   arch/armv7/broadcom/bcm2835_dwctwo.c            bcmdwctwo       needs-flag
index d11f539..f3805be 100644 (file)
@@ -1,4 +1,4 @@
-#      $OpenBSD: GENERIC,v 1.41 2016/08/06 10:07:45 jsg Exp $
+#      $OpenBSD: GENERIC,v 1.42 2016/08/07 17:46:36 kettenis Exp $
 #
 # For further information on compiling OpenBSD kernels, see the config(8)
 # man page.
@@ -125,6 +125,12 @@ exesdhc*   at exynos?
 sdmmc*         at exesdhc?
 exuart*                at exynos?
 
+# Raspberry Pi 2/3
+bcmintc*       at fdt?
+bcmmuart*      at fdt?
+dwctwo*                at fdt?
+usb*           at dwctwo?
+
 crosec*                at iic?
 wskbd*         at crosec? mux 1
 pcfrtc*                at iic?
index 2a4c331..27551dd 100644 (file)
@@ -1,4 +1,4 @@
-#      $OpenBSD: files.armv7,v 1.21 2016/08/06 17:16:13 kettenis Exp $
+#      $OpenBSD: files.armv7,v 1.22 2016/08/07 17:46:36 kettenis Exp $
 
 maxpartitions  16
 maxusers       2 8 64
@@ -69,3 +69,4 @@ include "arch/armv7/omap/files.omap"
 include "arch/armv7/sunxi/files.sunxi"
 include "arch/armv7/exynos/files.exynos"
 include "arch/armv7/vexpress/files.vexpress"
+include "arch/armv7/broadcom/files.broadcom"