From 367aba55752639a62e3e889e9837fec1c3b168c1 Mon Sep 17 00:00:00 2001 From: kettenis Date: Sun, 7 Aug 2016 17:46:36 +0000 Subject: [PATCH] Initial support for Raspberry Pi 2/3. All the hard work done by patrick@, I 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 | 4 +- sys/arch/armv7/broadcom/bcm2835_dwctwo.c | 144 ++++++ sys/arch/armv7/broadcom/bcm2835_muart.c | 112 +++++ sys/arch/armv7/broadcom/bcm2836_intr.c | 567 +++++++++++++++++++++++ sys/arch/armv7/broadcom/files.broadcom | 13 + sys/arch/armv7/conf/GENERIC | 8 +- sys/arch/armv7/conf/files.armv7 | 3 +- 7 files changed, 848 insertions(+), 3 deletions(-) create mode 100644 sys/arch/armv7/broadcom/bcm2835_dwctwo.c create mode 100644 sys/arch/armv7/broadcom/bcm2835_muart.c create mode 100644 sys/arch/armv7/broadcom/bcm2836_intr.c create mode 100644 sys/arch/armv7/broadcom/files.broadcom diff --git a/sys/arch/armv7/armv7/platform.c b/sys/arch/armv7/armv7/platform.c index f122c1fd200..b0eb4698645 100644 --- a/sys/arch/armv7/armv7/platform.c +++ b/sys/arch/armv7/armv7/platform.c @@ -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 * @@ -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 index 00000000000..35e2e94af35 --- /dev/null +++ b/sys/arch/armv7/broadcom/bcm2835_dwctwo.c @@ -0,0 +1,144 @@ +/* $OpenBSD: bcm2835_dwctwo.c,v 1.1 2016/08/07 17:46:36 kettenis Exp $ */ +/* + * Copyright (c) 2015 Masao Uebayashi + * + * 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 +#include +#include +#include +#include +#include + +#include +#include +#include + +#include +#include + +#include +#include +#include +#include +#include + +#include +#include +#include + +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 index 00000000000..8e7e31c563e --- /dev/null +++ b/sys/arch/armv7/broadcom/bcm2835_muart.c @@ -0,0 +1,112 @@ +/* $OpenBSD: bcm2835_muart.c,v 1.1 2016/08/07 17:46:36 kettenis Exp $ */ +/* + * Copyright (c) 2016 Patrick Wildt + * + * 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 +#include +#include +#include +#include + +#include +#include +#include + +#include +#include + +#include + +#include +#include + +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, ®)) + 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 index 00000000000..5fb7d54ff70 --- /dev/null +++ b/sys/arch/armv7/broadcom/bcm2836_intr.c @@ -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 + * Copyright (c) 2015 Patrick Wildt + * + * 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 +#include +#include +#include +#include +#include + +#include +#include + +#include + +#include +#include + +/* 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 index 00000000000..e6b43237b5c --- /dev/null +++ b/sys/arch/armv7/broadcom/files.broadcom @@ -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 diff --git a/sys/arch/armv7/conf/GENERIC b/sys/arch/armv7/conf/GENERIC index d11f539442c..f3805bea64e 100644 --- a/sys/arch/armv7/conf/GENERIC +++ b/sys/arch/armv7/conf/GENERIC @@ -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? diff --git a/sys/arch/armv7/conf/files.armv7 b/sys/arch/armv7/conf/files.armv7 index 2a4c331caf2..27551dd5211 100644 --- a/sys/arch/armv7/conf/files.armv7 +++ b/sys/arch/armv7/conf/files.armv7 @@ -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" -- 2.20.1