1 /* $OpenBSD: bpp.c,v 1.4 2003/06/03 21:09:02 deraadt Exp $ */
2
3 /*
4 * Copyright (c) 1997, Jason Downs. 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 *
15 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR(S) ``AS IS'' AND ANY EXPRESS
16 * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
17 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
18 * DISCLAIMED. IN NO EVENT SHALL THE AUTHOR(S) BE LIABLE FOR ANY DIRECT,
19 * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
20 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
21 * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
22 * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
23 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
24 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
25 * SUCH DAMAGE.
26 */
27
28 #include <sys/param.h>
29 #include <sys/buf.h>
30 #include <sys/kernel.h>
31 #include <sys/uio.h>
32 #include <sys/device.h>
33 #include <sys/conf.h>
34 #include <sys/systm.h>
35
36 #include <machine/autoconf.h>
37 #include <machine/conf.h>
38
39 #include <sparc/dev/bppreg.h>
40
41 #define BPP_BSIZE 1024
42
43 #define LONG_TIMEOUT 30 /* XXX */
44 #define SHORT_TIMEOUT 3 /* XXX */
45
46 struct bpp_softc {
47 struct device sc_dev;
48
49 size_t sc_count;
50 struct buf *sc_inbuf;
51 u_int8_t *sc_cp;
52
53 char sc_open;
54
55 volatile struct bppregs *sc_regs;
56 };
57
58 static int bppmatch(struct device *, void *, void *);
59 static void bppattach(struct device *, struct device *, void *);
60
61 #define BPPUNIT(s) minor(s)
62
63 struct cfattach bpp_ca = {
64 sizeof(struct bpp_softc), bppmatch, bppattach
65 };
66
67 struct cfdriver bpp_cd = {
68 NULL, "bpp", DV_DULL
69 };
70
71 static __inline__ void bpp_outb(struct bpp_softc *, u_int8_t);
72 static __inline__ u_int8_t bpp_inb(struct bpp_softc *);
73 static void bppreset(struct bpp_softc *, int);
74 static void bppresetmode(struct bpp_softc *);
75 static int bpppushbytes(struct bpp_softc *);
76
77 static int
bppmatch(parent,vcf,aux)78 bppmatch(parent, vcf, aux)
79 struct device *parent;
80 void *aux, *vcf;
81 {
82 register struct confargs *ca = aux;
83
84 if (strcmp(ca->ca_ra.ra_name, "SUNW,bpp"))
85 return (0);
86
87 return (1);
88 }
89
90 static void
bppattach(parent,self,aux)91 bppattach(parent, self, aux)
92 struct device *parent, *self;
93 void *aux;
94 {
95 struct confargs *ca = aux;
96 struct romaux *ra = &ca->ca_ra;
97 struct bpp_softc *bpp = (void *)self;
98
99 bpp->sc_regs = mapiodev(ra->ra_reg, 0, ra->ra_len);
100
101 bppreset(bpp, 0);
102
103 switch (bpp->sc_regs->bpp_csr & BPP_DEV_ID_MASK) {
104 case BPP_DEV_ID_ZEBRA:
105 printf(": Zebra\n");
106 break;
107 case BPP_DEV_ID_L64854:
108 printf(": DMA2\n");
109 break;
110 default:
111 printf(": Unknown type\n");
112 break;
113 }
114
115 bppresetmode(bpp);
116 }
117
118 static void
bppreset(bpp,verbose)119 bppreset(bpp, verbose)
120 struct bpp_softc *bpp;
121 int verbose;
122 {
123 volatile u_int32_t bpp_csr;
124
125 /* Reset hardware. */
126 bpp_csr = bpp->sc_regs->bpp_csr;
127 if ((bpp_csr & BPP_DRAINING) && !(bpp_csr & BPP_ERR_PEND)) {
128 delay(20);
129
130 bpp_csr = bpp->sc_regs->bpp_csr;
131 if (verbose && (bpp_csr & BPP_DRAINING) &&
132 !(bpp_csr & BPP_ERR_PEND))
133 printf("%s: draining still active (0x%08x)\n",
134 bpp->sc_dev.dv_xname, bpp_csr);
135 }
136 bpp->sc_regs->bpp_csr = (bpp_csr | BPP_RESET) & ~BPP_INT_EN;
137 delay(500);
138 bpp->sc_regs->bpp_csr &= ~BPP_RESET;
139 }
140
141 static void
bppresetmode(bpp)142 bppresetmode(bpp)
143 struct bpp_softc *bpp;
144 {
145 bpp->sc_regs->bpp_or = BPP_OR_AFXN|BPP_OR_SLCT_IN;
146 bpp->sc_regs->bpp_tcr = BPP_TCR_DS;
147 }
148
149 static __inline__ void
bpp_outb(bpp,byte)150 bpp_outb(bpp, byte)
151 struct bpp_softc *bpp;
152 u_int8_t byte;
153 {
154 bpp->sc_regs->bpp_dr = byte;
155 }
156
157 static __inline__ u_int8_t
bpp_inb(bpp)158 bpp_inb(bpp)
159 struct bpp_softc *bpp;
160 {
161 return (bpp->sc_regs->bpp_dr);
162 }
163
164 int
bppopen(dev,flag,mode,p)165 bppopen(dev, flag, mode, p)
166 dev_t dev;
167 int flag, mode;
168 struct proc *p;
169 {
170 int unit = BPPUNIT(dev);
171 struct bpp_softc *bpp;
172
173 if (unit >= bpp_cd.cd_ndevs)
174 return (ENXIO);
175 bpp = bpp_cd.cd_devs[unit];
176 if (!bpp)
177 return (ENXIO);
178
179 if (bpp->sc_open)
180 return (EBUSY);
181
182 bpp->sc_inbuf = geteblk(BPP_BSIZE);
183 bpp->sc_count = 0;
184 bpp->sc_open = 1;
185
186 /* bppreset(bpp, 1); */
187 bppresetmode(bpp);
188
189 return (0);
190 }
191
192 int
bppclose(dev,flag,mode,p)193 bppclose(dev, flag, mode, p)
194 dev_t dev;
195 int flag, mode;
196 struct proc *p;
197 {
198 struct bpp_softc *bpp = bpp_cd.cd_devs[BPPUNIT(dev)];
199 int error = 0;
200
201 if (bpp->sc_count)
202 (void) bpppushbytes(bpp);
203
204 /* XXX */
205 bppresetmode(bpp);
206 delay(100);
207 bppreset(bpp, 1);
208 delay(100);
209 bppresetmode(bpp);
210
211 brelse(bpp->sc_inbuf);
212
213 bpp->sc_open = 0;
214 return (error);
215 }
216
217 int
bpppushbytes(bpp)218 bpppushbytes(bpp)
219 struct bpp_softc *bpp;
220 {
221 int spin, error;
222
223 while (bpp->sc_count > 0) {
224 error = 0;
225
226 /* Wait for BPP_TCR_ACK and BPP_TCR_BUSY to clear. */
227 spin = 0;
228 while ((bpp->sc_regs->bpp_tcr & BPP_TCR_ACK) ||
229 (bpp->sc_regs->bpp_tcr & BPP_TCR_BUSY)) {
230 delay(1000);
231 if (++spin >= LONG_TIMEOUT)
232 break;
233 }
234
235 if ((bpp->sc_regs->bpp_tcr & BPP_TCR_ACK) ||
236 (bpp->sc_regs->bpp_tcr & BPP_TCR_BUSY))
237 return (EBUSY);
238
239 bpp_outb(bpp, *bpp->sc_cp++);
240
241 /* Clear BPP_TCR_DS. */
242 bpp->sc_regs->bpp_tcr &= ~BPP_TCR_DS;
243
244 /* Short wait for BPP_TCR_BUSY. */
245 spin = 0;
246 while (!(bpp->sc_regs->bpp_tcr & BPP_TCR_BUSY)) {
247 delay(1000);
248 if (++spin >= SHORT_TIMEOUT)
249 break;
250 }
251 if (!(bpp->sc_regs->bpp_tcr & BPP_TCR_BUSY))
252 error = EIO;
253
254 /* Set BPP_TCR_DS. */
255 bpp->sc_regs->bpp_tcr |= BPP_TCR_DS;
256
257 if (error)
258 return (error);
259
260 bpp->sc_count--;
261 }
262 return (error);
263 }
264
265 int
bppwrite(dev,uio,flags)266 bppwrite(dev, uio, flags)
267 dev_t dev;
268 struct uio *uio;
269 int flags;
270 {
271 struct bpp_softc *bpp = bpp_cd.cd_devs[BPPUNIT(dev)];
272 size_t n;
273 int error = 0;
274
275 while ((n = min(BPP_BSIZE, uio->uio_resid)) != 0) {
276 uiomove(bpp->sc_cp = bpp->sc_inbuf->b_data, n, uio);
277 bpp->sc_count = n;
278 error = bpppushbytes(bpp);
279 if (error) {
280 /*
281 * Return accurate residual if interrupted or timed
282 * out.
283 */
284 uio->uio_resid += bpp->sc_count;
285 bpp->sc_count = 0;
286 return (error);
287 }
288 }
289 return (0);
290 }
291
292 int
bppioctl(dev,cmd,data,flag,p)293 bppioctl(dev, cmd, data, flag, p)
294 dev_t dev;
295 u_long cmd;
296 caddr_t data;
297 int flag;
298 struct proc *p;
299 {
300 return (ENODEV);
301 }
302