Index: stable/12/sys/arm/broadcom/bcm2835/bcm2835_dma.c =================================================================== --- stable/12/sys/arm/broadcom/bcm2835/bcm2835_dma.c (revision 355664) +++ stable/12/sys/arm/broadcom/bcm2835/bcm2835_dma.c (revision 355665) @@ -1,771 +1,770 @@ /*- * SPDX-License-Identifier: BSD-2-Clause-FreeBSD * * Copyright (c) 2013 Daisuke Aoyama * Copyright (c) 2013 Oleksandr Tymoshenko * * 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. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``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 THE AUTHOR OR CONTRIBUTORS 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. * */ #include __FBSDID("$FreeBSD$"); #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include "bcm2835_dma.h" #include "bcm2835_vcbus.h" #define MAX_REG 9 /* private flags */ #define BCM_DMA_CH_USED 0x00000001 #define BCM_DMA_CH_FREE 0x40000000 #define BCM_DMA_CH_UNMAP 0x80000000 /* Register Map (4.2.1.2) */ #define BCM_DMA_CS(n) (0x100*(n) + 0x00) #define CS_ACTIVE (1 << 0) #define CS_END (1 << 1) #define CS_INT (1 << 2) #define CS_DREQ (1 << 3) #define CS_ISPAUSED (1 << 4) #define CS_ISHELD (1 << 5) #define CS_ISWAIT (1 << 6) #define CS_ERR (1 << 8) #define CS_WAITWRT (1 << 28) #define CS_DISDBG (1 << 29) #define CS_ABORT (1 << 30) #define CS_RESET (1U << 31) #define BCM_DMA_CBADDR(n) (0x100*(n) + 0x04) #define BCM_DMA_INFO(n) (0x100*(n) + 0x08) #define INFO_INT_EN (1 << 0) #define INFO_TDMODE (1 << 1) #define INFO_WAIT_RESP (1 << 3) #define INFO_D_INC (1 << 4) #define INFO_D_WIDTH (1 << 5) #define INFO_D_DREQ (1 << 6) #define INFO_S_INC (1 << 8) #define INFO_S_WIDTH (1 << 9) #define INFO_S_DREQ (1 << 10) #define INFO_WAITS_SHIFT (21) #define INFO_PERMAP_SHIFT (16) #define INFO_PERMAP_MASK (0x1f << INFO_PERMAP_SHIFT) #define BCM_DMA_SRC(n) (0x100*(n) + 0x0C) #define BCM_DMA_DST(n) (0x100*(n) + 0x10) #define BCM_DMA_LEN(n) (0x100*(n) + 0x14) #define BCM_DMA_STRIDE(n) (0x100*(n) + 0x18) #define BCM_DMA_CBNEXT(n) (0x100*(n) + 0x1C) #define BCM_DMA_DEBUG(n) (0x100*(n) + 0x20) #define DEBUG_ERROR_MASK (7) #define BCM_DMA_INT_STATUS 0xfe0 #define BCM_DMA_ENABLE 0xff0 /* relative offset from BCM_VC_DMA0_BASE (p.39) */ #define BCM_DMA_CH(n) (0x100*(n)) /* channels used by GPU */ #define BCM_DMA_CH_BULK 0 #define BCM_DMA_CH_FAST1 2 #define BCM_DMA_CH_FAST2 3 #define BCM_DMA_CH_GPU_MASK ((1 << BCM_DMA_CH_BULK) | \ (1 << BCM_DMA_CH_FAST1) | \ (1 << BCM_DMA_CH_FAST2)) /* DMA Control Block - 256bit aligned (p.40) */ struct bcm_dma_cb { uint32_t info; /* Transfer Information */ uint32_t src; /* Source Address */ uint32_t dst; /* Destination Address */ uint32_t len; /* Transfer Length */ uint32_t stride; /* 2D Mode Stride */ uint32_t next; /* Next Control Block Address */ uint32_t rsvd1; /* Reserved */ uint32_t rsvd2; /* Reserved */ }; #ifdef DEBUG static void bcm_dma_cb_dump(struct bcm_dma_cb *cb); static void bcm_dma_reg_dump(int ch); #endif /* DMA channel private info */ struct bcm_dma_ch { int ch; uint32_t flags; struct bcm_dma_cb * cb; uint32_t vc_cb; bus_dmamap_t dma_map; void (*intr_func)(int, void *); void * intr_arg; }; struct bcm_dma_softc { device_t sc_dev; struct mtx sc_mtx; struct resource * sc_mem; struct resource * sc_irq[BCM_DMA_CH_MAX]; void * sc_intrhand[BCM_DMA_CH_MAX]; struct bcm_dma_ch sc_dma_ch[BCM_DMA_CH_MAX]; bus_dma_tag_t sc_dma_tag; }; static struct bcm_dma_softc *bcm_dma_sc = NULL; static uint32_t bcm_dma_channel_mask; static struct ofw_compat_data compat_data[] = { {"broadcom,bcm2835-dma", 1}, {"brcm,bcm2835-dma", 1}, {NULL, 0} }; static void bcm_dmamap_cb(void *arg, bus_dma_segment_t *segs, int nseg, int err) { bus_addr_t *addr; if (err) return; addr = (bus_addr_t*)arg; - *addr = PHYS_TO_VCBUS(segs[0].ds_addr); + *addr = ARMC_TO_VCBUS(segs[0].ds_addr); } static void bcm_dma_reset(device_t dev, int ch) { struct bcm_dma_softc *sc = device_get_softc(dev); struct bcm_dma_cb *cb; uint32_t cs; int count; if (ch < 0 || ch >= BCM_DMA_CH_MAX) return; cs = bus_read_4(sc->sc_mem, BCM_DMA_CS(ch)); if (cs & CS_ACTIVE) { /* pause current task */ bus_write_4(sc->sc_mem, BCM_DMA_CS(ch), 0); count = 1000; do { cs = bus_read_4(sc->sc_mem, BCM_DMA_CS(ch)); } while (!(cs & CS_ISPAUSED) && (count-- > 0)); if (!(cs & CS_ISPAUSED)) { device_printf(dev, "Can't abort DMA transfer at channel %d\n", ch); } bus_write_4(sc->sc_mem, BCM_DMA_CBNEXT(ch), 0); /* Complete everything, clear interrupt */ bus_write_4(sc->sc_mem, BCM_DMA_CS(ch), CS_ABORT | CS_INT | CS_END| CS_ACTIVE); } /* clear control blocks */ bus_write_4(sc->sc_mem, BCM_DMA_CBADDR(ch), 0); bus_write_4(sc->sc_mem, BCM_DMA_CBNEXT(ch), 0); /* Reset control block */ cb = sc->sc_dma_ch[ch].cb; bzero(cb, sizeof(*cb)); cb->info = INFO_WAIT_RESP; } static int bcm_dma_init(device_t dev) { struct bcm_dma_softc *sc = device_get_softc(dev); uint32_t reg; struct bcm_dma_ch *ch; void *cb_virt; vm_paddr_t cb_phys; int err; int i; /* * Only channels set in bcm_dma_channel_mask can be controlled by us. * The others are out of our control as well as the corresponding bits * in both BCM_DMA_ENABLE and BCM_DMA_INT_STATUS global registers. As * these registers are RW ones, there is no safe way how to write only * the bits which can be controlled by us. * * Fortunately, after reset, all channels are enabled in BCM_DMA_ENABLE * register and all statuses are cleared in BCM_DMA_INT_STATUS one. * Not touching these registers is a trade off between correct * initialization which does not count on anything and not messing up * something we have no control over. */ reg = bus_read_4(sc->sc_mem, BCM_DMA_ENABLE); if ((reg & bcm_dma_channel_mask) != bcm_dma_channel_mask) device_printf(dev, "channels are not enabled\n"); reg = bus_read_4(sc->sc_mem, BCM_DMA_INT_STATUS); if ((reg & bcm_dma_channel_mask) != 0) device_printf(dev, "statuses are not cleared\n"); - /* Allocate DMA chunks control blocks */ - /* p.40 of spec - control block should be 32-bit aligned */ + /* + * Allocate DMA chunks control blocks based on p.40 of the peripheral + * spec - control block should be 32-bit aligned. The DMA controller + * has a full 32-bit register dedicated to this address, so we do not + * need to bother with the per-SoC peripheral restrictions. + */ err = bus_dma_tag_create(bus_get_dma_tag(dev), 1, 0, BUS_SPACE_MAXADDR_32BIT, BUS_SPACE_MAXADDR, NULL, NULL, sizeof(struct bcm_dma_cb), 1, sizeof(struct bcm_dma_cb), BUS_DMA_ALLOCNOW, NULL, NULL, &sc->sc_dma_tag); if (err) { device_printf(dev, "failed allocate DMA tag\n"); return (err); } /* setup initial settings */ for (i = 0; i < BCM_DMA_CH_MAX; i++) { ch = &sc->sc_dma_ch[i]; bzero(ch, sizeof(struct bcm_dma_ch)); ch->ch = i; ch->flags = BCM_DMA_CH_UNMAP; if ((bcm_dma_channel_mask & (1 << i)) == 0) continue; err = bus_dmamem_alloc(sc->sc_dma_tag, &cb_virt, BUS_DMA_WAITOK | BUS_DMA_COHERENT | BUS_DMA_ZERO, &ch->dma_map); if (err) { device_printf(dev, "cannot allocate DMA memory\n"); break; } /* * Least alignment for busdma-allocated stuff is cache * line size, so just make sure nothing stupid happened * and we got properly aligned address */ if ((uintptr_t)cb_virt & 0x1f) { device_printf(dev, "DMA address is not 32-bytes aligned: %p\n", (void*)cb_virt); break; } err = bus_dmamap_load(sc->sc_dma_tag, ch->dma_map, cb_virt, sizeof(struct bcm_dma_cb), bcm_dmamap_cb, &cb_phys, BUS_DMA_WAITOK); if (err) { device_printf(dev, "cannot load DMA memory\n"); break; } ch->cb = cb_virt; ch->vc_cb = cb_phys; ch->flags = BCM_DMA_CH_FREE; ch->cb->info = INFO_WAIT_RESP; /* reset DMA engine */ bus_write_4(sc->sc_mem, BCM_DMA_CS(i), CS_RESET); } return (0); } /* * Allocate DMA channel for further use, returns channel # or * BCM_DMA_CH_INVALID */ int bcm_dma_allocate(int req_ch) { struct bcm_dma_softc *sc = bcm_dma_sc; int ch = BCM_DMA_CH_INVALID; int i; if (req_ch >= BCM_DMA_CH_MAX) return (BCM_DMA_CH_INVALID); /* Auto(req_ch < 0) or CH specified */ mtx_lock(&sc->sc_mtx); if (req_ch < 0) { for (i = 0; i < BCM_DMA_CH_MAX; i++) { if (sc->sc_dma_ch[i].flags & BCM_DMA_CH_FREE) { ch = i; sc->sc_dma_ch[ch].flags &= ~BCM_DMA_CH_FREE; sc->sc_dma_ch[ch].flags |= BCM_DMA_CH_USED; break; } } } else { if (sc->sc_dma_ch[req_ch].flags & BCM_DMA_CH_FREE) { ch = req_ch; sc->sc_dma_ch[ch].flags &= ~BCM_DMA_CH_FREE; sc->sc_dma_ch[ch].flags |= BCM_DMA_CH_USED; } } mtx_unlock(&sc->sc_mtx); return (ch); } /* * Frees allocated channel. Returns 0 on success, -1 otherwise */ int bcm_dma_free(int ch) { struct bcm_dma_softc *sc = bcm_dma_sc; if (ch < 0 || ch >= BCM_DMA_CH_MAX) return (-1); mtx_lock(&sc->sc_mtx); if (sc->sc_dma_ch[ch].flags & BCM_DMA_CH_USED) { sc->sc_dma_ch[ch].flags |= BCM_DMA_CH_FREE; sc->sc_dma_ch[ch].flags &= ~BCM_DMA_CH_USED; sc->sc_dma_ch[ch].intr_func = NULL; sc->sc_dma_ch[ch].intr_arg = NULL; /* reset DMA engine */ bcm_dma_reset(sc->sc_dev, ch); } mtx_unlock(&sc->sc_mtx); return (0); } /* * Assign handler function for channel interrupt * Returns 0 on success, -1 otherwise */ int bcm_dma_setup_intr(int ch, void (*func)(int, void *), void *arg) { struct bcm_dma_softc *sc = bcm_dma_sc; struct bcm_dma_cb *cb; if (ch < 0 || ch >= BCM_DMA_CH_MAX) return (-1); if (!(sc->sc_dma_ch[ch].flags & BCM_DMA_CH_USED)) return (-1); sc->sc_dma_ch[ch].intr_func = func; sc->sc_dma_ch[ch].intr_arg = arg; cb = sc->sc_dma_ch[ch].cb; cb->info |= INFO_INT_EN; return (0); } /* * Setup DMA source parameters * ch - channel number * dreq - hardware DREQ # or BCM_DMA_DREQ_NONE if * source is physical memory * inc_addr - BCM_DMA_INC_ADDR if source address * should be increased after each access or * BCM_DMA_SAME_ADDR if address should remain * the same * width - size of read operation, BCM_DMA_32BIT * for 32bit bursts, BCM_DMA_128BIT for 128 bits * * Returns 0 on success, -1 otherwise */ int bcm_dma_setup_src(int ch, int dreq, int inc_addr, int width) { struct bcm_dma_softc *sc = bcm_dma_sc; uint32_t info; if (ch < 0 || ch >= BCM_DMA_CH_MAX) return (-1); if (!(sc->sc_dma_ch[ch].flags & BCM_DMA_CH_USED)) return (-1); info = sc->sc_dma_ch[ch].cb->info; info &= ~INFO_PERMAP_MASK; info |= (dreq << INFO_PERMAP_SHIFT) & INFO_PERMAP_MASK; if (dreq) info |= INFO_S_DREQ; else info &= ~INFO_S_DREQ; if (width == BCM_DMA_128BIT) info |= INFO_S_WIDTH; else info &= ~INFO_S_WIDTH; if (inc_addr == BCM_DMA_INC_ADDR) info |= INFO_S_INC; else info &= ~INFO_S_INC; sc->sc_dma_ch[ch].cb->info = info; return (0); } /* * Setup DMA destination parameters * ch - channel number * dreq - hardware DREQ # or BCM_DMA_DREQ_NONE if * destination is physical memory * inc_addr - BCM_DMA_INC_ADDR if source address * should be increased after each access or * BCM_DMA_SAME_ADDR if address should remain * the same * width - size of write operation, BCM_DMA_32BIT * for 32bit bursts, BCM_DMA_128BIT for 128 bits * * Returns 0 on success, -1 otherwise */ int bcm_dma_setup_dst(int ch, int dreq, int inc_addr, int width) { struct bcm_dma_softc *sc = bcm_dma_sc; uint32_t info; if (ch < 0 || ch >= BCM_DMA_CH_MAX) return (-1); if (!(sc->sc_dma_ch[ch].flags & BCM_DMA_CH_USED)) return (-1); info = sc->sc_dma_ch[ch].cb->info; info &= ~INFO_PERMAP_MASK; info |= (dreq << INFO_PERMAP_SHIFT) & INFO_PERMAP_MASK; if (dreq) info |= INFO_D_DREQ; else info &= ~INFO_D_DREQ; if (width == BCM_DMA_128BIT) info |= INFO_D_WIDTH; else info &= ~INFO_D_WIDTH; if (inc_addr == BCM_DMA_INC_ADDR) info |= INFO_D_INC; else info &= ~INFO_D_INC; sc->sc_dma_ch[ch].cb->info = info; return (0); } #ifdef DEBUG void bcm_dma_cb_dump(struct bcm_dma_cb *cb) { printf("DMA CB "); printf("INFO: %8.8x ", cb->info); printf("SRC: %8.8x ", cb->src); printf("DST: %8.8x ", cb->dst); printf("LEN: %8.8x ", cb->len); printf("\n"); printf("STRIDE: %8.8x ", cb->stride); printf("NEXT: %8.8x ", cb->next); printf("RSVD1: %8.8x ", cb->rsvd1); printf("RSVD2: %8.8x ", cb->rsvd2); printf("\n"); } void bcm_dma_reg_dump(int ch) { struct bcm_dma_softc *sc = bcm_dma_sc; int i; uint32_t reg; if (ch < 0 || ch >= BCM_DMA_CH_MAX) return; printf("DMA%d: ", ch); for (i = 0; i < MAX_REG; i++) { reg = bus_read_4(sc->sc_mem, BCM_DMA_CH(ch) + i*4); printf("%8.8x ", reg); } printf("\n"); } #endif /* * Start DMA transaction * ch - channel number * src, dst - source and destination address in * ARM physical memory address space. * len - amount of bytes to be transferred * * Returns 0 on success, -1 otherwise */ int bcm_dma_start(int ch, vm_paddr_t src, vm_paddr_t dst, int len) { struct bcm_dma_softc *sc = bcm_dma_sc; struct bcm_dma_cb *cb; if (ch < 0 || ch >= BCM_DMA_CH_MAX) return (-1); if (!(sc->sc_dma_ch[ch].flags & BCM_DMA_CH_USED)) return (-1); cb = sc->sc_dma_ch[ch].cb; - if (BCM2835_ARM_IS_IO(src)) - cb->src = IO_TO_VCBUS(src); - else - cb->src = PHYS_TO_VCBUS(src); - if (BCM2835_ARM_IS_IO(dst)) - cb->dst = IO_TO_VCBUS(dst); - else - cb->dst = PHYS_TO_VCBUS(dst); + cb->src = ARMC_TO_VCBUS(src); + cb->dst = ARMC_TO_VCBUS(dst); + cb->len = len; bus_dmamap_sync(sc->sc_dma_tag, sc->sc_dma_ch[ch].dma_map, BUS_DMASYNC_PREWRITE); bus_write_4(sc->sc_mem, BCM_DMA_CBADDR(ch), sc->sc_dma_ch[ch].vc_cb); bus_write_4(sc->sc_mem, BCM_DMA_CS(ch), CS_ACTIVE); #ifdef DEBUG bcm_dma_cb_dump(sc->sc_dma_ch[ch].cb); bcm_dma_reg_dump(ch); #endif return (0); } /* * Get length requested for DMA transaction * ch - channel number * * Returns size of transaction, 0 if channel is invalid */ uint32_t bcm_dma_length(int ch) { struct bcm_dma_softc *sc = bcm_dma_sc; struct bcm_dma_cb *cb; if (ch < 0 || ch >= BCM_DMA_CH_MAX) return (0); if (!(sc->sc_dma_ch[ch].flags & BCM_DMA_CH_USED)) return (0); cb = sc->sc_dma_ch[ch].cb; return (cb->len); } static void bcm_dma_intr(void *arg) { struct bcm_dma_softc *sc = bcm_dma_sc; struct bcm_dma_ch *ch = (struct bcm_dma_ch *)arg; uint32_t cs, debug; /* my interrupt? */ cs = bus_read_4(sc->sc_mem, BCM_DMA_CS(ch->ch)); - if (!(cs & (CS_INT | CS_ERR))) { - device_printf(sc->sc_dev, - "unexpected DMA intr CH=%d, CS=%x\n", ch->ch, cs); + /* + * Is it an active channel? Our diagnostics could be better here, but + * it's not necessarily an easy task to resolve a rid/resource to an + * actual irq number. We'd want to do this to set a flag indicating + * whether the irq is shared or not, so we know to complain. + */ + if (!(ch->flags & BCM_DMA_CH_USED)) return; - } - /* running? */ - if (!(ch->flags & BCM_DMA_CH_USED)) { - device_printf(sc->sc_dev, - "unused DMA intr CH=%d, CS=%x\n", ch->ch, cs); + /* Again, we can't complain here. The same logic applies. */ + if (!(cs & (CS_INT | CS_ERR))) return; - } if (cs & CS_ERR) { debug = bus_read_4(sc->sc_mem, BCM_DMA_DEBUG(ch->ch)); device_printf(sc->sc_dev, "DMA error %d on CH%d\n", debug & DEBUG_ERROR_MASK, ch->ch); bus_write_4(sc->sc_mem, BCM_DMA_DEBUG(ch->ch), debug & DEBUG_ERROR_MASK); bcm_dma_reset(sc->sc_dev, ch->ch); } if (cs & CS_INT) { /* acknowledge interrupt */ bus_write_4(sc->sc_mem, BCM_DMA_CS(ch->ch), CS_INT | CS_END); /* Prepare for possible access to len field */ bus_dmamap_sync(sc->sc_dma_tag, ch->dma_map, BUS_DMASYNC_POSTWRITE); /* save callback function and argument */ if (ch->intr_func) ch->intr_func(ch->ch, ch->intr_arg); } } static int bcm_dma_probe(device_t dev) { if (!ofw_bus_status_okay(dev)) return (ENXIO); if (ofw_bus_search_compatible(dev, compat_data)->ocd_data == 0) return (ENXIO); device_set_desc(dev, "BCM2835 DMA Controller"); return (BUS_PROBE_DEFAULT); } static int bcm_dma_attach(device_t dev) { struct bcm_dma_softc *sc = device_get_softc(dev); phandle_t node; int rid, err = 0; int i; sc->sc_dev = dev; if (bcm_dma_sc) return (ENXIO); for (i = 0; i < BCM_DMA_CH_MAX; i++) { sc->sc_irq[i] = NULL; sc->sc_intrhand[i] = NULL; } /* Get DMA channel mask. */ node = ofw_bus_get_node(sc->sc_dev); if (OF_getencprop(node, "brcm,dma-channel-mask", &bcm_dma_channel_mask, sizeof(bcm_dma_channel_mask)) == -1 && OF_getencprop(node, "broadcom,channels", &bcm_dma_channel_mask, sizeof(bcm_dma_channel_mask)) == -1) { device_printf(dev, "could not get channel mask property\n"); return (ENXIO); } /* Mask out channels used by GPU. */ bcm_dma_channel_mask &= ~BCM_DMA_CH_GPU_MASK; /* DMA0 - DMA14 */ rid = 0; sc->sc_mem = bus_alloc_resource_any(dev, SYS_RES_MEMORY, &rid, RF_ACTIVE); if (sc->sc_mem == NULL) { device_printf(dev, "could not allocate memory resource\n"); return (ENXIO); } /* IRQ DMA0 - DMA11 XXX NOT USE DMA12(spurious?) */ for (rid = 0; rid < BCM_DMA_CH_MAX; rid++) { if ((bcm_dma_channel_mask & (1 << rid)) == 0) continue; sc->sc_irq[rid] = bus_alloc_resource_any(dev, SYS_RES_IRQ, &rid, - RF_ACTIVE); + RF_ACTIVE | RF_SHAREABLE); if (sc->sc_irq[rid] == NULL) { device_printf(dev, "cannot allocate interrupt\n"); err = ENXIO; goto fail; } if (bus_setup_intr(dev, sc->sc_irq[rid], INTR_TYPE_MISC | INTR_MPSAFE, NULL, bcm_dma_intr, &sc->sc_dma_ch[rid], &sc->sc_intrhand[rid])) { device_printf(dev, "cannot setup interrupt handler\n"); err = ENXIO; goto fail; } } mtx_init(&sc->sc_mtx, "bcmdma", "bcmdma", MTX_DEF); bcm_dma_sc = sc; err = bcm_dma_init(dev); if (err) goto fail; return (err); fail: if (sc->sc_mem) bus_release_resource(dev, SYS_RES_MEMORY, 0, sc->sc_mem); for (i = 0; i < BCM_DMA_CH_MAX; i++) { if (sc->sc_intrhand[i]) bus_teardown_intr(dev, sc->sc_irq[i], sc->sc_intrhand[i]); if (sc->sc_irq[i]) bus_release_resource(dev, SYS_RES_IRQ, 0, sc->sc_irq[i]); } return (err); } static device_method_t bcm_dma_methods[] = { DEVMETHOD(device_probe, bcm_dma_probe), DEVMETHOD(device_attach, bcm_dma_attach), { 0, 0 } }; static driver_t bcm_dma_driver = { "bcm_dma", bcm_dma_methods, sizeof(struct bcm_dma_softc), }; static devclass_t bcm_dma_devclass; DRIVER_MODULE(bcm_dma, simplebus, bcm_dma_driver, bcm_dma_devclass, 0, 0); MODULE_VERSION(bcm_dma, 1); Index: stable/12/sys/arm/broadcom/bcm2835/bcm2835_dma.h =================================================================== --- stable/12/sys/arm/broadcom/bcm2835/bcm2835_dma.h (revision 355664) +++ stable/12/sys/arm/broadcom/bcm2835/bcm2835_dma.h (revision 355665) @@ -1,62 +1,66 @@ /*- * SPDX-License-Identifier: BSD-2-Clause-FreeBSD * * Copyright (c) 2013 Daisuke Aoyama * Copyright (c) 2013 Oleksandr Tymoshenko * * 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. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``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 THE AUTHOR OR CONTRIBUTORS 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 _BCM2835_DMA_H_ #define _BCM2835_DMA_H_ #define BCM_DMA_BLOCK_SIZE 512 /* DMA0-DMA15 but DMA15 is special */ #define BCM_DMA_CH_MAX 12 /* request CH for any nubmer */ #define BCM_DMA_CH_INVALID (-1) #define BCM_DMA_CH_ANY (-1) /* Peripheral DREQ Signals (4.2.1.3) */ #define BCM_DMA_DREQ_NONE 0 +/* + * XXX This doesn't seem to work for the Raspberry Pi 4, but the peripheral + * documentation still lists it at 11. + */ #define BCM_DMA_DREQ_EMMC 11 #define BCM_DMA_DREQ_SDHOST 13 #define BCM_DMA_SAME_ADDR 0 #define BCM_DMA_INC_ADDR 1 #define BCM_DMA_32BIT 0 #define BCM_DMA_128BIT 1 int bcm_dma_allocate(int req_ch); int bcm_dma_free(int ch); int bcm_dma_setup_intr(int ch, void (*func)(int, void *), void *arg); int bcm_dma_setup_src(int ch, int dreq, int inc_addr, int width); int bcm_dma_setup_dst(int ch, int dreq, int inc_addr, int width); int bcm_dma_start(int ch, vm_paddr_t src, vm_paddr_t dst, int len); uint32_t bcm_dma_length(int ch); #endif /* _BCM2835_DMA_H_ */ Index: stable/12/sys/arm/broadcom/bcm2835/bcm2835_ft5406.c =================================================================== --- stable/12/sys/arm/broadcom/bcm2835/bcm2835_ft5406.c (revision 355664) +++ stable/12/sys/arm/broadcom/bcm2835/bcm2835_ft5406.c (revision 355665) @@ -1,336 +1,336 @@ /*- * Copyright (C) 2016 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. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``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 THE AUTHOR OR CONTRIBUTORS 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. * */ #include __FBSDID("$FreeBSD$"); #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include "mbox_if.h" #ifdef DEBUG #define DPRINTF(fmt, ...) do { \ printf("%s:%u: ", __func__, __LINE__); \ printf(fmt, ##__VA_ARGS__); \ } while (0) #else #define DPRINTF(fmt, ...) #endif #define FT5406_LOCK(_sc) \ mtx_lock(&(_sc)->sc_mtx) #define FT5406_UNLOCK(_sc) \ mtx_unlock(&(_sc)->sc_mtx) #define FT5406_LOCK_INIT(_sc) \ mtx_init(&_sc->sc_mtx, device_get_nameunit(_sc->sc_dev), \ "ft5406", MTX_DEF) #define FT5406_LOCK_DESTROY(_sc) \ mtx_destroy(&_sc->sc_mtx); #define FT5406_LOCK_ASSERT(_sc) \ mtx_assert(&(_sc)->sc_mtx, MA_OWNED) #define FT5406_DEVICE_MODE 0 #define FT5406_GESTURE_ID 1 #define FT5406_NUM_POINTS 2 #define FT5406_POINT_XH(n) (0 + 3 + (n)*6) #define FT5406_POINT_XL(n) (1 + 3 + (n)*6) #define FT5406_POINT_YH(n) (2 + 3 + (n)*6) #define FT5406_POINT_YL(n) (3 + 3 + (n)*6) #define FT5406_WINDOW_SIZE 64 #define GET_NUM_POINTS(buf) (buf[FT5406_NUM_POINTS]) #define GET_X(buf, n) (((buf[FT5406_POINT_XH(n)] & 0xf) << 8) | \ (buf[FT5406_POINT_XL(n)])) #define GET_Y(buf, n) (((buf[FT5406_POINT_YH(n)] & 0xf) << 8) | \ (buf[FT5406_POINT_YL(n)])) #define GET_TOUCH_ID(buf, n) ((buf[FT5406_POINT_YH(n)] >> 4) & 0xf) #define NO_POINTS 99 #define SCREEN_WIDTH 800 #define SCREEN_HEIGHT 480 #define SCREEN_WIDTH_MM 155 #define SCREEN_HEIGHT_MM 86 #define SCREEN_RES_X (SCREEN_WIDTH / SCREEN_WIDTH_MM) #define SCREEN_RES_Y (SCREEN_HEIGHT / SCREEN_HEIGHT_MM) #define MAX_TOUCH_ID (10 - 1) struct ft5406ts_softc { device_t sc_dev; struct mtx sc_mtx; int sc_tick; struct callout sc_callout; /* mbox buffer (mapped to KVA) */ uint8_t *touch_buf; /* initial hook for waiting mbox intr */ struct intr_config_hook sc_init_hook; struct evdev_dev *sc_evdev; uint8_t sc_window[FT5406_WINDOW_SIZE]; }; static evdev_open_t ft5406ts_ev_open; static evdev_close_t ft5406ts_ev_close; static const struct evdev_methods ft5406ts_evdev_methods = { .ev_open = &ft5406ts_ev_open, .ev_close = &ft5406ts_ev_close, }; static void ft5406ts_callout(void *data) { struct ft5406ts_softc *sc = (struct ft5406ts_softc *)data; int points; int id, i, x, y; FT5406_LOCK_ASSERT(sc); memcpy(sc->sc_window, sc->touch_buf, FT5406_WINDOW_SIZE); sc->touch_buf[FT5406_NUM_POINTS] = NO_POINTS; points = GET_NUM_POINTS(sc->sc_window); /* * No update from VC - do nothing. */ if (points == NO_POINTS) goto out; for (i = 0; i < points; i++) { id = GET_TOUCH_ID(sc->sc_window, i); x = GET_X(sc->sc_window, i); y = GET_Y(sc->sc_window, i); if (id > MAX_TOUCH_ID) { device_printf(sc->sc_dev, "bad touch id: %d", id); continue; } evdev_push_event(sc->sc_evdev, EV_ABS, ABS_MT_SLOT, id); evdev_push_event(sc->sc_evdev, EV_ABS, ABS_MT_TRACKING_ID, id); evdev_push_event(sc->sc_evdev, EV_ABS, ABS_MT_POSITION_X, x); evdev_push_event(sc->sc_evdev, EV_ABS, ABS_MT_POSITION_Y, y); } evdev_sync(sc->sc_evdev); out: callout_reset(&sc->sc_callout, sc->sc_tick, ft5406ts_callout, sc); } static int ft5406ts_ev_close(struct evdev_dev *evdev) { struct ft5406ts_softc *sc = evdev_get_softc(evdev); FT5406_LOCK_ASSERT(sc); callout_stop(&sc->sc_callout); return (0); } static int ft5406ts_ev_open(struct evdev_dev *evdev) { struct ft5406ts_softc *sc = evdev_get_softc(evdev); FT5406_LOCK_ASSERT(sc); callout_reset(&sc->sc_callout, sc->sc_tick, ft5406ts_callout, sc); return (0); } static void ft5406ts_init(void *arg) { struct ft5406ts_softc *sc = arg; struct bcm2835_mbox_tag_touchbuf msg; uint32_t touchbuf; int err; /* release this hook (continue boot) */ config_intrhook_disestablish(&sc->sc_init_hook); memset(&msg, 0, sizeof(msg)); msg.hdr.buf_size = sizeof(msg); msg.hdr.code = BCM2835_MBOX_CODE_REQ; msg.tag_hdr.tag = BCM2835_MBOX_TAG_GET_TOUCHBUF; msg.tag_hdr.val_buf_size = sizeof(msg.body); msg.tag_hdr.val_len = sizeof(msg.body); msg.end_tag = 0; /* call mailbox property */ err = bcm2835_mbox_property(&msg, sizeof(msg)); if (err) { device_printf(sc->sc_dev, "failed to get touchbuf address\n"); return; } if (msg.body.resp.address == 0) { device_printf(sc->sc_dev, "touchscreen not detected\n"); return; } - touchbuf = VCBUS_TO_PHYS(msg.body.resp.address); + touchbuf = VCBUS_TO_ARMC(msg.body.resp.address); sc->touch_buf = (uint8_t*)pmap_mapdev(touchbuf, FT5406_WINDOW_SIZE); /* 60Hz */ sc->sc_tick = hz * 17 / 1000; if (sc->sc_tick == 0) sc->sc_tick = 1; sc->sc_evdev = evdev_alloc(); evdev_set_name(sc->sc_evdev, device_get_desc(sc->sc_dev)); evdev_set_phys(sc->sc_evdev, device_get_nameunit(sc->sc_dev)); evdev_set_id(sc->sc_evdev, BUS_HOST, 0, 0, 0); evdev_set_methods(sc->sc_evdev, sc, &ft5406ts_evdev_methods); evdev_set_flag(sc->sc_evdev, EVDEV_FLAG_MT_STCOMPAT); evdev_set_flag(sc->sc_evdev, EVDEV_FLAG_MT_AUTOREL); evdev_support_prop(sc->sc_evdev, INPUT_PROP_DIRECT); evdev_support_event(sc->sc_evdev, EV_SYN); evdev_support_event(sc->sc_evdev, EV_ABS); evdev_support_abs(sc->sc_evdev, ABS_MT_SLOT, 0, 0, MAX_TOUCH_ID, 0, 0, 0); evdev_support_abs(sc->sc_evdev, ABS_MT_TRACKING_ID, 0, -1, MAX_TOUCH_ID, 0, 0, 0); evdev_support_abs(sc->sc_evdev, ABS_MT_POSITION_X, 0, 0, SCREEN_WIDTH, 0, 0, SCREEN_RES_X); evdev_support_abs(sc->sc_evdev, ABS_MT_POSITION_Y, 0, 0, SCREEN_HEIGHT, 0, 0, SCREEN_RES_Y); err = evdev_register_mtx(sc->sc_evdev, &sc->sc_mtx); if (err) { evdev_free(sc->sc_evdev); sc->sc_evdev = NULL; /* Avoid double free */ return; } sc->touch_buf[FT5406_NUM_POINTS] = NO_POINTS; callout_init_mtx(&sc->sc_callout, &sc->sc_mtx, 0); } static int ft5406ts_probe(device_t dev) { if (!ofw_bus_is_compatible(dev, "rpi,rpi-ft5406")) return (ENXIO); device_set_desc(dev, "FT5406 touchscreen (VC memory interface)"); return (BUS_PROBE_DEFAULT); } static int ft5406ts_attach(device_t dev) { struct ft5406ts_softc *sc; /* set self dev */ sc = device_get_softc(dev); sc->sc_dev = dev; /* register callback for using mbox when interrupts are enabled */ sc->sc_init_hook.ich_func = ft5406ts_init; sc->sc_init_hook.ich_arg = sc; FT5406_LOCK_INIT(sc); if (config_intrhook_establish(&sc->sc_init_hook) != 0) { device_printf(dev, "config_intrhook_establish failed\n"); FT5406_LOCK_DESTROY(sc); return (ENOMEM); } return (0); } static int ft5406ts_detach(device_t dev) { struct ft5406ts_softc *sc; sc = device_get_softc(dev); evdev_free(sc->sc_evdev); FT5406_LOCK_DESTROY(sc); return (0); } static device_method_t ft5406ts_methods[] = { /* Device interface */ DEVMETHOD(device_probe, ft5406ts_probe), DEVMETHOD(device_attach, ft5406ts_attach), DEVMETHOD(device_detach, ft5406ts_detach), DEVMETHOD_END }; static devclass_t ft5406ts_devclass; static driver_t ft5406ts_driver = { "ft5406ts", ft5406ts_methods, sizeof(struct ft5406ts_softc), }; DRIVER_MODULE(ft5406ts, ofwbus, ft5406ts_driver, ft5406ts_devclass, 0, 0); MODULE_DEPEND(ft5406ts, evdev, 1, 1, 1); Index: stable/12/sys/arm/broadcom/bcm2835/bcm2835_mbox.c =================================================================== --- stable/12/sys/arm/broadcom/bcm2835/bcm2835_mbox.c (revision 355664) +++ stable/12/sys/arm/broadcom/bcm2835/bcm2835_mbox.c (revision 355665) @@ -1,542 +1,542 @@ /*- * SPDX-License-Identifier: BSD-2-Clause-FreeBSD * * Copyright (c) 2012 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. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``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 THE AUTHOR OR CONTRIBUTORS 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. */ #include __FBSDID("$FreeBSD$"); #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include "mbox_if.h" #define REG_READ 0x00 #define REG_POL 0x10 #define REG_SENDER 0x14 #define REG_STATUS 0x18 #define STATUS_FULL 0x80000000 #define STATUS_EMPTY 0x40000000 #define REG_CONFIG 0x1C #define CONFIG_DATA_IRQ 0x00000001 #define REG_WRITE 0x20 /* This is Mailbox 1 address */ #define MBOX_MSG(chan, data) (((data) & ~0xf) | ((chan) & 0xf)) #define MBOX_CHAN(msg) ((msg) & 0xf) #define MBOX_DATA(msg) ((msg) & ~0xf) #define MBOX_LOCK(sc) do { \ mtx_lock(&(sc)->lock); \ } while(0) #define MBOX_UNLOCK(sc) do { \ mtx_unlock(&(sc)->lock); \ } while(0) #ifdef DEBUG #define dprintf(fmt, args...) printf(fmt, ##args) #else #define dprintf(fmt, args...) #endif struct bcm_mbox_softc { struct mtx lock; struct resource * mem_res; struct resource * irq_res; void* intr_hl; bus_space_tag_t bst; bus_space_handle_t bsh; int msg[BCM2835_MBOX_CHANS]; int have_message[BCM2835_MBOX_CHANS]; struct sx property_chan_lock; }; #define mbox_read_4(sc, reg) \ bus_space_read_4((sc)->bst, (sc)->bsh, reg) #define mbox_write_4(sc, reg, val) \ bus_space_write_4((sc)->bst, (sc)->bsh, reg, val) static struct ofw_compat_data compat_data[] = { {"broadcom,bcm2835-mbox", 1}, {"brcm,bcm2835-mbox", 1}, {NULL, 0} }; static int bcm_mbox_read_msg(struct bcm_mbox_softc *sc, int *ochan) { #ifdef DEBUG uint32_t data; #endif uint32_t msg; int chan; msg = mbox_read_4(sc, REG_READ); dprintf("bcm_mbox_intr: raw data %08x\n", msg); chan = MBOX_CHAN(msg); #ifdef DEBUG data = MBOX_DATA(msg); #endif if (sc->msg[chan]) { printf("bcm_mbox_intr: channel %d oveflow\n", chan); return (1); } dprintf("bcm_mbox_intr: chan %d, data %08x\n", chan, data); sc->msg[chan] = msg; if (ochan != NULL) *ochan = chan; return (0); } static void bcm_mbox_intr(void *arg) { struct bcm_mbox_softc *sc = arg; int chan; MBOX_LOCK(sc); while (!(mbox_read_4(sc, REG_STATUS) & STATUS_EMPTY)) if (bcm_mbox_read_msg(sc, &chan) == 0) { sc->have_message[chan] = 1; wakeup(&sc->have_message[chan]); } MBOX_UNLOCK(sc); } static int bcm_mbox_probe(device_t dev) { if (!ofw_bus_status_okay(dev)) return (ENXIO); if (ofw_bus_search_compatible(dev, compat_data)->ocd_data == 0) return (ENXIO); device_set_desc(dev, "BCM2835 VideoCore Mailbox"); return (BUS_PROBE_DEFAULT); } static int bcm_mbox_attach(device_t dev) { struct bcm_mbox_softc *sc = device_get_softc(dev); int i; int 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 resource\n"); return (ENXIO); } sc->bst = rman_get_bustag(sc->mem_res); sc->bsh = rman_get_bushandle(sc->mem_res); 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 interrupt resource\n"); return (ENXIO); } /* Setup and enable the timer */ if (bus_setup_intr(dev, sc->irq_res, INTR_MPSAFE | INTR_TYPE_MISC, NULL, bcm_mbox_intr, sc, &sc->intr_hl) != 0) { bus_release_resource(dev, SYS_RES_IRQ, rid, sc->irq_res); device_printf(dev, "Unable to setup the clock irq handler.\n"); return (ENXIO); } mtx_init(&sc->lock, "vcio mbox", NULL, MTX_DEF); for (i = 0; i < BCM2835_MBOX_CHANS; i++) { sc->msg[i] = 0; sc->have_message[i] = 0; } sx_init(&sc->property_chan_lock, "mboxprop"); /* Read all pending messages */ while ((mbox_read_4(sc, REG_STATUS) & STATUS_EMPTY) == 0) (void)mbox_read_4(sc, REG_READ); mbox_write_4(sc, REG_CONFIG, CONFIG_DATA_IRQ); return (0); } /* * Mailbox API */ static int bcm_mbox_write(device_t dev, int chan, uint32_t data) { int limit = 1000; struct bcm_mbox_softc *sc = device_get_softc(dev); dprintf("bcm_mbox_write: chan %d, data %08x\n", chan, data); MBOX_LOCK(sc); sc->have_message[chan] = 0; while ((mbox_read_4(sc, REG_STATUS) & STATUS_FULL) && --limit) DELAY(5); if (limit == 0) { printf("bcm_mbox_write: STATUS_FULL stuck"); MBOX_UNLOCK(sc); return (EAGAIN); } mbox_write_4(sc, REG_WRITE, MBOX_MSG(chan, data)); MBOX_UNLOCK(sc); return (0); } static int bcm_mbox_read(device_t dev, int chan, uint32_t *data) { struct bcm_mbox_softc *sc = device_get_softc(dev); int err, read_chan; dprintf("bcm_mbox_read: chan %d\n", chan); err = 0; MBOX_LOCK(sc); if (!cold) { if (sc->have_message[chan] == 0) { if (mtx_sleep(&sc->have_message[chan], &sc->lock, 0, "mbox", 10*hz) != 0) { device_printf(dev, "timeout waiting for message on chan %d\n", chan); err = ETIMEDOUT; } } } else { do { /* Wait for a message */ while ((mbox_read_4(sc, REG_STATUS) & STATUS_EMPTY)) ; /* Read the message */ if (bcm_mbox_read_msg(sc, &read_chan) != 0) { err = EINVAL; goto out; } } while (read_chan != chan); } /* * get data from intr handler, the same channel is never coming * because of holding sc lock. */ *data = MBOX_DATA(sc->msg[chan]); sc->msg[chan] = 0; sc->have_message[chan] = 0; out: MBOX_UNLOCK(sc); dprintf("bcm_mbox_read: chan %d, data %08x\n", chan, *data); return (err); } static device_method_t bcm_mbox_methods[] = { DEVMETHOD(device_probe, bcm_mbox_probe), DEVMETHOD(device_attach, bcm_mbox_attach), DEVMETHOD(mbox_read, bcm_mbox_read), DEVMETHOD(mbox_write, bcm_mbox_write), DEVMETHOD_END }; static driver_t bcm_mbox_driver = { "mbox", bcm_mbox_methods, sizeof(struct bcm_mbox_softc), }; static devclass_t bcm_mbox_devclass; DRIVER_MODULE(mbox, simplebus, bcm_mbox_driver, bcm_mbox_devclass, 0, 0); static void bcm2835_mbox_dma_cb(void *arg, bus_dma_segment_t *segs, int nseg, int err) { bus_addr_t *addr; if (err) return; addr = (bus_addr_t *)arg; - *addr = PHYS_TO_VCBUS(segs[0].ds_addr); + *addr = ARMC_TO_VCBUS(segs[0].ds_addr); } static void * bcm2835_mbox_init_dma(device_t dev, size_t len, bus_dma_tag_t *tag, bus_dmamap_t *map, bus_addr_t *phys) { void *buf; int err; err = bus_dma_tag_create(bus_get_dma_tag(dev), 16, 0, - BUS_SPACE_MAXADDR_32BIT, BUS_SPACE_MAXADDR, NULL, NULL, + bcm283x_dmabus_peripheral_lowaddr(), BUS_SPACE_MAXADDR, NULL, NULL, len, 1, len, 0, NULL, NULL, tag); if (err != 0) { device_printf(dev, "can't create DMA tag\n"); return (NULL); } err = bus_dmamem_alloc(*tag, &buf, 0, map); if (err != 0) { bus_dma_tag_destroy(*tag); device_printf(dev, "can't allocate dmamem\n"); return (NULL); } err = bus_dmamap_load(*tag, *map, buf, len, bcm2835_mbox_dma_cb, phys, 0); if (err != 0) { bus_dmamem_free(*tag, buf, *map); bus_dma_tag_destroy(*tag); device_printf(dev, "can't load DMA map\n"); return (NULL); } return (buf); } static int bcm2835_mbox_err(device_t dev, bus_addr_t msg_phys, uint32_t resp_phys, struct bcm2835_mbox_hdr *msg, size_t len) { int idx; struct bcm2835_mbox_tag_hdr *tag; uint8_t *last; if ((uint32_t)msg_phys != resp_phys) { device_printf(dev, "response channel mismatch\n"); return (EIO); } if (msg->code != BCM2835_MBOX_CODE_RESP_SUCCESS) { device_printf(dev, "mbox response error\n"); return (EIO); } /* Loop until the end tag. */ tag = (struct bcm2835_mbox_tag_hdr *)(msg + 1); last = (uint8_t *)msg + len; for (idx = 0; tag->tag != 0; idx++) { if ((tag->val_len & BCM2835_MBOX_TAG_VAL_LEN_RESPONSE) == 0) { device_printf(dev, "tag %d response error\n", idx); return (EIO); } /* Clear the response bit. */ tag->val_len &= ~BCM2835_MBOX_TAG_VAL_LEN_RESPONSE; /* Next tag. */ tag = (struct bcm2835_mbox_tag_hdr *)((uint8_t *)tag + sizeof(*tag) + tag->val_buf_size); if ((uint8_t *)tag > last) { device_printf(dev, "mbox buffer size error\n"); return (EIO); } } return (0); } int bcm2835_mbox_property(void *msg, size_t msg_size) { struct bcm_mbox_softc *sc; struct msg_set_power_state *buf; bus_dma_tag_t msg_tag; bus_dmamap_t msg_map; bus_addr_t msg_phys; uint32_t reg; device_t mbox; int err; /* get mbox device */ mbox = devclass_get_device(devclass_find("mbox"), 0); if (mbox == NULL) return (ENXIO); sc = device_get_softc(mbox); sx_xlock(&sc->property_chan_lock); /* Allocate memory for the message */ buf = bcm2835_mbox_init_dma(mbox, msg_size, &msg_tag, &msg_map, &msg_phys); if (buf == NULL) { err = ENOMEM; goto out; } memcpy(buf, msg, msg_size); bus_dmamap_sync(msg_tag, msg_map, BUS_DMASYNC_PREWRITE); MBOX_WRITE(mbox, BCM2835_MBOX_CHAN_PROP, (uint32_t)msg_phys); MBOX_READ(mbox, BCM2835_MBOX_CHAN_PROP, ®); bus_dmamap_sync(msg_tag, msg_map, BUS_DMASYNC_PREREAD); memcpy(msg, buf, msg_size); err = bcm2835_mbox_err(mbox, msg_phys, reg, (struct bcm2835_mbox_hdr *)msg, msg_size); bus_dmamap_unload(msg_tag, msg_map); bus_dmamem_free(msg_tag, buf, msg_map); bus_dma_tag_destroy(msg_tag); out: sx_xunlock(&sc->property_chan_lock); return (err); } int bcm2835_mbox_set_power_state(uint32_t device_id, boolean_t on) { struct msg_set_power_state msg; int err; memset(&msg, 0, sizeof(msg)); msg.hdr.buf_size = sizeof(msg); msg.hdr.code = BCM2835_MBOX_CODE_REQ; msg.tag_hdr.tag = BCM2835_MBOX_TAG_SET_POWER_STATE; msg.tag_hdr.val_buf_size = sizeof(msg.body); msg.tag_hdr.val_len = sizeof(msg.body.req); msg.body.req.device_id = device_id; msg.body.req.state = (on ? BCM2835_MBOX_POWER_ON : 0) | BCM2835_MBOX_POWER_WAIT; msg.end_tag = 0; err = bcm2835_mbox_property(&msg, sizeof(msg)); return (err); } int bcm2835_mbox_get_clock_rate(uint32_t clock_id, uint32_t *hz) { struct msg_get_clock_rate msg; int err; memset(&msg, 0, sizeof(msg)); msg.hdr.buf_size = sizeof(msg); msg.hdr.code = BCM2835_MBOX_CODE_REQ; msg.tag_hdr.tag = BCM2835_MBOX_TAG_GET_CLOCK_RATE; msg.tag_hdr.val_buf_size = sizeof(msg.body); msg.tag_hdr.val_len = sizeof(msg.body.req); msg.body.req.clock_id = clock_id; msg.end_tag = 0; err = bcm2835_mbox_property(&msg, sizeof(msg)); *hz = msg.body.resp.rate_hz; return (err); } int bcm2835_mbox_fb_get_w_h(struct bcm2835_fb_config *fb) { int err; struct msg_fb_get_w_h msg; memset(&msg, 0, sizeof(msg)); msg.hdr.buf_size = sizeof(msg); msg.hdr.code = BCM2835_MBOX_CODE_REQ; BCM2835_MBOX_INIT_TAG(&msg.physical_w_h, GET_PHYSICAL_W_H); msg.physical_w_h.tag_hdr.val_len = 0; msg.end_tag = 0; err = bcm2835_mbox_property(&msg, sizeof(msg)); if (err == 0) { fb->xres = msg.physical_w_h.body.resp.width; fb->yres = msg.physical_w_h.body.resp.height; } return (err); } int bcm2835_mbox_fb_init(struct bcm2835_fb_config *fb) { int err; struct msg_fb_setup msg; memset(&msg, 0, sizeof(msg)); msg.hdr.buf_size = sizeof(msg); msg.hdr.code = BCM2835_MBOX_CODE_REQ; BCM2835_MBOX_INIT_TAG(&msg.physical_w_h, SET_PHYSICAL_W_H); msg.physical_w_h.body.req.width = fb->xres; msg.physical_w_h.body.req.height = fb->yres; BCM2835_MBOX_INIT_TAG(&msg.virtual_w_h, SET_VIRTUAL_W_H); msg.virtual_w_h.body.req.width = fb->vxres; msg.virtual_w_h.body.req.height = fb->vyres; BCM2835_MBOX_INIT_TAG(&msg.offset, SET_VIRTUAL_OFFSET); msg.offset.body.req.x = fb->xoffset; msg.offset.body.req.y = fb->yoffset; BCM2835_MBOX_INIT_TAG(&msg.depth, SET_DEPTH); msg.depth.body.req.bpp = fb->bpp; BCM2835_MBOX_INIT_TAG(&msg.alpha, SET_ALPHA_MODE); msg.alpha.body.req.alpha = BCM2835_MBOX_ALPHA_MODE_IGNORED; BCM2835_MBOX_INIT_TAG(&msg.buffer, ALLOCATE_BUFFER); msg.buffer.body.req.alignment = PAGE_SIZE; BCM2835_MBOX_INIT_TAG(&msg.pitch, GET_PITCH); msg.end_tag = 0; err = bcm2835_mbox_property(&msg, sizeof(msg)); if (err == 0) { fb->xres = msg.physical_w_h.body.resp.width; fb->yres = msg.physical_w_h.body.resp.height; fb->vxres = msg.virtual_w_h.body.resp.width; fb->vyres = msg.virtual_w_h.body.resp.height; fb->xoffset = msg.offset.body.resp.x; fb->yoffset = msg.offset.body.resp.y; fb->pitch = msg.pitch.body.resp.pitch; - fb->base = VCBUS_TO_PHYS(msg.buffer.body.resp.fb_address); + fb->base = VCBUS_TO_ARMC(msg.buffer.body.resp.fb_address); fb->size = msg.buffer.body.resp.fb_size; } return (err); } Index: stable/12/sys/arm/broadcom/bcm2835/bcm2835_mbox_prop.h =================================================================== --- stable/12/sys/arm/broadcom/bcm2835/bcm2835_mbox_prop.h (revision 355664) +++ stable/12/sys/arm/broadcom/bcm2835/bcm2835_mbox_prop.h (revision 355665) @@ -1,493 +1,494 @@ /*- * Copyright (C) 2013-2014 Daisuke Aoyama * 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. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``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 THE AUTHOR OR CONTRIBUTORS 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 _BCM2835_MBOX_PROP_H_ #define _BCM2835_MBOX_PROP_H_ #include #include /* * Mailbox property interface: * https://github.com/raspberrypi/firmware/wiki/Mailbox-property-interface */ #define BCM2835_MBOX_CODE_REQ 0 #define BCM2835_MBOX_CODE_RESP_SUCCESS 0x80000000 #define BCM2835_MBOX_CODE_RESP_ERROR 0x80000001 #define BCM2835_MBOX_TAG_VAL_LEN_RESPONSE 0x80000000 struct bcm2835_mbox_hdr { uint32_t buf_size; uint32_t code; }; struct bcm2835_mbox_tag_hdr { uint32_t tag; uint32_t val_buf_size; uint32_t val_len; }; #define BCM2835_MBOX_INIT_TAG(tag_, tagid_) do { \ (tag_)->tag_hdr.tag = BCM2835_MBOX_TAG_##tagid_; \ (tag_)->tag_hdr.val_buf_size = sizeof((tag_)->body); \ (tag_)->tag_hdr.val_len = sizeof((tag_)->body.req); \ } while (0) #define BCM2835_MBOX_POWER_ID_EMMC 0x00000000 #define BCM2835_MBOX_POWER_ID_UART0 0x00000001 #define BCM2835_MBOX_POWER_ID_UART1 0x00000002 #define BCM2835_MBOX_POWER_ID_USB_HCD 0x00000003 #define BCM2835_MBOX_POWER_ID_I2C0 0x00000004 #define BCM2835_MBOX_POWER_ID_I2C1 0x00000005 #define BCM2835_MBOX_POWER_ID_I2C2 0x00000006 #define BCM2835_MBOX_POWER_ID_SPI 0x00000007 #define BCM2835_MBOX_POWER_ID_CCP2TX 0x00000008 #define BCM2835_MBOX_POWER_ON (1 << 0) #define BCM2835_MBOX_POWER_WAIT (1 << 1) #define BCM2835_MBOX_TAG_GET_POWER_STATE 0x00020001 #define BCM2835_MBOX_TAG_SET_POWER_STATE 0x00028001 struct msg_get_power_state { struct bcm2835_mbox_hdr hdr; struct bcm2835_mbox_tag_hdr tag_hdr; union { struct { uint32_t device_id; } req; struct { uint32_t device_id; uint32_t state; } resp; } body; uint32_t end_tag; }; struct msg_set_power_state { struct bcm2835_mbox_hdr hdr; struct bcm2835_mbox_tag_hdr tag_hdr; union { struct { uint32_t device_id; uint32_t state; } req; struct { uint32_t device_id; uint32_t state; } resp; } body; uint32_t end_tag; }; /* Sets the power state for a given device */ int bcm2835_mbox_set_power_state(uint32_t, boolean_t); #define BCM2835_MBOX_CLOCK_ID_EMMC 0x00000001 #define BCM2835_MBOX_CLOCK_ID_UART 0x00000002 #define BCM2835_MBOX_CLOCK_ID_ARM 0x00000003 #define BCM2835_MBOX_CLOCK_ID_CORE 0x00000004 #define BCM2835_MBOX_CLOCK_ID_V3D 0x00000005 #define BCM2835_MBOX_CLOCK_ID_H264 0x00000006 #define BCM2835_MBOX_CLOCK_ID_ISP 0x00000007 #define BCM2835_MBOX_CLOCK_ID_SDRAM 0x00000008 #define BCM2835_MBOX_CLOCK_ID_PIXEL 0x00000009 #define BCM2835_MBOX_CLOCK_ID_PWM 0x0000000a +#define BCM2838_MBOX_CLOCK_ID_EMMC2 0x0000000c #define BCM2835_MBOX_TAG_GET_CLOCK_RATE 0x00030002 #define BCM2835_MBOX_TAG_SET_CLOCK_RATE 0x00038002 #define BCM2835_MBOX_TAG_GET_MAX_CLOCK_RATE 0x00030004 #define BCM2835_MBOX_TAG_GET_MIN_CLOCK_RATE 0x00030007 struct msg_get_clock_rate { struct bcm2835_mbox_hdr hdr; struct bcm2835_mbox_tag_hdr tag_hdr; union { struct { uint32_t clock_id; } req; struct { uint32_t clock_id; uint32_t rate_hz; } resp; } body; uint32_t end_tag; }; struct msg_set_clock_rate { struct bcm2835_mbox_hdr hdr; struct bcm2835_mbox_tag_hdr tag_hdr; union { struct { uint32_t clock_id; uint32_t rate_hz; } req; struct { uint32_t clock_id; uint32_t rate_hz; } resp; } body; uint32_t end_tag; }; struct msg_get_max_clock_rate { struct bcm2835_mbox_hdr hdr; struct bcm2835_mbox_tag_hdr tag_hdr; union { struct { uint32_t clock_id; } req; struct { uint32_t clock_id; uint32_t rate_hz; } resp; } body; uint32_t end_tag; }; struct msg_get_min_clock_rate { struct bcm2835_mbox_hdr hdr; struct bcm2835_mbox_tag_hdr tag_hdr; union { struct { uint32_t clock_id; } req; struct { uint32_t clock_id; uint32_t rate_hz; } resp; } body; uint32_t end_tag; }; int bcm2835_mbox_get_clock_rate(uint32_t, uint32_t *); #define BCM2835_MBOX_TURBO_ON 1 #define BCM2835_MBOX_TURBO_OFF 0 #define BCM2835_MBOX_TAG_GET_TURBO 0x00030009 #define BCM2835_MBOX_TAG_SET_TURBO 0x00038009 struct msg_get_turbo { struct bcm2835_mbox_hdr hdr; struct bcm2835_mbox_tag_hdr tag_hdr; union { struct { uint32_t id; } req; struct { uint32_t id; uint32_t level; } resp; } body; uint32_t end_tag; }; struct msg_set_turbo { struct bcm2835_mbox_hdr hdr; struct bcm2835_mbox_tag_hdr tag_hdr; union { struct { uint32_t id; uint32_t level; } req; struct { uint32_t id; uint32_t level; } resp; } body; uint32_t end_tag; }; #define BCM2835_MBOX_VOLTAGE_ID_CORE 0x00000001 #define BCM2835_MBOX_VOLTAGE_ID_SDRAM_C 0x00000002 #define BCM2835_MBOX_VOLTAGE_ID_SDRAM_P 0x00000003 #define BCM2835_MBOX_VOLTAGE_ID_SDRAM_I 0x00000004 #define BCM2835_MBOX_TAG_GET_VOLTAGE 0x00030003 #define BCM2835_MBOX_TAG_SET_VOLTAGE 0x00038003 #define BCM2835_MBOX_TAG_GET_MAX_VOLTAGE 0x00030005 #define BCM2835_MBOX_TAG_GET_MIN_VOLTAGE 0x00030008 struct msg_get_voltage { struct bcm2835_mbox_hdr hdr; struct bcm2835_mbox_tag_hdr tag_hdr; union { struct { uint32_t voltage_id; } req; struct { uint32_t voltage_id; uint32_t value; } resp; } body; uint32_t end_tag; }; struct msg_set_voltage { struct bcm2835_mbox_hdr hdr; struct bcm2835_mbox_tag_hdr tag_hdr; union { struct { uint32_t voltage_id; uint32_t value; } req; struct { uint32_t voltage_id; uint32_t value; } resp; } body; uint32_t end_tag; }; struct msg_get_max_voltage { struct bcm2835_mbox_hdr hdr; struct bcm2835_mbox_tag_hdr tag_hdr; union { struct { uint32_t voltage_id; } req; struct { uint32_t voltage_id; uint32_t value; } resp; } body; uint32_t end_tag; }; struct msg_get_min_voltage { struct bcm2835_mbox_hdr hdr; struct bcm2835_mbox_tag_hdr tag_hdr; union { struct { uint32_t voltage_id; } req; struct { uint32_t voltage_id; uint32_t value; } resp; } body; uint32_t end_tag; }; #define BCM2835_MBOX_TAG_GET_TEMPERATURE 0x00030006 #define BCM2835_MBOX_TAG_GET_MAX_TEMPERATURE 0x0003000a struct msg_get_temperature { struct bcm2835_mbox_hdr hdr; struct bcm2835_mbox_tag_hdr tag_hdr; union { struct { uint32_t temperature_id; } req; struct { uint32_t temperature_id; uint32_t value; } resp; } body; uint32_t end_tag; }; struct msg_get_max_temperature { struct bcm2835_mbox_hdr hdr; struct bcm2835_mbox_tag_hdr tag_hdr; union { struct { uint32_t temperature_id; } req; struct { uint32_t temperature_id; uint32_t value; } resp; } body; uint32_t end_tag; }; #define BCM2835_MBOX_TAG_GET_PHYSICAL_W_H 0x00040003 #define BCM2835_MBOX_TAG_SET_PHYSICAL_W_H 0x00048003 #define BCM2835_MBOX_TAG_GET_VIRTUAL_W_H 0x00040004 #define BCM2835_MBOX_TAG_SET_VIRTUAL_W_H 0x00048004 struct bcm2835_mbox_tag_fb_w_h { struct bcm2835_mbox_tag_hdr tag_hdr; union { struct { uint32_t width; uint32_t height; } req; struct { uint32_t width; uint32_t height; } resp; } body; }; #define BCM2835_MBOX_TAG_GET_DEPTH 0x00040005 #define BCM2835_MBOX_TAG_SET_DEPTH 0x00048005 struct bcm2835_mbox_tag_depth { struct bcm2835_mbox_tag_hdr tag_hdr; union { struct { uint32_t bpp; } req; struct { uint32_t bpp; } resp; } body; }; #define BCM2835_MBOX_TAG_GET_ALPHA_MODE 0x00040007 #define BCM2835_MBOX_TAG_SET_ALPHA_MODE 0x00048007 #define BCM2835_MBOX_ALPHA_MODE_0_OPAQUE 0 #define BCM2835_MBOX_ALPHA_MODE_0_TRANSPARENT 1 #define BCM2835_MBOX_ALPHA_MODE_IGNORED 2 struct bcm2835_mbox_tag_alpha_mode { struct bcm2835_mbox_tag_hdr tag_hdr; union { struct { uint32_t alpha; } req; struct { uint32_t alpha; } resp; } body; }; #define BCM2835_MBOX_TAG_GET_VIRTUAL_OFFSET 0x00040009 #define BCM2835_MBOX_TAG_SET_VIRTUAL_OFFSET 0x00048009 struct bcm2835_mbox_tag_virtual_offset { struct bcm2835_mbox_tag_hdr tag_hdr; union { struct { uint32_t x; uint32_t y; } req; struct { uint32_t x; uint32_t y; } resp; } body; }; #define BCM2835_MBOX_TAG_GET_PITCH 0x00040008 struct bcm2835_mbox_tag_pitch { struct bcm2835_mbox_tag_hdr tag_hdr; union { struct { } req; struct { uint32_t pitch; } resp; } body; }; #define BCM2835_MBOX_TAG_ALLOCATE_BUFFER 0x00040001 struct bcm2835_mbox_tag_allocate_buffer { struct bcm2835_mbox_tag_hdr tag_hdr; union { struct { uint32_t alignment; } req; struct { uint32_t fb_address; uint32_t fb_size; } resp; } body; }; #define BCM2835_MBOX_TAG_RELEASE_BUFFER 0x00048001 struct bcm2835_mbox_tag_release_buffer { struct bcm2835_mbox_tag_hdr tag_hdr; union { struct { } req; struct { } resp; } body; }; #define BCM2835_MBOX_TAG_GET_TOUCHBUF 0x0004000f struct bcm2835_mbox_tag_touchbuf { struct bcm2835_mbox_hdr hdr; struct bcm2835_mbox_tag_hdr tag_hdr; union { struct { } req; struct { uint32_t address; } resp; } body; uint32_t end_tag; }; struct bcm2835_fb_config { uint32_t xres; uint32_t yres; uint32_t vxres; uint32_t vyres; uint32_t xoffset; uint32_t yoffset; uint32_t bpp; uint32_t pitch; uint32_t base; uint32_t size; }; struct msg_fb_get_w_h { struct bcm2835_mbox_hdr hdr; struct bcm2835_mbox_tag_fb_w_h physical_w_h; uint32_t end_tag; }; int bcm2835_mbox_fb_get_w_h(struct bcm2835_fb_config *); struct msg_fb_setup { struct bcm2835_mbox_hdr hdr; struct bcm2835_mbox_tag_fb_w_h physical_w_h; struct bcm2835_mbox_tag_fb_w_h virtual_w_h; struct bcm2835_mbox_tag_virtual_offset offset; struct bcm2835_mbox_tag_depth depth; struct bcm2835_mbox_tag_alpha_mode alpha; struct bcm2835_mbox_tag_allocate_buffer buffer; struct bcm2835_mbox_tag_pitch pitch; uint32_t end_tag; }; int bcm2835_mbox_fb_init(struct bcm2835_fb_config *); int bcm2835_mbox_property(void *, size_t); #endif /* _BCM2835_MBOX_PROP_H_ */ Index: stable/12/sys/arm/broadcom/bcm2835/bcm2835_sdhci.c =================================================================== --- stable/12/sys/arm/broadcom/bcm2835/bcm2835_sdhci.c (revision 355664) +++ stable/12/sys/arm/broadcom/bcm2835/bcm2835_sdhci.c (revision 355665) @@ -1,698 +1,828 @@ /*- * SPDX-License-Identifier: BSD-2-Clause-FreeBSD * * Copyright (c) 2012 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. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``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 THE AUTHOR OR CONTRIBUTORS 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. * */ #include __FBSDID("$FreeBSD$"); #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include "mmcbr_if.h" #include "sdhci_if.h" #include "opt_mmccam.h" #include "bcm2835_dma.h" #include -#include "bcm2835_vcbus.h" +#ifdef NOTYET +#include +#endif +#include #define BCM2835_DEFAULT_SDHCI_FREQ 50 +#define BCM2838_DEFAULT_SDHCI_FREQ 100 #define BCM_SDHCI_BUFFER_SIZE 512 -#define NUM_DMA_SEGS 2 +/* + * NUM_DMA_SEGS is the number of DMA segments we want to accommodate on average. + * We add in a number of segments based on how much we may need to spill into + * another segment due to crossing page boundaries. e.g. up to PAGE_SIZE, an + * extra page is needed as we can cross a page boundary exactly once. + */ +#define NUM_DMA_SEGS 1 +#define NUM_DMA_SPILL_SEGS \ + ((((NUM_DMA_SEGS * BCM_SDHCI_BUFFER_SIZE) - 1) / PAGE_SIZE) + 1) +#define ALLOCATED_DMA_SEGS (NUM_DMA_SEGS + NUM_DMA_SPILL_SEGS) +#define BCM_DMA_MAXSIZE (NUM_DMA_SEGS * BCM_SDHCI_BUFFER_SIZE) +#define BCM_SDHCI_SLOT_LEFT(slot) \ + ((slot)->curcmd->data->len - (slot)->offset) + +#define BCM_SDHCI_SEGSZ_LEFT(slot) \ + min(BCM_DMA_MAXSIZE, \ + rounddown(BCM_SDHCI_SLOT_LEFT(slot), BCM_SDHCI_BUFFER_SIZE)) + +#define DATA_PENDING_MASK (SDHCI_INT_DATA_AVAIL | SDHCI_INT_SPACE_AVAIL) +#define DATA_XFER_MASK (DATA_PENDING_MASK | SDHCI_INT_DATA_END) + #ifdef DEBUG static int bcm2835_sdhci_debug = 0; TUNABLE_INT("hw.bcm2835.sdhci.debug", &bcm2835_sdhci_debug); SYSCTL_INT(_hw_sdhci, OID_AUTO, bcm2835_sdhci_debug, CTLFLAG_RWTUN, &bcm2835_sdhci_debug, 0, "bcm2835 SDHCI debug level"); #define dprintf(fmt, args...) \ do { \ if (bcm2835_sdhci_debug) \ printf("%s: " fmt, __func__, ##args); \ } while (0) #else #define dprintf(fmt, args...) #endif static int bcm2835_sdhci_hs = 1; static int bcm2835_sdhci_pio_mode = 0; +struct bcm_mmc_conf { + int clock_id; + int clock_src; + int default_freq; + int quirks; + int emmc_dreq; +}; + +struct bcm_mmc_conf bcm2835_sdhci_conf = { + .clock_id = BCM2835_MBOX_CLOCK_ID_EMMC, + .clock_src = -1, + .default_freq = BCM2835_DEFAULT_SDHCI_FREQ, + .quirks = SDHCI_QUIRK_DATA_TIMEOUT_USES_SDCLK | + SDHCI_QUIRK_BROKEN_TIMEOUT_VAL | SDHCI_QUIRK_DONT_SET_HISPD_BIT | + SDHCI_QUIRK_MISSING_CAPS, + .emmc_dreq = BCM_DMA_DREQ_EMMC, +}; + +struct bcm_mmc_conf bcm2838_emmc2_conf = { + .clock_id = BCM2838_MBOX_CLOCK_ID_EMMC2, + .clock_src = -1, + .default_freq = BCM2838_DEFAULT_SDHCI_FREQ, + .quirks = 0, + .emmc_dreq = BCM_DMA_DREQ_NONE, +}; + static struct ofw_compat_data compat_data[] = { - {"broadcom,bcm2835-sdhci", 1}, - {"brcm,bcm2835-sdhci", 1}, - {"brcm,bcm2835-mmc", 1}, + {"broadcom,bcm2835-sdhci", (uintptr_t)&bcm2835_sdhci_conf}, + {"brcm,bcm2835-sdhci", (uintptr_t)&bcm2835_sdhci_conf}, + {"brcm,bcm2835-mmc", (uintptr_t)&bcm2835_sdhci_conf}, + {"brcm,bcm2711-emmc2", (uintptr_t)&bcm2838_emmc2_conf}, + {"brcm,bcm2838-emmc2", (uintptr_t)&bcm2838_emmc2_conf}, {NULL, 0} }; TUNABLE_INT("hw.bcm2835.sdhci.hs", &bcm2835_sdhci_hs); TUNABLE_INT("hw.bcm2835.sdhci.pio_mode", &bcm2835_sdhci_pio_mode); struct bcm_sdhci_softc { device_t sc_dev; struct resource * sc_mem_res; struct resource * sc_irq_res; bus_space_tag_t sc_bst; bus_space_handle_t sc_bsh; void * sc_intrhand; struct mmc_request * sc_req; struct sdhci_slot sc_slot; int sc_dma_ch; bus_dma_tag_t sc_dma_tag; bus_dmamap_t sc_dma_map; vm_paddr_t sc_sdhci_buffer_phys; - uint32_t cmd_and_mode; - bus_addr_t dmamap_seg_addrs[NUM_DMA_SEGS]; - bus_size_t dmamap_seg_sizes[NUM_DMA_SEGS]; + bus_addr_t dmamap_seg_addrs[ALLOCATED_DMA_SEGS]; + bus_size_t dmamap_seg_sizes[ALLOCATED_DMA_SEGS]; int dmamap_seg_count; int dmamap_seg_index; int dmamap_status; + uint32_t blksz_and_count; + uint32_t cmd_and_mode; + bool need_update_blk; +#ifdef NOTYET + device_t clkman; +#endif + struct bcm_mmc_conf * conf; }; static int bcm_sdhci_probe(device_t); static int bcm_sdhci_attach(device_t); static int bcm_sdhci_detach(device_t); static void bcm_sdhci_intr(void *); static int bcm_sdhci_get_ro(device_t, device_t); static void bcm_sdhci_dma_intr(int ch, void *arg); +static void bcm_sdhci_start_dma(struct sdhci_slot *slot); static void bcm_sdhci_dmacb(void *arg, bus_dma_segment_t *segs, int nseg, int err) { struct bcm_sdhci_softc *sc = arg; int i; + /* Sanity check: we can only ever have one mapping at a time. */ + KASSERT(sc->dmamap_seg_count == 0, ("leaked DMA segment")); sc->dmamap_status = err; sc->dmamap_seg_count = nseg; /* Note nseg is guaranteed to be zero if err is non-zero. */ for (i = 0; i < nseg; i++) { sc->dmamap_seg_addrs[i] = segs[i].ds_addr; sc->dmamap_seg_sizes[i] = segs[i].ds_len; } } static int bcm_sdhci_probe(device_t dev) { if (!ofw_bus_status_okay(dev)) return (ENXIO); if (ofw_bus_search_compatible(dev, compat_data)->ocd_data == 0) return (ENXIO); device_set_desc(dev, "Broadcom 2708 SDHCI controller"); return (BUS_PROBE_DEFAULT); } static int bcm_sdhci_attach(device_t dev) { struct bcm_sdhci_softc *sc = device_get_softc(dev); int rid, err; phandle_t node; pcell_t cell; u_int default_freq; sc->sc_dev = dev; sc->sc_req = NULL; - err = bcm2835_mbox_set_power_state(BCM2835_MBOX_POWER_ID_EMMC, - TRUE); + sc->conf = (struct bcm_mmc_conf *)ofw_bus_search_compatible(dev, + compat_data)->ocd_data; + if (sc->conf == 0) + return (ENXIO); + + err = bcm2835_mbox_set_power_state(BCM2835_MBOX_POWER_ID_EMMC, TRUE); if (err != 0) { if (bootverbose) device_printf(dev, "Unable to enable the power\n"); return (err); } default_freq = 0; - err = bcm2835_mbox_get_clock_rate(BCM2835_MBOX_CLOCK_ID_EMMC, - &default_freq); + err = bcm2835_mbox_get_clock_rate(sc->conf->clock_id, &default_freq); if (err == 0) { /* Convert to MHz */ default_freq /= 1000000; } if (default_freq == 0) { node = ofw_bus_get_node(sc->sc_dev); if ((OF_getencprop(node, "clock-frequency", &cell, sizeof(cell))) > 0) default_freq = cell / 1000000; } if (default_freq == 0) - default_freq = BCM2835_DEFAULT_SDHCI_FREQ; + default_freq = sc->conf->default_freq; if (bootverbose) device_printf(dev, "SDHCI frequency: %dMHz\n", default_freq); +#ifdef NOTYET + if (sc->conf->clock_src > 0) { + uint32_t f; + sc->clkman = devclass_get_device( + devclass_find("bcm2835_clkman"), 0); + if (sc->clkman == NULL) { + device_printf(dev, "cannot find Clock Manager\n"); + return (ENXIO); + } + f = bcm2835_clkman_set_frequency(sc->clkman, + sc->conf->clock_src, default_freq); + if (f == 0) + return (EINVAL); + + if (bootverbose) + device_printf(dev, "Clock source frequency: %dMHz\n", + f); + } +#endif + rid = 0; sc->sc_mem_res = bus_alloc_resource_any(dev, SYS_RES_MEMORY, &rid, RF_ACTIVE); if (!sc->sc_mem_res) { device_printf(dev, "cannot allocate memory window\n"); err = ENXIO; goto fail; } sc->sc_bst = rman_get_bustag(sc->sc_mem_res); sc->sc_bsh = rman_get_bushandle(sc->sc_mem_res); rid = 0; sc->sc_irq_res = bus_alloc_resource_any(dev, SYS_RES_IRQ, &rid, - RF_ACTIVE); + RF_ACTIVE | RF_SHAREABLE); if (!sc->sc_irq_res) { device_printf(dev, "cannot allocate interrupt\n"); err = ENXIO; goto fail; } if (bus_setup_intr(dev, sc->sc_irq_res, INTR_TYPE_BIO | INTR_MPSAFE, NULL, bcm_sdhci_intr, sc, &sc->sc_intrhand)) { device_printf(dev, "cannot setup interrupt handler\n"); err = ENXIO; goto fail; } if (!bcm2835_sdhci_pio_mode) sc->sc_slot.opt = SDHCI_PLATFORM_TRANSFER; sc->sc_slot.caps = SDHCI_CAN_VDD_330 | SDHCI_CAN_VDD_180; if (bcm2835_sdhci_hs) sc->sc_slot.caps |= SDHCI_CAN_DO_HISPD; sc->sc_slot.caps |= (default_freq << SDHCI_CLOCK_BASE_SHIFT); - sc->sc_slot.quirks = SDHCI_QUIRK_DATA_TIMEOUT_USES_SDCLK - | SDHCI_QUIRK_BROKEN_TIMEOUT_VAL - | SDHCI_QUIRK_DONT_SET_HISPD_BIT - | SDHCI_QUIRK_MISSING_CAPS; - + sc->sc_slot.quirks = sc->conf->quirks; + sdhci_init_slot(dev, &sc->sc_slot, 0); sc->sc_dma_ch = bcm_dma_allocate(BCM_DMA_CH_ANY); if (sc->sc_dma_ch == BCM_DMA_CH_INVALID) goto fail; - bcm_dma_setup_intr(sc->sc_dma_ch, bcm_sdhci_dma_intr, sc); + err = bcm_dma_setup_intr(sc->sc_dma_ch, bcm_sdhci_dma_intr, sc); + if (err != 0) { + device_printf(dev, + "cannot setup dma interrupt handler\n"); + err = ENXIO; + goto fail; + } /* Allocate bus_dma resources. */ err = bus_dma_tag_create(bus_get_dma_tag(dev), - 1, 0, BUS_SPACE_MAXADDR_32BIT, + 1, 0, bcm283x_dmabus_peripheral_lowaddr(), BUS_SPACE_MAXADDR, NULL, NULL, - BCM_SDHCI_BUFFER_SIZE, NUM_DMA_SEGS, BCM_SDHCI_BUFFER_SIZE, + BCM_DMA_MAXSIZE, ALLOCATED_DMA_SEGS, BCM_SDHCI_BUFFER_SIZE, BUS_DMA_ALLOCNOW, NULL, NULL, &sc->sc_dma_tag); if (err) { device_printf(dev, "failed allocate DMA tag"); goto fail; } err = bus_dmamap_create(sc->sc_dma_tag, 0, &sc->sc_dma_map); if (err) { device_printf(dev, "bus_dmamap_create failed\n"); goto fail; } /* FIXME: Fix along with other BUS_SPACE_PHYSADDR instances */ sc->sc_sdhci_buffer_phys = rman_get_start(sc->sc_mem_res) + SDHCI_BUFFER; bus_generic_probe(dev); bus_generic_attach(dev); sdhci_start_slot(&sc->sc_slot); + /* Seed our copies. */ + sc->blksz_and_count = SDHCI_READ_4(dev, &sc->sc_slot, SDHCI_BLOCK_SIZE); + sc->cmd_and_mode = SDHCI_READ_4(dev, &sc->sc_slot, SDHCI_TRANSFER_MODE); + return (0); fail: if (sc->sc_intrhand) bus_teardown_intr(dev, sc->sc_irq_res, sc->sc_intrhand); if (sc->sc_irq_res) bus_release_resource(dev, SYS_RES_IRQ, 0, sc->sc_irq_res); if (sc->sc_mem_res) bus_release_resource(dev, SYS_RES_MEMORY, 0, sc->sc_mem_res); return (err); } static int bcm_sdhci_detach(device_t dev) { return (EBUSY); } static void bcm_sdhci_intr(void *arg) { struct bcm_sdhci_softc *sc = arg; sdhci_generic_intr(&sc->sc_slot); } static int bcm_sdhci_get_ro(device_t bus, device_t child) { return (0); } static inline uint32_t RD4(struct bcm_sdhci_softc *sc, bus_size_t off) { uint32_t val = bus_space_read_4(sc->sc_bst, sc->sc_bsh, off); return val; } static inline void WR4(struct bcm_sdhci_softc *sc, bus_size_t off, uint32_t val) { bus_space_write_4(sc->sc_bst, sc->sc_bsh, off, val); /* * The Arasan HC has a bug where it may lose the content of * consecutive writes to registers that are within two SD-card - * clock cycles of each other (a clock domain crossing problem). + * clock cycles of each other (a clock domain crossing problem). */ if (sc->sc_slot.clock > 0) DELAY(((2 * 1000000) / sc->sc_slot.clock) + 1); } static uint8_t bcm_sdhci_read_1(device_t dev, struct sdhci_slot *slot, bus_size_t off) { struct bcm_sdhci_softc *sc = device_get_softc(dev); uint32_t val = RD4(sc, off & ~3); return ((val >> (off & 3)*8) & 0xff); } static uint16_t bcm_sdhci_read_2(device_t dev, struct sdhci_slot *slot, bus_size_t off) { struct bcm_sdhci_softc *sc = device_get_softc(dev); - uint32_t val = RD4(sc, off & ~3); + uint32_t val32; /* - * Standard 32-bit handling of command and transfer mode. + * Standard 32-bit handling of command and transfer mode, as + * well as block size and count. */ - if (off == SDHCI_TRANSFER_MODE) { - return (sc->cmd_and_mode >> 16); - } else if (off == SDHCI_COMMAND_FLAGS) { - return (sc->cmd_and_mode & 0x0000ffff); - } - return ((val >> (off & 3)*8) & 0xffff); + if ((off == SDHCI_BLOCK_SIZE || off == SDHCI_BLOCK_COUNT) && + sc->need_update_blk) + val32 = sc->blksz_and_count; + else if (off == SDHCI_TRANSFER_MODE || off == SDHCI_COMMAND_FLAGS) + val32 = sc->cmd_and_mode; + else + val32 = RD4(sc, off & ~3); + + return ((val32 >> (off & 3)*8) & 0xffff); } static uint32_t bcm_sdhci_read_4(device_t dev, struct sdhci_slot *slot, bus_size_t off) { struct bcm_sdhci_softc *sc = device_get_softc(dev); return RD4(sc, off); } static void bcm_sdhci_read_multi_4(device_t dev, struct sdhci_slot *slot, bus_size_t off, uint32_t *data, bus_size_t count) { struct bcm_sdhci_softc *sc = device_get_softc(dev); bus_space_read_multi_4(sc->sc_bst, sc->sc_bsh, off, data, count); } static void -bcm_sdhci_write_1(device_t dev, struct sdhci_slot *slot, bus_size_t off, uint8_t val) +bcm_sdhci_write_1(device_t dev, struct sdhci_slot *slot, bus_size_t off, + uint8_t val) { struct bcm_sdhci_softc *sc = device_get_softc(dev); uint32_t val32 = RD4(sc, off & ~3); val32 &= ~(0xff << (off & 3)*8); val32 |= (val << (off & 3)*8); WR4(sc, off & ~3, val32); } static void -bcm_sdhci_write_2(device_t dev, struct sdhci_slot *slot, bus_size_t off, uint16_t val) +bcm_sdhci_write_2(device_t dev, struct sdhci_slot *slot, bus_size_t off, + uint16_t val) { struct bcm_sdhci_softc *sc = device_get_softc(dev); uint32_t val32; - if (off == SDHCI_COMMAND_FLAGS) + + /* + * If we have a queued up 16bit value for blk size or count, use and + * update the saved value rather than doing any real register access. + * If we did not touch either since the last write, then read from + * register as at least block count can change. + * Similarly, if we are about to issue a command, always use the saved + * value for transfer mode as we can never write that without issuing + * a command. + */ + if ((off == SDHCI_BLOCK_SIZE || off == SDHCI_BLOCK_COUNT) && + sc->need_update_blk) + val32 = sc->blksz_and_count; + else if (off == SDHCI_COMMAND_FLAGS) val32 = sc->cmd_and_mode; else val32 = RD4(sc, off & ~3); + val32 &= ~(0xffff << (off & 3)*8); val32 |= (val << (off & 3)*8); + if (off == SDHCI_TRANSFER_MODE) sc->cmd_and_mode = val32; - else { - WR4(sc, off & ~3, val32); - if (off == SDHCI_COMMAND_FLAGS) + else if (off == SDHCI_BLOCK_SIZE || off == SDHCI_BLOCK_COUNT) { + sc->blksz_and_count = val32; + sc->need_update_blk = true; + } else { + if (off == SDHCI_COMMAND_FLAGS) { + /* If we saved blk writes, do them now before cmd. */ + if (sc->need_update_blk) { + WR4(sc, SDHCI_BLOCK_SIZE, sc->blksz_and_count); + sc->need_update_blk = false; + } + /* Always save cmd and mode registers. */ sc->cmd_and_mode = val32; + } + WR4(sc, off & ~3, val32); } } static void -bcm_sdhci_write_4(device_t dev, struct sdhci_slot *slot, bus_size_t off, uint32_t val) +bcm_sdhci_write_4(device_t dev, struct sdhci_slot *slot, bus_size_t off, + uint32_t val) { struct bcm_sdhci_softc *sc = device_get_softc(dev); WR4(sc, off, val); } static void bcm_sdhci_write_multi_4(device_t dev, struct sdhci_slot *slot, bus_size_t off, uint32_t *data, bus_size_t count) { struct bcm_sdhci_softc *sc = device_get_softc(dev); bus_space_write_multi_4(sc->sc_bst, sc->sc_bsh, off, data, count); } static void bcm_sdhci_start_dma_seg(struct bcm_sdhci_softc *sc) { struct sdhci_slot *slot; vm_paddr_t pdst, psrc; - int err, idx, len, sync_op; + int err, idx, len, sync_op, width; slot = &sc->sc_slot; + mtx_assert(&slot->mtx, MA_OWNED); idx = sc->dmamap_seg_index++; len = sc->dmamap_seg_sizes[idx]; slot->offset += len; + width = (len & 0xf ? BCM_DMA_32BIT : BCM_DMA_128BIT); if (slot->curcmd->data->flags & MMC_DATA_READ) { - bcm_dma_setup_src(sc->sc_dma_ch, BCM_DMA_DREQ_EMMC, - BCM_DMA_SAME_ADDR, BCM_DMA_32BIT); + /* + * Peripherals on the AXI bus do not need DREQ pacing for reads + * from the ARM core, so we can safely set this to NONE. + */ + bcm_dma_setup_src(sc->sc_dma_ch, BCM_DMA_DREQ_NONE, + BCM_DMA_SAME_ADDR, BCM_DMA_32BIT); bcm_dma_setup_dst(sc->sc_dma_ch, BCM_DMA_DREQ_NONE, - BCM_DMA_INC_ADDR, - (len & 0xf) ? BCM_DMA_32BIT : BCM_DMA_128BIT); + BCM_DMA_INC_ADDR, width); psrc = sc->sc_sdhci_buffer_phys; pdst = sc->dmamap_seg_addrs[idx]; sync_op = BUS_DMASYNC_PREREAD; } else { + /* + * The ordering here is important, because the last write to + * dst/src in the dma control block writes the real dreq value. + */ bcm_dma_setup_src(sc->sc_dma_ch, BCM_DMA_DREQ_NONE, - BCM_DMA_INC_ADDR, - (len & 0xf) ? BCM_DMA_32BIT : BCM_DMA_128BIT); - bcm_dma_setup_dst(sc->sc_dma_ch, BCM_DMA_DREQ_EMMC, + BCM_DMA_INC_ADDR, width); + bcm_dma_setup_dst(sc->sc_dma_ch, sc->conf->emmc_dreq, BCM_DMA_SAME_ADDR, BCM_DMA_32BIT); psrc = sc->dmamap_seg_addrs[idx]; pdst = sc->sc_sdhci_buffer_phys; sync_op = BUS_DMASYNC_PREWRITE; } /* * When starting a new DMA operation do the busdma sync operation, and * disable SDCHI data interrrupts because we'll be driven by DMA * interrupts (or SDHCI error interrupts) until the IO is done. */ if (idx == 0) { bus_dmamap_sync(sc->sc_dma_tag, sc->sc_dma_map, sync_op); - slot->intmask &= ~(SDHCI_INT_DATA_AVAIL | - SDHCI_INT_SPACE_AVAIL | SDHCI_INT_DATA_END); - bcm_sdhci_write_4(sc->sc_dev, &sc->sc_slot, SDHCI_SIGNAL_ENABLE, + + slot->intmask &= ~DATA_XFER_MASK; + bcm_sdhci_write_4(sc->sc_dev, slot, SDHCI_SIGNAL_ENABLE, slot->intmask); } /* * Start the DMA transfer. Only programming errors (like failing to * allocate a channel) cause a non-zero return from bcm_dma_start(). */ err = bcm_dma_start(sc->sc_dma_ch, psrc, pdst, len); KASSERT((err == 0), ("bcm2835_sdhci: failed DMA start")); } static void +bcm_sdhci_dma_exit(struct bcm_sdhci_softc *sc) +{ + struct sdhci_slot *slot = &sc->sc_slot; + + mtx_assert(&slot->mtx, MA_OWNED); + + /* Re-enable interrupts */ + slot->intmask |= DATA_XFER_MASK; + bcm_sdhci_write_4(slot->bus, slot, SDHCI_SIGNAL_ENABLE, + slot->intmask); +} + +static void +bcm_sdhci_dma_unload(struct bcm_sdhci_softc *sc) +{ + struct sdhci_slot *slot = &sc->sc_slot; + + if (sc->dmamap_seg_count == 0) + return; + if ((slot->curcmd->data->flags & MMC_DATA_READ) != 0) + bus_dmamap_sync(sc->sc_dma_tag, sc->sc_dma_map, + BUS_DMASYNC_POSTREAD); + else + bus_dmamap_sync(sc->sc_dma_tag, sc->sc_dma_map, + BUS_DMASYNC_POSTWRITE); + bus_dmamap_unload(sc->sc_dma_tag, sc->sc_dma_map); + + sc->dmamap_seg_count = 0; + sc->dmamap_seg_index = 0; +} + +static void bcm_sdhci_dma_intr(int ch, void *arg) { struct bcm_sdhci_softc *sc = (struct bcm_sdhci_softc *)arg; struct sdhci_slot *slot = &sc->sc_slot; - uint32_t reg, mask; - int left, sync_op; + uint32_t reg; mtx_lock(&slot->mtx); - + if (slot->curcmd == NULL) + goto out; /* * If there are more segments for the current dma, start the next one. * Otherwise unload the dma map and decide what to do next based on the * status of the sdhci controller and whether there's more data left. */ if (sc->dmamap_seg_index < sc->dmamap_seg_count) { bcm_sdhci_start_dma_seg(sc); - mtx_unlock(&slot->mtx); - return; + goto out; } - if (slot->curcmd->data->flags & MMC_DATA_READ) { - sync_op = BUS_DMASYNC_POSTREAD; - mask = SDHCI_INT_DATA_AVAIL; - } else { - sync_op = BUS_DMASYNC_POSTWRITE; - mask = SDHCI_INT_SPACE_AVAIL; - } - bus_dmamap_sync(sc->sc_dma_tag, sc->sc_dma_map, sync_op); - bus_dmamap_unload(sc->sc_dma_tag, sc->sc_dma_map); + bcm_sdhci_dma_unload(sc); - sc->dmamap_seg_count = 0; - sc->dmamap_seg_index = 0; + /* + * If we had no further segments pending, we need to determine how to + * proceed next. If the 'data/space pending' bit is already set and we + * can continue via DMA, do so. Otherwise, re-enable interrupts and + * return. + */ + reg = bcm_sdhci_read_4(slot->bus, slot, SDHCI_INT_STATUS) & + DATA_XFER_MASK; + if ((reg & DATA_PENDING_MASK) != 0 && + BCM_SDHCI_SEGSZ_LEFT(slot) >= BCM_SDHCI_BUFFER_SIZE) { + /* ACK any pending interrupts */ + bcm_sdhci_write_4(slot->bus, slot, SDHCI_INT_STATUS, + DATA_PENDING_MASK); - left = min(BCM_SDHCI_BUFFER_SIZE, - slot->curcmd->data->len - slot->offset); - - /* DATA END? */ - reg = bcm_sdhci_read_4(slot->bus, slot, SDHCI_INT_STATUS); - - if (reg & SDHCI_INT_DATA_END) { - /* ACK for all outstanding interrupts */ - bcm_sdhci_write_4(slot->bus, slot, SDHCI_INT_STATUS, reg); - - /* enable INT */ - slot->intmask |= SDHCI_INT_DATA_AVAIL | SDHCI_INT_SPACE_AVAIL - | SDHCI_INT_DATA_END; - bcm_sdhci_write_4(slot->bus, slot, SDHCI_SIGNAL_ENABLE, - slot->intmask); - - /* finish this data */ - sdhci_finish_data(slot); - } - else { - /* already available? */ - if (reg & mask) { - - /* ACK for DATA_AVAIL or SPACE_AVAIL */ - bcm_sdhci_write_4(slot->bus, slot, - SDHCI_INT_STATUS, mask); - - /* continue next DMA transfer */ - if (bus_dmamap_load(sc->sc_dma_tag, sc->sc_dma_map, - (uint8_t *)slot->curcmd->data->data + - slot->offset, left, bcm_sdhci_dmacb, sc, - BUS_DMA_NOWAIT) != 0 || sc->dmamap_status != 0) { - slot->curcmd->error = MMC_ERR_NO_MEMORY; - sdhci_finish_data(slot); - } else { - bcm_sdhci_start_dma_seg(sc); - } - } else { - /* wait for next data by INT */ - - /* enable INT */ - slot->intmask |= SDHCI_INT_DATA_AVAIL | - SDHCI_INT_SPACE_AVAIL | SDHCI_INT_DATA_END; - bcm_sdhci_write_4(slot->bus, slot, SDHCI_SIGNAL_ENABLE, - slot->intmask); + bcm_sdhci_start_dma(slot); + if (slot->curcmd->error != 0) { + /* We won't recover from this error for this command. */ + bcm_sdhci_dma_unload(sc); + bcm_sdhci_dma_exit(sc); + sdhci_finish_data(slot); } + } else if ((reg & SDHCI_INT_DATA_END) != 0) { + bcm_sdhci_dma_exit(sc); + bcm_sdhci_write_4(slot->bus, slot, SDHCI_INT_STATUS, + reg); + slot->flags &= ~PLATFORM_DATA_STARTED; + sdhci_finish_data(slot); + } else { + bcm_sdhci_dma_exit(sc); } - +out: mtx_unlock(&slot->mtx); } static void -bcm_sdhci_read_dma(device_t dev, struct sdhci_slot *slot) +bcm_sdhci_start_dma(struct sdhci_slot *slot) { struct bcm_sdhci_softc *sc = device_get_softc(slot->bus); + uint8_t *buf; size_t left; - if (sc->dmamap_seg_count != 0) { - device_printf(sc->sc_dev, "DMA in use\n"); - return; - } + mtx_assert(&slot->mtx, MA_OWNED); - left = min(BCM_SDHCI_BUFFER_SIZE, - slot->curcmd->data->len - slot->offset); + left = BCM_SDHCI_SEGSZ_LEFT(slot); + buf = (uint8_t *)slot->curcmd->data->data + slot->offset; + KASSERT(left != 0, + ("%s: DMA handling incorrectly indicated", __func__)); - KASSERT((left & 3) == 0, - ("%s: len = %zu, not word-aligned", __func__, left)); - - if (bus_dmamap_load(sc->sc_dma_tag, sc->sc_dma_map, - (uint8_t *)slot->curcmd->data->data + slot->offset, left, + /* + * No need to check segment count here; if we've not yet unloaded + * previous segments, we'll catch that in bcm_sdhci_dmacb. + */ + if (bus_dmamap_load(sc->sc_dma_tag, sc->sc_dma_map, buf, left, bcm_sdhci_dmacb, sc, BUS_DMA_NOWAIT) != 0 || sc->dmamap_status != 0) { slot->curcmd->error = MMC_ERR_NO_MEMORY; return; } /* DMA start */ bcm_sdhci_start_dma_seg(sc); } -static void -bcm_sdhci_write_dma(device_t dev, struct sdhci_slot *slot) -{ - struct bcm_sdhci_softc *sc = device_get_softc(slot->bus); - size_t left; - - if (sc->dmamap_seg_count != 0) { - device_printf(sc->sc_dev, "DMA in use\n"); - return; - } - - left = min(BCM_SDHCI_BUFFER_SIZE, - slot->curcmd->data->len - slot->offset); - - KASSERT((left & 3) == 0, - ("%s: len = %zu, not word-aligned", __func__, left)); - - if (bus_dmamap_load(sc->sc_dma_tag, sc->sc_dma_map, - (uint8_t *)slot->curcmd->data->data + slot->offset, left, - bcm_sdhci_dmacb, sc, BUS_DMA_NOWAIT) != 0 || - sc->dmamap_status != 0) { - slot->curcmd->error = MMC_ERR_NO_MEMORY; - return; - } - - /* DMA start */ - bcm_sdhci_start_dma_seg(sc); -} - static int bcm_sdhci_will_handle_transfer(device_t dev, struct sdhci_slot *slot) { - size_t left; +#ifdef INVARIANTS + struct bcm_sdhci_softc *sc = device_get_softc(slot->bus); +#endif /* - * Do not use DMA for transfers less than block size or with a length - * that is not a multiple of four. + * This indicates that we somehow let a data interrupt slip by into the + * SDHCI framework, when it should not have. This really needs to be + * caught and fixed ASAP, as it really shouldn't happen. */ - left = min(BCM_DMA_BLOCK_SIZE, - slot->curcmd->data->len - slot->offset); - if (left < BCM_DMA_BLOCK_SIZE) + KASSERT(sc->dmamap_seg_count == 0, + ("data pending interrupt pushed through SDHCI framework")); + + /* + * Do not use DMA for transfers less than our block size. Checking + * alignment serves little benefit, as we round transfer sizes down to + * a multiple of the block size and push the transfer back to + * SDHCI-driven PIO once we're below the block size. + */ + if (BCM_SDHCI_SEGSZ_LEFT(slot) < BCM_DMA_BLOCK_SIZE) return (0); - if (left & 0x03) - return (0); return (1); } static void bcm_sdhci_start_transfer(device_t dev, struct sdhci_slot *slot, uint32_t *intmask) { /* DMA transfer FIFO 1KB */ - if (slot->curcmd->data->flags & MMC_DATA_READ) - bcm_sdhci_read_dma(dev, slot); - else - bcm_sdhci_write_dma(dev, slot); + bcm_sdhci_start_dma(slot); } static void bcm_sdhci_finish_transfer(device_t dev, struct sdhci_slot *slot) { + struct bcm_sdhci_softc *sc = device_get_softc(slot->bus); + /* + * Clean up. Interrupts are clearly enabled, because we received an + * SDHCI_INT_DATA_END to get this far -- just make sure we don't leave + * anything laying around. + */ + if (sc->dmamap_seg_count != 0) { + /* + * Our segment math should have worked out such that we would + * never finish the transfer without having used up all of the + * segments. If we haven't, that means we must have erroneously + * regressed to SDHCI-driven PIO to finish the operation and + * this is certainly caused by developer-error. + */ + bcm_sdhci_dma_unload(sc); + } + sdhci_finish_data(slot); } static device_method_t bcm_sdhci_methods[] = { /* Device interface */ DEVMETHOD(device_probe, bcm_sdhci_probe), DEVMETHOD(device_attach, bcm_sdhci_attach), DEVMETHOD(device_detach, bcm_sdhci_detach), /* Bus interface */ DEVMETHOD(bus_read_ivar, sdhci_generic_read_ivar), DEVMETHOD(bus_write_ivar, sdhci_generic_write_ivar), /* MMC bridge interface */ DEVMETHOD(mmcbr_update_ios, sdhci_generic_update_ios), DEVMETHOD(mmcbr_request, sdhci_generic_request), DEVMETHOD(mmcbr_get_ro, bcm_sdhci_get_ro), DEVMETHOD(mmcbr_acquire_host, sdhci_generic_acquire_host), DEVMETHOD(mmcbr_release_host, sdhci_generic_release_host), /* Platform transfer methods */ DEVMETHOD(sdhci_platform_will_handle, bcm_sdhci_will_handle_transfer), DEVMETHOD(sdhci_platform_start_transfer, bcm_sdhci_start_transfer), DEVMETHOD(sdhci_platform_finish_transfer, bcm_sdhci_finish_transfer), /* SDHCI registers accessors */ DEVMETHOD(sdhci_read_1, bcm_sdhci_read_1), DEVMETHOD(sdhci_read_2, bcm_sdhci_read_2), DEVMETHOD(sdhci_read_4, bcm_sdhci_read_4), DEVMETHOD(sdhci_read_multi_4, bcm_sdhci_read_multi_4), DEVMETHOD(sdhci_write_1, bcm_sdhci_write_1), DEVMETHOD(sdhci_write_2, bcm_sdhci_write_2), DEVMETHOD(sdhci_write_4, bcm_sdhci_write_4), DEVMETHOD(sdhci_write_multi_4, bcm_sdhci_write_multi_4), DEVMETHOD_END }; static devclass_t bcm_sdhci_devclass; static driver_t bcm_sdhci_driver = { "sdhci_bcm", bcm_sdhci_methods, sizeof(struct bcm_sdhci_softc), }; DRIVER_MODULE(sdhci_bcm, simplebus, bcm_sdhci_driver, bcm_sdhci_devclass, NULL, NULL); +#ifdef NOTYET +MODULE_DEPEND(sdhci_bcm, bcm2835_clkman, 1, 1, 1); +#endif SDHCI_DEPEND(sdhci_bcm); #ifndef MMCCAM MMC_DECLARE_BRIDGE(sdhci_bcm); #endif Index: stable/12/sys/arm/broadcom/bcm2835/bcm2835_vcbus.c =================================================================== --- stable/12/sys/arm/broadcom/bcm2835/bcm2835_vcbus.c (nonexistent) +++ stable/12/sys/arm/broadcom/bcm2835/bcm2835_vcbus.c (revision 355665) @@ -0,0 +1,286 @@ +/*- + * SPDX-License-Identifier: BSD-2-Clause-FreeBSD + * + * Copyright (c) 2019 Kyle Evans + * + * 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. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``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 THE AUTHOR OR CONTRIBUTORS 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$ + */ + +#include +__FBSDID("$FreeBSD$"); + +/* + * This file contains facilities for runtime determination of address space + * mappings for use in DMA/mailbox interactions. This is only used for the + * arm64 SoC because the 32-bit SoC used the same mappings. + */ +#if defined (__aarch64__) +#include "opt_soc.h" +#endif + +#include +#include + +#include +#include +#include + +#include + +#include + +/* + * This structure describes mappings that need to take place when transforming + * ARM core addresses into vcbus addresses for use with the DMA/mailbox + * interfaces. Currently, we only deal with peripheral/SDRAM address spaces + * here. + * + * The SDRAM address space is consistently mapped starting at 0 and extends to + * the size of the installed SDRAM. + * + * Peripherals are mapped further up at spots that vary per-SOC. + */ +struct bcm283x_memory_mapping { + vm_paddr_t armc_start; + vm_paddr_t armc_size; + vm_paddr_t vcbus_start; +}; + +#ifdef SOC_BCM2835 +static struct bcm283x_memory_mapping bcm2835_memmap[] = { + { + /* SDRAM */ + .armc_start = 0x00000000, + .armc_size = BCM2835_ARM_IO_BASE, + .vcbus_start = BCM2835_VCBUS_SDRAM_BASE, + }, + { + /* Peripherals */ + .armc_start = BCM2835_ARM_IO_BASE, + .armc_size = BCM28XX_ARM_IO_SIZE, + .vcbus_start = BCM2835_VCBUS_IO_BASE, + }, + { 0, 0, 0 }, +}; +#endif + +#ifdef SOC_BCM2836 +static struct bcm283x_memory_mapping bcm2836_memmap[] = { + { + /* SDRAM */ + .armc_start = 0x00000000, + .armc_size = BCM2836_ARM_IO_BASE, + .vcbus_start = BCM2836_VCBUS_SDRAM_BASE, + }, + { + /* Peripherals */ + .armc_start = BCM2836_ARM_IO_BASE, + .armc_size = BCM28XX_ARM_IO_SIZE, + .vcbus_start = BCM2836_VCBUS_IO_BASE, + }, + { 0, 0, 0 }, +}; +#endif + +#ifdef SOC_BRCM_BCM2837 +static struct bcm283x_memory_mapping bcm2837_memmap[] = { + { + /* SDRAM */ + .armc_start = 0x00000000, + .armc_size = BCM2837_ARM_IO_BASE, + .vcbus_start = BCM2837_VCBUS_SDRAM_BASE, + }, + { + /* Peripherals */ + .armc_start = BCM2837_ARM_IO_BASE, + .armc_size = BCM28XX_ARM_IO_SIZE, + .vcbus_start = BCM2837_VCBUS_IO_BASE, + }, + { 0, 0, 0 }, +}; +#endif + +#ifdef SOC_BRCM_BCM2838 + +/* + * The BCM2838 supports up to 4GB of SDRAM, but unfortunately we can still only + * map the first 1GB into the "legacy master view" (vcbus) address space. Thus, + * peripherals can still only access the lower end of SDRAM. For this reason, + * we also capture the main-peripheral busdma restriction below. + */ +static struct bcm283x_memory_mapping bcm2838_memmap[] = { + { + /* SDRAM */ + .armc_start = 0x00000000, + .armc_size = 0x40000000, + .vcbus_start = BCM2838_VCBUS_SDRAM_BASE, + }, + { + /* Main peripherals */ + .armc_start = BCM2838_ARM_IO_BASE, + .armc_size = BCM28XX_ARM_IO_SIZE, + .vcbus_start = BCM2838_VCBUS_IO_BASE, + }, + { 0, 0, 0 }, +}; +#endif + +static struct bcm283x_memory_soc_cfg { + struct bcm283x_memory_mapping *memmap; + const char *soc_compat; + bus_addr_t busdma_lowaddr; +} bcm283x_memory_configs[] = { +#ifdef SOC_BCM2835 + { + .memmap = bcm2835_memmap, + .soc_compat = "brcm,bcm2835", + .busdma_lowaddr = BUS_SPACE_MAXADDR_32BIT, + }, +#endif +#ifdef SOC_BCM2836 + { + .memmap = bcm2836_memmap, + .soc_compat = "brcm,bcm2836", + .busdma_lowaddr = BUS_SPACE_MAXADDR_32BIT, + }, + +#endif +#ifdef SOC_BRCM_BCM2837 + { + .memmap = bcm2837_memmap, + .soc_compat = "brcm,bcm2837", + .busdma_lowaddr = BUS_SPACE_MAXADDR_32BIT, + }, +#endif +#ifdef SOC_BRCM_BCM2838 + { + .memmap = bcm2838_memmap, + .soc_compat = "brcm,bcm2711", + .busdma_lowaddr = BCM2838_PERIPH_MAXADDR, + }, + { + .memmap = bcm2838_memmap, + .soc_compat = "brcm,bcm2838", + .busdma_lowaddr = BCM2838_PERIPH_MAXADDR, + }, +#endif +}; + +static struct bcm283x_memory_soc_cfg *booted_soc_memcfg; + +static struct bcm283x_memory_soc_cfg * +bcm283x_get_current_memcfg(void) +{ + phandle_t root; + int i; + + /* We'll cache it once we decide, because it won't change per-boot. */ + if (booted_soc_memcfg != NULL) + return (booted_soc_memcfg); + + KASSERT(nitems(bcm283x_memory_configs) != 0, + ("No SOC memory configurations enabled!")); + + root = OF_finddevice("/"); + for (i = 0; i < nitems(bcm283x_memory_configs); ++i) { + booted_soc_memcfg = &bcm283x_memory_configs[i]; + printf("Checking root against %s\n", + booted_soc_memcfg->soc_compat); + if (ofw_bus_node_is_compatible(root, + booted_soc_memcfg->soc_compat)) + return (booted_soc_memcfg); + } + + /* + * The kernel doesn't fit the board; we can't really make a reasonable + * guess, as these SOC are different enough that something will blow up + * later. + */ + panic("No suitable SOC memory configuration found."); +} + +#define BCM283X_MEMMAP_ISTERM(ent) \ + ((ent)->armc_start == 0 && (ent)->armc_size == 0 && \ + (ent)->vcbus_start == 0) + +vm_paddr_t +bcm283x_armc_to_vcbus(vm_paddr_t pa) +{ + struct bcm283x_memory_soc_cfg *cfg; + struct bcm283x_memory_mapping *map, *ment; + + /* Guaranteed not NULL if we haven't panicked yet. */ + cfg = bcm283x_get_current_memcfg(); + map = cfg->memmap; + for (ment = map; !BCM283X_MEMMAP_ISTERM(ment); ++ment) { + if (pa >= ment->armc_start && + pa < ment->armc_start + ment->armc_size) { + return (pa - ment->armc_start) + ment->vcbus_start; + } + } + + /* + * Assume 1:1 mapping for anything else, but complain about it on + * verbose boots. + */ + if (bootverbose) + printf("bcm283x_vcbus: No armc -> vcbus mapping found: %jx\n", + (uintmax_t)pa); + return (pa); +} + +vm_paddr_t +bcm283x_vcbus_to_armc(vm_paddr_t vca) +{ + struct bcm283x_memory_soc_cfg *cfg; + struct bcm283x_memory_mapping *map, *ment; + + /* Guaranteed not NULL if we haven't panicked yet. */ + cfg = bcm283x_get_current_memcfg(); + map = cfg->memmap; + for (ment = map; !BCM283X_MEMMAP_ISTERM(ment); ++ment) { + if (vca >= ment->vcbus_start && + vca < ment->vcbus_start + ment->armc_size) { + return (vca - ment->vcbus_start) + ment->armc_start; + } + } + + /* + * Assume 1:1 mapping for anything else, but complain about it on + * verbose boots. + */ + if (bootverbose) + printf("bcm283x_vcbus: No vcbus -> armc mapping found: %jx\n", + (uintmax_t)vca); + return (vca); +} + +bus_addr_t +bcm283x_dmabus_peripheral_lowaddr(void) +{ + struct bcm283x_memory_soc_cfg *cfg; + + cfg = bcm283x_get_current_memcfg(); + return (cfg->busdma_lowaddr); +} Property changes on: stable/12/sys/arm/broadcom/bcm2835/bcm2835_vcbus.c ___________________________________________________________________ Added: svn:eol-style ## -0,0 +1 ## +native \ No newline at end of property Added: svn:keywords ## -0,0 +1 ## +FreeBSD=%H \ No newline at end of property Added: svn:mime-type ## -0,0 +1 ## +text/plain \ No newline at end of property Index: stable/12/sys/arm/broadcom/bcm2835/bcm2835_vcbus.h =================================================================== --- stable/12/sys/arm/broadcom/bcm2835/bcm2835_vcbus.h (revision 355664) +++ stable/12/sys/arm/broadcom/bcm2835/bcm2835_vcbus.h (revision 355665) @@ -1,81 +1,81 @@ /*- * SPDX-License-Identifier: BSD-2-Clause-FreeBSD * * Copyright (c) 2012 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. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``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 THE AUTHOR OR CONTRIBUTORS 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$ */ /* * Defines for converting physical address to VideoCore bus address and back */ #ifndef _BCM2835_VCBUS_H_ #define _BCM2835_VCBUS_H_ -/* - * ARM64 define its SOC options in opt_soc.h - */ -#if defined(__aarch64__) -#include "opt_soc.h" -#endif - #define BCM2835_VCBUS_SDRAM_CACHED 0x40000000 -#define BCM2835_VCBUS_IO_BASE 0x7E000000 #define BCM2835_VCBUS_SDRAM_UNCACHED 0xC0000000 -#if defined(SOC_BCM2835) #define BCM2835_ARM_IO_BASE 0x20000000 +#define BCM2835_VCBUS_IO_BASE 0x7E000000 #define BCM2835_VCBUS_SDRAM_BASE BCM2835_VCBUS_SDRAM_CACHED -#else -#define BCM2835_ARM_IO_BASE 0x3f000000 -#define BCM2835_VCBUS_SDRAM_BASE BCM2835_VCBUS_SDRAM_UNCACHED -#endif -#define BCM2835_ARM_IO_SIZE 0x01000000 -/* - * Convert physical address to VC bus address. Should be used - * when submitting address over mailbox interface - */ -#define PHYS_TO_VCBUS(pa) ((pa) + BCM2835_VCBUS_SDRAM_BASE) +#define BCM2836_ARM_IO_BASE 0x3f000000 +#define BCM2836_VCBUS_IO_BASE BCM2835_VCBUS_IO_BASE +#define BCM2836_VCBUS_SDRAM_BASE BCM2835_VCBUS_SDRAM_UNCACHED -/* Check whether pa bellong top IO window */ -#define BCM2835_ARM_IS_IO(pa) (((pa) >= BCM2835_ARM_IO_BASE) && \ - ((pa) < BCM2835_ARM_IO_BASE + BCM2835_ARM_IO_SIZE)) +#define BCM2837_ARM_IO_BASE BCM2836_ARM_IO_BASE +#define BCM2837_VCBUS_IO_BASE BCM2835_VCBUS_IO_BASE +#define BCM2837_VCBUS_SDRAM_BASE BCM2835_VCBUS_SDRAM_UNCACHED -/* - * Convert physical address in IO space to VC bus address. - */ -#define IO_TO_VCBUS(pa) ((pa - BCM2835_ARM_IO_BASE) + \ - BCM2835_VCBUS_IO_BASE) +#define BCM2838_ARM_IO_BASE 0xfe000000 +#define BCM2838_VCBUS_IO_BASE BCM2835_VCBUS_IO_BASE +#define BCM2838_VCBUS_SDRAM_BASE BCM2835_VCBUS_SDRAM_UNCACHED /* - * Convert address from VC bus space to physical. Should be used - * when address is returned by VC over mailbox interface. e.g. - * framebuffer base + * Max allowed SDRAM mapping for most peripherals. The Raspberry Pi 4 has more + * than 1 GB of SDRAM, but only the lowest 1 GB is mapped into the "Legacy + * Master view" of the address space accessible by the DMA engine. Technically, + * we can slide this window around to whatever similarly sized range is + * convenient, but this is the most useful window given how busdma(9) works and + * that the window must be reconfigured for all channels in a given DMA engine. + * The DMA lite engine's window can be configured separately from the 30-bit DMA + * engine. */ -#define VCBUS_TO_PHYS(vca) ((vca) & ~(BCM2835_VCBUS_SDRAM_BASE)) +#define BCM2838_PERIPH_MAXADDR 0x3fffffff + +#define BCM28XX_ARM_IO_SIZE 0x01000000 + +vm_paddr_t bcm283x_armc_to_vcbus(vm_paddr_t pa); +vm_paddr_t bcm283x_vcbus_to_armc(vm_paddr_t vca); +bus_addr_t bcm283x_dmabus_peripheral_lowaddr(void); + +#define ARMC_TO_VCBUS(pa) bcm283x_armc_to_vcbus(pa) +#define VCBUS_TO_ARMC(vca) bcm283x_vcbus_to_armc(vca) + +/* Compatibility name for vchiq arm interface. */ +#define PHYS_TO_VCBUS ARMC_TO_VCBUS #endif /* _BCM2835_VCBUS_H_ */ Index: stable/12/sys/arm/broadcom/bcm2835/bcm2836.c =================================================================== --- stable/12/sys/arm/broadcom/bcm2835/bcm2836.c (revision 355664) +++ stable/12/sys/arm/broadcom/bcm2835/bcm2836.c (revision 355665) @@ -1,741 +1,743 @@ /* * Copyright 2015 Andrew Turner. * Copyright 2016 Svatopluk Kraus * 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. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``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 THE AUTHOR OR CONTRIBUTORS 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. */ #include __FBSDID("$FreeBSD$"); #include "opt_platform.h" #include #include #include #include #include #include #include #include #ifdef SMP #include #endif #include #include #include #ifdef SMP #include #endif #include #include #include "pic_if.h" #define BCM_LINTC_CONTROL_REG 0x00 #define BCM_LINTC_PRESCALER_REG 0x08 #define BCM_LINTC_GPU_ROUTING_REG 0x0c #define BCM_LINTC_PMU_ROUTING_SET_REG 0x10 #define BCM_LINTC_PMU_ROUTING_CLR_REG 0x14 #define BCM_LINTC_TIMER_CFG_REG(n) (0x40 + (n) * 4) #define BCM_LINTC_MBOX_CFG_REG(n) (0x50 + (n) * 4) #define BCM_LINTC_PENDING_REG(n) (0x60 + (n) * 4) #define BCM_LINTC_MBOX0_SET_REG(n) (0x80 + (n) * 16) #define BCM_LINTC_MBOX1_SET_REG(n) (0x84 + (n) * 16) #define BCM_LINTC_MBOX2_SET_REG(n) (0x88 + (n) * 16) #define BCM_LINTC_MBOX3_SET_REG(n) (0x8C + (n) * 16) #define BCM_LINTC_MBOX0_CLR_REG(n) (0xC0 + (n) * 16) #define BCM_LINTC_MBOX1_CLR_REG(n) (0xC4 + (n) * 16) #define BCM_LINTC_MBOX2_CLR_REG(n) (0xC8 + (n) * 16) #define BCM_LINTC_MBOX3_CLR_REG(n) (0xCC + (n) * 16) /* Prescaler Register */ #define BCM_LINTC_PSR_19_2 0x80000000 /* 19.2 MHz */ /* GPU Interrupt Routing Register */ #define BCM_LINTC_GIRR_IRQ_CORE(n) (n) #define BCM_LINTC_GIRR_FIQ_CORE(n) ((n) << 2) /* PMU Interrupt Routing Register */ #define BCM_LINTC_PIRR_IRQ_EN_CORE(n) (1 << (n)) #define BCM_LINTC_PIRR_FIQ_EN_CORE(n) (1 << ((n) + 4)) /* Timer Config Register */ #define BCM_LINTC_TCR_IRQ_EN_TIMER(n) (1 << (n)) #define BCM_LINTC_TCR_FIQ_EN_TIMER(n) (1 << ((n) + 4)) /* MBOX Config Register */ #define BCM_LINTC_MCR_IRQ_EN_MBOX(n) (1 << (n)) #define BCM_LINTC_MCR_FIQ_EN_MBOX(n) (1 << ((n) + 4)) #define BCM_LINTC_CNTPSIRQ_IRQ 0 #define BCM_LINTC_CNTPNSIRQ_IRQ 1 #define BCM_LINTC_CNTHPIRQ_IRQ 2 #define BCM_LINTC_CNTVIRQ_IRQ 3 #define BCM_LINTC_MBOX0_IRQ 4 #define BCM_LINTC_MBOX1_IRQ 5 #define BCM_LINTC_MBOX2_IRQ 6 #define BCM_LINTC_MBOX3_IRQ 7 #define BCM_LINTC_GPU_IRQ 8 #define BCM_LINTC_PMU_IRQ 9 #define BCM_LINTC_AXI_IRQ 10 #define BCM_LINTC_LTIMER_IRQ 11 #define BCM_LINTC_NIRQS 12 #define BCM_LINTC_TIMER0_IRQ BCM_LINTC_CNTPSIRQ_IRQ #define BCM_LINTC_TIMER1_IRQ BCM_LINTC_CNTPNSIRQ_IRQ #define BCM_LINTC_TIMER2_IRQ BCM_LINTC_CNTHPIRQ_IRQ #define BCM_LINTC_TIMER3_IRQ BCM_LINTC_CNTVIRQ_IRQ #define BCM_LINTC_TIMER0_IRQ_MASK (1 << BCM_LINTC_TIMER0_IRQ) #define BCM_LINTC_TIMER1_IRQ_MASK (1 << BCM_LINTC_TIMER1_IRQ) #define BCM_LINTC_TIMER2_IRQ_MASK (1 << BCM_LINTC_TIMER2_IRQ) #define BCM_LINTC_TIMER3_IRQ_MASK (1 << BCM_LINTC_TIMER3_IRQ) #define BCM_LINTC_MBOX0_IRQ_MASK (1 << BCM_LINTC_MBOX0_IRQ) #define BCM_LINTC_GPU_IRQ_MASK (1 << BCM_LINTC_GPU_IRQ) #define BCM_LINTC_PMU_IRQ_MASK (1 << BCM_LINTC_PMU_IRQ) #define BCM_LINTC_UP_PENDING_MASK \ (BCM_LINTC_TIMER0_IRQ_MASK | \ BCM_LINTC_TIMER1_IRQ_MASK | \ BCM_LINTC_TIMER2_IRQ_MASK | \ BCM_LINTC_TIMER3_IRQ_MASK | \ BCM_LINTC_GPU_IRQ_MASK | \ BCM_LINTC_PMU_IRQ_MASK) #define BCM_LINTC_SMP_PENDING_MASK \ (BCM_LINTC_UP_PENDING_MASK | \ BCM_LINTC_MBOX0_IRQ_MASK) #ifdef SMP #define BCM_LINTC_PENDING_MASK BCM_LINTC_SMP_PENDING_MASK #else #define BCM_LINTC_PENDING_MASK BCM_LINTC_UP_PENDING_MASK #endif struct bcm_lintc_irqsrc { struct intr_irqsrc bli_isrc; u_int bli_irq; union { u_int bli_mask; /* for timers */ u_int bli_value; /* for GPU */ }; }; struct bcm_lintc_softc { device_t bls_dev; struct mtx bls_mtx; struct resource * bls_mem; bus_space_tag_t bls_bst; bus_space_handle_t bls_bsh; struct bcm_lintc_irqsrc bls_isrcs[BCM_LINTC_NIRQS]; }; static struct bcm_lintc_softc *bcm_lintc_sc; #ifdef SMP #define BCM_LINTC_NIPIS 32 /* only mailbox 0 is used for IPI */ CTASSERT(INTR_IPI_COUNT <= BCM_LINTC_NIPIS); #endif #define BCM_LINTC_LOCK(sc) mtx_lock_spin(&(sc)->bls_mtx) #define BCM_LINTC_UNLOCK(sc) mtx_unlock_spin(&(sc)->bls_mtx) #define BCM_LINTC_LOCK_INIT(sc) mtx_init(&(sc)->bls_mtx, \ device_get_nameunit((sc)->bls_dev), "bmc_local_intc", MTX_SPIN) #define BCM_LINTC_LOCK_DESTROY(sc) mtx_destroy(&(sc)->bls_mtx) #define bcm_lintc_read_4(sc, reg) \ bus_space_read_4((sc)->bls_bst, (sc)->bls_bsh, (reg)) #define bcm_lintc_write_4(sc, reg, val) \ bus_space_write_4((sc)->bls_bst, (sc)->bls_bsh, (reg), (val)) static inline void bcm_lintc_rwreg_clr(struct bcm_lintc_softc *sc, uint32_t reg, uint32_t mask) { bcm_lintc_write_4(sc, reg, bcm_lintc_read_4(sc, reg) & ~mask); } static inline void bcm_lintc_rwreg_set(struct bcm_lintc_softc *sc, uint32_t reg, uint32_t mask) { bcm_lintc_write_4(sc, reg, bcm_lintc_read_4(sc, reg) | mask); } static void bcm_lintc_timer_mask(struct bcm_lintc_softc *sc, struct bcm_lintc_irqsrc *bli) { cpuset_t *cpus; uint32_t cpu; cpus = &bli->bli_isrc.isrc_cpu; BCM_LINTC_LOCK(sc); for (cpu = 0; cpu < 4; cpu++) if (CPU_ISSET(cpu, cpus)) bcm_lintc_rwreg_clr(sc, BCM_LINTC_TIMER_CFG_REG(cpu), bli->bli_mask); BCM_LINTC_UNLOCK(sc); } static void bcm_lintc_timer_unmask(struct bcm_lintc_softc *sc, struct bcm_lintc_irqsrc *bli) { cpuset_t *cpus; uint32_t cpu; cpus = &bli->bli_isrc.isrc_cpu; BCM_LINTC_LOCK(sc); for (cpu = 0; cpu < 4; cpu++) if (CPU_ISSET(cpu, cpus)) bcm_lintc_rwreg_set(sc, BCM_LINTC_TIMER_CFG_REG(cpu), bli->bli_mask); BCM_LINTC_UNLOCK(sc); } static inline void bcm_lintc_gpu_mask(struct bcm_lintc_softc *sc, struct bcm_lintc_irqsrc *bli) { /* It's accessed just and only by one core. */ bcm_lintc_write_4(sc, BCM_LINTC_GPU_ROUTING_REG, 0); } static inline void bcm_lintc_gpu_unmask(struct bcm_lintc_softc *sc, struct bcm_lintc_irqsrc *bli) { /* It's accessed just and only by one core. */ bcm_lintc_write_4(sc, BCM_LINTC_GPU_ROUTING_REG, bli->bli_value); } static inline void bcm_lintc_pmu_mask(struct bcm_lintc_softc *sc, struct bcm_lintc_irqsrc *bli) { cpuset_t *cpus; uint32_t cpu, mask; mask = 0; cpus = &bli->bli_isrc.isrc_cpu; BCM_LINTC_LOCK(sc); for (cpu = 0; cpu < 4; cpu++) if (CPU_ISSET(cpu, cpus)) mask |= BCM_LINTC_PIRR_IRQ_EN_CORE(cpu); /* Write-clear register. */ bcm_lintc_write_4(sc, BCM_LINTC_PMU_ROUTING_CLR_REG, mask); BCM_LINTC_UNLOCK(sc); } static inline void bcm_lintc_pmu_unmask(struct bcm_lintc_softc *sc, struct bcm_lintc_irqsrc *bli) { cpuset_t *cpus; uint32_t cpu, mask; mask = 0; cpus = &bli->bli_isrc.isrc_cpu; BCM_LINTC_LOCK(sc); for (cpu = 0; cpu < 4; cpu++) if (CPU_ISSET(cpu, cpus)) mask |= BCM_LINTC_PIRR_IRQ_EN_CORE(cpu); /* Write-set register. */ bcm_lintc_write_4(sc, BCM_LINTC_PMU_ROUTING_SET_REG, mask); BCM_LINTC_UNLOCK(sc); } static void bcm_lintc_mask(struct bcm_lintc_softc *sc, struct bcm_lintc_irqsrc *bli) { switch (bli->bli_irq) { case BCM_LINTC_TIMER0_IRQ: case BCM_LINTC_TIMER1_IRQ: case BCM_LINTC_TIMER2_IRQ: case BCM_LINTC_TIMER3_IRQ: bcm_lintc_timer_mask(sc, bli); return; case BCM_LINTC_MBOX0_IRQ: case BCM_LINTC_MBOX1_IRQ: case BCM_LINTC_MBOX2_IRQ: case BCM_LINTC_MBOX3_IRQ: return; case BCM_LINTC_GPU_IRQ: bcm_lintc_gpu_mask(sc, bli); return; case BCM_LINTC_PMU_IRQ: bcm_lintc_pmu_mask(sc, bli); return; default: panic("%s: not implemented for irq %u", __func__, bli->bli_irq); } } static void bcm_lintc_unmask(struct bcm_lintc_softc *sc, struct bcm_lintc_irqsrc *bli) { switch (bli->bli_irq) { case BCM_LINTC_TIMER0_IRQ: case BCM_LINTC_TIMER1_IRQ: case BCM_LINTC_TIMER2_IRQ: case BCM_LINTC_TIMER3_IRQ: bcm_lintc_timer_unmask(sc, bli); return; case BCM_LINTC_MBOX0_IRQ: case BCM_LINTC_MBOX1_IRQ: case BCM_LINTC_MBOX2_IRQ: case BCM_LINTC_MBOX3_IRQ: return; case BCM_LINTC_GPU_IRQ: bcm_lintc_gpu_unmask(sc, bli); return; case BCM_LINTC_PMU_IRQ: bcm_lintc_pmu_unmask(sc, bli); return; default: panic("%s: not implemented for irq %u", __func__, bli->bli_irq); } } #ifdef SMP static inline void bcm_lintc_ipi_write(struct bcm_lintc_softc *sc, cpuset_t cpus, u_int ipi) { u_int cpu; uint32_t mask; mask = 1 << ipi; for (cpu = 0; cpu < mp_ncpus; cpu++) if (CPU_ISSET(cpu, &cpus)) bcm_lintc_write_4(sc, BCM_LINTC_MBOX0_SET_REG(cpu), mask); } static inline void bcm_lintc_ipi_dispatch(struct bcm_lintc_softc *sc, u_int cpu, struct trapframe *tf) { u_int ipi; uint32_t mask; mask = bcm_lintc_read_4(sc, BCM_LINTC_MBOX0_CLR_REG(cpu)); if (mask == 0) { device_printf(sc->bls_dev, "Spurious ipi detected\n"); return; } for (ipi = 0; mask != 0; mask >>= 1, ipi++) { if ((mask & 0x01) == 0) continue; /* * Clear an IPI before dispatching to not miss anyone * and make sure that it's observed by everybody. */ bcm_lintc_write_4(sc, BCM_LINTC_MBOX0_CLR_REG(cpu), 1 << ipi); #if defined(__aarch64__) dsb(sy); #else dsb(); #endif intr_ipi_dispatch(ipi, tf); } } #endif static inline void bcm_lintc_irq_dispatch(struct bcm_lintc_softc *sc, u_int irq, struct trapframe *tf) { struct bcm_lintc_irqsrc *bli; bli = &sc->bls_isrcs[irq]; if (intr_isrc_dispatch(&bli->bli_isrc, tf) != 0) device_printf(sc->bls_dev, "Stray irq %u detected\n", irq); } static int bcm_lintc_intr(void *arg) { struct bcm_lintc_softc *sc; u_int cpu; uint32_t num, reg; struct trapframe *tf; sc = arg; cpu = PCPU_GET(cpuid); tf = curthread->td_intr_frame; for (num = 0; ; num++) { reg = bcm_lintc_read_4(sc, BCM_LINTC_PENDING_REG(cpu)); if ((reg & BCM_LINTC_PENDING_MASK) == 0) break; #ifdef SMP if (reg & BCM_LINTC_MBOX0_IRQ_MASK) bcm_lintc_ipi_dispatch(sc, cpu, tf); #endif if (reg & BCM_LINTC_TIMER0_IRQ_MASK) bcm_lintc_irq_dispatch(sc, BCM_LINTC_TIMER0_IRQ, tf); if (reg & BCM_LINTC_TIMER1_IRQ_MASK) bcm_lintc_irq_dispatch(sc, BCM_LINTC_TIMER1_IRQ, tf); if (reg & BCM_LINTC_TIMER2_IRQ_MASK) bcm_lintc_irq_dispatch(sc, BCM_LINTC_TIMER2_IRQ, tf); if (reg & BCM_LINTC_TIMER3_IRQ_MASK) bcm_lintc_irq_dispatch(sc, BCM_LINTC_TIMER3_IRQ, tf); if (reg & BCM_LINTC_GPU_IRQ_MASK) bcm_lintc_irq_dispatch(sc, BCM_LINTC_GPU_IRQ, tf); if (reg & BCM_LINTC_PMU_IRQ_MASK) bcm_lintc_irq_dispatch(sc, BCM_LINTC_PMU_IRQ, tf); arm_irq_memory_barrier(0); /* XXX */ } reg &= ~BCM_LINTC_PENDING_MASK; if (reg != 0) device_printf(sc->bls_dev, "Unknown interrupt(s) %x\n", reg); else if (num == 0 && bootverbose) device_printf(sc->bls_dev, "Spurious interrupt detected\n"); return (FILTER_HANDLED); } static void bcm_lintc_disable_intr(device_t dev, struct intr_irqsrc *isrc) { bcm_lintc_mask(device_get_softc(dev), (struct bcm_lintc_irqsrc *)isrc); } static void bcm_lintc_enable_intr(device_t dev, struct intr_irqsrc *isrc) { struct bcm_lintc_irqsrc *bli = (struct bcm_lintc_irqsrc *)isrc; arm_irq_memory_barrier(bli->bli_irq); bcm_lintc_unmask(device_get_softc(dev), bli); } static int bcm_lintc_map_intr(device_t dev, struct intr_map_data *data, struct intr_irqsrc **isrcp) { struct intr_map_data_fdt *daf; struct bcm_lintc_softc *sc; if (data->type != INTR_MAP_DATA_FDT) return (ENOTSUP); daf = (struct intr_map_data_fdt *)data; if (daf->ncells > 2 || daf->cells[0] >= BCM_LINTC_NIRQS) return (EINVAL); /* TODO: handle IRQ type here */ sc = device_get_softc(dev); *isrcp = &sc->bls_isrcs[daf->cells[0]].bli_isrc; return (0); } static void bcm_lintc_pre_ithread(device_t dev, struct intr_irqsrc *isrc) { struct bcm_lintc_irqsrc *bli = (struct bcm_lintc_irqsrc *)isrc; if (bli->bli_irq == BCM_LINTC_GPU_IRQ) bcm_lintc_gpu_mask(device_get_softc(dev), bli); else { /* * Handler for PPI interrupt does not make sense much unless * there is one bound ithread for each core for it. Thus the * interrupt can be masked on current core only while ithread * bounded to this core ensures unmasking on the same core. */ panic ("%s: handlers are not supported", __func__); } } static void bcm_lintc_post_ithread(device_t dev, struct intr_irqsrc *isrc) { struct bcm_lintc_irqsrc *bli = (struct bcm_lintc_irqsrc *)isrc; if (bli->bli_irq == BCM_LINTC_GPU_IRQ) bcm_lintc_gpu_unmask(device_get_softc(dev), bli); else { /* See comment in bcm_lintc_pre_ithread(). */ panic ("%s: handlers are not supported", __func__); } } static void bcm_lintc_post_filter(device_t dev, struct intr_irqsrc *isrc) { } static int bcm_lintc_setup_intr(device_t dev, struct intr_irqsrc *isrc, struct resource *res, struct intr_map_data *data) { struct bcm_lintc_softc *sc; if (isrc->isrc_handlers == 0 && isrc->isrc_flags & INTR_ISRCF_PPI) { sc = device_get_softc(dev); BCM_LINTC_LOCK(sc); CPU_SET(PCPU_GET(cpuid), &isrc->isrc_cpu); BCM_LINTC_UNLOCK(sc); } return (0); } #ifdef SMP static void bcm_lintc_init_rwreg_on_ap(struct bcm_lintc_softc *sc, u_int cpu, u_int irq, uint32_t reg, uint32_t mask) { if (intr_isrc_init_on_cpu(&sc->bls_isrcs[irq].bli_isrc, cpu)) bcm_lintc_rwreg_set(sc, reg, mask); } static void bcm_lintc_init_pmu_on_ap(struct bcm_lintc_softc *sc, u_int cpu) { struct intr_irqsrc *isrc = &sc->bls_isrcs[BCM_LINTC_PMU_IRQ].bli_isrc; if (intr_isrc_init_on_cpu(isrc, cpu)) { /* Write-set register. */ bcm_lintc_write_4(sc, BCM_LINTC_PMU_ROUTING_SET_REG, BCM_LINTC_PIRR_IRQ_EN_CORE(cpu)); } } static void bcm_lintc_init_secondary(device_t dev) { u_int cpu; struct bcm_lintc_softc *sc; cpu = PCPU_GET(cpuid); sc = device_get_softc(dev); BCM_LINTC_LOCK(sc); bcm_lintc_init_rwreg_on_ap(sc, cpu, BCM_LINTC_TIMER0_IRQ, BCM_LINTC_TIMER_CFG_REG(cpu), BCM_LINTC_TCR_IRQ_EN_TIMER(0)); bcm_lintc_init_rwreg_on_ap(sc, cpu, BCM_LINTC_TIMER1_IRQ, BCM_LINTC_TIMER_CFG_REG(cpu), BCM_LINTC_TCR_IRQ_EN_TIMER(1)); bcm_lintc_init_rwreg_on_ap(sc, cpu, BCM_LINTC_TIMER2_IRQ, BCM_LINTC_TIMER_CFG_REG(cpu), BCM_LINTC_TCR_IRQ_EN_TIMER(2)); bcm_lintc_init_rwreg_on_ap(sc, cpu, BCM_LINTC_TIMER3_IRQ, BCM_LINTC_TIMER_CFG_REG(cpu), BCM_LINTC_TCR_IRQ_EN_TIMER(3)); bcm_lintc_init_pmu_on_ap(sc, cpu); BCM_LINTC_UNLOCK(sc); } static void bcm_lintc_ipi_send(device_t dev, struct intr_irqsrc *isrc, cpuset_t cpus, u_int ipi) { struct bcm_lintc_softc *sc = device_get_softc(dev); KASSERT(isrc == &sc->bls_isrcs[BCM_LINTC_MBOX0_IRQ].bli_isrc, ("%s: bad ISRC %p argument", __func__, isrc)); bcm_lintc_ipi_write(sc, cpus, ipi); } static int bcm_lintc_ipi_setup(device_t dev, u_int ipi, struct intr_irqsrc **isrcp) { struct bcm_lintc_softc *sc = device_get_softc(dev); KASSERT(ipi < BCM_LINTC_NIPIS, ("%s: too high ipi %u", __func__, ipi)); *isrcp = &sc->bls_isrcs[BCM_LINTC_MBOX0_IRQ].bli_isrc; return (0); } #endif static int bcm_lintc_pic_attach(struct bcm_lintc_softc *sc) { struct bcm_lintc_irqsrc *bisrcs; struct intr_pic *pic; int error; u_int flags; uint32_t irq; const char *name; intptr_t xref; bisrcs = sc->bls_isrcs; name = device_get_nameunit(sc->bls_dev); for (irq = 0; irq < BCM_LINTC_NIRQS; irq++) { bisrcs[irq].bli_irq = irq; switch (irq) { case BCM_LINTC_TIMER0_IRQ: bisrcs[irq].bli_mask = BCM_LINTC_TCR_IRQ_EN_TIMER(0); flags = INTR_ISRCF_PPI; break; case BCM_LINTC_TIMER1_IRQ: bisrcs[irq].bli_mask = BCM_LINTC_TCR_IRQ_EN_TIMER(1); flags = INTR_ISRCF_PPI; break; case BCM_LINTC_TIMER2_IRQ: bisrcs[irq].bli_mask = BCM_LINTC_TCR_IRQ_EN_TIMER(2); flags = INTR_ISRCF_PPI; break; case BCM_LINTC_TIMER3_IRQ: bisrcs[irq].bli_mask = BCM_LINTC_TCR_IRQ_EN_TIMER(3); flags = INTR_ISRCF_PPI; break; case BCM_LINTC_MBOX0_IRQ: case BCM_LINTC_MBOX1_IRQ: case BCM_LINTC_MBOX2_IRQ: case BCM_LINTC_MBOX3_IRQ: bisrcs[irq].bli_value = 0; /* not used */ flags = INTR_ISRCF_IPI; break; case BCM_LINTC_GPU_IRQ: bisrcs[irq].bli_value = BCM_LINTC_GIRR_IRQ_CORE(0); flags = 0; break; case BCM_LINTC_PMU_IRQ: bisrcs[irq].bli_value = 0; /* not used */ flags = INTR_ISRCF_PPI; break; default: bisrcs[irq].bli_value = 0; /* not used */ flags = 0; break; } error = intr_isrc_register(&bisrcs[irq].bli_isrc, sc->bls_dev, flags, "%s,%u", name, irq); if (error != 0) return (error); } xref = OF_xref_from_node(ofw_bus_get_node(sc->bls_dev)); pic = intr_pic_register(sc->bls_dev, xref); if (pic == NULL) return (ENXIO); return (intr_pic_claim_root(sc->bls_dev, xref, bcm_lintc_intr, sc, 0)); } static int bcm_lintc_probe(device_t dev) { if (!ofw_bus_status_okay(dev)) return (ENXIO); if (!ofw_bus_is_compatible(dev, "brcm,bcm2836-l1-intc")) return (ENXIO); + if (!ofw_bus_has_prop(dev, "interrupt-controller")) + return (ENXIO); device_set_desc(dev, "BCM2836 Interrupt Controller"); return (BUS_PROBE_DEFAULT); } static int bcm_lintc_attach(device_t dev) { struct bcm_lintc_softc *sc; int cpu, rid; sc = device_get_softc(dev); sc->bls_dev = dev; if (bcm_lintc_sc != NULL) return (ENXIO); rid = 0; sc->bls_mem = bus_alloc_resource_any(dev, SYS_RES_MEMORY, &rid, RF_ACTIVE); if (sc->bls_mem == NULL) { device_printf(dev, "could not allocate memory resource\n"); return (ENXIO); } sc->bls_bst = rman_get_bustag(sc->bls_mem); sc->bls_bsh = rman_get_bushandle(sc->bls_mem); bcm_lintc_write_4(sc, BCM_LINTC_CONTROL_REG, 0); bcm_lintc_write_4(sc, BCM_LINTC_PRESCALER_REG, BCM_LINTC_PSR_19_2); /* Disable all timers on all cores. */ for (cpu = 0; cpu < 4; cpu++) bcm_lintc_write_4(sc, BCM_LINTC_TIMER_CFG_REG(cpu), 0); #ifdef SMP /* Enable mailbox 0 on all cores used for IPI. */ for (cpu = 0; cpu < 4; cpu++) bcm_lintc_write_4(sc, BCM_LINTC_MBOX_CFG_REG(cpu), BCM_LINTC_MCR_IRQ_EN_MBOX(0)); #endif if (bcm_lintc_pic_attach(sc) != 0) { device_printf(dev, "could not attach PIC\n"); return (ENXIO); } BCM_LINTC_LOCK_INIT(sc); bcm_lintc_sc = sc; return (0); } static device_method_t bcm_lintc_methods[] = { DEVMETHOD(device_probe, bcm_lintc_probe), DEVMETHOD(device_attach, bcm_lintc_attach), DEVMETHOD(pic_disable_intr, bcm_lintc_disable_intr), DEVMETHOD(pic_enable_intr, bcm_lintc_enable_intr), DEVMETHOD(pic_map_intr, bcm_lintc_map_intr), DEVMETHOD(pic_post_filter, bcm_lintc_post_filter), DEVMETHOD(pic_post_ithread, bcm_lintc_post_ithread), DEVMETHOD(pic_pre_ithread, bcm_lintc_pre_ithread), DEVMETHOD(pic_setup_intr, bcm_lintc_setup_intr), #ifdef SMP DEVMETHOD(pic_init_secondary, bcm_lintc_init_secondary), DEVMETHOD(pic_ipi_send, bcm_lintc_ipi_send), DEVMETHOD(pic_ipi_setup, bcm_lintc_ipi_setup), #endif DEVMETHOD_END }; static driver_t bcm_lintc_driver = { "lintc", bcm_lintc_methods, sizeof(struct bcm_lintc_softc), }; static devclass_t bcm_lintc_devclass; EARLY_DRIVER_MODULE(lintc, simplebus, bcm_lintc_driver, bcm_lintc_devclass, 0, 0, BUS_PASS_INTERRUPT); Index: stable/12/sys/arm/broadcom/bcm2835/files.bcm283x =================================================================== --- stable/12/sys/arm/broadcom/bcm2835/files.bcm283x (revision 355664) +++ stable/12/sys/arm/broadcom/bcm2835/files.bcm283x (revision 355665) @@ -1,44 +1,45 @@ # $FreeBSD$ arm/broadcom/bcm2835/bcm2835_bsc.c optional bcm2835_bsc arm/broadcom/bcm2835/bcm2835_cpufreq.c standard arm/broadcom/bcm2835/bcm2835_dma.c standard arm/broadcom/bcm2835/bcm2835_fb.c optional sc arm/broadcom/bcm2835/bcm2835_fbd.c optional vt arm/broadcom/bcm2835/bcm2835_ft5406.c optional evdev bcm2835_ft5406 arm/broadcom/bcm2835/bcm2835_gpio.c optional gpio arm/broadcom/bcm2835/bcm2835_intr.c standard arm/broadcom/bcm2835/bcm2835_machdep.c optional platform arm/broadcom/bcm2835/bcm2835_mbox.c standard arm/broadcom/bcm2835/bcm2835_rng.c optional random arm/broadcom/bcm2835/bcm2835_sdhci.c optional sdhci arm/broadcom/bcm2835/bcm2835_sdhost.c optional sdhci arm/broadcom/bcm2835/bcm2835_spi.c optional bcm2835_spi +arm/broadcom/bcm2835/bcm2835_vcbus.c standard arm/broadcom/bcm2835/bcm2835_vcio.c standard arm/broadcom/bcm2835/bcm2835_wdog.c standard arm/broadcom/bcm2835/bcm283x_dwc_fdt.c optional dwcotg fdt dev/mbox/mbox_if.m standard arm/broadcom/bcm2835/bcm2835_audio.c optional sound vchiq \ compile-with "${NORMAL_C} -DUSE_VCHIQ_ARM -D__VCCOREVER__=0x04000000 -I$S/contrib/vchiq" # VideoCore driver contrib/vchiq/interface/compat/vchi_bsd.c optional vchiq \ compile-with "${NORMAL_C} -DUSE_VCHIQ_ARM -D__VCCOREVER__=0x04000000 -I$S/contrib/vchiq" contrib/vchiq/interface/vchiq_arm/vchiq_2835_arm.c optional vchiq \ compile-with "${NORMAL_C} -Wno-unused -DUSE_VCHIQ_ARM -D__VCCOREVER__=0x04000000 -I$S/contrib/vchiq" contrib/vchiq/interface/vchiq_arm/vchiq_arm.c optional vchiq \ compile-with "${NORMAL_C} -Wno-unused -DUSE_VCHIQ_ARM -D__VCCOREVER__=0x04000000 -I$S/contrib/vchiq" contrib/vchiq/interface/vchiq_arm/vchiq_connected.c optional vchiq \ compile-with "${NORMAL_C} -DUSE_VCHIQ_ARM -D__VCCOREVER__=0x04000000 -I$S/contrib/vchiq" contrib/vchiq/interface/vchiq_arm/vchiq_core.c optional vchiq \ compile-with "${NORMAL_C} -DUSE_VCHIQ_ARM -D__VCCOREVER__=0x04000000 -I$S/contrib/vchiq" contrib/vchiq/interface/vchiq_arm/vchiq_kern_lib.c optional vchiq \ compile-with "${NORMAL_C} -DUSE_VCHIQ_ARM -D__VCCOREVER__=0x04000000 -I$S/contrib/vchiq" contrib/vchiq/interface/vchiq_arm/vchiq_kmod.c optional vchiq \ compile-with "${NORMAL_C} -DUSE_VCHIQ_ARM -D__VCCOREVER__=0x04000000 -I$S/contrib/vchiq" contrib/vchiq/interface/vchiq_arm/vchiq_shim.c optional vchiq \ compile-with "${NORMAL_C} -DUSE_VCHIQ_ARM -D__VCCOREVER__=0x04000000 -I$S/contrib/vchiq" contrib/vchiq/interface/vchiq_arm/vchiq_util.c optional vchiq \ compile-with "${NORMAL_C} -DUSE_VCHIQ_ARM -D__VCCOREVER__=0x04000000 -I$S/contrib/vchiq" Index: stable/12/sys/arm64/conf/GENERIC =================================================================== --- stable/12/sys/arm64/conf/GENERIC (revision 355664) +++ stable/12/sys/arm64/conf/GENERIC (revision 355665) @@ -1,302 +1,303 @@ # # GENERIC -- Generic kernel configuration file for FreeBSD/arm64 # # For more information on this file, please read the config(5) manual page, # and/or the handbook section on Kernel Configuration Files: # # https://www.FreeBSD.org/doc/en_US.ISO8859-1/books/handbook/kernelconfig-config.html # # The handbook is also available locally in /usr/share/doc/handbook # if you've installed the doc distribution, otherwise always see the # FreeBSD World Wide Web server (https://www.FreeBSD.org/) for the # latest information. # # An exhaustive list of options and more detailed explanations of the # device lines is also present in the ../../conf/NOTES and NOTES files. # If you are in doubt as to the purpose or necessity of a line, check first # in NOTES. # # $FreeBSD$ cpu ARM64 ident GENERIC makeoptions DEBUG=-g # Build kernel with gdb(1) debug symbols makeoptions WITH_CTF=1 # Run ctfconvert(1) for DTrace support options SCHED_ULE # ULE scheduler options PREEMPTION # Enable kernel thread preemption options VIMAGE # Subsystem virtualization, e.g. VNET options INET # InterNETworking options INET6 # IPv6 communications protocols options IPSEC # IP (v4/v6) security options IPSEC_SUPPORT # Allow kldload of ipsec and tcpmd5 options TCP_HHOOK # hhook(9) framework for TCP options TCP_OFFLOAD # TCP offload options TCP_RFC7413 # TCP Fast Open options SCTP # Stream Control Transmission Protocol options FFS # Berkeley Fast Filesystem options SOFTUPDATES # Enable FFS soft updates support options UFS_ACL # Support for access control lists options UFS_DIRHASH # Improve performance on big directories options UFS_GJOURNAL # Enable gjournal-based UFS journaling options QUOTA # Enable disk quotas for UFS options MD_ROOT # MD is a potential root device options NFSCL # Network Filesystem Client options NFSD # Network Filesystem Server options NFSLOCKD # Network Lock Manager options NFS_ROOT # NFS usable as /, requires NFSCL options MSDOSFS # MSDOS Filesystem options CD9660 # ISO 9660 Filesystem options PROCFS # Process filesystem (requires PSEUDOFS) options PSEUDOFS # Pseudo-filesystem framework options GEOM_RAID # Soft RAID functionality. options GEOM_LABEL # Provides labelization options COMPAT_FREEBSD32 # Incomplete, but used by cloudabi32.ko. options COMPAT_FREEBSD11 # Compatible with FreeBSD11 options SCSI_DELAY=5000 # Delay (in ms) before probing SCSI options KTRACE # ktrace(1) support options STACK # stack(9) support options SYSVSHM # SYSV-style shared memory options SYSVMSG # SYSV-style message queues options SYSVSEM # SYSV-style semaphores options _KPOSIX_PRIORITY_SCHEDULING # POSIX P1003_1B real-time extensions options PRINTF_BUFR_SIZE=128 # Prevent printf output being interspersed. options KBD_INSTALL_CDEV # install a CDEV entry in /dev options HWPMC_HOOKS # Necessary kernel hooks for hwpmc(4) options AUDIT # Security event auditing options CAPABILITY_MODE # Capsicum capability mode options CAPABILITIES # Capsicum capabilities options MAC # TrustedBSD MAC Framework options KDTRACE_FRAME # Ensure frames are compiled in options KDTRACE_HOOKS # Kernel DTrace hooks options VFP # Floating-point support options RACCT # Resource accounting framework options RACCT_DEFAULT_TO_DISABLED # Set kern.racct.enable=0 by default options RCTL # Resource limits options SMP options INTRNG # Debugging support. Always need this: options KDB # Enable kernel debugger support. options KDB_TRACE # Print a stack trace for a panic. # Kernel dump features. options EKCD # Support for encrypted kernel dumps options GZIO # gzip-compressed kernel and user dumps options ZSTDIO # zstd-compressed kernel and user dumps options NETDUMP # netdump(4) client support # SoC support options SOC_ALLWINNER_A64 options SOC_ALLWINNER_H5 options SOC_CAVM_THUNDERX options SOC_HISI_HI6220 options SOC_BRCM_BCM2837 +options SOC_BRCM_BCM2838 options SOC_MARVELL_8K options SOC_ROCKCHIP_RK3328 options SOC_ROCKCHIP_RK3399 options SOC_XILINX_ZYNQ # Timer drivers device a10_timer # Annapurna Alpine drivers device al_ccu # Alpine Cache Coherency Unit device al_nb_service # Alpine North Bridge Service device al_iofic # I/O Fabric Interrupt Controller device al_serdes # Serializer/Deserializer device al_udma # Universal DMA # Qualcomm Snapdragon drivers device qcom_gcc # Global Clock Controller # VirtIO support device virtio device virtio_pci device virtio_mmio device virtio_blk device vtnet # CPU frequency control device cpufreq # Bus drivers device pci device al_pci # Annapurna Alpine PCI-E options PCI_HP # PCI-Express native HotPlug options PCI_IOV # PCI SR-IOV support # PCI/PCI-X/PCIe Ethernet NICs that use iflib infrastructure device iflib device em # Intel PRO/1000 Gigabit Ethernet Family device ix # Intel 10Gb Ethernet Family # Ethernet NICs device mdio device mii device miibus # MII bus support device awg # Allwinner EMAC Gigabit Ethernet device axgbe # AMD Opteron A1100 integrated NIC device msk # Marvell/SysKonnect Yukon II Gigabit Ethernet device neta # Marvell Armada 370/38x/XP/3700 NIC device smc # SMSC LAN91C111 device vnic # Cavium ThunderX NIC device al_eth # Annapurna Alpine Ethernet NIC device dwc_rk # Rockchip Designware # Block devices device ahci device scbus device da # ATA/SCSI peripherals device pass # Passthrough device (direct ATA/SCSI access) # NVM Express (NVMe) support device nvme # base NVMe driver options NVME_USE_NVD=0 # prefer the cam(4) based nda(4) driver device nvd # expose NVMe namespaces as disks, depends on nvme # MMC/SD/SDIO Card slot support device sdhci device sdhci_xenon # Marvell Xenon SD/MMC controller device aw_mmc # Allwinner SD/MMC controller device mmc # mmc/sd bus device mmcsd # mmc/sd flash cards device dwmmc # Serial (COM) ports device uart # Generic UART driver device uart_msm # Qualcomm MSM UART driver device uart_mu # RPI3 aux port device uart_mvebu # Armada 3700 UART driver device uart_ns8250 # ns8250-type UART driver device uart_snps device pl011 # USB support device aw_usbphy # Allwinner USB PHY device rk_usb2phy # Rockchip USB2PHY device dwcotg # DWC OTG controller device ohci # OHCI USB interface device ehci # EHCI USB interface (USB 2.0) device ehci_mv # Marvell EHCI USB interface device xhci # XHCI PCI->USB interface (USB 3.0) device usb # USB Bus (required) device ukbd # Keyboard device umass # Disks/Mass storage - Requires scbus and da # USB ethernet support device muge device smcphy device smsc # Sound support device sound device a10_codec # DMA controller device a31_dmac # GPIO / PINCTRL device a37x0_gpio # Marvell Armada 37x0 GPIO controller device aw_gpio # Allwinner GPIO controller device gpio device gpioled device fdt_pinctrl device gpioregulator device mv_gpio # Marvell GPIO controller device mvebu_pinctrl # Marvell Pinmux Controller device rk_gpio # RockChip GPIO Controller device rk_pinctrl # RockChip Pinmux Controller # I2C device aw_rsb # Allwinner Reduced Serial Bus device bcm2835_bsc # Broadcom BCM283x I2C bus device iicbus device iic device twsi # Allwinner I2C controller device syr827 # Silergy SYR827 PMIC device rk_i2c # RockChip I2C controller # Clock and reset controllers device aw_ccu # Allwinner clock controller # Interrupt controllers device aw_nmi # Allwinner NMI support device mv_cp110_icu # Marvell CP110 ICU device mv_ap806_gicp # Marvell AP806 GICP # Real-time clock support device aw_rtc # Allwinner Real-time Clock device mv_rtc # Marvell Real-time Clock # Watchdog controllers device aw_wdog # Allwinner Watchdog # Power management controllers device axp81x # X-Powers AXP81x PMIC device rk805 # RockChip RK805 PMIC # EFUSE device aw_sid # Allwinner Secure ID EFUSE # Thermal sensors device aw_thermal # Allwinner Thermal Sensor Controller device mv_thermal # Marvell Thermal Sensor Controller # SPI device spibus device bcm2835_spi # Broadcom BCM283x SPI bus # PWM device pwm device aw_pwm # Console device vt device kbdmux device vt_efifb # EVDEV support device evdev # input event device support options EVDEV_SUPPORT # evdev support in legacy drivers device uinput # install /dev/uinput cdev # Pseudo devices. device crypto # core crypto support device loop # Network loopback device random # Entropy device device ether # Ethernet support device vlan # 802.1Q VLAN support device tuntap # Packet tunnel. device md # Memory "disks" device gif # IPv6 and IPv4 tunneling device firmware # firmware assist module options EFIRT # EFI Runtime Services # EXT_RESOURCES pseudo devices options EXT_RESOURCES device clk device phy device hwreset device nvmem device regulator device syscon device aw_syscon # The `bpf' device enables the Berkeley Packet Filter. # Be aware of the administrative consequences of enabling this! # Note that 'bpf' is required for DHCP. device bpf # Berkeley packet filter # Chip-specific errata options THUNDERX_PASS_1_1_ERRATA options FDT device acpi # DTBs makeoptions MODULES_EXTRA="dtb/allwinner dtb/rockchip dtb/rpi" Index: stable/12/sys/conf/files.arm64 =================================================================== --- stable/12/sys/conf/files.arm64 (revision 355664) +++ stable/12/sys/conf/files.arm64 (revision 355665) @@ -1,298 +1,300 @@ # $FreeBSD$ cloudabi32_vdso.o optional compat_cloudabi32 \ dependency "$S/contrib/cloudabi/cloudabi_vdso_armv6_on_64bit.S" \ compile-with "${CC} -x assembler-with-cpp -m32 -shared -nostdinc -nostdlib -Wl,-T$S/compat/cloudabi/cloudabi_vdso.lds $S/contrib/cloudabi/cloudabi_vdso_armv6_on_64bit.S -o ${.TARGET}" \ no-obj no-implicit-rule \ clean "cloudabi32_vdso.o" # cloudabi32_vdso_blob.o optional compat_cloudabi32 \ dependency "cloudabi32_vdso.o" \ compile-with "${OBJCOPY} --input-target binary --output-target elf64-littleaarch64 --binary-architecture aarch64 cloudabi32_vdso.o ${.TARGET}" \ no-implicit-rule \ clean "cloudabi32_vdso_blob.o" # cloudabi64_vdso.o optional compat_cloudabi64 \ dependency "$S/contrib/cloudabi/cloudabi_vdso_aarch64.S" \ compile-with "${CC} -x assembler-with-cpp -shared -nostdinc -nostdlib -Wl,-T$S/compat/cloudabi/cloudabi_vdso.lds $S/contrib/cloudabi/cloudabi_vdso_aarch64.S -o ${.TARGET}" \ no-obj no-implicit-rule \ clean "cloudabi64_vdso.o" # cloudabi64_vdso_blob.o optional compat_cloudabi64 \ dependency "cloudabi64_vdso.o" \ compile-with "${OBJCOPY} --input-target binary --output-target elf64-littleaarch64 --binary-architecture aarch64 cloudabi64_vdso.o ${.TARGET}" \ no-implicit-rule \ clean "cloudabi64_vdso_blob.o" # # Allwinner common files arm/allwinner/a10_timer.c optional a10_timer fdt arm/allwinner/a10_codec.c optional sound a10_codec arm/allwinner/a31_dmac.c optional a31_dmac arm/allwinner/sunxi_dma_if.m optional a31_dmac arm/allwinner/aw_cir.c optional evdev aw_cir fdt arm/allwinner/aw_gpio.c optional gpio aw_gpio fdt arm/allwinner/aw_mmc.c optional mmc aw_mmc fdt | mmccam aw_mmc fdt arm/allwinner/aw_nmi.c optional aw_nmi fdt \ compile-with "${NORMAL_C} -I$S/gnu/dts/include" arm/allwinner/aw_pwm.c optional aw_pwm fdt arm/allwinner/aw_rsb.c optional aw_rsb fdt arm/allwinner/aw_rtc.c optional aw_rtc fdt arm/allwinner/aw_sid.c optional aw_sid nvmem fdt arm/allwinner/aw_spi.c optional aw_spi fdt arm/allwinner/aw_syscon.c optional aw_syscon ext_resources syscon fdt arm/allwinner/aw_thermal.c optional aw_thermal nvmem fdt arm/allwinner/aw_usbphy.c optional ehci aw_usbphy fdt arm/allwinner/aw_wdog.c optional aw_wdog fdt arm/allwinner/axp81x.c optional axp81x fdt arm/allwinner/if_awg.c optional awg ext_resources syscon aw_sid nvmem fdt # Allwinner clock driver arm/allwinner/clkng/aw_ccung.c optional aw_ccu fdt arm/allwinner/clkng/aw_clk_frac.c optional aw_ccu fdt arm/allwinner/clkng/aw_clk_m.c optional aw_ccu fdt arm/allwinner/clkng/aw_clk_mipi.c optional aw_ccu fdt arm/allwinner/clkng/aw_clk_nkmp.c optional aw_ccu fdt arm/allwinner/clkng/aw_clk_nm.c optional aw_ccu fdt arm/allwinner/clkng/aw_clk_nmm.c optional aw_ccu fdt arm/allwinner/clkng/aw_clk_np.c optional aw_ccu fdt arm/allwinner/clkng/aw_clk_prediv_mux.c optional aw_ccu fdt arm/allwinner/clkng/ccu_a64.c optional soc_allwinner_a64 aw_ccu fdt arm/allwinner/clkng/ccu_h3.c optional soc_allwinner_h5 aw_ccu fdt arm/allwinner/clkng/ccu_sun8i_r.c optional aw_ccu fdt arm/allwinner/clkng/ccu_de2.c optional aw_ccu fdt # Allwinner padconf files arm/allwinner/a64/a64_padconf.c optional soc_allwinner_a64 fdt arm/allwinner/a64/a64_r_padconf.c optional soc_allwinner_a64 fdt arm/allwinner/h3/h3_padconf.c optional soc_allwinner_h5 fdt arm/allwinner/h3/h3_r_padconf.c optional soc_allwinner_h5 fdt arm/annapurna/alpine/alpine_ccu.c optional al_ccu fdt arm/annapurna/alpine/alpine_nb_service.c optional al_nb_service fdt arm/annapurna/alpine/alpine_pci.c optional al_pci fdt arm/annapurna/alpine/alpine_pci_msix.c optional al_pci fdt arm/annapurna/alpine/alpine_serdes.c optional al_serdes fdt \ no-depend \ compile-with "${CC} -c -o ${.TARGET} ${CFLAGS} -I$S/contrib/alpine-hal -I$S/contrib/alpine-hal/eth ${PROF} ${.IMPSRC}" arm/arm/generic_timer.c standard arm/arm/gic.c standard arm/arm/gic_acpi.c optional acpi arm/arm/gic_fdt.c optional fdt arm/arm/pmu.c standard arm/arm/physmem.c standard arm/broadcom/bcm2835/bcm2835_audio.c optional sound vchiq fdt \ compile-with "${NORMAL_C} -DUSE_VCHIQ_ARM -D__VCCOREVER__=0x04000000 -I$S/contrib/vchiq" arm/broadcom/bcm2835/bcm2835_bsc.c optional bcm2835_bsc fdt -arm/broadcom/bcm2835/bcm2835_cpufreq.c optional soc_brcm_bcm2837 fdt -arm/broadcom/bcm2835/bcm2835_dma.c optional soc_brcm_bcm2837 fdt -arm/broadcom/bcm2835/bcm2835_fbd.c optional vt soc_brcm_bcm2837 fdt +arm/broadcom/bcm2835/bcm2835_clkman.c optional soc_brcm_bcm2837 fdt | soc_brcm_bcm2838 fdt +arm/broadcom/bcm2835/bcm2835_cpufreq.c optional soc_brcm_bcm2837 fdt | soc_brcm_bcm2838 fdt +arm/broadcom/bcm2835/bcm2835_dma.c optional soc_brcm_bcm2837 fdt | soc_brcm_bcm2838 fdt +arm/broadcom/bcm2835/bcm2835_fbd.c optional vt soc_brcm_bcm2837 fdt | vt soc_brcm_bcm2838 fdt arm/broadcom/bcm2835/bcm2835_ft5406.c optional evdev bcm2835_ft5406 fdt -arm/broadcom/bcm2835/bcm2835_gpio.c optional gpio soc_brcm_bcm2837 fdt -arm/broadcom/bcm2835/bcm2835_intr.c optional soc_brcm_bcm2837 fdt -arm/broadcom/bcm2835/bcm2835_mbox.c optional soc_brcm_bcm2837 fdt -arm/broadcom/bcm2835/bcm2835_rng.c optional random soc_brcm_bcm2837 fdt -arm/broadcom/bcm2835/bcm2835_sdhci.c optional sdhci soc_brcm_bcm2837 fdt -arm/broadcom/bcm2835/bcm2835_sdhost.c optional sdhci soc_brcm_bcm2837 fdt +arm/broadcom/bcm2835/bcm2835_gpio.c optional gpio soc_brcm_bcm2837 fdt | gpio soc_brcm_bcm2838 fdt +arm/broadcom/bcm2835/bcm2835_intr.c optional soc_brcm_bcm2837 fdt | soc_brcm_bcm2838 fdt +arm/broadcom/bcm2835/bcm2835_mbox.c optional soc_brcm_bcm2837 fdt | soc_brcm_bcm2838 fdt +arm/broadcom/bcm2835/bcm2835_rng.c optional random soc_brcm_bcm2837 fdt | random soc_brcm_bcm2838 fdt +arm/broadcom/bcm2835/bcm2835_sdhci.c optional sdhci soc_brcm_bcm2837 fdt | sdhci soc_brcm_bcm2838 fdt +arm/broadcom/bcm2835/bcm2835_sdhost.c optional sdhci soc_brcm_bcm2837 fdt | sdhci soc_brcm_bcm2838 fdt arm/broadcom/bcm2835/bcm2835_spi.c optional bcm2835_spi fdt -arm/broadcom/bcm2835/bcm2835_vcio.c optional soc_brcm_bcm2837 fdt -arm/broadcom/bcm2835/bcm2835_wdog.c optional soc_brcm_bcm2837 fdt -arm/broadcom/bcm2835/bcm2836.c optional soc_brcm_bcm2837 fdt -arm/broadcom/bcm2835/bcm283x_dwc_fdt.c optional dwcotg fdt soc_brcm_bcm2837 +arm/broadcom/bcm2835/bcm2835_vcbus.c optional soc_brcm_bcm2837 fdt | soc_brcm_bcm2838 fdt +arm/broadcom/bcm2835/bcm2835_vcio.c optional soc_brcm_bcm2837 fdt | soc_brcm_bcm2838 fdt +arm/broadcom/bcm2835/bcm2835_wdog.c optional soc_brcm_bcm2837 fdt | soc_brcm_bcm2838 fdt +arm/broadcom/bcm2835/bcm2836.c optional soc_brcm_bcm2837 fdt | soc_brcm_bcm2838 fdt +arm/broadcom/bcm2835/bcm283x_dwc_fdt.c optional dwcotg fdt soc_brcm_bcm2837 | dwcotg fdt soc_brcm_bcm2838 arm/mv/a37x0_gpio.c optional a37x0_gpio gpio fdt arm/mv/gpio.c optional mv_gpio fdt arm/mv/mvebu_pinctrl.c optional mvebu_pinctrl fdt arm/mv/mv_cp110_icu.c optional mv_cp110_icu fdt arm/mv/mv_ap806_gicp.c optional mv_ap806_gicp fdt arm/mv/mv_ap806_clock.c optional SOC_MARVELL_8K fdt arm/mv/mv_cp110_clock.c optional SOC_MARVELL_8K fdt arm/mv/mv_thermal.c optional SOC_MARVELL_8K mv_thermal fdt arm/mv/armada38x/armada38x_rtc.c optional mv_rtc fdt arm/xilinx/uart_dev_cdnc.c optional uart soc_xilinx_zynq arm64/acpica/acpi_iort.c optional acpi arm64/acpica/acpi_machdep.c optional acpi arm64/acpica/OsdEnvironment.c optional acpi arm64/acpica/acpi_wakeup.c optional acpi arm64/acpica/pci_cfgreg.c optional acpi pci arm64/arm64/autoconf.c standard arm64/arm64/bus_machdep.c standard arm64/arm64/bus_space_asm.S standard arm64/arm64/busdma_bounce.c standard arm64/arm64/busdma_machdep.c standard arm64/arm64/bzero.S standard arm64/arm64/clock.c standard arm64/arm64/copyinout.S standard arm64/arm64/copystr.c standard arm64/arm64/cpu_errata.c standard arm64/arm64/cpufunc_asm.S standard arm64/arm64/db_disasm.c optional ddb arm64/arm64/db_interface.c optional ddb arm64/arm64/db_trace.c optional ddb arm64/arm64/debug_monitor.c optional ddb arm64/arm64/disassem.c optional ddb arm64/arm64/dump_machdep.c standard arm64/arm64/efirt_machdep.c optional efirt arm64/arm64/elf32_machdep.c optional compat_freebsd32 arm64/arm64/elf_machdep.c standard arm64/arm64/exception.S standard arm64/arm64/freebsd32_machdep.c optional compat_freebsd32 arm64/arm64/gicv3_its.c optional intrng fdt arm64/arm64/gic_v3.c standard arm64/arm64/gic_v3_acpi.c optional acpi arm64/arm64/gic_v3_fdt.c optional fdt arm64/arm64/identcpu.c standard arm64/arm64/in_cksum.c optional inet | inet6 arm64/arm64/locore.S standard no-obj arm64/arm64/machdep.c standard arm64/arm64/mem.c standard arm64/arm64/memcpy.S standard arm64/arm64/memmove.S standard arm64/arm64/minidump_machdep.c standard arm64/arm64/mp_machdep.c optional smp arm64/arm64/nexus.c standard arm64/arm64/ofw_machdep.c optional fdt arm64/arm64/pmap.c standard arm64/arm64/stack_machdep.c optional ddb | stack arm64/arm64/support.S standard arm64/arm64/swtch.S standard arm64/arm64/sys_machdep.c standard arm64/arm64/trap.c standard arm64/arm64/uio_machdep.c standard arm64/arm64/uma_machdep.c standard arm64/arm64/undefined.c standard arm64/arm64/unwind.c optional ddb | kdtrace_hooks | stack arm64/arm64/vfp.c standard arm64/arm64/vm_machdep.c standard arm64/cavium/thunder_pcie_fdt.c optional soc_cavm_thunderx pci fdt arm64/cavium/thunder_pcie_pem.c optional soc_cavm_thunderx pci arm64/cavium/thunder_pcie_pem_fdt.c optional soc_cavm_thunderx pci fdt arm64/cavium/thunder_pcie_common.c optional soc_cavm_thunderx pci arm64/cloudabi32/cloudabi32_sysvec.c optional compat_cloudabi32 arm64/cloudabi64/cloudabi64_sysvec.c optional compat_cloudabi64 arm64/coresight/coresight.c standard arm64/coresight/coresight_if.m standard arm64/coresight/coresight-cmd.c standard arm64/coresight/coresight-cpu-debug.c standard arm64/coresight/coresight-dynamic-replicator.c standard arm64/coresight/coresight-etm4x.c standard arm64/coresight/coresight-funnel.c standard arm64/coresight/coresight-tmc.c standard arm64/qualcomm/qcom_gcc.c optional qcom_gcc fdt contrib/vchiq/interface/compat/vchi_bsd.c optional vchiq soc_brcm_bcm2837 \ compile-with "${NORMAL_C} -DUSE_VCHIQ_ARM -D__VCCOREVER__=0x04000000 -I$S/contrib/vchiq" contrib/vchiq/interface/vchiq_arm/vchiq_2835_arm.c optional vchiq soc_brcm_bcm2837 \ compile-with "${NORMAL_C} -Wno-unused -DUSE_VCHIQ_ARM -D__VCCOREVER__=0x04000000 -I$S/contrib/vchiq" contrib/vchiq/interface/vchiq_arm/vchiq_arm.c optional vchiq soc_brcm_bcm2837 \ compile-with "${NORMAL_C} -Wno-unused -DUSE_VCHIQ_ARM -D__VCCOREVER__=0x04000000 -I$S/contrib/vchiq" contrib/vchiq/interface/vchiq_arm/vchiq_connected.c optional vchiq soc_brcm_bcm2837 \ compile-with "${NORMAL_C} -DUSE_VCHIQ_ARM -D__VCCOREVER__=0x04000000 -I$S/contrib/vchiq" contrib/vchiq/interface/vchiq_arm/vchiq_core.c optional vchiq soc_brcm_bcm2837 \ compile-with "${NORMAL_C} -DUSE_VCHIQ_ARM -D__VCCOREVER__=0x04000000 -I$S/contrib/vchiq" contrib/vchiq/interface/vchiq_arm/vchiq_kern_lib.c optional vchiq soc_brcm_bcm2837 \ compile-with "${NORMAL_C} -DUSE_VCHIQ_ARM -D__VCCOREVER__=0x04000000 -I$S/contrib/vchiq" contrib/vchiq/interface/vchiq_arm/vchiq_kmod.c optional vchiq soc_brcm_bcm2837 \ compile-with "${NORMAL_C} -DUSE_VCHIQ_ARM -D__VCCOREVER__=0x04000000 -I$S/contrib/vchiq" contrib/vchiq/interface/vchiq_arm/vchiq_shim.c optional vchiq soc_brcm_bcm2837 \ compile-with "${NORMAL_C} -DUSE_VCHIQ_ARM -D__VCCOREVER__=0x04000000 -I$S/contrib/vchiq" contrib/vchiq/interface/vchiq_arm/vchiq_util.c optional vchiq soc_brcm_bcm2837 \ compile-with "${NORMAL_C} -DUSE_VCHIQ_ARM -D__VCCOREVER__=0x04000000 -I$S/contrib/vchiq" crypto/armv8/armv8_crypto.c optional armv8crypto armv8_crypto_wrap.o optional armv8crypto \ dependency "$S/crypto/armv8/armv8_crypto_wrap.c" \ compile-with "${CC} -c ${CFLAGS:C/^-O2$/-O3/:N-nostdinc:N-mgeneral-regs-only} -I$S/crypto/armv8/ ${WERROR} ${NO_WCAST_QUAL} ${PROF} -march=armv8-a+crypto ${.IMPSRC}" \ no-implicit-rule \ clean "armv8_crypto_wrap.o" crypto/blowfish/bf_enc.c optional crypto | ipsec | ipsec_support crypto/des/des_enc.c optional crypto | ipsec | ipsec_support | netsmb dev/acpica/acpi_bus_if.m optional acpi dev/acpica/acpi_if.m optional acpi dev/acpica/acpi_pci_link.c optional acpi pci dev/acpica/acpi_pcib.c optional acpi pci dev/acpica/acpi_pxm.c optional acpi dev/ahci/ahci_generic.c optional ahci dev/axgbe/if_axgbe.c optional axgbe dev/axgbe/xgbe-desc.c optional axgbe dev/axgbe/xgbe-dev.c optional axgbe dev/axgbe/xgbe-drv.c optional axgbe dev/axgbe/xgbe-mdio.c optional axgbe dev/cpufreq/cpufreq_dt.c optional cpufreq fdt dev/iicbus/twsi/mv_twsi.c optional twsi fdt dev/iicbus/twsi/a10_twsi.c optional twsi fdt dev/iicbus/twsi/twsi.c optional twsi fdt dev/hwpmc/hwpmc_arm64.c optional hwpmc dev/hwpmc/hwpmc_arm64_md.c optional hwpmc dev/mbox/mbox_if.m optional soc_brcm_bcm2837 dev/mmc/host/dwmmc.c optional dwmmc fdt dev/mmc/host/dwmmc_hisi.c optional dwmmc fdt soc_hisi_hi6220 dev/mmc/host/dwmmc_rockchip.c optional dwmmc fdt soc_rockchip_rk3328 dev/neta/if_mvneta_fdt.c optional neta fdt dev/neta/if_mvneta.c optional neta mdio mii dev/ofw/ofw_cpu.c optional fdt dev/ofw/ofwpci.c optional fdt pci dev/pci/pci_host_generic.c optional pci dev/pci/pci_host_generic_acpi.c optional pci acpi dev/pci/pci_host_generic_fdt.c optional pci fdt dev/psci/psci.c standard dev/psci/psci_arm64.S standard dev/psci/smccc.c standard dev/sdhci/sdhci_xenon.c optional sdhci_xenon sdhci fdt dev/uart/uart_cpu_arm64.c optional uart dev/uart/uart_dev_mu.c optional uart uart_mu dev/uart/uart_dev_pl011.c optional uart pl011 dev/usb/controller/dwc_otg_hisi.c optional dwcotg fdt soc_hisi_hi6220 dev/usb/controller/ehci_mv.c optional ehci_mv fdt dev/usb/controller/generic_ehci.c optional ehci dev/usb/controller/generic_ehci_acpi.c optional ehci acpi dev/usb/controller/generic_ehci_fdt.c optional ehci fdt dev/usb/controller/generic_ohci.c optional ohci fdt dev/usb/controller/generic_usb_if.m optional ohci fdt dev/usb/controller/usb_nop_xceiv.c optional fdt ext_resources dev/usb/controller/generic_xhci.c optional xhci fdt dev/vnic/mrml_bridge.c optional vnic fdt dev/vnic/nic_main.c optional vnic pci dev/vnic/nicvf_main.c optional vnic pci pci_iov dev/vnic/nicvf_queues.c optional vnic pci pci_iov dev/vnic/thunder_bgx_fdt.c optional vnic fdt dev/vnic/thunder_bgx.c optional vnic pci dev/vnic/thunder_mdio_fdt.c optional vnic fdt dev/vnic/thunder_mdio.c optional vnic dev/vnic/lmac_if.m optional inet | inet6 | vnic kern/kern_clocksource.c standard kern/msi_if.m optional intrng kern/pic_if.m optional intrng kern/subr_devmap.c standard kern/subr_intr.c optional intrng libkern/bcmp.c standard libkern/ffs.c standard libkern/ffsl.c standard libkern/ffsll.c standard libkern/fls.c standard libkern/flsl.c standard libkern/flsll.c standard libkern/memcmp.c standard libkern/memset.c standard libkern/arm64/crc32c_armv8.S standard cddl/dev/dtrace/aarch64/dtrace_asm.S optional dtrace compile-with "${DTRACE_S}" cddl/dev/dtrace/aarch64/dtrace_subr.c optional dtrace compile-with "${DTRACE_C}" cddl/dev/fbt/aarch64/fbt_isa.c optional dtrace_fbt | dtraceall compile-with "${FBT_C}" # RockChip Drivers arm64/rockchip/rk_i2c.c optional fdt rk_i2c soc_rockchip_rk3328 | fdt rk_i2c soc_rockchip_rk3399 arm64/rockchip/rk805.c optional fdt rk805 soc_rockchip_rk3328 | fdt rk805 soc_rockchip_rk3399 arm64/rockchip/rk_grf.c optional fdt soc_rockchip_rk3328 | fdt soc_rockchip_rk3399 arm64/rockchip/rk_pinctrl.c optional fdt rk_pinctrl soc_rockchip_rk3328 | fdt rk_pinctrl soc_rockchip_rk3399 arm64/rockchip/rk_gpio.c optional fdt rk_gpio soc_rockchip_rk3328 | fdt rk_gpio soc_rockchip_rk3399 arm64/rockchip/rk_usb2phy.c optional fdt rk_usb2phy soc_rockchip_rk3328 | soc_rockchip_rk3399 arm64/rockchip/if_dwc_rk.c optional fdt dwc_rk soc_rockchip_rk3328 | fdt dwc_rk soc_rockchip_rk3399 dev/dwc/if_dwc.c optional fdt dwc_rk soc_rockchip_rk3328 | fdt dwc_rk soc_rockchip_rk3399 dev/dwc/if_dwc_if.m optional fdt dwc_rk soc_rockchip_rk3328 | fdt dwc_rk soc_rockchip_rk3399 # RockChip Clock support arm64/rockchip/clk/rk_cru.c optional fdt soc_rockchip_rk3328 | fdt soc_rockchip_rk3399 arm64/rockchip/clk/rk_clk_armclk.c optional fdt soc_rockchip_rk3328 | fdt soc_rockchip_rk3399 arm64/rockchip/clk/rk_clk_composite.c optional fdt soc_rockchip_rk3328 | fdt soc_rockchip_rk3399 arm64/rockchip/clk/rk_clk_gate.c optional fdt soc_rockchip_rk3328 | fdt soc_rockchip_rk3399 arm64/rockchip/clk/rk_clk_mux.c optional fdt soc_rockchip_rk3328 | fdt soc_rockchip_rk3399 arm64/rockchip/clk/rk_clk_pll.c optional fdt soc_rockchip_rk3328 | fdt soc_rockchip_rk3399 arm64/rockchip/clk/rk3328_cru.c optional fdt soc_rockchip_rk3328 arm64/rockchip/clk/rk3399_cru.c optional fdt soc_rockchip_rk3399 arm64/rockchip/clk/rk3399_pmucru.c optional fdt soc_rockchip_rk3399 Index: stable/12/sys/conf/options.arm64 =================================================================== --- stable/12/sys/conf/options.arm64 (revision 355664) +++ stable/12/sys/conf/options.arm64 (revision 355665) @@ -1,25 +1,26 @@ # $FreeBSD$ ARM64 opt_global.h INTRNG opt_global.h SOCDEV_PA opt_global.h SOCDEV_VA opt_global.h THUNDERX_PASS_1_1_ERRATA opt_global.h VFP opt_global.h # Binary compatibility COMPAT_FREEBSD32 opt_global.h # EFI Runtime services support EFIRT opt_efirt.h # SoC Support SOC_ALLWINNER_A64 opt_soc.h SOC_ALLWINNER_H5 opt_soc.h SOC_BRCM_BCM2837 opt_soc.h +SOC_BRCM_BCM2838 opt_soc.h SOC_CAVM_THUNDERX opt_soc.h SOC_HISI_HI6220 opt_soc.h SOC_MARVELL_8K opt_soc.h SOC_ROCKCHIP_RK3328 opt_soc.h SOC_ROCKCHIP_RK3399 opt_soc.h SOC_XILINX_ZYNQ opt_soc.h Index: stable/12 =================================================================== --- stable/12 (revision 355664) +++ stable/12 (revision 355665) Property changes on: stable/12 ___________________________________________________________________ Modified: svn:mergeinfo ## -0,0 +0,1 ## Merged /head:r348803-348804,354488,354524,354560-354561,354563,354577,354579,354823,354825,354844-354846,354868,354875-354876,354930-354933,354956,355016,355025-355026,355031,355563