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