Add __DragonFly__
[dragonfly.git] / sys / dev / disk / i386 / bs / bshw_dma.c
1 /* $FreeBSD: src/sys/i386/isa/bs/bshw_dma.c,v 1.6.6.1 2000/10/21 07:44:26 nyan Exp $ */
2 /* $DragonFly: src/sys/dev/disk/i386/bs/Attic/bshw_dma.c,v 1.4 2004/02/13 01:04:14 joerg Exp $ */
3 /*      $NecBSD: bshw_dma.c,v 1.3 1997/07/26 06:03:16 honda Exp $       */
4 /*      $NetBSD$        */
5 /*
6  * [NetBSD for NEC PC98 series]
7  *  Copyright (c) 1994, 1995, 1996 NetBSD/pc98 porting staff.
8  *  All rights reserved.
9  * 
10  *  Redistribution and use in source and binary forms, with or without
11  *  modification, are permitted provided that the following conditions
12  *  are met:
13  *  1. Redistributions of source code must retain the above copyright
14  *     notice, this list of conditions and the following disclaimer.
15  *  2. Redistributions in binary form must reproduce the above copyright
16  *     notice, this list of conditions and the following disclaimer in the
17  *     documentation and/or other materials provided with the distribution.
18  *  3. The name of the author may not be used to endorse or promote products
19  *     derived from this software without specific prior written permission.
20  * 
21  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
22  * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
23  * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
24  * DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT,
25  * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
26  * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
27  * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
28  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
29  * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
30  * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
31  * POSSIBILITY OF SUCH DAMAGE.
32  */
33 /*
34  * Copyright (c) 1994, 1995, 1996 Naofumi HONDA.  All rights reserved.
35  */
36
37 /*********************************************************
38  * static declare.
39  *********************************************************/
40 static void bshw_dmastart (struct bs_softc *);
41 static void bshw_dmadone (struct bs_softc *);
42
43 /**********************************************
44  * UPPER INTERFACE FUNCS (all funcs exported)
45  **********************************************/
46 void
47 bshw_dmaabort(bsc, ti)
48         struct bs_softc *bsc;
49         struct targ_info *ti;
50 {
51
52         bshw_dmadone(bsc);
53         bsc->sc_p.seglen = 0;
54         bshw_set_count(bsc, 0);
55
56         if (ti == NULL)
57         {
58                 int i;
59                 struct targ_info *tmpti;
60
61                 for (i = 0; i < NTARGETS; i++)
62                         if ((tmpti = bsc->sc_ti[i]) != NULL)
63                                 tmpti->ti_scsp.seglen = 0;
64         }
65         else
66                 ti->ti_scsp.seglen = 0;
67 }
68
69 /* DMA TRANSFER */
70 void
71 bs_dma_xfer(ti, direction)
72         struct targ_info *ti;
73         u_int direction;
74 {
75         vm_offset_t va, endva, phys, nphys;
76         struct bs_softc *bsc = ti->ti_bsc;
77         struct sc_p *sp = &bsc->sc_p;
78
79         bsc->sc_dmadir = direction;
80         bshw_set_dma_trans(bsc, ti->ti_cfgflags);
81
82         if (sp->seglen == 0)
83         {
84                 phys = vtophys((vm_offset_t) sp->data);
85                 if (phys >= RAM_END)
86                 {
87                         /* setup segaddr */
88                         sp->segaddr = ti->bounce_phys;
89                         /* setup seglen */
90                         sp->seglen = sp->datalen;
91                         if (sp->seglen > ti->bounce_size)
92                                 sp->seglen = ti->bounce_size;
93                         /* setup bufp */
94                         sp->bufp = ti->bounce_addr;
95                         if (bsc->sc_dmadir != BSHW_READ)
96                                 bcopy(sp->data, sp->bufp, sp->seglen);
97 #ifdef  BS_STATICS
98                         bs_bounce_used[ti->ti_id]++;
99 #endif  /* BS_STATICS */
100                 }
101                 else
102                 {
103                         /* setup segaddr */
104                         sp->segaddr = (u_int8_t *) phys;
105                         /* setup seglen */
106                         endva = (vm_offset_t)round_page((unsigned long)(sp->data + sp->datalen));
107                         for (va = (vm_offset_t) sp->data; ; phys = nphys)
108                         {
109                                 if ((va += BSHW_NBPG) >= endva)
110                                 {
111                                         sp->seglen = sp->datalen;
112                                         break;
113                                 }
114
115                                 nphys = vtophys(va);
116                                 if (phys + BSHW_NBPG != nphys || nphys >= RAM_END)
117                                 {
118                                         sp->seglen =
119                                             (u_int8_t *) trunc_page(va) - sp->data;
120                                         break;
121                                 }
122                         }
123                         /* setup bufp */
124                         sp->bufp = NULL;
125                 }
126         }
127
128         bshw_dmastart(bsc);
129         bshw_set_count(bsc, sp->seglen);
130 }
131
132 void
133 bs_dma_xfer_end(ti)
134         struct targ_info *ti;
135 {
136         struct bs_softc *bsc = ti->ti_bsc;
137         struct sc_p *sp = &bsc->sc_p;
138         u_int count, transbytes;
139
140         bshw_dmadone(bsc);
141         if (ti->ti_phase == DATAPHASE)
142         {
143                 count = bshw_get_count(bsc);
144                 if (count < (u_int) sp->seglen)
145                 {
146                         transbytes = sp->seglen - count;
147                         if (sp->bufp)
148                         {
149                                 if (bsc->sc_dmadir == BSHW_READ)
150                                         bcopy(sp->bufp, sp->data, transbytes);
151                                 sp->bufp += transbytes;
152                         }
153                         sp->seglen = count;
154                         sp->segaddr += transbytes;
155                         sp->data += transbytes;
156                         sp->datalen -= transbytes;
157                         return;
158                 }
159                 else if (count == (u_int) sp->seglen)
160                 {
161                         return;
162                 }
163
164                 bs_printf(ti, "xfer_end", "strange count");
165                 printf("port data %x seglen %x\n", count, sp->seglen);
166         }
167         else
168                 bs_printf(ti, "xfer_end", "extra dma interrupt");
169
170         ti->ti_error |= BSDMAABNORMAL;
171         sp->seglen = ti->ti_scsp.seglen = 0;    /* XXX */
172 }
173
174 /**********************************************
175  * GENERIC DMA FUNCS
176  **********************************************/
177 static u_int8_t dmapageport[4] = { 0x27, 0x21, 0x23, 0x25 };
178
179 /* common dma settings */
180 #undef  DMA1_SMSK
181 #define DMA1_SMSK       (0x15)
182 #undef  DMA1_MODE
183 #define DMA1_MODE       (0x17)
184 #undef  DMA1_FFC
185 #define DMA1_FFC        (0x19)
186 #undef  DMA37SM_SET
187 #define DMA37SM_SET     0x04
188 #undef  DMA1_CHN
189 #define DMA1_CHN(c)     (0x01 + ((c) << 2))
190
191 static void
192 bshw_dmastart(bsc)
193         struct bs_softc *bsc;
194 {
195         int chan = bsc->sc_dmachan;
196         int waport;
197         u_int8_t *phys = bsc->sc_p.segaddr;
198         u_int nbytes = bsc->sc_p.seglen;
199
200         /*
201          * Program one of DMA channels 0..3. These are
202          * byte mode channels.
203          */
204         /* set dma channel mode, and reset address ff */
205 #if defined(__DragonFly__) || defined(__FreeBSD__)
206         if (need_pre_dma_flush)
207                 wbinvd();
208 #else   /* NetBSD/pc98 */
209         if (bsc->sc_dmadir & BSHW_READ)
210                 cpu_cf_preRead(curcpu);
211         else
212                 cpu_cf_preWrite(curcpu);
213 #endif
214
215         if (bsc->sc_dmadir & BSHW_READ)
216                 outb(DMA1_MODE, DMA37MD_SINGLE | DMA37MD_WRITE | chan);
217         else
218                 outb(DMA1_MODE, DMA37MD_SINGLE | DMA37MD_READ | chan);
219         outb(DMA1_FFC, 0);
220
221         /* send start address */
222         waport = DMA1_CHN(chan);
223         outb(waport, (u_int) phys);
224         outb(waport, ((u_int) phys) >> 8);
225         outb(dmapageport[chan], ((u_int) phys) >> 16);
226
227         /* send count */
228         outb(waport + 2, --nbytes);
229         outb(waport + 2, nbytes >> 8);
230
231         /* vendor unique hook */
232         if (bsc->sc_hw->dma_start)
233                 (*bsc->sc_hw->dma_start)(bsc);
234
235         outb(DMA1_SMSK, chan);
236         BUS_IOW(cmd_port, CMDP_DMES);
237
238         bsc->sc_flags |= BSDMASTART;
239 }
240
241 static void
242 bshw_dmadone(bsc)
243         struct bs_softc *bsc;
244 {
245
246         outb(DMA1_SMSK, (bsc->sc_dmachan | DMA37SM_SET));
247         BUS_IOW(cmd_port, CMDP_DMER);
248
249         /* vendor unique hook */
250         if (bsc->sc_hw->dma_stop)
251                 (*bsc->sc_hw->dma_stop)(bsc);
252
253 #if defined(__DragonFly__) || defined(__FreeBSD__)
254         if (need_post_dma_flush)
255                 invd();
256 #else
257         if (bsc->sc_dmadir & BSHW_READ)
258                 cpu_cf_postRead(curcpu);
259         else
260                 cpu_cf_postWrite(curcpu);
261 #endif
262
263         bsc->sc_flags &= (~BSDMASTART);
264 }
265
266 /**********************************************
267  * VENDOR UNIQUE DMA FUNCS
268  **********************************************/
269 static int
270 bshw_dma_init_texa(bsc)
271         struct bs_softc *bsc;
272 {
273         u_int8_t regval;
274
275         if ((regval = read_wd33c93(bsc, 0x37)) & 0x08)
276                 return 0;
277
278         write_wd33c93(bsc, 0x37, regval | 0x08);
279         regval = read_wd33c93(bsc, 0x3f);
280         write_wd33c93(bsc, 0x3f, regval | 0x08);
281         return 1;
282 }
283
284 static int
285 bshw_dma_init_sc98(bsc)
286         struct bs_softc *bsc;
287 {
288
289         if (read_wd33c93(bsc, 0x37) & 0x08)
290                 return 0;
291
292         /* If your card is SC98 with bios ver 1.01 or 1.02 under no PCI */
293         write_wd33c93(bsc, 0x37, 0x1a);
294         write_wd33c93(bsc, 0x3f, 0x1a);
295 #if     0
296         /* only valid for IO */
297         write_wd33c93(bsc, 0x40, 0xf4);
298         write_wd33c93(bsc, 0x41, 0x9);
299         write_wd33c93(bsc, 0x43, 0xff);
300         write_wd33c93(bsc, 0x46, 0x4e);
301
302         write_wd33c93(bsc, 0x48, 0xf4);
303         write_wd33c93(bsc, 0x49, 0x9);
304         write_wd33c93(bsc, 0x4b, 0xff);
305         write_wd33c93(bsc, 0x4e, 0x4e);
306 #endif
307         return 1;
308 }
309
310 static void
311 bshw_dma_start_sc98(bsc)
312         struct bs_softc *bsc;
313 {
314
315         write_wd33c93(bsc, 0x73, 0x32);
316         write_wd33c93(bsc, 0x74, 0x23);
317 }
318
319 static void
320 bshw_dma_stop_sc98(bsc)
321         struct bs_softc *bsc;
322 {
323
324         write_wd33c93(bsc, 0x73, 0x43);
325         write_wd33c93(bsc, 0x74, 0x34);
326 }
327
328 static void
329 bshw_dma_start_elecom(bsc)
330         struct bs_softc *bsc;
331 {
332         u_int8_t tmp = read_wd33c93(bsc, 0x4c);
333
334         write_wd33c93(bsc, 0x32, tmp & 0xdf);
335 }
336
337 static void
338 bshw_dma_stop_elecom(bsc)
339         struct bs_softc *bsc;
340 {
341         u_int8_t tmp = read_wd33c93(bsc, 0x4c);
342
343         write_wd33c93(bsc, 0x32, tmp | 0x20);
344 }