dmac3.c revision 1.1 1 /* $NetBSD: dmac3.c,v 1.1 2000/10/30 10:07:35 tsubai Exp $ */
2
3 /*-
4 * Copyright (c) 2000 Tsubai Masanari. All rights reserved.
5 *
6 * Redistribution and use in source and binary forms, with or without
7 * modification, are permitted provided that the following conditions
8 * are met:
9 * 1. Redistributions of source code must retain the above copyright
10 * notice, this list of conditions and the following disclaimer.
11 * 2. Redistributions in binary form must reproduce the above copyright
12 * notice, this list of conditions and the following disclaimer in the
13 * documentation and/or other materials provided with the distribution.
14 * 3. The name of the author may not be used to endorse or promote products
15 * derived from this software without specific prior written permission.
16 *
17 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
18 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
19 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
20 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
21 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
22 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
23 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
24 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
25 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
26 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
27 */
28
29 #include <sys/param.h>
30 #include <sys/device.h>
31 #include <sys/kernel.h>
32 #include <sys/systm.h>
33
34 #include <uvm/uvm_extern.h>
35
36 #include <machine/locore.h>
37
38 #include <newsmips/apbus/apbusvar.h>
39 #include <newsmips/apbus/dmac3reg.h>
40
41 #define DMA_BURST
42 #define DMA_APAD_OFF
43
44 #ifdef DMA_APAD_OFF
45 # define APAD_MODE 0
46 #else
47 # define APAD_MODE DMAC3_CSR_APAD
48 #endif
49
50 #ifdef DMA_BURST
51 # define BURST_MODE (DMAC3_CSR_DBURST | DMAC3_CSR_MBURST)
52 #else
53 # define BURST_MODE 0
54 #endif
55
56 struct dmac3_softc {
57 struct device sc_dev;
58 struct dmac3reg *sc_reg;
59 vaddr_t sc_dmaaddr;
60 int *sc_dmamap;
61 int sc_conf;
62 int sc_ctlnum;
63 };
64
65 int dmac3_match __P((struct device *, struct cfdata *, void *));
66 void dmac3_attach __P((struct device *, struct device *, void *));
67
68 paddr_t kvtophys __P((vaddr_t));
69
70 struct cfattach dmac_ca = {
71 sizeof(struct dmac3_softc), dmac3_match, dmac3_attach
72 };
73
74 int
75 dmac3_match(parent, cf, aux)
76 struct device *parent;
77 struct cfdata *cf;
78 void *aux;
79 {
80 struct apbus_attach_args *apa = aux;
81
82 if (strcmp(apa->apa_name, "dmac3") == 0)
83 return 1;
84
85 return 0;
86 }
87
88 void
89 dmac3_attach(parent, self, aux)
90 struct device *parent, *self;
91 void *aux;
92 {
93 struct dmac3_softc *sc = (void *)self;
94 struct apbus_attach_args *apa = aux;
95 struct dmac3reg *reg;
96
97 static paddr_t dmamap = DMAC3_PAGEMAP;
98 static vaddr_t dmaaddr = 0;
99
100 reg = (void *)apa->apa_hwbase;
101 sc->sc_reg = reg;
102 sc->sc_ctlnum = apa->apa_ctlnum;
103 sc->sc_dmamap = (int *)dmamap;
104 sc->sc_dmaaddr = dmaaddr;
105 dmamap += 0x1000;
106 dmaaddr += 0x200000;
107
108 sc->sc_conf = DMAC3_CONF_PCEN | DMAC3_CONF_DCEN | DMAC3_CONF_FASTACCESS;
109
110 dmac3_reset(sc);
111
112 printf(" slot%d addr 0x%lx", apa->apa_slotno, apa->apa_hwbase);
113 printf(": ctlnum = %d, map = %p, va = %lx",
114 apa->apa_ctlnum, sc->sc_dmamap, sc->sc_dmaaddr);
115 printf("\n");
116 }
117
118 void *
119 dmac3_link(ctlnum)
120 int ctlnum;
121 {
122 struct dmac3_softc *sc;
123 struct device *dv;
124
125 for (dv = alldevs.tqh_first; dv; dv = dv->dv_list.tqe_next) {
126 if (strncmp(dv->dv_xname, "dmac", 4) == 0) {
127 sc = (void *)dv;
128 if (sc->sc_ctlnum == ctlnum)
129 return sc;
130 }
131 }
132 return NULL;
133 }
134
135 void
136 dmac3_reset(sc)
137 struct dmac3_softc *sc;
138 {
139 struct dmac3reg *reg = sc->sc_reg;
140
141 reg->csr = DMAC3_CSR_RESET;
142 reg->csr = 0;
143 reg->intr = DMAC3_INTR_EOPIE | DMAC3_INTR_INTEN;
144 reg->conf = sc->sc_conf;
145 }
146
147 void
148 dmac3_start(sc, addr, len, direction)
149 struct dmac3_softc *sc;
150 vaddr_t addr;
151 int len, direction;
152 {
153 struct dmac3reg *reg = sc->sc_reg;
154 paddr_t pa;
155 vaddr_t start, end, v;
156 u_int *p;
157
158 if (reg->csr & DMAC3_CSR_ENABLE)
159 dmac3_reset(sc);
160
161 start = mips_trunc_page(addr);
162 end = mips_round_page(addr + len);
163 p = sc->sc_dmamap;
164 for (v = start; v < end; v += NBPG) {
165 pa = kvtophys(v);
166 MachFlushDCache(MIPS_PHYS_TO_KSEG0(pa), NBPG);
167 *p++ = 0;
168 *p++ = (pa >> PGSHIFT) | 0xc0000000;
169 }
170 *p++ = 0;
171 *p++ = 0x003fffff;
172
173 addr &= PGOFSET;
174 addr += sc->sc_dmaaddr;
175
176 reg->len = len;
177 reg->addr = addr;
178 reg->intr = DMAC3_INTR_EOPIE | DMAC3_INTR_INTEN;
179 reg->csr = DMAC3_CSR_ENABLE | direction | BURST_MODE | APAD_MODE;
180 }
181
182 int
183 dmac3_intr(v)
184 void *v;
185 {
186 struct dmac3_softc *sc = v;
187 struct dmac3reg *reg = sc->sc_reg;
188 int intr, conf, rv = 1;
189
190 intr = reg->intr;
191 if ((intr & DMAC3_INTR_INT) == 0)
192 return 0;
193
194 /* clear interrupt */
195 conf = reg->conf;
196 reg->conf = conf;
197 reg->intr = intr;
198
199 if (intr & DMAC3_INTR_PERR) {
200 printf("%s: intr = 0x%x\n", sc->sc_dev.dv_xname, intr);
201 rv = -1;
202 }
203
204 if (conf & (DMAC3_CONF_IPER | DMAC3_CONF_MPER | DMAC3_CONF_DERR)) {
205 printf("%s: conf = 0x%x\n", sc->sc_dev.dv_xname, conf);
206 if (conf & DMAC3_CONF_DERR) {
207 printf("DMA address = 0x%x\n", reg->addr);
208 printf("resetting DMA...\n");
209 dmac3_reset(sc);
210 }
211 }
212
213 return rv;
214 }
215
216 void
217 dmac3_misc(sc, cmd)
218 struct dmac3_softc *sc;
219 int cmd;
220 {
221 struct dmac3reg *reg = sc->sc_reg;
222 int conf;
223
224 conf = DMAC3_CONF_PCEN | DMAC3_CONF_DCEN | cmd;
225 sc->sc_conf = conf;
226 reg->conf = conf;
227 }
228