1 /* $OpenBSD: dbdma.c,v 1.11 2015/09/08 08:29:35 deraadt Exp $ */
2 /* $NetBSD: dbdma.c,v 1.2 1998/08/21 16:13:28 tsubai Exp $ */
3
4 /*
5 * Copyright 1991-1998 by Open Software Foundation, Inc.
6 * All Rights Reserved
7 *
8 * Permission to use, copy, modify, and distribute this software and
9 * its documentation for any purpose and without fee is hereby granted,
10 * provided that the above copyright notice appears in all copies and
11 * that both the copyright notice and this permission notice appear in
12 * supporting documentation.
13 *
14 * OSF DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE
15 * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
16 * FOR A PARTICULAR PURPOSE.
17 *
18 * IN NO EVENT SHALL OSF BE LIABLE FOR ANY SPECIAL, INDIRECT, OR
19 * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
20 * LOSS OF USE, DATA OR PROFITS, WHETHER IN ACTION OF CONTRACT,
21 * NEGLIGENCE, OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION
22 * WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
23 *
24 */
25
26 #include <sys/param.h>
27 #include <sys/malloc.h>
28 #include <sys/systm.h>
29
30 #include <uvm/uvm_extern.h>
31
32 #include <machine/bus.h>
33 #include <macppc/dev/dbdma.h>
34
35 dbdma_command_t *dbdma_alloc_commands = NULL;
36
37 void
dbdma_start(dbdma_regmap_t * dmap,dbdma_t dt)38 dbdma_start(dbdma_regmap_t *dmap, dbdma_t dt)
39 {
40 u_int32_t addr = dt->d_paddr;
41
42 DBDMA_ST4_ENDIAN(&dmap->d_intselect, DBDMA_CLEAR_CNTRL((0xffff)));
43 DBDMA_ST4_ENDIAN(&dmap->d_control, DBDMA_CLEAR_CNTRL((
44 DBDMA_CNTRL_ACTIVE |
45 DBDMA_CNTRL_DEAD |
46 DBDMA_CNTRL_WAKE |
47 DBDMA_CNTRL_FLUSH |
48 DBDMA_CNTRL_PAUSE |
49 DBDMA_CNTRL_RUN)));
50
51 /* XXX time-bind it? */
52 do {
53 delay(10);
54 } while (DBDMA_LD4_ENDIAN(&dmap->d_status) & DBDMA_CNTRL_ACTIVE);
55
56
57 DBDMA_ST4_ENDIAN(&dmap->d_cmdptrhi, 0); /* 64-bit not yet */
58 DBDMA_ST4_ENDIAN(&dmap->d_cmdptrlo, addr);
59
60 DBDMA_ST4_ENDIAN(&dmap->d_control,
61 DBDMA_SET_CNTRL(DBDMA_CNTRL_RUN|DBDMA_CNTRL_WAKE)|
62 DBDMA_CLEAR_CNTRL(DBDMA_CNTRL_PAUSE|DBDMA_CNTRL_DEAD) );
63 }
64
65 void
dbdma_stop(dbdma_regmap_t * dmap)66 dbdma_stop(dbdma_regmap_t *dmap)
67 {
68 DBDMA_ST4_ENDIAN(&dmap->d_control, DBDMA_CLEAR_CNTRL(DBDMA_CNTRL_RUN) |
69 DBDMA_SET_CNTRL(DBDMA_CNTRL_FLUSH));
70
71 while (DBDMA_LD4_ENDIAN(&dmap->d_status) &
72 (DBDMA_CNTRL_ACTIVE|DBDMA_CNTRL_FLUSH));
73 }
74
75 void
dbdma_flush(dbdma_regmap_t * dmap)76 dbdma_flush(dbdma_regmap_t *dmap)
77 {
78 DBDMA_ST4_ENDIAN(&dmap->d_control, DBDMA_SET_CNTRL(DBDMA_CNTRL_FLUSH));
79
80 /* XXX time-bind it? */
81 while (DBDMA_LD4_ENDIAN(&dmap->d_status) & (DBDMA_CNTRL_FLUSH));
82 }
83
84 void
dbdma_reset(dbdma_regmap_t * dmap)85 dbdma_reset(dbdma_regmap_t *dmap)
86 {
87 DBDMA_ST4_ENDIAN(&dmap->d_control,
88 DBDMA_CLEAR_CNTRL( (DBDMA_CNTRL_ACTIVE |
89 DBDMA_CNTRL_DEAD |
90 DBDMA_CNTRL_WAKE |
91 DBDMA_CNTRL_FLUSH |
92 DBDMA_CNTRL_PAUSE |
93 DBDMA_CNTRL_RUN )));
94
95 /* XXX time-bind it? */
96 while (DBDMA_LD4_ENDIAN(&dmap->d_status) & DBDMA_CNTRL_RUN);
97 }
98
99 void
dbdma_continue(dbdma_regmap_t * dmap)100 dbdma_continue(dbdma_regmap_t *dmap)
101 {
102 DBDMA_ST4_ENDIAN(&dmap->d_control,
103 DBDMA_SET_CNTRL(DBDMA_CNTRL_RUN | DBDMA_CNTRL_WAKE) |
104 DBDMA_CLEAR_CNTRL(DBDMA_CNTRL_PAUSE | DBDMA_CNTRL_DEAD));
105 }
106
107 void
dbdma_pause(dbdma_regmap_t * dmap)108 dbdma_pause(dbdma_regmap_t *dmap)
109 {
110 DBDMA_ST4_ENDIAN(&dmap->d_control,DBDMA_SET_CNTRL(DBDMA_CNTRL_PAUSE));
111
112 /* XXX time-bind it? */
113 while (DBDMA_LD4_ENDIAN(&dmap->d_status) & DBDMA_CNTRL_ACTIVE);
114 }
115
116 dbdma_t
dbdma_alloc(bus_dma_tag_t dmat,int size)117 dbdma_alloc(bus_dma_tag_t dmat, int size)
118 {
119 dbdma_t dt;
120 int error;
121
122 dt = malloc(sizeof *dt, M_DEVBUF, M_NOWAIT | M_ZERO);
123 if (!dt)
124 return (dt);
125
126 dt->d_size = size *= sizeof(dbdma_command_t);
127 dt->d_dmat = dmat;
128 if ((error = bus_dmamem_alloc(dmat, size, NBPG, 0, dt->d_segs,
129 1, &dt->d_nsegs, BUS_DMA_NOWAIT)) != 0) {
130 printf("dbdma: unable to allocate dma, error = %d\n", error);
131 } else if ((error = bus_dmamem_map(dmat, dt->d_segs, dt->d_nsegs, size,
132 (caddr_t *)&dt->d_addr, BUS_DMA_NOWAIT | BUS_DMA_COHERENT)) != 0) {
133 printf("dbdma: unable to map dma, error = %d\n", error);
134 } else if ((error = bus_dmamap_create(dmat, dt->d_size, 1,
135 dt->d_size, 0, BUS_DMA_NOWAIT, &dt->d_map)) != 0) {
136 printf("dbdma: unable to create dma map, error = %d\n", error);
137 } else if ((error = bus_dmamap_load_raw(dmat, dt->d_map,
138 dt->d_segs, dt->d_nsegs, size, BUS_DMA_NOWAIT)) != 0) {
139 printf("dbdma: unable to load dma map, error = %d\n", error);
140 } else
141 return dt;
142
143 dbdma_free(dt);
144 return (NULL);
145 }
146
147 void
dbdma_free(dbdma_t dt)148 dbdma_free(dbdma_t dt)
149 {
150 if (dt->d_map)
151 bus_dmamap_destroy(dt->d_dmat, dt->d_map);
152 if (dt->d_addr)
153 bus_dmamem_unmap(dt->d_dmat, (caddr_t)dt->d_addr, dt->d_size);
154 if (dt->d_nsegs)
155 bus_dmamem_free(dt->d_dmat, dt->d_segs, dt->d_nsegs);
156 free(dt, M_DEVBUF, sizeof *dt);
157 }
158