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