1/* $OpenBSD: edma.c,v 1.8 2021/10/24 17:52:27 mpi Exp $ */ 2/* 3 * Copyright (c) 2013 Sylvestre Gallon <ccna.syl@gmail.com> 4 * 5 * Permission to use, copy, modify, and distribute this software for any 6 * purpose with or without fee is hereby granted, provided that the above 7 * copyright notice and this permission notice appear in all copies. 8 * 9 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 10 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 11 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR 12 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 13 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 14 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF 15 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 16 */ 17 18#include <sys/param.h> 19#include <sys/systm.h> 20 21#include <machine/fdt.h> 22 23#include <armv7/armv7/armv7var.h> 24#include <armv7/omap/prcmvar.h> 25#include <armv7/omap/edmavar.h> 26 27#include <dev/ofw/openfirm.h> 28#include <dev/ofw/fdt.h> 29 30#define DEVNAME(s) ((s)->sc_dev.dv_xname) 31 32struct edma_softc { 33 struct device sc_dev; 34 35 bus_space_tag_t sc_iot; 36 bus_space_handle_t sc_tpcc; 37 38 void *sc_ih_comp; 39 edma_intr_cb_t sc_intr_cb[64]; 40 void *sc_intr_dat[64]; 41}; 42 43#define EDMA_NUM_DMA_CHANS 64 44#define EDMA_NUM_QDMA_CHANS 8 45#define EDMA_TPCC_DHCM(x) (0x100 + (x * 4)) 46#define EDMA_REG_X(x) (0x1000 + (0x200 * x)) 47#define EDMA_TPCC_PID 0x0 48#define EDMA_TPCC_EMCR 0x308 49#define EDMA_TPCC_EMCRH 0x30c 50#define EDMA_TPCC_CCERRCLR 0x31c 51#define EDMA_TPCC_DRAE0 0x340 52#define EDMA_TPCC_DRAEH0 0x344 53#define EDMA_TPCC_ESR 0x1010 54#define EDMA_TPCC_ESRH 0x1014 55#define EDMA_TPCC_EESR 0x1030 56#define EDMA_TPCC_EESRH 0x1034 57#define EDMA_TPCC_SECR 0x1040 58#define EDMA_TPCC_SECRH 0x1044 59#define EDMA_TPCC_IER 0x1050 60#define EDMA_TPCC_IERH 0x1054 61#define EDMA_TPCC_IECR 0x1058 62#define EDMA_TPCC_IECRH 0x105c 63#define EDMA_TPCC_IESR 0x1060 64#define EDMA_TPCC_IESRH 0x1064 65#define EDMA_TPCC_IPR 0x1068 66#define EDMA_TPCC_IPRH 0x106c 67#define EDMA_TPCC_ICR 0x1070 68#define EDMA_TPCC_ICRH 0x1074 69#define EDMA_TPCC_IEVAL 0x1078 70#define EDMA_TPCC_OPT(x) (0x4000 + (x * 0x20)) 71 72#define TPCC_READ_4(sc, reg) \ 73 (bus_space_read_4((sc)->sc_iot, (sc)->sc_tpcc, (reg))) 74#define TPCC_WRITE_4(sc, reg, val) \ 75 (bus_space_write_4((sc)->sc_iot, (sc)->sc_tpcc, (reg), (val))) 76#define TPCC_SET(sc, reg, val) \ 77 (TPCC_WRITE_4((sc), (reg), (TPCC_READ_4(sc, reg) | (val)))) 78#define TPCC_FILTSET(sc, reg, val, filt) \ 79 (TPCC_WRITE_4((sc), (reg), (TPCC_READ_4(sc, reg) & (filt)) | (val))) 80 81struct edma_softc *edma_sc; 82 83int edma_match(struct device *, void *, void *); 84void edma_attach(struct device *, struct device *, void *); 85int edma_comp_intr(void *); 86 87const struct cfattach edma_ca = { 88 sizeof(struct edma_softc), edma_match, edma_attach 89}; 90 91struct cfdriver edma_cd = { 92 NULL, "edma", DV_DULL 93}; 94 95int 96edma_match(struct device *parent, void *match, void *aux) 97{ 98 struct fdt_attach_args *faa = aux; 99 100 return OF_is_compatible(faa->fa_node, "ti,edma3-tpcc"); 101} 102 103void 104edma_attach(struct device *parent, struct device *self, void *aux) 105{ 106 struct fdt_attach_args *faa = aux; 107 struct edma_softc *sc = (struct edma_softc *)self; 108 uint32_t rev; 109 int i; 110 111 if (faa->fa_nreg < 1) 112 return; 113 114 sc->sc_iot = faa->fa_iot; 115 116 /* Map Base address for TPCC and TPCTX */ 117 if (bus_space_map(sc->sc_iot, faa->fa_reg[0].addr, 118 faa->fa_reg[0].size, 0, &sc->sc_tpcc)) { 119 printf("%s: bus_space_map failed for TPCC\n", DEVNAME(sc)); 120 return ; 121 } 122 123 /* Enable TPCC and TPTC0 in PRCM */ 124 prcm_enablemodule(PRCM_TPCC); 125 prcm_enablemodule(PRCM_TPTC0); 126 127 rev = TPCC_READ_4(sc, EDMA_TPCC_PID); 128 printf(" rev %d.%d\n", rev >> 4 & 0xf, rev & 0xf); 129 130 /* XXX IPL_VM ? */ 131 /* Enable interrupts line */ 132 sc->sc_ih_comp = arm_intr_establish_fdt(faa->fa_node, IPL_VM, 133 edma_comp_intr, sc, DEVNAME(sc)); 134 if (sc->sc_ih_comp == NULL) { 135 printf("%s: unable to establish interrupt comp\n", DEVNAME(sc)); 136 bus_space_unmap(sc->sc_iot, sc->sc_tpcc, 137 faa->fa_reg[0].size); 138 return ; 139 } 140 141 /* Set global softc */ 142 edma_sc = sc; 143 144 /* Clear Event Missed Events */ 145 TPCC_WRITE_4(sc, EDMA_TPCC_EMCR, 0xffffffff); 146 TPCC_WRITE_4(sc, EDMA_TPCC_EMCRH, 0xffffffff); 147 TPCC_WRITE_4(sc, EDMA_TPCC_CCERRCLR, 0xffffffff); 148 149 /* Identity Map Channels PaRAM */ 150 for (i = 0; i < EDMA_NUM_DMA_CHANS; i++) 151 TPCC_WRITE_4(sc, EDMA_TPCC_DHCM(i), i << 5); 152 153 /* 154 * Enable SHADOW Region 0 and only use this region 155 * This is needed to have working intr... 156 */ 157 TPCC_WRITE_4(sc, EDMA_TPCC_DRAE0, 0xffffffff); 158 TPCC_WRITE_4(sc, EDMA_TPCC_DRAEH0, 0xffffffff); 159 160 return ; 161} 162 163int 164edma_comp_intr(void *arg) 165{ 166 struct edma_softc *sc = arg; 167 uint32_t ipr, iprh; 168 int i; 169 170 ipr = TPCC_READ_4(sc, EDMA_TPCC_IPR); 171 iprh = TPCC_READ_4(sc, EDMA_TPCC_IPRH); 172 173 /* Lookup to intr in the first 32 chans */ 174 for (i = 0; i < (EDMA_NUM_DMA_CHANS/2); i++) { 175 if (ISSET(ipr, (1<<i))) { 176 TPCC_WRITE_4(sc, EDMA_TPCC_ICR, (1<<i)); 177 if (sc->sc_intr_cb[i]) 178 sc->sc_intr_cb[i](sc->sc_intr_dat[i]); 179 } 180 } 181 182 for (i = 0; i < (EDMA_NUM_DMA_CHANS/2); i++) { 183 if (ISSET(iprh, (1<<i))) { 184 TPCC_WRITE_4(sc, EDMA_TPCC_ICRH, (1<<i)); 185 if (sc->sc_intr_cb[i + 32]) 186 sc->sc_intr_cb[i + 32](sc->sc_intr_dat[i + 32]); 187 } 188 } 189 190 /* Trig pending intr */ 191 TPCC_WRITE_4(sc, EDMA_TPCC_IEVAL, 1); 192 193 return (1); 194} 195 196int 197edma_intr_dma_en(uint32_t ch, edma_intr_cb_t cb, void *dat) 198{ 199 if (edma_sc == NULL || ch >= EDMA_NUM_DMA_CHANS) 200 return (EINVAL); 201 202 edma_sc->sc_intr_cb[ch] = cb; 203 edma_sc->sc_intr_dat[ch] = dat; 204 205 if (ch < 32) { 206 TPCC_WRITE_4(edma_sc, EDMA_TPCC_IESR, 1 << ch); 207 TPCC_WRITE_4(edma_sc, EDMA_TPCC_IESR + EDMA_REG_X(0), 1 << ch); 208 } else { 209 TPCC_WRITE_4(edma_sc, EDMA_TPCC_IESRH, 1 << (ch - 32)); 210 TPCC_WRITE_4(edma_sc, EDMA_TPCC_IESRH + EDMA_REG_X(0), 211 1 << (ch - 32)); 212 } 213 214 return (0); 215} 216 217int 218edma_intr_dma_dis(uint32_t ch) 219{ 220 if (edma_sc == NULL || ch >= EDMA_NUM_DMA_CHANS) 221 return (EINVAL); 222 223 if (ch < 32) 224 TPCC_WRITE_4(edma_sc, EDMA_TPCC_IECR, 1 << ch); 225 else 226 TPCC_WRITE_4(edma_sc, EDMA_TPCC_IECRH, 1 << (ch - 32)); 227 edma_sc->sc_intr_cb[ch] = NULL; 228 edma_sc->sc_intr_dat[ch] = NULL; 229 230 return (0); 231} 232 233int 234edma_trig_xfer_man(uint32_t ch) 235{ 236 if (edma_sc == NULL || ch >= EDMA_NUM_DMA_CHANS) 237 return (EINVAL); 238 239 /* 240 * Trig xfer 241 * enable IEVAL only if there is an intr associated 242 */ 243 if (ch < 32) { 244 if (ISSET(TPCC_READ_4(edma_sc, EDMA_TPCC_IER), 1 << ch)) 245 TPCC_WRITE_4(edma_sc, EDMA_TPCC_IEVAL, 1); 246 TPCC_WRITE_4(edma_sc, EDMA_TPCC_ICR, 1 << ch); 247 TPCC_WRITE_4(edma_sc, EDMA_TPCC_EMCR, 1 << ch); 248 TPCC_WRITE_4(edma_sc, EDMA_TPCC_ESR, 1 << ch); 249 } else { 250 if (ISSET(TPCC_READ_4(edma_sc, EDMA_TPCC_IERH), 1 << (ch - 32))) 251 TPCC_WRITE_4(edma_sc, EDMA_TPCC_IEVAL, 1); 252 TPCC_WRITE_4(edma_sc, EDMA_TPCC_ICRH, 1 << (ch - 32)); 253 TPCC_WRITE_4(edma_sc, EDMA_TPCC_EMCRH, 1 << (ch - 32)); 254 TPCC_WRITE_4(edma_sc, EDMA_TPCC_ESRH, 1 << (ch - 32)); 255 } 256 257 return (0); 258} 259 260int 261edma_trig_xfer_by_dev(uint32_t ch) 262{ 263 if (edma_sc == NULL || ch >= EDMA_NUM_DMA_CHANS) 264 return (EINVAL); 265 266 if (ch < 32) { 267 if (ISSET(TPCC_READ_4(edma_sc, EDMA_TPCC_IER), 1 << ch)) 268 TPCC_WRITE_4(edma_sc, EDMA_TPCC_IEVAL, 1); 269 TPCC_WRITE_4(edma_sc, EDMA_TPCC_ICR, 1 << ch); 270 TPCC_WRITE_4(edma_sc, EDMA_TPCC_SECR, 1 << ch); 271 TPCC_WRITE_4(edma_sc, EDMA_TPCC_EMCR, 1 << ch); 272 TPCC_WRITE_4(edma_sc, EDMA_TPCC_EESR, 1 << ch); 273 } else { 274 if (ISSET(TPCC_READ_4(edma_sc, EDMA_TPCC_IERH), 1 << (ch - 32))) 275 TPCC_WRITE_4(edma_sc, EDMA_TPCC_IEVAL, 1); 276 TPCC_WRITE_4(edma_sc, EDMA_TPCC_ICRH, 1 << (ch - 32)); 277 TPCC_WRITE_4(edma_sc, EDMA_TPCC_SECRH, 1 << (ch - 32)); 278 TPCC_WRITE_4(edma_sc, EDMA_TPCC_EMCRH, 1 << (ch - 32)); 279 TPCC_WRITE_4(edma_sc, EDMA_TPCC_EESRH, 1 << (ch - 32)); 280 } 281 return (0); 282} 283 284void 285edma_param_write(uint32_t ch, struct edma_param *params) 286{ 287 bus_space_write_region_4(edma_sc->sc_iot, edma_sc->sc_tpcc, 288 EDMA_TPCC_OPT(ch), (uint32_t *)params, 8); 289} 290 291void 292edma_param_read(uint32_t ch, struct edma_param *params) 293{ 294 bus_space_read_region_4(edma_sc->sc_iot, edma_sc->sc_tpcc, 295 EDMA_TPCC_OPT(ch), (uint32_t *)params, 8); 296} 297 298