Module Name: src Committed By: jmcneill Date: Sun Oct 27 12:14:51 UTC 2019
Modified Files: src/sys/arch/arm/ti: am3_prcm.c files.ti ti_com.c ti_prcm.c ti_prcm.h Added Files: src/sys/arch/arm/ti: ti_edma.c ti_edma.h ti_tptc.c Log Message: Add EDMA TPCC and TPTC drivers. To generate a diff of this commit: cvs rdiff -u -r1.1 -r1.2 src/sys/arch/arm/ti/am3_prcm.c \ src/sys/arch/arm/ti/ti_prcm.c src/sys/arch/arm/ti/ti_prcm.h cvs rdiff -u -r1.7 -r1.8 src/sys/arch/arm/ti/files.ti cvs rdiff -u -r1.6 -r1.7 src/sys/arch/arm/ti/ti_com.c cvs rdiff -u -r0 -r1.1 src/sys/arch/arm/ti/ti_edma.c \ src/sys/arch/arm/ti/ti_edma.h src/sys/arch/arm/ti/ti_tptc.c Please note that diffs are not public domain; they are subject to the copyright notices on the relevant files.
Modified files: Index: src/sys/arch/arm/ti/am3_prcm.c diff -u src/sys/arch/arm/ti/am3_prcm.c:1.1 src/sys/arch/arm/ti/am3_prcm.c:1.2 --- src/sys/arch/arm/ti/am3_prcm.c:1.1 Thu Oct 26 23:28:15 2017 +++ src/sys/arch/arm/ti/am3_prcm.c Sun Oct 27 12:14:51 2019 @@ -1,4 +1,4 @@ -/* $NetBSD: am3_prcm.c,v 1.1 2017/10/26 23:28:15 jmcneill Exp $ */ +/* $NetBSD: am3_prcm.c,v 1.2 2019/10/27 12:14:51 jmcneill Exp $ */ /*- * Copyright (c) 2017 Jared McNeill <jmcne...@invisible.ca> @@ -28,7 +28,7 @@ #include <sys/cdefs.h> -__KERNEL_RCSID(1, "$NetBSD: am3_prcm.c,v 1.1 2017/10/26 23:28:15 jmcneill Exp $"); +__KERNEL_RCSID(1, "$NetBSD: am3_prcm.c,v 1.2 2019/10/27 12:14:51 jmcneill Exp $"); #include <sys/param.h> #include <sys/bus.h> @@ -108,6 +108,11 @@ static struct ti_prcm_clk am3_prcm_clks[ AM3_PRCM_HWMOD_PER("mmc0", 0x3c, "MMC_CLK"), AM3_PRCM_HWMOD_PER("mmc1", 0xf4, "MMC_CLK"), AM3_PRCM_HWMOD_PER("mmc2", 0xf8, "MMC_CLK"), + + AM3_PRCM_HWMOD_PER("tpcc", 0xbc, "PERIPH_CLK"), + AM3_PRCM_HWMOD_PER("tptc0", 0x24, "PERIPH_CLK"), + AM3_PRCM_HWMOD_PER("tptc1", 0xfc, "PERIPH_CLK"), + AM3_PRCM_HWMOD_PER("tptc2", 0x100, "PERIPH_CLK"), }; static int Index: src/sys/arch/arm/ti/ti_prcm.c diff -u src/sys/arch/arm/ti/ti_prcm.c:1.1 src/sys/arch/arm/ti/ti_prcm.c:1.2 --- src/sys/arch/arm/ti/ti_prcm.c:1.1 Thu Oct 26 23:28:15 2017 +++ src/sys/arch/arm/ti/ti_prcm.c Sun Oct 27 12:14:51 2019 @@ -1,4 +1,4 @@ -/* $NetBSD: ti_prcm.c,v 1.1 2017/10/26 23:28:15 jmcneill Exp $ */ +/* $NetBSD: ti_prcm.c,v 1.2 2019/10/27 12:14:51 jmcneill Exp $ */ /*- * Copyright (c) 2017 Jared McNeill <jmcne...@invisible.ca> @@ -27,7 +27,7 @@ */ #include <sys/cdefs.h> -__KERNEL_RCSID(0, "$NetBSD: ti_prcm.c,v 1.1 2017/10/26 23:28:15 jmcneill Exp $"); +__KERNEL_RCSID(0, "$NetBSD: ti_prcm.c,v 1.2 2019/10/27 12:14:51 jmcneill Exp $"); #include <sys/param.h> #include <sys/bus.h> @@ -255,3 +255,15 @@ ti_prcm_get_hwmod(const int phandle, u_i return NULL; } + +int +ti_prcm_enable_hwmod(const int phandle, u_int index) +{ + struct clk *clk; + + clk = ti_prcm_get_hwmod(phandle, index); + if (clk == NULL) + return ENOENT; + + return clk_enable(clk); +} Index: src/sys/arch/arm/ti/ti_prcm.h diff -u src/sys/arch/arm/ti/ti_prcm.h:1.1 src/sys/arch/arm/ti/ti_prcm.h:1.2 --- src/sys/arch/arm/ti/ti_prcm.h:1.1 Thu Oct 26 23:28:15 2017 +++ src/sys/arch/arm/ti/ti_prcm.h Sun Oct 27 12:14:51 2019 @@ -1,4 +1,4 @@ -/* $NetBSD: ti_prcm.h,v 1.1 2017/10/26 23:28:15 jmcneill Exp $ */ +/* $NetBSD: ti_prcm.h,v 1.2 2019/10/27 12:14:51 jmcneill Exp $ */ /*- * Copyright (c) 2017 Jared McNeill <jmcne...@invisible.ca> @@ -165,5 +165,6 @@ struct ti_prcm_softc { #endif /* !TI_PRCM_PRIVATE */ struct clk * ti_prcm_get_hwmod(const int, u_int); +int ti_prcm_enable_hwmod(const int, u_int); #endif /* !_ARM_TI_PRCM_H */ Index: src/sys/arch/arm/ti/files.ti diff -u src/sys/arch/arm/ti/files.ti:1.7 src/sys/arch/arm/ti/files.ti:1.8 --- src/sys/arch/arm/ti/files.ti:1.7 Sun Oct 27 11:33:56 2019 +++ src/sys/arch/arm/ti/files.ti Sun Oct 27 12:14:51 2019 @@ -1,4 +1,4 @@ -# $NetBSD: files.ti,v 1.7 2019/10/27 11:33:56 jmcneill Exp $ +# $NetBSD: files.ti,v 1.8 2019/10/27 12:14:51 jmcneill Exp $ # file arch/arm/ti/ti_platform.c soc_ti @@ -36,6 +36,14 @@ device cpsw: ether, ifnet, arp, mii, mi attach cpsw at fdt file arch/arm/ti/if_cpsw.c cpsw +# EDMA +device tiedma +attach tiedma at fdt with ti_edma +file arch/arm/ti/ti_edma.c ti_edma +device titptc +attach titptc at fdt with ti_tptc +file arch/arm/ti/ti_tptc.c ti_tptc + # SOC parameters defflag opt_soc.h SOC_TI defflag opt_soc.h SOC_TI_AM335X: SOC_TI Index: src/sys/arch/arm/ti/ti_com.c diff -u src/sys/arch/arm/ti/ti_com.c:1.6 src/sys/arch/arm/ti/ti_com.c:1.7 --- src/sys/arch/arm/ti/ti_com.c:1.6 Sun Oct 27 11:33:56 2019 +++ src/sys/arch/arm/ti/ti_com.c Sun Oct 27 12:14:51 2019 @@ -1,4 +1,4 @@ -/* $NetBSD: ti_com.c,v 1.6 2019/10/27 11:33:56 jmcneill Exp $ */ +/* $NetBSD: ti_com.c,v 1.7 2019/10/27 12:14:51 jmcneill Exp $ */ /*- * Copyright (c) 2017 Jared McNeill <jmcne...@invisible.ca> @@ -28,7 +28,7 @@ #include <sys/cdefs.h> -__KERNEL_RCSID(1, "$NetBSD: ti_com.c,v 1.6 2019/10/27 11:33:56 jmcneill Exp $"); +__KERNEL_RCSID(1, "$NetBSD: ti_com.c,v 1.7 2019/10/27 12:14:51 jmcneill Exp $"); #include <sys/param.h> #include <sys/bus.h> @@ -79,7 +79,6 @@ ti_com_attach(device_t parent, device_t bus_space_handle_t bsh; bus_space_tag_t bst; char intrstr[128]; - struct clk *hwmod; bus_addr_t addr; bus_size_t size; int error; @@ -106,9 +105,7 @@ ti_com_attach(device_t parent, device_t return; } - hwmod = ti_prcm_get_hwmod(OF_parent(phandle), 0); - KASSERT(hwmod != NULL); - if (clk_enable(hwmod) != 0) { + if (ti_prcm_enable_hwmod(OF_parent(phandle), 0) != 0) { aprint_error(": couldn't enable module\n"); return; } Added files: Index: src/sys/arch/arm/ti/ti_edma.c diff -u /dev/null src/sys/arch/arm/ti/ti_edma.c:1.1 --- /dev/null Sun Oct 27 12:14:51 2019 +++ src/sys/arch/arm/ti/ti_edma.c Sun Oct 27 12:14:51 2019 @@ -0,0 +1,550 @@ +/* $NetBSD: ti_edma.c,v 1.1 2019/10/27 12:14:51 jmcneill Exp $ */ + +/*- + * Copyright (c) 2014 Jared D. McNeill <jmcne...@invisible.ca> + * 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. The name of the author may not be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 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 <sys/cdefs.h> +__KERNEL_RCSID(0, "$NetBSD: ti_edma.c,v 1.1 2019/10/27 12:14:51 jmcneill Exp $"); + +#include <sys/param.h> +#include <sys/systm.h> +#include <sys/device.h> +#include <sys/conf.h> +#include <sys/intr.h> +#include <sys/mutex.h> +#include <sys/bus.h> +#include <sys/bitops.h> + +#include <dev/fdt/fdtvar.h> + +#include <arm/ti/ti_prcm.h> +#include <arm/ti/ti_edma.h> + +#define NUM_DMA_CHANNELS 64 +#define NUM_PARAM_SETS 256 +#define MAX_PARAM_PER_CHANNEL 32 + +#ifdef EDMA_DEBUG +int edmadebug = 1; +#define DPRINTF(n,s) do { if ((n) <= edmadebug) device_printf s; } while (0) +#else +#define DPRINTF(n,s) do {} while (0) +#endif + +struct edma_softc; + +struct edma_channel { + struct edma_softc *ch_sc; + enum edma_type ch_type; + uint8_t ch_index; + void (*ch_callback)(void *); + void *ch_callbackarg; + unsigned int ch_nparams; +}; + +struct edma_softc { + device_t sc_dev; + bus_space_tag_t sc_iot; + bus_space_handle_t sc_ioh; + kmutex_t sc_lock; + struct edma_channel sc_dma[NUM_DMA_CHANNELS]; + + void *sc_ih; + + uint32_t sc_dmamask[NUM_DMA_CHANNELS / 32]; + uint32_t sc_parammask[NUM_PARAM_SETS / 32]; +}; + +static int edma_match(device_t, cfdata_t, void *); +static void edma_attach(device_t, device_t, void *); + +static void edma_init(struct edma_softc *); +static int edma_intr(void *); +static void edma_write_param(struct edma_softc *, + unsigned int, const struct edma_param *); +static bool edma_bit_isset(uint32_t *, unsigned int); +static void edma_bit_set(uint32_t *, unsigned int); +static void edma_bit_clr(uint32_t *, unsigned int); + +CFATTACH_DECL_NEW(ti_edma, sizeof(struct edma_softc), + edma_match, edma_attach, NULL, NULL); + +#define EDMA_READ(sc, reg) \ + bus_space_read_4((sc)->sc_iot, (sc)->sc_ioh, (reg)) +#define EDMA_WRITE(sc, reg, val) \ + bus_space_write_4((sc)->sc_iot, (sc)->sc_ioh, (reg), (val)) + +static const char * compatible[] = { + "ti,edma3-tpcc", + NULL +}; + +static int +edma_match(device_t parent, cfdata_t match, void *aux) +{ + struct fdt_attach_args * const faa = aux; + + return of_match_compatible(faa->faa_phandle, compatible); +} + +static void +edma_attach(device_t parent, device_t self, void *aux) +{ + struct edma_softc *sc = device_private(self); + struct fdt_attach_args * const faa = aux; + const int phandle = faa->faa_phandle; + char intrstr[128]; + bus_addr_t addr; + bus_size_t size; + int idx; + + if (fdtbus_get_reg(phandle, 0, &addr, &size) != 0) { + aprint_error(": couldn't get registers\n"); + return; + } + + if (!fdtbus_intr_str(phandle, 0, intrstr, sizeof(intrstr))) { + aprint_error(": failed to decode interrupt\n"); + return; + } + + sc->sc_dev = self; + sc->sc_iot = faa->faa_bst; + mutex_init(&sc->sc_lock, MUTEX_DEFAULT, IPL_VM); + if (bus_space_map(sc->sc_iot, addr, size, 0, &sc->sc_ioh) != 0) { + aprint_error(": couldn't map registers\n"); + return; + } + + aprint_naive("\n"); + aprint_normal(": EDMA Channel Controller\n"); + + for (idx = 0; idx < NUM_DMA_CHANNELS; idx++) { + struct edma_channel *ch = &sc->sc_dma[idx]; + ch->ch_sc = sc; + ch->ch_type = EDMA_TYPE_DMA; + ch->ch_index = idx; + ch->ch_callback = NULL; + ch->ch_callbackarg = NULL; + ch->ch_nparams = 0; + } + + if (ti_prcm_enable_hwmod(phandle, 0) != 0) { + aprint_error_dev(self, "couldn't enable module\n"); + return; + } + + edma_init(sc); + + sc->sc_ih = fdtbus_intr_establish_byname(phandle, "edma3_ccint", + IPL_VM, FDT_INTR_MPSAFE, edma_intr, sc); + if (sc->sc_ih == NULL) { + aprint_error_dev(self, "failed to establish interrupt\n"); + return; + } + aprint_normal_dev(self, "interrupting on %s\n", intrstr); +} + +/* + * Hardware initialization + */ +static void +edma_init(struct edma_softc *sc) +{ + struct edma_param param; + uint32_t val; + int idx; + + val = EDMA_READ(sc, EDMA_CCCFG_REG); + if (val & EDMA_CCCFG_CHMAP_EXIST) { + for (idx = 0; idx < NUM_DMA_CHANNELS; idx++) { + EDMA_WRITE(sc, EDMA_DCHMAP_REG(idx), + __SHIFTIN(0, EDMA_DCHMAP_PAENTRY)); + } + } + + memset(¶m, 0, sizeof(param)); + param.ep_bcnt = 1; + for (idx = 0; idx < NUM_PARAM_SETS; idx++) { + edma_write_param(sc, idx, ¶m); + } + + /* reserve PaRAM entry 0 for dummy slot */ + edma_bit_set(sc->sc_parammask, 0); + for (idx = 1; idx <= 32; idx++) { + edma_bit_set(sc->sc_parammask, idx); + } +} + +/* + * Write a PaRAM entry + */ +static void +edma_write_param(struct edma_softc *sc, + unsigned int idx, const struct edma_param *ep) +{ + EDMA_WRITE(sc, EDMA_PARAM_OPT_REG(idx), ep->ep_opt); + EDMA_WRITE(sc, EDMA_PARAM_SRC_REG(idx), ep->ep_src); + EDMA_WRITE(sc, EDMA_PARAM_CNT_REG(idx), + __SHIFTIN(ep->ep_bcnt, EDMA_PARAM_CNT_BCNT) | + __SHIFTIN(ep->ep_acnt, EDMA_PARAM_CNT_ACNT)); + EDMA_WRITE(sc, EDMA_PARAM_DST_REG(idx), ep->ep_dst); + EDMA_WRITE(sc, EDMA_PARAM_BIDX_REG(idx), + __SHIFTIN(ep->ep_dstbidx, EDMA_PARAM_BIDX_DSTBIDX) | + __SHIFTIN(ep->ep_srcbidx, EDMA_PARAM_BIDX_SRCBIDX)); + EDMA_WRITE(sc, EDMA_PARAM_LNK_REG(idx), + __SHIFTIN(ep->ep_bcntrld, EDMA_PARAM_LNK_BCNTRLD) | + __SHIFTIN(ep->ep_link, EDMA_PARAM_LNK_LINK)); + EDMA_WRITE(sc, EDMA_PARAM_CIDX_REG(idx), + __SHIFTIN(ep->ep_dstcidx, EDMA_PARAM_CIDX_DSTCIDX) | + __SHIFTIN(ep->ep_srccidx, EDMA_PARAM_CIDX_SRCCIDX)); + EDMA_WRITE(sc, EDMA_PARAM_CCNT_REG(idx), + __SHIFTIN(ep->ep_ccnt, EDMA_PARAM_CCNT_CCNT)); +} + +static bool +edma_bit_isset(uint32_t *bits, unsigned int bit) +{ + return !!(bits[bit >> 5] & (1 << (bit & 0x1f))); +} + +static void +edma_bit_set(uint32_t *bits, unsigned int bit) +{ + bits[bit >> 5] |= (1 << (bit & 0x1f)); +} + +static void +edma_bit_clr(uint32_t *bits, unsigned int bit) +{ + bits[bit >> 5] &= ~(1 << (bit & 0x1f)); +} + +static int +edma_intr(void *priv) +{ + struct edma_softc *sc = priv; + uint64_t ipr, ier; + int bit, idx; + + ipr = EDMA_READ(sc, EDMA_IPR_REG); + ipr |= (uint64_t)EDMA_READ(sc, EDMA_IPRH_REG) << 32; + if (ipr == 0) + return 0; + + ier = EDMA_READ(sc, EDMA_IER_REG); + ier |= (uint64_t)EDMA_READ(sc, EDMA_IERH_REG) << 32; + + DPRINTF(2, (sc->sc_dev, "ipr = 0x%016llx ier 0x%016llx\n", ipr, ier)); + + EDMA_WRITE(sc, EDMA_ICR_REG, ipr & 0xffffffff); + EDMA_WRITE(sc, EDMA_ICRH_REG, ipr >> 32); + + while ((bit = ffs64(ipr)) != 0) { + idx = bit - 1; + ipr &= ~__BIT(idx); + if (!(ier & __BIT(idx))) + continue; + if (!edma_bit_isset(sc->sc_dmamask, idx)) + continue; + + sc->sc_dma[idx].ch_callback(sc->sc_dma[idx].ch_callbackarg); + } + + EDMA_WRITE(sc, EDMA_IEVAL_REG, EDMA_IEVAL_EVAL); + + return 1; +} + +/* + * Allocate a DMA channel. Currently only DMA types are supported, not QDMA. + * Returns NULL on failure. + */ +struct edma_channel * +edma_channel_alloc(enum edma_type type, unsigned int drq, + void (*cb)(void *), void *cbarg) +{ + struct edma_softc *sc; + device_t dev; + struct edma_channel *ch = NULL; + + KASSERT(drq < __arraycount(sc->sc_dma)); + KASSERT(type == EDMA_TYPE_DMA); /* QDMA not implemented */ + KASSERT(cb != NULL); + KASSERT(cbarg != NULL); + + dev = device_find_by_driver_unit("tiedma", 0); + if (dev == NULL) + return NULL; + sc = device_private(dev); + + mutex_enter(&sc->sc_lock); + if (!edma_bit_isset(sc->sc_dmamask, drq)) { + ch = &sc->sc_dma[drq]; + KASSERT(ch->ch_callback == NULL); + KASSERT(ch->ch_index == drq); + ch->ch_callback = cb; + ch->ch_callbackarg = cbarg; + edma_bit_set(sc->sc_dmamask, drq); + } + + if (ch == NULL) + goto done; + + EDMA_WRITE(sc, EDMA_DRAE_REG(0), sc->sc_dmamask[0]); + EDMA_WRITE(sc, EDMA_DRAEH_REG(0), sc->sc_dmamask[1]); + + if (ch->ch_index < 32) { + EDMA_WRITE(sc, EDMA_ICR_REG, __BIT(ch->ch_index)); + EDMA_WRITE(sc, EDMA_IESR_REG, __BIT(ch->ch_index)); + } else { + EDMA_WRITE(sc, EDMA_ICRH_REG, __BIT(ch->ch_index - 32)); + EDMA_WRITE(sc, EDMA_IESRH_REG, __BIT(ch->ch_index - 32)); + } + +done: + mutex_exit(&sc->sc_lock); + + return ch; +} + +/* + * Free a DMA channel allocated with edma_channel_alloc + */ +void +edma_channel_free(struct edma_channel *ch) +{ + struct edma_softc *sc = ch->ch_sc; + + KASSERT(ch->ch_nparams == 0); + + mutex_enter(&sc->sc_lock); + if (ch->ch_index < 32) { + EDMA_WRITE(sc, EDMA_IECR_REG, __BIT(ch->ch_index)); + } else { + EDMA_WRITE(sc, EDMA_IECRH_REG, __BIT(ch->ch_index - 32)); + } + ch->ch_callback = NULL; + ch->ch_callbackarg = NULL; + edma_bit_clr(sc->sc_dmamask, ch->ch_index); + mutex_exit(&sc->sc_lock); +} + +/* + * Allocate a PaRAM entry. The driver artifically restricts the number + * of PaRAM entries available for each channel to MAX_PARAM_PER_CHANNEL. + * If the number of entries for the channel has been exceeded, or there + * are no entries available, 0xffff is returned. + */ +uint16_t +edma_param_alloc(struct edma_channel *ch) +{ + struct edma_softc *sc = ch->ch_sc; + uint16_t param_entry = 0xffff; + int idx; + + if (ch->ch_nparams == MAX_PARAM_PER_CHANNEL) + return param_entry; + + mutex_enter(&sc->sc_lock); + for (idx = 0; idx < NUM_PARAM_SETS; idx++) { + if (!edma_bit_isset(sc->sc_parammask, idx)) { + param_entry = idx; + edma_bit_set(sc->sc_parammask, idx); + ch->ch_nparams++; + break; + } + } + mutex_exit(&sc->sc_lock); + + return param_entry; +} + +/* + * Free a PaRAM entry allocated with edma_param_alloc + */ +void +edma_param_free(struct edma_channel *ch, uint16_t param_entry) +{ + struct edma_softc *sc = ch->ch_sc; + + KASSERT(param_entry < NUM_PARAM_SETS); + KASSERT(ch->ch_nparams > 0); + KASSERT(edma_bit_isset(sc->sc_parammask, param_entry)); + + mutex_enter(&sc->sc_lock); + edma_bit_clr(sc->sc_parammask, param_entry); + ch->ch_nparams--; + mutex_exit(&sc->sc_lock); +} + +/* + * Update a PaRAM entry register set with caller-provided values + */ +void +edma_set_param(struct edma_channel *ch, uint16_t param_entry, + struct edma_param *ep) +{ + struct edma_softc *sc = ch->ch_sc; + + KASSERT(param_entry < NUM_PARAM_SETS); + KASSERT(ch->ch_nparams > 0); + KASSERT(edma_bit_isset(sc->sc_parammask, param_entry)); + + DPRINTF(1, (sc->sc_dev, "write param entry ch# %d pe %d: 0x%08x -> 0x%08x (%u, %u, %u)\n", ch->ch_index, param_entry, ep->ep_src, ep->ep_dst, ep->ep_acnt, ep->ep_bcnt, ep->ep_ccnt)); + edma_write_param(sc, param_entry, ep); +} + +/* + * Enable a DMA channel: Point channel to the PaRam entry, + * clear error if any, and only set the Event Enable bit. + * The Even will either be generated by hardware, or with + * edma_transfer_start() + */ +int +edma_transfer_enable(struct edma_channel *ch, uint16_t param_entry) +{ + struct edma_softc *sc = ch->ch_sc; + bus_size_t off = (ch->ch_index < 32 ? 0 : 4); + uint32_t bit = __BIT(ch->ch_index < 32 ? + ch->ch_index : ch->ch_index - 32); + + DPRINTF(1, (sc->sc_dev, "enable transfer ch# %d off %d bit %x pe %d\n", ch->ch_index, (int)off, bit, param_entry)); + + EDMA_WRITE(sc, EDMA_DCHMAP_REG(ch->ch_index), + __SHIFTIN(param_entry, EDMA_DCHMAP_PAENTRY)); + + uint32_t ccerr = EDMA_READ(sc, EDMA_CCERR_REG); + if (ccerr) { + device_printf(sc->sc_dev, " !!! CCER %08x\n", ccerr); + EDMA_WRITE(sc, EDMA_CCERRCLR_REG, ccerr); + } + + EDMA_WRITE(sc, EDMA_EESR_REG + off, bit); + return 0; +} + +/* + * Software-start a DMA channel: Set the Event bit. + */ +int +edma_transfer_start(struct edma_channel *ch) +{ + struct edma_softc *sc = ch->ch_sc; + bus_size_t off = (ch->ch_index < 32 ? 0 : 4); + uint32_t bit = __BIT(ch->ch_index < 32 ? + ch->ch_index : ch->ch_index - 32); + + DPRINTF(1, (sc->sc_dev, "start transfer ch# %d off %d bit %x pe %d\n", ch->ch_index, (int)off, bit)); + + EDMA_WRITE(sc, EDMA_ESR_REG + off, bit); + return 0; +} + +/* + * Halt a DMA transfer. Called after successfull transfer, or to abort + * a transfer. + */ +void +edma_halt(struct edma_channel *ch) +{ + struct edma_softc *sc = ch->ch_sc; + bus_size_t off = (ch->ch_index < 32 ? 0 : 4); + uint32_t bit = __BIT(ch->ch_index < 32 ? + ch->ch_index : ch->ch_index - 32); + + EDMA_WRITE(sc, EDMA_EECR_REG + off, bit); + EDMA_WRITE(sc, EDMA_ECR_REG + off, bit); + EDMA_WRITE(sc, EDMA_SECR_REG + off, bit); + EDMA_WRITE(sc, EDMA_EMCR_REG + off, bit); + + EDMA_WRITE(sc, EDMA_DCHMAP_REG(ch->ch_index), + __SHIFTIN(0, EDMA_DCHMAP_PAENTRY)); +} + +uint8_t +edma_channel_index(struct edma_channel *ch) +{ + return ch->ch_index; +} + +void +edma_dump(struct edma_channel *ch) +{ + static const struct { + const char *name; + uint16_t off; + } regs[] = { + { "ER", EDMA_ER_REG }, + { "ERH", EDMA_ERH_REG }, + { "EER", EDMA_EER_REG }, + { "EERH", EDMA_EERH_REG }, + { "SER", EDMA_SER_REG }, + { "SERH", EDMA_SERH_REG }, + { "IER", EDMA_IER_REG }, + { "IERH", EDMA_IERH_REG }, + { "IPR", EDMA_IPR_REG }, + { "IPRH", EDMA_IPRH_REG }, + { "CCERR", EDMA_CCERR_REG }, + { "CCSTAT", EDMA_CCSTAT_REG }, + { "DRAE0", EDMA_DRAE_REG(0) }, + { "DRAEH0", EDMA_DRAEH_REG(0) }, + { NULL, 0 } + }; + struct edma_softc *sc = ch->ch_sc; + int i; + + for (i = 0; regs[i].name; i++) { + device_printf(sc->sc_dev, "%s: %08x\n", + regs[i].name, EDMA_READ(sc, regs[i].off)); + } + device_printf(sc->sc_dev, "DCHMAP%d: %08x\n", ch->ch_index, + EDMA_READ(sc, EDMA_DCHMAP_REG(ch->ch_index))); +} + +void +edma_dump_param(struct edma_channel *ch, uint16_t param_entry) +{ + struct { + const char *name; + uint16_t off; + } regs[] = { + { "OPT", EDMA_PARAM_OPT_REG(param_entry) }, + { "CNT", EDMA_PARAM_CNT_REG(param_entry) }, + { "DST", EDMA_PARAM_DST_REG(param_entry) }, + { "BIDX", EDMA_PARAM_BIDX_REG(param_entry) }, + { "LNK", EDMA_PARAM_LNK_REG(param_entry) }, + { "CIDX", EDMA_PARAM_CIDX_REG(param_entry) }, + { "CCNT", EDMA_PARAM_CCNT_REG(param_entry) }, + { NULL, 0 } + }; + struct edma_softc *sc = ch->ch_sc; + int i; + + for (i = 0; regs[i].name; i++) { + device_printf(sc->sc_dev, "%s%d: %08x\n", + regs[i].name, param_entry, EDMA_READ(sc, regs[i].off)); + } +} Index: src/sys/arch/arm/ti/ti_edma.h diff -u /dev/null src/sys/arch/arm/ti/ti_edma.h:1.1 --- /dev/null Sun Oct 27 12:14:51 2019 +++ src/sys/arch/arm/ti/ti_edma.h Sun Oct 27 12:14:51 2019 @@ -0,0 +1,173 @@ +/* $NetBSD: ti_edma.h,v 1.1 2019/10/27 12:14:51 jmcneill Exp $ */ + +/*- + * Copyright (c) 2014 Jared D. McNeill <jmcne...@invisible.ca> + * 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. The name of the author may not be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 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. + */ + +#ifndef _TI_EDMA_H +#define _TI_EDMA_H + +#define EDMA_PID_REG 0x0000 +#define EDMA_CCCFG_REG 0x0004 +#define EDMA_CCCFG_MP_EXIST __BIT(25) +#define EDMA_CCCFG_CHMAP_EXIST __BIT(24) +#define EDMA_CCCFG_NUM_REGN __BITS(21,20) +#define EDMA_CCCFG_NUM_EVQUEUE __BITS(18,16) +#define EDMA_CCCFG_NUM_PAENTRY __BITS(14,12) +#define EDMA_CCCFG_NUM_INTCH __BITS(10,8) +#define EDMA_CCCFG_NUM_QDMACH __BITS(6,4) +#define EDMA_CCCFG_NUM_DMACH __BITS(2,0) +#define EDMA_SYSCONFIG_REG 0x0010 +#define EDMA_DCHMAP_REG(n) (0x0100 + 4 * (n)) +#define EDMA_DCHMAP_PAENTRY __BITS(13,5) +#define EDMA_QCHMAP_REG(n) (0x0200 + 4 * (n)) +#define EDMA_DMAQNUM_REG(n) (0x0240 + 4 * (n)) +#define EDMA_QDMAQNUM_REG 0x0260 +#define EDMA_QUEPRI_REG 0x0284 +#define EDMA_EMR_REG 0x0300 +#define EDMA_EMRH_REG 0x0304 +#define EDMA_EMCR_REG 0x0308 +#define EDMA_EMCRH_REG 0x030c +#define EDMA_QEMR_REG 0x0310 +#define EDMA_QEMRC_REG 0x0314 +#define EDMA_CCERR_REG 0x0318 +#define EDMA_CCERRCLR_REG 0x031c +#define EDMA_EEVAL_REG 0x0320 +#define EDMA_DRAE_REG(n) (0x0340 + 8 * (n)) +#define EDMA_DRAEH_REG(n) (0x0340 + 8 * (n) + 4) +#define EDMA_QRAE_REG(n) (0x0380 + 4 * (n)) +#define EDMA_QE_REG(q, e) (0x0400 + 0x40 * (q) + 4 * (e)) +#define EDMA_QSTAT_REG(n) (0x0600 + 4 * (n)) +#define EDMA_QWMTHRA_REG 0x0620 +#define EDMA_CCSTAT_REG 0x0640 +#define EDMA_MPFAR_REG 0x0800 +#define EDMA_MPFSR_REG 0x0804 +#define EDMA_MPFCR_REG 0x0808 +#define EDMA_MPPAG_REG 0x080c +#define EDMA_MPPA_REG(n) (0x0810 + 4 * (n)) +#define EDMA_ER_REG 0x1000 +#define EDMA_ERH_REG 0x1004 +#define EDMA_ECR_REG 0x1008 +#define EDMA_ECRH_REG 0x100c +#define EDMA_ESR_REG 0x1010 +#define EDMA_ESRH_REG 0x1014 +#define EDMA_CER_REG 0x1018 +#define EDMA_CERH_REG 0x101c +#define EDMA_EER_REG 0x1020 +#define EDMA_EERH_REG 0x1024 +#define EDMA_EECR_REG 0x1028 +#define EDMA_EECRH_REG 0x102c +#define EDMA_EESR_REG 0x1030 +#define EDMA_EESRH_REG 0x1034 +#define EDMA_SER_REG 0x1038 +#define EDMA_SERH_REG 0x103c +#define EDMA_SECR_REG 0x1040 +#define EDMA_SECRH_REG 0x1044 +#define EDMA_IER_REG 0x1050 +#define EDMA_IERH_REG 0x1054 +#define EDMA_IECR_REG 0x1058 +#define EDMA_IECRH_REG 0x105c +#define EDMA_IESR_REG 0x1060 +#define EDMA_IESRH_REG 0x1064 +#define EDMA_IPR_REG 0x1068 +#define EDMA_IPRH_REG 0x106c +#define EDMA_ICR_REG 0x1070 +#define EDMA_ICRH_REG 0x1074 +#define EDMA_IEVAL_REG 0x1078 +#define EDMA_IEVAL_EVAL __BIT(0) +#define EDMA_QER_REG 0x1080 +#define EDMA_QEER_REG 0x1084 +#define EDMA_QEECR_REG 0x1088 +#define EDMA_QEESR_REG 0x108c +#define EDMA_QSER_REG 0x1090 +#define EDMA_QSECR_REG 0x1094 + +#define EDMA_PARAM_BASE(n) (0x4000 + 0x20 * (n)) +#define EDMA_PARAM_OPT_REG(n) (EDMA_PARAM_BASE(n) + 0x00) +#define EDMA_PARAM_OPT_PRIV __BIT(31) +#define EDMA_PARAM_OPT_PRIVID __BITS(27,24) +#define EDMA_PARAM_OPT_ITCCHEN __BIT(23) +#define EDMA_PARAM_OPT_TCCHEN __BIT(22) +#define EDMA_PARAM_OPT_ITCINTEN __BIT(21) +#define EDMA_PARAM_OPT_TCINTEN __BIT(20) +#define EDMA_PARAM_OPT_TCC __BITS(17,12) +#define EDMA_PARAM_OPT_TCCMODE __BIT(11) +#define EDMA_PARAM_OPT_FWID __BITS(10,8) +#define EDMA_PARAM_OPT_STATIC __BIT(3) +#define EDMA_PARAM_OPT_SYNCDIM __BIT(2) +#define EDMA_PARAM_OPT_DAM __BIT(1) +#define EDMA_PARAM_OPT_SAM __BIT(0) +#define EDMA_PARAM_SRC_REG(n) (EDMA_PARAM_BASE(n) + 0x04) +#define EDMA_PARAM_CNT_REG(n) (EDMA_PARAM_BASE(n) + 0x08) +#define EDMA_PARAM_CNT_BCNT __BITS(31,16) +#define EDMA_PARAM_CNT_ACNT __BITS(15,0) +#define EDMA_PARAM_DST_REG(n) (EDMA_PARAM_BASE(n) + 0x0c) +#define EDMA_PARAM_BIDX_REG(n) (EDMA_PARAM_BASE(n) + 0x10) +#define EDMA_PARAM_BIDX_DSTBIDX __BITS(31,16) +#define EDMA_PARAM_BIDX_SRCBIDX __BITS(15,0) +#define EDMA_PARAM_LNK_REG(n) (EDMA_PARAM_BASE(n) + 0x14) +#define EDMA_PARAM_LNK_BCNTRLD __BITS(31,16) +#define EDMA_PARAM_LNK_LINK __BITS(15,0) +#define EDMA_PARAM_CIDX_REG(n) (EDMA_PARAM_BASE(n) + 0x18) +#define EDMA_PARAM_CIDX_DSTCIDX __BITS(31,16) +#define EDMA_PARAM_CIDX_SRCCIDX __BITS(15,0) +#define EDMA_PARAM_CCNT_REG(n) (EDMA_PARAM_BASE(n) + 0x1c) +#define EDMA_PARAM_CCNT_CCNT __BITS(15,0) + +enum edma_type { + EDMA_TYPE_DMA, + EDMA_TYPE_QDMA +}; + +struct edma_param { + uint32_t ep_opt; + uint32_t ep_src; + uint32_t ep_dst; + uint16_t ep_bcnt; + uint16_t ep_acnt; + uint16_t ep_dstbidx; + uint16_t ep_srcbidx; + uint16_t ep_bcntrld; + uint16_t ep_link; + uint16_t ep_dstcidx; + uint16_t ep_srccidx; + uint16_t ep_ccnt; +}; + +struct edma_channel; + +struct edma_channel *edma_channel_alloc(enum edma_type, unsigned int, + void (*)(void *), void *); +void edma_channel_free(struct edma_channel *); +uint16_t edma_param_alloc(struct edma_channel *); +void edma_param_free(struct edma_channel *, uint16_t); +void edma_set_param(struct edma_channel *, uint16_t, struct edma_param *); +int edma_transfer_enable(struct edma_channel *, uint16_t); +int edma_transfer_start(struct edma_channel *); +void edma_halt(struct edma_channel *); +uint8_t edma_channel_index(struct edma_channel *); +void edma_dump(struct edma_channel *); +void edma_dump_param(struct edma_channel *, uint16_t); + +#endif /* !_TI_EDMA_H */ Index: src/sys/arch/arm/ti/ti_tptc.c diff -u /dev/null src/sys/arch/arm/ti/ti_tptc.c:1.1 --- /dev/null Sun Oct 27 12:14:51 2019 +++ src/sys/arch/arm/ti/ti_tptc.c Sun Oct 27 12:14:51 2019 @@ -0,0 +1,75 @@ +/* $NetBSD: ti_tptc.c,v 1.1 2019/10/27 12:14:51 jmcneill Exp $ */ + +/*- + * Copyright (c) 2019 Jared McNeill <jmcne...@invisible.ca> + * 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 ``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 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 <sys/cdefs.h> +__KERNEL_RCSID(0, "$NetBSD: ti_tptc.c,v 1.1 2019/10/27 12:14:51 jmcneill Exp $"); + +#include <sys/param.h> +#include <sys/bus.h> +#include <sys/device.h> +#include <sys/intr.h> +#include <sys/systm.h> +#include <sys/kernel.h> +#include <sys/kmem.h> + +#include <dev/fdt/fdtvar.h> + +#include <arm/ti/ti_prcm.h> + +static int ti_tptc_match(device_t, cfdata_t, void *); +static void ti_tptc_attach(device_t, device_t, void *); + +CFATTACH_DECL_NEW(ti_tptc, 0, ti_tptc_match, ti_tptc_attach, NULL, NULL); + +static const char * compatible[] = { + "ti,edma3-tptc", + NULL +}; + +static int +ti_tptc_match(device_t parent, cfdata_t cf, void *aux) +{ + struct fdt_attach_args * const faa = aux; + + return of_match_compatible(faa->faa_phandle, compatible); +} + +static void +ti_tptc_attach(device_t parent, device_t self, void *aux) +{ + struct fdt_attach_args * const faa = aux; + const int phandle = faa->faa_phandle; + + aprint_naive("\n"); + aprint_normal(": EDMA Transfer Controller\n"); + + if (ti_prcm_enable_hwmod(phandle, 0) != 0) { + aprint_error_dev(self, "couldn't enable module\n"); + return; + } +}