diff --git a/sys/arm/arm/pl190.c b/sys/arm/arm/pl190.c index 9817fa5ac17b..223d10ec1c90 100644 --- a/sys/arm/arm/pl190.c +++ b/sys/arm/arm/pl190.c @@ -1,5 +1,5 @@ /*- - * Copyright (c) 2012 Oleksandr Tymoshenko + * Copyright (c) 2012-2017 Oleksandr Tymoshenko * All rights reserved. * * Redistribution and use in source and binary forms, with or without @@ -24,7 +24,6 @@ * SUCH DAMAGE. */ - #include __FBSDID("$FreeBSD$"); @@ -34,6 +33,7 @@ __FBSDID("$FreeBSD$"); #include #include #include +#include #include #include #include @@ -42,6 +42,8 @@ __FBSDID("$FreeBSD$"); #include #include +#include "pic_if.h" + #ifdef DEBUG #define dprintf(fmt, args...) printf(fmt, ##args) #else @@ -62,17 +64,139 @@ __FBSDID("$FreeBSD$"); #define VIC_NIRQS 32 -struct pl190_intc_softc { - device_t sc_dev; - struct resource * intc_res; +struct pl190_intc_irqsrc { + struct intr_irqsrc isrc; + u_int irq; }; -static struct pl190_intc_softc *pl190_intc_sc = NULL; +struct pl190_intc_softc { + device_t dev; + struct mtx mtx; + struct resource * intc_res; + struct pl190_intc_irqsrc isrcs[VIC_NIRQS]; +}; -#define intc_vic_read_4(reg) \ - bus_read_4(pl190_intc_sc->intc_res, (reg)) -#define intc_vic_write_4(reg, val) \ - bus_write_4(pl190_intc_sc->intc_res, (reg), (val)) +#define INTC_VIC_READ_4(sc, reg) \ + bus_read_4(sc->intc_res, (reg)) +#define INTC_VIC_WRITE_4(sc, reg, val) \ + bus_write_4(sc->intc_res, (reg), (val)) + +#define VIC_LOCK(_sc) mtx_lock_spin(&(_sc)->mtx) +#define VIC_UNLOCK(_sc) mtx_unlock_spin(&(_sc)->mtx) + +static inline void +pl190_intc_irq_dispatch(struct pl190_intc_softc *sc, u_int irq, + struct trapframe *tf) +{ + struct pl190_intc_irqsrc *src; + + src = &sc->isrcs[irq]; + if (intr_isrc_dispatch(&src->isrc, tf) != 0) + device_printf(sc->dev, "Stray irq %u detected\n", irq); +} + +static int +pl190_intc_intr(void *arg) +{ + struct pl190_intc_softc *sc; + u_int cpu; + uint32_t num, pending; + struct trapframe *tf; + + sc = arg; + cpu = PCPU_GET(cpuid); + tf = curthread->td_intr_frame; + + VIC_LOCK(sc); + pending = INTC_VIC_READ_4(sc, VICIRQSTATUS); + VIC_UNLOCK(sc); + for (num = 0 ; num < VIC_NIRQS; num++) { + if (pending & (1 << num)) + pl190_intc_irq_dispatch(sc, num, tf); + } + + return (FILTER_HANDLED); +} + +static void +pl190_intc_disable_intr(device_t dev, struct intr_irqsrc *isrc) +{ + struct pl190_intc_softc *sc; + struct pl190_intc_irqsrc *src; + + sc = device_get_softc(dev); + src = (struct pl190_intc_irqsrc *)isrc; + + VIC_LOCK(sc); + INTC_VIC_WRITE_4(sc, VICINTENCLEAR, (1 << src->irq)); + VIC_UNLOCK(sc); +} + +static void +pl190_intc_enable_intr(device_t dev, struct intr_irqsrc *isrc) +{ + struct pl190_intc_softc *sc; + struct pl190_intc_irqsrc *src; + + sc = device_get_softc(dev); + src = (struct pl190_intc_irqsrc *)isrc; + + VIC_LOCK(sc); + INTC_VIC_WRITE_4(sc, VICINTENABLE, (1 << src->irq)); + VIC_UNLOCK(sc); +} + +static int +pl190_intc_map_intr(device_t dev, struct intr_map_data *data, + struct intr_irqsrc **isrcp) +{ + struct intr_map_data_fdt *daf; + struct pl190_intc_softc *sc; + + if (data->type != INTR_MAP_DATA_FDT) + return (ENOTSUP); + + daf = (struct intr_map_data_fdt *)data; + if (daf->ncells != 1 || daf->cells[0] >= VIC_NIRQS) + return (EINVAL); + + sc = device_get_softc(dev); + *isrcp = &sc->isrcs[daf->cells[0]].isrc; + return (0); +} + +static void +pl190_intc_pre_ithread(device_t dev, struct intr_irqsrc *isrc) +{ + pl190_intc_disable_intr(dev, isrc); +} + +static void +pl190_intc_post_ithread(device_t dev, struct intr_irqsrc *isrc) +{ + struct pl190_intc_irqsrc *src; + + src = (struct pl190_intc_irqsrc *)isrc; + pl190_intc_enable_intr(dev, isrc); + arm_irq_memory_barrier(src->irq); +} + +static void +pl190_intc_post_filter(device_t dev, struct intr_irqsrc *isrc) +{ + struct pl190_intc_irqsrc *src; + + src = (struct pl190_intc_irqsrc *)isrc; + arm_irq_memory_barrier(src->irq); +} + +static int +pl190_intc_setup_intr(device_t dev, struct intr_irqsrc *isrc, + struct resource *res, struct intr_map_data *data) +{ + + return (0); +} static int pl190_intc_probe(device_t dev) @@ -90,14 +214,20 @@ pl190_intc_probe(device_t dev) static int pl190_intc_attach(device_t dev) { - struct pl190_intc_softc *sc = device_get_softc(dev); + struct pl190_intc_softc *sc; uint32_t id; int i, rid; + struct pl190_intc_irqsrc *isrcs; + struct intr_pic *pic; + int error; + uint32_t irq; + const char *name; + phandle_t xref; - sc->sc_dev = dev; - - if (pl190_intc_sc) - return (ENXIO); + sc = device_get_softc(dev); + sc->dev = dev; + mtx_init(&sc->mtx, device_get_nameunit(dev), "pl190", + MTX_SPIN); /* Request memory resources */ rid = 0; @@ -108,20 +238,17 @@ pl190_intc_attach(device_t dev) return (ENXIO); } - pl190_intc_sc = sc; /* * All interrupts should use IRQ line */ - intc_vic_write_4(VICINTSELECT, 0x00000000); + INTC_VIC_WRITE_4(sc, VICINTSELECT, 0x00000000); /* Disable all interrupts */ - intc_vic_write_4(VICINTENCLEAR, 0xffffffff); - /* Enable INT31, SIC IRQ */ - intc_vic_write_4(VICINTENABLE, (1U << 31)); + INTC_VIC_WRITE_4(sc, VICINTENCLEAR, 0xffffffff); id = 0; for (i = 3; i >= 0; i--) { id = (id << 8) | - (intc_vic_read_4(VICPERIPHID + i*4) & 0xff); + (INTC_VIC_READ_4(sc, VICPERIPHID + i*4) & 0xff); } device_printf(dev, "Peripheral ID: %08x\n", id); @@ -129,18 +256,43 @@ pl190_intc_attach(device_t dev) id = 0; for (i = 3; i >= 0; i--) { id = (id << 8) | - (intc_vic_read_4(VICPRIMECELLID + i*4) & 0xff); + (INTC_VIC_READ_4(sc, VICPRIMECELLID + i*4) & 0xff); } device_printf(dev, "PrimeCell ID: %08x\n", id); - return (0); + /* PIC attachment */ + isrcs = sc->isrcs; + name = device_get_nameunit(sc->dev); + for (irq = 0; irq < VIC_NIRQS; irq++) { + isrcs[irq].irq = irq; + error = intr_isrc_register(&isrcs[irq].isrc, sc->dev, + 0, "%s,%u", name, irq); + if (error != 0) + return (error); + } + + xref = OF_xref_from_node(ofw_bus_get_node(sc->dev)); + pic = intr_pic_register(sc->dev, xref); + if (pic == NULL) + return (ENXIO); + + return (intr_pic_claim_root(sc->dev, xref, pl190_intc_intr, sc, 0)); } static device_method_t pl190_intc_methods[] = { DEVMETHOD(device_probe, pl190_intc_probe), DEVMETHOD(device_attach, pl190_intc_attach), - { 0, 0 } + + DEVMETHOD(pic_disable_intr, pl190_intc_disable_intr), + DEVMETHOD(pic_enable_intr, pl190_intc_enable_intr), + DEVMETHOD(pic_map_intr, pl190_intc_map_intr), + DEVMETHOD(pic_post_filter, pl190_intc_post_filter), + DEVMETHOD(pic_post_ithread, pl190_intc_post_ithread), + DEVMETHOD(pic_pre_ithread, pl190_intc_pre_ithread), + DEVMETHOD(pic_setup_intr, pl190_intc_setup_intr), + + DEVMETHOD_END }; static driver_t pl190_intc_driver = { @@ -153,39 +305,3 @@ static devclass_t pl190_intc_devclass; EARLY_DRIVER_MODULE(intc, simplebus, pl190_intc_driver, pl190_intc_devclass, 0, 0, BUS_PASS_INTERRUPT + BUS_PASS_ORDER_MIDDLE); - -int -arm_get_next_irq(int last_irq) -{ - uint32_t pending; - int32_t irq = last_irq + 1; - - /* Sanity check */ - if (irq < 0) - irq = 0; - - pending = intc_vic_read_4(VICIRQSTATUS); - while (irq < VIC_NIRQS) { - if (pending & (1 << irq)) - return (irq); - irq++; - } - - return (-1); -} - -void -arm_mask_irq(uintptr_t nb) -{ - - dprintf("%s: %d\n", __func__, nb); - intc_vic_write_4(VICINTENCLEAR, (1 << nb)); -} - -void -arm_unmask_irq(uintptr_t nb) -{ - - dprintf("%s: %d\n", __func__, nb); - intc_vic_write_4(VICINTENABLE, (1 << nb)); -} diff --git a/sys/arm/conf/VERSATILEPB b/sys/arm/conf/VERSATILEPB index 7cfc5f6759c0..9525ac41fe42 100644 --- a/sys/arm/conf/VERSATILEPB +++ b/sys/arm/conf/VERSATILEPB @@ -68,7 +68,9 @@ makeoptions SC_DFLT_FONT=cp437 device md device random # Entropy device +options INTRNG + # Flattened Device Tree options FDT # Configure using FDT/DTB data options FDT_DTB_STATIC -makeoptions FDT_DTS_FILE=versatilepb.dts +makeoptions FDT_DTS_FILE=versatile-pb.dts diff --git a/sys/arm/versatile/files.versatile b/sys/arm/versatile/files.versatile index c7dabb7bff84..d805abf879aa 100644 --- a/sys/arm/versatile/files.versatile +++ b/sys/arm/versatile/files.versatile @@ -6,6 +6,7 @@ arm/versatile/versatile_machdep.c standard arm/versatile/versatile_clcd.c optional sc arm/versatile/versatile_common.c standard arm/versatile/versatile_pci.c optional pci +arm/versatile/versatile_scm.c standard arm/versatile/versatile_sic.c standard arm/versatile/versatile_timer.c standard diff --git a/sys/arm/versatile/versatile_clcd.c b/sys/arm/versatile/versatile_clcd.c index 93f71d53f034..4c428a976e1e 100644 --- a/sys/arm/versatile/versatile_clcd.c +++ b/sys/arm/versatile/versatile_clcd.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2012 Oleksandr Tymoshenko + * Copyright (c) 2012-2017 Oleksandr Tymoshenko * All rights reserved. * * Redistribution and use in source and binary forms, with or without @@ -49,22 +49,12 @@ __FBSDID("$FreeBSD$"); #include #include +#include + #include #define PL110_VENDOR_ARM926PXP 1 -#define MEM_SYS 0 -#define MEM_CLCD 1 -#define MEM_REGIONS 2 - -#define SYS_CLCD 0x00 -#define SYS_CLCD_CLCDID_SHIFT 0x08 -#define SYS_CLCD_CLCDID_MASK 0x1f -#define SYS_CLCD_PWR3V5VSWITCH (1 << 4) -#define SYS_CLCD_VDDPOSSWITCH (1 << 3) -#define SYS_CLCD_NLCDIOON (1 << 2) -#define SYS_CLCD_LCD_MODE_MASK 0x03 - #define CLCD_MODE_RGB888 0x0 #define CLCD_MODE_RGB555 0x01 #define CLCD_MODE_RBG565 0x02 @@ -119,18 +109,13 @@ __FBSDID("$FreeBSD$"); #define dprintf(fmt, args...) #endif -#define versatile_clcdc_sys_read_4(sc, reg) \ - bus_read_4((sc)->mem_res[MEM_SYS], (reg)) -#define versatile_clcdc_sys_write_4(sc, reg, val) \ - bus_write_4((sc)->mem_res[MEM_SYS], (reg), (val)) - #define versatile_clcdc_read_4(sc, reg) \ - bus_read_4((sc)->mem_res[MEM_CLCD], (reg)) + bus_read_4((sc)->mem_res, (reg)) #define versatile_clcdc_write_4(sc, reg, val) \ - bus_write_4((sc)->mem_res[MEM_CLCD], (reg), (val)) + bus_write_4((sc)->mem_res, (reg), (val)) struct versatile_clcdc_softc { - struct resource* mem_res[MEM_REGIONS]; + struct resource* mem_res; struct mtx mtx; @@ -205,12 +190,6 @@ static u_char mouse_pointer[16] = { static struct video_adapter_softc va_softc; -static struct resource_spec versatile_clcdc_mem_spec[] = { - { SYS_RES_MEMORY, 0, RF_ACTIVE }, - { SYS_RES_MEMORY, 1, RF_ACTIVE }, - { -1, 0, 0 } -}; - static int versatilefb_configure(int); static void versatilefb_update_margins(video_adapter_t *adp); @@ -246,21 +225,25 @@ versatile_clcdc_attach(device_t dev) { struct versatile_clcdc_softc *sc = device_get_softc(dev); struct video_adapter_softc *va_sc = &va_softc; - int err; + int err, rid; uint32_t reg; int clcdid; int dma_size; /* Request memory resources */ - err = bus_alloc_resources(dev, versatile_clcdc_mem_spec, - sc->mem_res); - if (err) { - device_printf(dev, "Error: could not allocate memory resources\n"); + rid = 0; + sc->mem_res = bus_alloc_resource_any(dev, SYS_RES_MEMORY, &rid, RF_ACTIVE); + if (sc->mem_res == NULL) { + device_printf(dev, "could not allocate memory resources\n"); return (ENXIO); } - reg = versatile_clcdc_sys_read_4(sc, SYS_CLCD); - clcdid = (reg >> SYS_CLCD_CLCDID_SHIFT) & SYS_CLCD_CLCDID_MASK; + err = versatile_scm_reg_read_4(SCM_CLCD, ®); + if (err) { + device_printf(dev, "failed to read SCM register\n"); + goto fail; + } + clcdid = (reg >> SCM_CLCD_CLCDID_SHIFT) & SCM_CLCD_CLCDID_MASK; switch (clcdid) { case 31: device_printf(dev, "QEMU VGA 640x480\n"); @@ -272,17 +255,17 @@ versatile_clcdc_attach(device_t dev) goto fail; } - reg &= ~SYS_CLCD_LCD_MODE_MASK; + reg &= ~SCM_CLCD_LCD_MODE_MASK; reg |= CLCD_MODE_RGB565; sc->mode = CLCD_MODE_RGB565; - versatile_clcdc_sys_write_4(sc, SYS_CLCD, reg); - dma_size = sc->width*sc->height*2; - - /* + versatile_scm_reg_write_4(SCM_CLCD, reg); + dma_size = sc->width*sc->height*2; + + /* * Power on LCD */ - reg |= SYS_CLCD_PWR3V5VSWITCH | SYS_CLCD_NLCDIOON; - versatile_clcdc_sys_write_4(sc, SYS_CLCD, reg); + reg |= SCM_CLCD_PWR3V5VSWITCH | SCM_CLCD_NLCDIOON; + versatile_scm_reg_write_4(SCM_CLCD, reg); /* * XXX: hardcoded timing for VGA. For other modes/panels @@ -655,7 +638,6 @@ versatilefb_init(int unit, video_adapter_t *adp, int flags) sc->xmargin = (sc->width - (vi->vi_width * vi->vi_cwidth)) / 2; sc->ymargin = (sc->height - (vi->vi_height * vi->vi_cheight))/2; - adp->va_window = (vm_offset_t) versatilefb_static_window; adp->va_flags |= V_ADP_FONT /* | V_ADP_COLOR | V_ADP_MODECHANGE */; diff --git a/sys/arm/versatile/versatile_pci.c b/sys/arm/versatile/versatile_pci.c index 96684c73198a..4f0460e60aeb 100644 --- a/sys/arm/versatile/versatile_pci.c +++ b/sys/arm/versatile/versatile_pci.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2012 Oleksandr Tymoshenko + * Copyright (c) 2012-2017 Oleksandr Tymoshenko * All rights reserved. * * Redistribution and use in source and binary forms, with or without @@ -52,17 +52,17 @@ __FBSDID("$FreeBSD$"); #include #include #include +#include + +#include #include #include -#define MEM_SYS 0 -#define MEM_CORE 1 -#define MEM_BASE 2 -#define MEM_CONF_BASE 3 -#define MEM_REGIONS 4 - -#define SYS_PCICTL 0x00 +#define MEM_CORE 0 +#define MEM_BASE 1 +#define MEM_CONF_BASE 2 +#define MEM_REGIONS 3 #define PCI_CORE_IMAP0 0x00 #define PCI_CORE_IMAP1 0x04 @@ -92,12 +92,6 @@ __FBSDID("$FreeBSD$"); #define dprintf(fmt, args...) #endif - -#define versatile_pci_sys_read_4(reg) \ - bus_read_4(sc->mem_res[MEM_SYS], (reg)) -#define versatile_pci_sys_write_4(reg, val) \ - bus_write_4(sc->mem_res[MEM_SYS], (reg), (val)) - #define versatile_pci_core_read_4(reg) \ bus_read_4(sc->mem_res[MEM_CORE], (reg)) #define versatile_pci_core_write_4(reg, val) \ @@ -131,13 +125,13 @@ struct versatile_pci_softc { struct rman mem_rman; struct mtx mtx; + struct ofw_bus_iinfo pci_iinfo; }; static struct resource_spec versatile_pci_mem_spec[] = { { SYS_RES_MEMORY, 0, RF_ACTIVE }, { SYS_RES_MEMORY, 1, RF_ACTIVE }, { SYS_RES_MEMORY, 2, RF_ACTIVE }, - { SYS_RES_MEMORY, 3, RF_ACTIVE }, { -1, 0, 0 } }; @@ -148,7 +142,7 @@ versatile_pci_probe(device_t dev) if (!ofw_bus_status_okay(dev)) return (ENXIO); - if (ofw_bus_is_compatible(dev, "versatile,pci")) { + if (ofw_bus_is_compatible(dev, "arm,versatile-pci")) { device_set_desc(dev, "Versatile PCI controller"); return (BUS_PROBE_DEFAULT); } @@ -164,6 +158,9 @@ versatile_pci_attach(device_t dev) int slot; uint32_t vendordev_id, class_id; uint32_t val; + phandle_t node; + + node = ofw_bus_get_node(dev); /* Request memory resources */ err = bus_alloc_resources(dev, versatile_pci_mem_spec, @@ -188,7 +185,7 @@ versatile_pci_attach(device_t dev) versatile_pci_core_write_4(PCI_CORE_SMAP1, (PCI_NPREFETCH_WINDOW >> 28)); versatile_pci_core_write_4(PCI_CORE_SMAP2, (PCI_NPREFETCH_WINDOW >> 28)); - versatile_pci_sys_write_4(SYS_PCICTL, 1); + versatile_scm_reg_write_4(SCM_PCICTL, 1); for (slot = 0; slot <= PCI_SLOTMAX; slot++) { vendordev_id = versatile_pci_read_4((slot << 11) + PCIR_DEVVENDOR); @@ -265,6 +262,8 @@ versatile_pci_attach(device_t dev) versatile_pci_conf_write_4((slot << 11) + PCIR_COMMAND, val); } + ofw_bus_setup_iinfo(node, &sc->pci_iinfo, sizeof(cell_t)); + device_add_child(dev, "pci", -1); return (bus_generic_attach(dev)); } @@ -318,7 +317,7 @@ versatile_pci_alloc_resource(device_t bus, device_t child, int type, int *rid, rm = &sc->io_rman; break; case SYS_RES_IRQ: - rm = &sc->irq_rman; + rm = NULL; break; case SYS_RES_MEMORY: rm = &sc->mem_rman; @@ -327,8 +326,11 @@ versatile_pci_alloc_resource(device_t bus, device_t child, int type, int *rid, return (NULL); } - rv = rman_reserve_resource(rm, start, end, count, flags, child); + if (rm == NULL) + return (BUS_ALLOC_RESOURCE(device_get_parent(bus), + child, type, rid, start, end, count, flags)); + rv = rman_reserve_resource(rm, start, end, count, flags, child); if (rv == NULL) return (NULL); @@ -389,8 +391,6 @@ versatile_pci_teardown_intr(device_t dev, device_t child, struct resource *ires, return BUS_TEARDOWN_INTR(device_get_parent(dev), dev, ires, cookie); } - - static int versatile_pci_maxslots(device_t dev) { @@ -399,10 +399,33 @@ versatile_pci_maxslots(device_t dev) } static int -versatile_pci_route_interrupt(device_t pcib, device_t device, int pin) +versatile_pci_route_interrupt(device_t bus, device_t dev, int pin) { + struct versatile_pci_softc *sc; + struct ofw_pci_register reg; + uint32_t pintr, mintr[4]; + phandle_t iparent; + int intrcells; - return (27 + ((pci_get_slot(device) + pin - 1) & 3)); + sc = device_get_softc(bus); + pintr = pin; + + bzero(®, sizeof(reg)); + reg.phys_hi = (pci_get_bus(dev) << OFW_PCI_PHYS_HI_BUSSHIFT) | + (pci_get_slot(dev) << OFW_PCI_PHYS_HI_DEVICESHIFT) | + (pci_get_function(dev) << OFW_PCI_PHYS_HI_FUNCTIONSHIFT); + + intrcells = ofw_bus_lookup_imap(ofw_bus_get_node(dev), + &sc->pci_iinfo, ®, sizeof(reg), &pintr, sizeof(pintr), + mintr, sizeof(mintr), &iparent); + if (intrcells) { + pintr = ofw_bus_map_intr(dev, iparent, intrcells, mintr); + return (pintr); + } + + device_printf(bus, "could not route pin %d for device %d.%d\n", + pin, pci_get_slot(dev), pci_get_function(dev)); + return (PCI_INVALID_IRQ); } static uint32_t diff --git a/sys/arm/versatile/versatile_scm.c b/sys/arm/versatile/versatile_scm.c new file mode 100644 index 000000000000..835d2381075d --- /dev/null +++ b/sys/arm/versatile/versatile_scm.c @@ -0,0 +1,144 @@ +/* + * Copyright (c) 2017 Oleksandr Tymoshenko + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by Ben Gray. + * 4. The name of the company nor the name of the author may be used to + * endorse or promote products derived from this software without specific + * prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY BEN GRAY ``AS IS'' AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. + * IN NO EVENT SHALL BEN GRAY BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; + * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, + * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR + * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF + * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +/* + * SCM - System Control Module + */ +#include +__FBSDID("$FreeBSD$"); + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include + +#include +#include +#include + +#include "versatile_scm.h" + +struct versatile_scm_softc { + device_t sc_dev; + struct resource * sc_mem_res; +}; + +static struct versatile_scm_softc *versatile_scm_sc; + +#define versatile_scm_read_4(sc, reg) \ + bus_read_4((sc)->sc_mem_res, (reg)) +#define versatile_scm_write_4(sc, reg, val) \ + bus_write_4((sc)->sc_mem_res, (reg), (val)) + +static int +versatile_scm_probe(device_t dev) +{ + if (!ofw_bus_status_okay(dev)) + return (ENXIO); + + if (!ofw_bus_is_compatible(dev, "syscon")) + return (ENXIO); + + if (versatile_scm_sc) { + return (EEXIST); + } + + device_set_desc(dev, "Versatile Control Module"); + return (BUS_PROBE_DEFAULT); +} + +static int +versatile_scm_attach(device_t dev) +{ + struct versatile_scm_softc *sc; + int rid; + + sc = device_get_softc(dev); + sc->sc_dev = dev; + + rid = 0; + sc->sc_mem_res = bus_alloc_resource_any(dev, SYS_RES_MEMORY, &rid, RF_ACTIVE); + + if (sc->sc_mem_res == NULL) { + device_printf(dev, "could not allocate memory resources\n"); + return (ENXIO); + } + + versatile_scm_sc = sc; + + return (0); +} + +int +versatile_scm_reg_read_4(uint32_t reg, uint32_t *val) +{ + if (!versatile_scm_sc) + return (ENXIO); + + *val = versatile_scm_read_4(versatile_scm_sc, reg); + return (0); +} + +int +versatile_scm_reg_write_4(uint32_t reg, uint32_t val) +{ + if (!versatile_scm_sc) + return (ENXIO); + + versatile_scm_write_4(versatile_scm_sc, reg, val); + return (0); +} + +static device_method_t versatile_scm_methods[] = { + DEVMETHOD(device_probe, versatile_scm_probe), + DEVMETHOD(device_attach, versatile_scm_attach), + + DEVMETHOD_END +}; + +static driver_t versatile_scm_driver = { + "scm", + versatile_scm_methods, + sizeof(struct versatile_scm_softc), +}; + +static devclass_t versatile_scm_devclass; + +EARLY_DRIVER_MODULE(versatile_scm, simplebus, versatile_scm_driver, versatile_scm_devclass, 0, 0, + BUS_PASS_BUS + BUS_PASS_ORDER_MIDDLE); diff --git a/sys/arm/versatile/versatile_scm.h b/sys/arm/versatile/versatile_scm.h new file mode 100644 index 000000000000..a59ad0664528 --- /dev/null +++ b/sys/arm/versatile/versatile_scm.h @@ -0,0 +1,49 @@ +/* + * Copyright (c) 2017 Oleksandr Tymoshenko + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by Ben Gray. + * 4. The name of the company nor the name of the author may be used to + * endorse or promote products derived from this software without specific + * prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY BEN GRAY ``AS IS'' AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. + * IN NO EVENT SHALL BEN GRAY BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; + * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, + * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR + * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF + * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * $FreeBSD$ + */ + +#ifndef _VERSATILE_SCM_H_ +#define _VERSATILE_SCM_H_ + +#define SCM_PCICTL 0x44 +#define SCM_CLCD 0x50 +#define SCM_CLCD_CLCDID_SHIFT 0x08 +#define SCM_CLCD_CLCDID_MASK 0x1f +#define SCM_CLCD_PWR3V5VSWITCH (1 << 4) +#define SCM_CLCD_VDDPOSSWITCH (1 << 3) +#define SCM_CLCD_NLCDIOON (1 << 2) +#define SCM_CLCD_LCD_MODE_MASK 0x03 + +int versatile_scm_reg_read_4(uint32_t reg, uint32_t *val); +int versatile_scm_reg_write_4(uint32_t reg, uint32_t val); + +#endif /* _VERSATILE_SCM_H_ */ diff --git a/sys/arm/versatile/versatile_sic.c b/sys/arm/versatile/versatile_sic.c index d695bbfa7548..0df1e3e5bf49 100644 --- a/sys/arm/versatile/versatile_sic.c +++ b/sys/arm/versatile/versatile_sic.c @@ -1,5 +1,5 @@ /*- - * Copyright (c) 2012 Oleksandr Tymoshenko + * Copyright (c) 2012-2017 Oleksandr Tymoshenko * All rights reserved. * * Redistribution and use in source and binary forms, with or without @@ -24,7 +24,6 @@ * SUCH DAMAGE. */ - #include __FBSDID("$FreeBSD$"); @@ -34,6 +33,7 @@ __FBSDID("$FreeBSD$"); #include #include #include +#include #include #include #include @@ -42,6 +42,8 @@ __FBSDID("$FreeBSD$"); #include #include +#include "pic_if.h" + #ifdef DEBUG #define dprintf(fmt, args...) printf(fmt, ##args) #else @@ -59,16 +61,142 @@ __FBSDID("$FreeBSD$"); #define SIC_PICENSET 0x20 #define SIC_PICENCLR 0x24 -struct versatile_sic_softc { - device_t sc_dev; - struct resource * mem_res; +#define SIC_NIRQS 32 + +struct versatile_sic_irqsrc { + struct intr_irqsrc isrc; + u_int irq; }; -#define sic_read_4(sc, reg) \ +struct versatile_sic_softc { + device_t dev; + struct mtx mtx; + struct resource * mem_res; + struct resource * irq_res; + void *intrh; + struct versatile_sic_irqsrc isrcs[SIC_NIRQS]; +}; + +#define SIC_LOCK(_sc) mtx_lock_spin(&(_sc)->mtx) +#define SIC_UNLOCK(_sc) mtx_unlock_spin(&(_sc)->mtx) + +#define SIC_READ_4(sc, reg) \ bus_read_4(sc->mem_res, (reg)) -#define sic_write_4(sc, reg, val) \ +#define SIC_WRITE_4(sc, reg, val) \ bus_write_4(sc->mem_res, (reg), (val)) +/* + * Driver stuff + */ +static int versatile_sic_probe(device_t); +static int versatile_sic_attach(device_t); +static int versatile_sic_detach(device_t); + +static void +versatile_sic_disable_intr(device_t dev, struct intr_irqsrc *isrc) +{ + struct versatile_sic_softc *sc; + struct versatile_sic_irqsrc *src; + + sc = device_get_softc(dev); + src = (struct versatile_sic_irqsrc *)isrc; + + SIC_LOCK(sc); + SIC_WRITE_4(sc, SIC_ENCLR, (1 << src->irq)); + SIC_UNLOCK(sc); +} + +static void +versatile_sic_enable_intr(device_t dev, struct intr_irqsrc *isrc) +{ + struct versatile_sic_softc *sc; + struct versatile_sic_irqsrc *src; + + sc = device_get_softc(dev); + src = (struct versatile_sic_irqsrc *)isrc; + + SIC_LOCK(sc); + SIC_WRITE_4(sc, SIC_ENSET, (1 << src->irq)); + SIC_UNLOCK(sc); +} + +static int +versatile_sic_map_intr(device_t dev, struct intr_map_data *data, + struct intr_irqsrc **isrcp) +{ + struct intr_map_data_fdt *daf; + struct versatile_sic_softc *sc; + + if (data->type != INTR_MAP_DATA_FDT) + return (ENOTSUP); + + daf = (struct intr_map_data_fdt *)data; + if (daf->ncells != 1 || daf->cells[0] >= SIC_NIRQS) + return (EINVAL); + + sc = device_get_softc(dev); + *isrcp = &sc->isrcs[daf->cells[0]].isrc; + return (0); +} + +static void +versatile_sic_pre_ithread(device_t dev, struct intr_irqsrc *isrc) +{ + versatile_sic_disable_intr(dev, isrc); +} + +static void +versatile_sic_post_ithread(device_t dev, struct intr_irqsrc *isrc) +{ + struct versatile_sic_irqsrc *src; + + src = (struct versatile_sic_irqsrc *)isrc; + arm_irq_memory_barrier(src->irq); + versatile_sic_enable_intr(dev, isrc); +} + +static void +versatile_sic_post_filter(device_t dev, struct intr_irqsrc *isrc) +{ + struct versatile_sic_irqsrc *src; + + src = (struct versatile_sic_irqsrc *)isrc; + arm_irq_memory_barrier(src->irq); +} + +static int +versatile_sic_setup_intr(device_t dev, struct intr_irqsrc *isrc, + struct resource *res, struct intr_map_data *data) +{ + + return (0); +} + +static int +versatile_sic_filter(void *arg) +{ + struct versatile_sic_softc *sc; + struct intr_irqsrc *isrc; + uint32_t i, interrupts; + + sc = arg; + SIC_LOCK(sc); + interrupts = SIC_READ_4(sc, SIC_STATUS); + SIC_UNLOCK(sc); + for (i = 0; interrupts != 0; i++, interrupts >>= 1) { + if ((interrupts & 0x1) == 0) + continue; + isrc = &sc->isrcs[i].isrc; + if (intr_isrc_dispatch(isrc, curthread->td_intr_frame) != 0) { + versatile_sic_disable_intr(sc->dev, isrc); + versatile_sic_post_filter(sc->dev, isrc); + device_printf(sc->dev, "Stray irq %u disabled\n", i); + } + } + + return (FILTER_HANDLED); +} + static int versatile_sic_probe(device_t dev) { @@ -86,10 +214,14 @@ static int versatile_sic_attach(device_t dev) { struct versatile_sic_softc *sc = device_get_softc(dev); - uint32_t pass_irqs; - int rid; + int rid, error; + uint32_t irq; + const char *name; + struct versatile_sic_irqsrc *isrcs; - sc->sc_dev = dev; + sc->dev = dev; + mtx_init(&sc->mtx, device_get_nameunit(dev), "sic", + MTX_SPIN); /* Request memory resources */ rid = 0; @@ -100,29 +232,81 @@ versatile_sic_attach(device_t dev) return (ENXIO); } + /* Request memory resources */ + rid = 0; + sc->irq_res = bus_alloc_resource_any(dev, SYS_RES_IRQ, &rid, + RF_ACTIVE); + if (sc->irq_res == NULL) { + device_printf(dev, "could not allocate IRQ resources\n"); + versatile_sic_detach(dev); + return (ENXIO); + } + + if ((bus_setup_intr(dev, sc->irq_res, INTR_TYPE_MISC, + versatile_sic_filter, NULL, sc, &sc->intrh))) { + device_printf(dev, + "unable to register interrupt handler\n"); + versatile_sic_detach(dev); + return (ENXIO); + } + /* Disable all interrupts on SIC */ - sic_write_4(sc, SIC_ENCLR, 0xffffffff); + SIC_WRITE_4(sc, SIC_ENCLR, 0xffffffff); - /* - * XXX: Enable IRQ3 for KMI - * Should be replaced by proper interrupts cascading - */ - sic_write_4(sc, SIC_ENSET, (1 << 3)); + /* PIC attachment */ + isrcs = sc->isrcs; + name = device_get_nameunit(sc->dev); + for (irq = 0; irq < SIC_NIRQS; irq++) { + isrcs[irq].irq = irq; + error = intr_isrc_register(&isrcs[irq].isrc, sc->dev, + 0, "%s,%u", name, irq); + if (error != 0) + return (error); + } - /* - * Let PCI and Ethernet interrupts pass through - * IRQ25, IRQ27..IRQ31 - */ - pass_irqs = (0x1f << 27) | (1 << 25); - sic_write_4(sc, SIC_PICENSET, pass_irqs); + intr_pic_register(dev, OF_xref_from_node(ofw_bus_get_node(dev))); return (0); } +static int +versatile_sic_detach(device_t dev) +{ + struct versatile_sic_softc *sc; + + sc = device_get_softc(dev); + + if (sc->intrh) + bus_teardown_intr(dev, sc->irq_res, sc->intrh); + + if (sc->mem_res == NULL) + bus_release_resource(dev, SYS_RES_MEMORY, + rman_get_rid(sc->mem_res), sc->mem_res); + + if (sc->irq_res == NULL) + bus_release_resource(dev, SYS_RES_IRQ, + rman_get_rid(sc->irq_res), sc->irq_res); + + mtx_destroy(&sc->mtx); + + return (0); + +} + static device_method_t versatile_sic_methods[] = { DEVMETHOD(device_probe, versatile_sic_probe), DEVMETHOD(device_attach, versatile_sic_attach), - { 0, 0 } + DEVMETHOD(device_detach, versatile_sic_detach), + + DEVMETHOD(pic_disable_intr, versatile_sic_disable_intr), + DEVMETHOD(pic_enable_intr, versatile_sic_enable_intr), + DEVMETHOD(pic_map_intr, versatile_sic_map_intr), + DEVMETHOD(pic_post_filter, versatile_sic_post_filter), + DEVMETHOD(pic_post_ithread, versatile_sic_post_ithread), + DEVMETHOD(pic_pre_ithread, versatile_sic_pre_ithread), + DEVMETHOD(pic_setup_intr, versatile_sic_setup_intr), + + DEVMETHOD_END }; static driver_t versatile_sic_driver = {