1 /* $OpenBSD: edma.c,v 1.7 2017/09/08 05:36:51 deraadt 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 32 struct 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 81 struct edma_softc *edma_sc; 82 83 int edma_match(struct device *, void *, void *); 84 void edma_attach(struct device *, struct device *, void *); 85 int edma_comp_intr(void *); 86 87 struct cfattach edma_ca = { 88 sizeof(struct edma_softc), edma_match, edma_attach 89 }; 90 91 struct cfdriver edma_cd = { 92 NULL, "edma", DV_DULL 93 }; 94 95 int 96 edma_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 103 void 104 edma_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 163 int 164 edma_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 196 int 197 edma_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 217 int 218 edma_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 233 int 234 edma_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 260 int 261 edma_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 284 void 285 edma_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 291 void 292 edma_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