1 /* $OpenBSD: edma.c,v 1.5 2015/01/22 14:33:01 krw 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/types.h> 20 #include <sys/systm.h> 21 22 #include <machine/bus.h> 23 24 #include <armv7/armv7/armv7var.h> 25 #include <armv7/omap/prcmvar.h> 26 #include <armv7/omap/edmavar.h> 27 28 #define DEVNAME(s) ((s)->sc_dev.dv_xname) 29 30 struct edma_softc { 31 struct device sc_dev; 32 33 bus_space_tag_t sc_iot; 34 bus_space_handle_t sc_tpcc; 35 36 void *sc_ih_comp; 37 edma_intr_cb_t sc_intr_cb[64]; 38 void *sc_intr_dat[64]; 39 }; 40 41 #define EDMA_NUM_DMA_CHANS 64 42 #define EDMA_NUM_QDMA_CHANS 8 43 #define EDMA_TPCC_DHCM(x) (0x100 + (x * 4)) 44 #define EDMA_REG_X(x) (0x1000 + (0x200 * x)) 45 #define EDMA_TPCC_PID 0x0 46 #define EDMA_TPCC_EMCR 0x308 47 #define EDMA_TPCC_EMCRH 0x30c 48 #define EDMA_TPCC_CCERRCLR 0x31c 49 #define EDMA_TPCC_DRAE0 0x340 50 #define EDMA_TPCC_DRAEH0 0x344 51 #define EDMA_TPCC_ESR 0x1010 52 #define EDMA_TPCC_ESRH 0x1014 53 #define EDMA_TPCC_EESR 0x1030 54 #define EDMA_TPCC_EESRH 0x1034 55 #define EDMA_TPCC_SECR 0x1040 56 #define EDMA_TPCC_SECRH 0x1044 57 #define EDMA_TPCC_IER 0x1050 58 #define EDMA_TPCC_IERH 0x1054 59 #define EDMA_TPCC_IECR 0x1058 60 #define EDMA_TPCC_IECRH 0x105c 61 #define EDMA_TPCC_IESR 0x1060 62 #define EDMA_TPCC_IESRH 0x1064 63 #define EDMA_TPCC_IPR 0x1068 64 #define EDMA_TPCC_IPRH 0x106c 65 #define EDMA_TPCC_ICR 0x1070 66 #define EDMA_TPCC_ICRH 0x1074 67 #define EDMA_TPCC_IEVAL 0x1078 68 #define EDMA_TPCC_OPT(x) (0x4000 + (x * 0x20)) 69 70 #define TPCC_READ_4(sc, reg) \ 71 (bus_space_read_4((sc)->sc_iot, (sc)->sc_tpcc, (reg))) 72 #define TPCC_WRITE_4(sc, reg, val) \ 73 (bus_space_write_4((sc)->sc_iot, (sc)->sc_tpcc, (reg), (val))) 74 #define TPCC_SET(sc, reg, val) \ 75 (TPCC_WRITE_4((sc), (reg), (TPCC_READ_4(sc, reg) | (val)))) 76 #define TPCC_FILTSET(sc, reg, val, filt) \ 77 (TPCC_WRITE_4((sc), (reg), (TPCC_READ_4(sc, reg) & (filt)) | (val))) 78 79 struct edma_softc *edma_sc; 80 81 void edma_attach(struct device *, struct device *, void *); 82 int edma_comp_intr(void *); 83 84 struct cfattach edma_ca = { 85 sizeof(struct edma_softc), NULL, edma_attach 86 }; 87 88 struct cfdriver edma_cd = { 89 NULL, "edma", DV_DULL 90 }; 91 92 void 93 edma_attach(struct device *parent, struct device *self, void *aux) 94 { 95 struct armv7_attach_args *aa = aux; 96 struct edma_softc *sc = (struct edma_softc *)self; 97 uint32_t rev; 98 int i; 99 100 sc->sc_iot = aa->aa_iot; 101 102 /* Map Base address for TPCC and TPCTX */ 103 if (bus_space_map(sc->sc_iot, aa->aa_dev->mem[0].addr, 104 aa->aa_dev->mem[0].size, 0, &sc->sc_tpcc)) { 105 printf("%s: bus_space_map failed for TPCC\n", DEVNAME(sc)); 106 return ; 107 } 108 109 /* Enable TPCC and TPTC0 in PRCM */ 110 prcm_enablemodule(PRCM_TPCC); 111 prcm_enablemodule(PRCM_TPTC0); 112 113 rev = TPCC_READ_4(sc, EDMA_TPCC_PID); 114 printf(" rev %d.%d\n", rev >> 4 & 0xf, rev & 0xf); 115 116 /* XXX IPL_VM ? */ 117 /* Enable interrupts line */ 118 sc->sc_ih_comp = arm_intr_establish(aa->aa_dev->irq[0], IPL_VM, 119 edma_comp_intr, sc, DEVNAME(sc)); 120 if (sc->sc_ih_comp == NULL) { 121 printf("%s: unable to establish interrupt comp\n", DEVNAME(sc)); 122 bus_space_unmap(sc->sc_iot, sc->sc_tpcc, 123 aa->aa_dev->mem[0].size); 124 return ; 125 } 126 127 /* Set global softc */ 128 edma_sc = sc; 129 130 /* Clear Event Missed Events */ 131 TPCC_WRITE_4(sc, EDMA_TPCC_EMCR, 0xffffffff); 132 TPCC_WRITE_4(sc, EDMA_TPCC_EMCRH, 0xffffffff); 133 TPCC_WRITE_4(sc, EDMA_TPCC_CCERRCLR, 0xffffffff); 134 135 /* Identity Map Channels PaRAM */ 136 for (i = 0; i < EDMA_NUM_DMA_CHANS; i++) 137 TPCC_WRITE_4(sc, EDMA_TPCC_DHCM(i), i << 5); 138 139 /* 140 * Enable SHADOW Region 0 and only use this region 141 * This is needed to have working intr... 142 */ 143 TPCC_WRITE_4(sc, EDMA_TPCC_DRAE0, 0xffffffff); 144 TPCC_WRITE_4(sc, EDMA_TPCC_DRAEH0, 0xffffffff); 145 146 return ; 147 } 148 149 int 150 edma_comp_intr(void *arg) 151 { 152 struct edma_softc *sc = arg; 153 uint32_t ipr, iprh; 154 int i; 155 156 ipr = TPCC_READ_4(sc, EDMA_TPCC_IPR); 157 iprh = TPCC_READ_4(sc, EDMA_TPCC_IPRH); 158 159 /* Lookup to intr in the first 32 chans */ 160 for (i = 0; i < (EDMA_NUM_DMA_CHANS/2); i++) { 161 if (ISSET(ipr, (1<<i))) { 162 TPCC_WRITE_4(sc, EDMA_TPCC_ICR, (1<<i)); 163 if (sc->sc_intr_cb[i]) 164 sc->sc_intr_cb[i](sc->sc_intr_dat[i]); 165 } 166 } 167 168 for (i = 0; i < (EDMA_NUM_DMA_CHANS/2); i++) { 169 if (ISSET(iprh, (1<<i))) { 170 TPCC_WRITE_4(sc, EDMA_TPCC_ICRH, (1<<i)); 171 if (sc->sc_intr_cb[i + 32]) 172 sc->sc_intr_cb[i + 32](sc->sc_intr_dat[i + 32]); 173 } 174 } 175 176 /* Trig pending intr */ 177 TPCC_WRITE_4(sc, EDMA_TPCC_IEVAL, 1); 178 179 return (1); 180 } 181 182 int 183 edma_intr_dma_en(uint32_t ch, edma_intr_cb_t cb, void *dat) 184 { 185 if (edma_sc == NULL || ch >= EDMA_NUM_DMA_CHANS) 186 return (EINVAL); 187 188 edma_sc->sc_intr_cb[ch] = cb; 189 edma_sc->sc_intr_dat[ch] = dat; 190 191 if (ch < 32) { 192 TPCC_WRITE_4(edma_sc, EDMA_TPCC_IESR, 1 << ch); 193 TPCC_WRITE_4(edma_sc, EDMA_TPCC_IESR + EDMA_REG_X(0), 1 << ch); 194 } else { 195 TPCC_WRITE_4(edma_sc, EDMA_TPCC_IESRH, 1 << (ch - 32)); 196 TPCC_WRITE_4(edma_sc, EDMA_TPCC_IESRH + EDMA_REG_X(0), 197 1 << (ch - 32)); 198 } 199 200 return (0); 201 } 202 203 int 204 edma_intr_dma_dis(uint32_t ch) 205 { 206 if (edma_sc == NULL || ch >= EDMA_NUM_DMA_CHANS) 207 return (EINVAL); 208 209 if (ch < 32) 210 TPCC_WRITE_4(edma_sc, EDMA_TPCC_IECR, 1 << ch); 211 else 212 TPCC_WRITE_4(edma_sc, EDMA_TPCC_IECRH, 1 << (ch - 32)); 213 edma_sc->sc_intr_cb[ch] = NULL; 214 edma_sc->sc_intr_dat[ch] = NULL; 215 216 return (0); 217 } 218 219 int 220 edma_trig_xfer_man(uint32_t ch) 221 { 222 if (edma_sc == NULL || ch >= EDMA_NUM_DMA_CHANS) 223 return (EINVAL); 224 225 /* 226 * Trig xfer 227 * enable IEVAL only if there is an intr associated 228 */ 229 if (ch < 32) { 230 if (ISSET(TPCC_READ_4(edma_sc, EDMA_TPCC_IER), 1 << ch)) 231 TPCC_WRITE_4(edma_sc, EDMA_TPCC_IEVAL, 1); 232 TPCC_WRITE_4(edma_sc, EDMA_TPCC_ICR, 1 << ch); 233 TPCC_WRITE_4(edma_sc, EDMA_TPCC_EMCR, 1 << ch); 234 TPCC_WRITE_4(edma_sc, EDMA_TPCC_ESR, 1 << ch); 235 } else { 236 if (ISSET(TPCC_READ_4(edma_sc, EDMA_TPCC_IERH), 1 << (ch - 32))) 237 TPCC_WRITE_4(edma_sc, EDMA_TPCC_IEVAL, 1); 238 TPCC_WRITE_4(edma_sc, EDMA_TPCC_ICRH, 1 << (ch - 32)); 239 TPCC_WRITE_4(edma_sc, EDMA_TPCC_EMCRH, 1 << (ch - 32)); 240 TPCC_WRITE_4(edma_sc, EDMA_TPCC_ESRH, 1 << (ch - 32)); 241 } 242 243 return (0); 244 } 245 246 int 247 edma_trig_xfer_by_dev(uint32_t ch) 248 { 249 if (edma_sc == NULL || ch >= EDMA_NUM_DMA_CHANS) 250 return (EINVAL); 251 252 if (ch < 32) { 253 if (ISSET(TPCC_READ_4(edma_sc, EDMA_TPCC_IER), 1 << ch)) 254 TPCC_WRITE_4(edma_sc, EDMA_TPCC_IEVAL, 1); 255 TPCC_WRITE_4(edma_sc, EDMA_TPCC_ICR, 1 << ch); 256 TPCC_WRITE_4(edma_sc, EDMA_TPCC_SECR, 1 << ch); 257 TPCC_WRITE_4(edma_sc, EDMA_TPCC_EMCR, 1 << ch); 258 TPCC_WRITE_4(edma_sc, EDMA_TPCC_EESR, 1 << ch); 259 } else { 260 if (ISSET(TPCC_READ_4(edma_sc, EDMA_TPCC_IERH), 1 << (ch - 32))) 261 TPCC_WRITE_4(edma_sc, EDMA_TPCC_IEVAL, 1); 262 TPCC_WRITE_4(edma_sc, EDMA_TPCC_ICRH, 1 << (ch - 32)); 263 TPCC_WRITE_4(edma_sc, EDMA_TPCC_SECRH, 1 << (ch - 32)); 264 TPCC_WRITE_4(edma_sc, EDMA_TPCC_EMCRH, 1 << (ch - 32)); 265 TPCC_WRITE_4(edma_sc, EDMA_TPCC_EESRH, 1 << (ch - 32)); 266 } 267 return (0); 268 } 269 270 void 271 edma_param_write(uint32_t ch, struct edma_param *params) 272 { 273 bus_space_write_region_4(edma_sc->sc_iot, edma_sc->sc_tpcc, 274 EDMA_TPCC_OPT(ch), (uint32_t *)params, 8); 275 } 276 277 void 278 edma_param_read(uint32_t ch, struct edma_param *params) 279 { 280 bus_space_read_region_4(edma_sc->sc_iot, edma_sc->sc_tpcc, 281 EDMA_TPCC_OPT(ch), (uint32_t *)params, 8); 282 } 283 284