1 /* $NetBSD: bpp.c,v 1.47 2021/09/26 01:16:09 thorpej Exp $ */
2
3 /*-
4 * Copyright (c) 1998 The NetBSD Foundation, Inc.
5 * All rights reserved.
6 *
7 * This code is derived from software contributed to The NetBSD Foundation
8 * by Paul Kranenburg.
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 *
19 * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
20 * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
21 * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
22 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
23 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
24 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
25 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
26 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
27 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
28 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
29 * POSSIBILITY OF SUCH DAMAGE.
30 */
31
32 #include <sys/cdefs.h>
33 __KERNEL_RCSID(0, "$NetBSD: bpp.c,v 1.47 2021/09/26 01:16:09 thorpej Exp $");
34
35 #include <sys/param.h>
36 #include <sys/ioctl.h>
37 #include <sys/fcntl.h>
38 #include <sys/systm.h>
39 #include <sys/kernel.h>
40 #include <sys/vnode.h>
41 #include <sys/poll.h>
42 #include <sys/select.h>
43 #include <sys/malloc.h>
44 #include <sys/proc.h>
45 #include <sys/signalvar.h>
46 #include <sys/conf.h>
47 #include <sys/errno.h>
48 #include <sys/device.h>
49 #include <sys/bus.h>
50 #include <sys/intr.h>
51
52 #include <machine/autoconf.h>
53
54 #include <dev/ic/lsi64854reg.h>
55 #include <dev/ic/lsi64854var.h>
56
57 #include <dev/sbus/sbusvar.h>
58 #include <dev/sbus/bppreg.h>
59
60 #include "ioconf.h"
61
62 #define splbpp() spltty() /* XXX */
63
64 #ifdef DEBUG
65 #define DPRINTF(x) do { if (bppdebug) printf x ; } while (0)
66 int bppdebug = 1;
67 #else
68 #define DPRINTF(x)
69 #endif
70
71 #if 0
72 struct bpp_param {
73 int bpp_dss; /* data setup to strobe */
74 int bpp_dsw; /* data strobe width */
75 int bpp_outputpins; /* Select/Autofeed/Init pins */
76 int bpp_inputpins; /* Error/Select/Paperout pins */
77 };
78 #endif
79
80 struct hwstate {
81 uint16_t hw_hcr; /* Hardware config register */
82 uint16_t hw_ocr; /* Operation config register */
83 uint8_t hw_tcr; /* Transfer Control register */
84 uint8_t hw_or; /* Output register */
85 uint16_t hw_irq; /* IRQ; polarity bits only */
86 };
87
88 struct bpp_softc {
89 struct lsi64854_softc sc_lsi64854; /* base device */
90
91 size_t sc_bufsz; /* temp buffer */
92 uint8_t *sc_buf;
93
94 int sc_error; /* bottom-half error */
95 int sc_flags;
96 #define BPP_OPEN 0x01 /* Device is open */
97 #define BPP_XCLUDE 0x02 /* Exclusive-open mode */
98 #define BPP_ASYNC 0x04 /* Asynchronous I/O mode */
99 #define BPP_LOCKED 0x08 /* DMA in progress */
100 #define BPP_WANT 0x10 /* Waiting for DMA */
101
102 struct selinfo sc_rsel;
103 struct selinfo sc_wsel;
104 struct proc *sc_asyncproc; /* Process to notify if async */
105 void *sc_sih;
106
107 /* Hardware state */
108 struct hwstate sc_hwdefault;
109 struct hwstate sc_hwcurrent;
110 };
111
112 static int bppmatch(device_t, cfdata_t, void *);
113 static void bppattach(device_t, device_t, void *);
114 static int bppintr(void *);
115 static void bppsoftintr(void *);
116 static void bpp_setparams(struct bpp_softc *, struct hwstate *);
117
118 CFATTACH_DECL_NEW(bpp, sizeof(struct bpp_softc),
119 bppmatch, bppattach, NULL, NULL);
120
121 dev_type_open(bppopen);
122 dev_type_close(bppclose);
123 dev_type_write(bppwrite);
124 dev_type_ioctl(bppioctl);
125 dev_type_poll(bpppoll);
126 dev_type_kqfilter(bppkqfilter);
127
128 const struct cdevsw bpp_cdevsw = {
129 .d_open = bppopen,
130 .d_close = bppclose,
131 .d_read = noread,
132 .d_write = bppwrite,
133 .d_ioctl = bppioctl,
134 .d_stop = nostop,
135 .d_tty = notty,
136 .d_poll = bpppoll,
137 .d_mmap = nommap,
138 .d_kqfilter = bppkqfilter,
139 .d_discard = nodiscard,
140 .d_flag = D_TTY
141 };
142
143 #define BPPUNIT(dev) (minor(dev))
144
145
146 int
bppmatch(device_t parent,cfdata_t cf,void * aux)147 bppmatch(device_t parent, cfdata_t cf, void *aux)
148 {
149 struct sbus_attach_args *sa = aux;
150
151 return strcmp("SUNW,bpp", sa->sa_name) == 0;
152 }
153
154 void
bppattach(device_t parent,device_t self,void * aux)155 bppattach(device_t parent, device_t self, void *aux)
156 {
157 struct bpp_softc *dsc = device_private(self);
158 struct lsi64854_softc *sc = &dsc->sc_lsi64854;
159 struct sbus_softc *sbsc = device_private(parent);
160 struct sbus_attach_args *sa = aux;
161 int burst, sbusburst;
162 int node;
163
164 sc->sc_dev = self;
165
166 selinit(&dsc->sc_rsel);
167 selinit(&dsc->sc_wsel);
168 dsc->sc_sih = softint_establish(SOFTINT_CLOCK, bppsoftintr, dsc);
169
170 sc->sc_bustag = sa->sa_bustag;
171 sc->sc_dmatag = sa->sa_dmatag;
172 node = sa->sa_node;
173
174 /* Map device registers */
175 if (sbus_bus_map(sa->sa_bustag,
176 sa->sa_slot, sa->sa_offset, sa->sa_size,
177 0, &sc->sc_regs) != 0) {
178 aprint_error(": cannot map registers\n");
179 return;
180 }
181
182 /*
183 * Get transfer burst size from PROM and plug it into the
184 * controller registers. This is needed on the Sun4m; do
185 * others need it too?
186 */
187 sbusburst = sbsc->sc_burst;
188 if (sbusburst == 0)
189 sbusburst = SBUS_BURST_32 - 1; /* 1->16 */
190
191 burst = prom_getpropint(node, "burst-sizes", -1);
192 if (burst == -1)
193 /* take SBus burst sizes */
194 burst = sbusburst;
195
196 /* Clamp at parent's burst sizes */
197 burst &= sbusburst;
198 sc->sc_burst = (burst & SBUS_BURST_32) ? 32 :
199 (burst & SBUS_BURST_16) ? 16 : 0;
200
201 /* Initialize the DMA channel */
202 sc->sc_channel = L64854_CHANNEL_PP;
203 lsi64854_attach(sc);
204
205 /* Establish interrupt handler */
206 if (sa->sa_nintr) {
207 sc->sc_intrchain = bppintr;
208 sc->sc_intrchainarg = dsc;
209 (void)bus_intr_establish(sa->sa_bustag, sa->sa_pri, IPL_TTY,
210 bppintr, sc);
211 }
212
213 /* Allocate buffer XXX - should actually use dmamap_uio() */
214 dsc->sc_bufsz = 1024;
215 dsc->sc_buf = malloc(dsc->sc_bufsz, M_DEVBUF, M_WAITOK);
216
217 /* XXX read default state */
218 {
219 bus_space_handle_t h = sc->sc_regs;
220 struct hwstate *hw = &dsc->sc_hwdefault;
221 int ack_rate = sa->sa_frequency / 1000000;
222
223 hw->hw_hcr = bus_space_read_2(sc->sc_bustag, h, L64854_REG_HCR);
224 hw->hw_ocr = bus_space_read_2(sc->sc_bustag, h, L64854_REG_OCR);
225 hw->hw_tcr = bus_space_read_1(sc->sc_bustag, h, L64854_REG_TCR);
226 hw->hw_or = bus_space_read_1(sc->sc_bustag, h, L64854_REG_OR);
227
228 DPRINTF(("bpp: hcr %x ocr %x tcr %x or %x\n",
229 hw->hw_hcr, hw->hw_ocr, hw->hw_tcr, hw->hw_or));
230 /* Set these to sane values */
231 hw->hw_hcr = ((ack_rate<<BPP_HCR_DSS_SHFT)&BPP_HCR_DSS_MASK)
232 | ((ack_rate<<BPP_HCR_DSW_SHFT)&BPP_HCR_DSW_MASK);
233 hw->hw_ocr |= BPP_OCR_ACK_OP;
234 }
235 }
236
237 void
bpp_setparams(struct bpp_softc * sc,struct hwstate * hw)238 bpp_setparams(struct bpp_softc *sc, struct hwstate *hw)
239 {
240 uint16_t irq;
241 bus_space_tag_t t = sc->sc_lsi64854.sc_bustag;
242 bus_space_handle_t h = sc->sc_lsi64854.sc_regs;
243
244 bus_space_write_2(t, h, L64854_REG_HCR, hw->hw_hcr);
245 bus_space_write_2(t, h, L64854_REG_OCR, hw->hw_ocr);
246 bus_space_write_1(t, h, L64854_REG_TCR, hw->hw_tcr);
247 bus_space_write_1(t, h, L64854_REG_OR, hw->hw_or);
248
249 /* Only change IRP settings in interrupt status register */
250 irq = bus_space_read_2(t, h, L64854_REG_ICR);
251 irq &= ~BPP_ALLIRP;
252 irq |= (hw->hw_irq & BPP_ALLIRP);
253 bus_space_write_2(t, h, L64854_REG_ICR, irq);
254 DPRINTF(("bpp_setparams: hcr %x ocr %x tcr %x or %x, irq %x\n",
255 hw->hw_hcr, hw->hw_ocr, hw->hw_tcr, hw->hw_or, irq));
256 }
257
258 int
bppopen(dev_t dev,int flags,int mode,struct lwp * l)259 bppopen(dev_t dev, int flags, int mode, struct lwp *l)
260 {
261 int unit = BPPUNIT(dev);
262 struct bpp_softc *sc;
263 struct lsi64854_softc *lsi;
264 uint16_t irq;
265 int s;
266
267 if (unit >= bpp_cd.cd_ndevs)
268 return ENXIO;
269 sc = device_lookup_private(&bpp_cd, unit);
270
271 if ((sc->sc_flags & (BPP_OPEN|BPP_XCLUDE)) == (BPP_OPEN|BPP_XCLUDE))
272 return EBUSY;
273
274 lsi = &sc->sc_lsi64854;
275
276 /* Set default parameters */
277 sc->sc_hwcurrent = sc->sc_hwdefault;
278 s = splbpp();
279 bpp_setparams(sc, &sc->sc_hwdefault);
280 splx(s);
281
282 /* Enable interrupts */
283 irq = BPP_ERR_IRQ_EN;
284 irq |= sc->sc_hwdefault.hw_irq;
285 bus_space_write_2(lsi->sc_bustag, lsi->sc_regs, L64854_REG_ICR, irq);
286 return 0;
287 }
288
289 int
bppclose(dev_t dev,int flags,int mode,struct lwp * l)290 bppclose(dev_t dev, int flags, int mode, struct lwp *l)
291 {
292 struct bpp_softc *sc;
293 struct lsi64854_softc *lsi;
294 uint16_t irq;
295
296 sc = device_lookup_private(&bpp_cd, BPPUNIT(dev));
297 lsi = &sc->sc_lsi64854;
298
299 /* Turn off all interrupt enables */
300 irq = sc->sc_hwdefault.hw_irq | BPP_ALLIRQ;
301 irq &= ~BPP_ALLEN;
302 bus_space_write_2(lsi->sc_bustag, lsi->sc_regs, L64854_REG_ICR, irq);
303
304 mutex_enter(&proc_lock);
305 sc->sc_asyncproc = NULL;
306 mutex_exit(&proc_lock);
307 sc->sc_flags = 0;
308 return 0;
309 }
310
311 int
bppwrite(dev_t dev,struct uio * uio,int flags)312 bppwrite(dev_t dev, struct uio *uio, int flags)
313 {
314 struct bpp_softc *sc;
315 struct lsi64854_softc *lsi;
316 int error = 0;
317 int s;
318
319 sc = device_lookup_private(&bpp_cd, BPPUNIT(dev));
320 lsi = &sc->sc_lsi64854;
321
322 /*
323 * Wait until the DMA engine is free.
324 */
325 s = splbpp();
326 while ((sc->sc_flags & BPP_LOCKED) != 0) {
327 if ((flags & IO_NDELAY) != 0) {
328 splx(s);
329 return EWOULDBLOCK;
330 }
331
332 sc->sc_flags |= BPP_WANT;
333 error = tsleep(sc->sc_buf, PZERO|PCATCH, "bppwrite", 0);
334 if (error != 0) {
335 splx(s);
336 return error;
337 }
338 }
339 sc->sc_flags |= BPP_LOCKED;
340 splx(s);
341
342 /*
343 * Move data from user space into our private buffer
344 * and start DMA.
345 */
346 while (uio->uio_resid > 0) {
347 uint8_t *bp = sc->sc_buf;
348 size_t len = uimin(sc->sc_bufsz, uio->uio_resid);
349
350 if ((error = uiomove(bp, len, uio)) != 0)
351 break;
352
353 while (len > 0) {
354 uint8_t tcr;
355 size_t size = len;
356 DMA_SETUP(lsi, &bp, &len, 0, &size);
357
358 #ifdef DEBUG
359 if (bppdebug) {
360 int i;
361 uint8_t *b = bp;
362 printf("bpp: writing %ld : ", len);
363 for (i = 0; i < len; i++)
364 printf("%c(0x%x)", b[i], b[i]);
365 printf("\n");
366 }
367 #endif
368
369 /* Clear direction control bit */
370 tcr = bus_space_read_1(lsi->sc_bustag, lsi->sc_regs,
371 L64854_REG_TCR);
372 tcr &= ~BPP_TCR_DIR;
373 bus_space_write_1(lsi->sc_bustag, lsi->sc_regs,
374 L64854_REG_TCR, tcr);
375
376 /* Enable DMA */
377 s = splbpp();
378 DMA_GO(lsi);
379 error = tsleep(sc, PZERO|PCATCH, "bppdma", 0);
380 splx(s);
381 if (error != 0)
382 goto out;
383
384 /* Bail out if bottom half reported an error */
385 if ((error = sc->sc_error) != 0)
386 goto out;
387
388 /*
389 * lsi64854_pp_intr() does this part.
390 *
391 * len -= size;
392 */
393 }
394 }
395
396 out:
397 DPRINTF(("bpp done %x\n", error));
398 s = splbpp();
399 sc->sc_flags &= ~BPP_LOCKED;
400 if ((sc->sc_flags & BPP_WANT) != 0) {
401 sc->sc_flags &= ~BPP_WANT;
402 wakeup(sc->sc_buf);
403 }
404 splx(s);
405 return error;
406 }
407
408 /* move to header: */
409 #define BPPIOCSPARAM _IOW('P', 0x1, struct hwstate)
410 #define BPPIOCGPARAM _IOR('P', 0x2, struct hwstate)
411
412 int
bppioctl(dev_t dev,u_long cmd,void * data,int flag,struct lwp * l)413 bppioctl(dev_t dev, u_long cmd, void *data, int flag, struct lwp *l)
414 {
415 struct bpp_softc *sc;
416 struct proc *p = l->l_proc;
417 struct hwstate *hw, *chw;
418 int error = 0;
419 int s;
420
421 sc = device_lookup_private(&bpp_cd, BPPUNIT(dev));
422
423 switch(cmd) {
424 case BPPIOCSPARAM:
425 chw = &sc->sc_hwcurrent;
426 hw = (struct hwstate *)data;
427
428 /*
429 * Extract and store user-settable bits.
430 */
431 #define _bpp_set(reg,mask) do { \
432 chw->reg &= ~(mask); \
433 chw->reg |= (hw->reg & (mask)); \
434 } while (/* CONSTCOND */ 0)
435 _bpp_set(hw_hcr, BPP_HCR_DSS_MASK|BPP_HCR_DSW_MASK);
436 _bpp_set(hw_ocr, BPP_OCR_USER);
437 _bpp_set(hw_tcr, BPP_TCR_USER);
438 _bpp_set(hw_or, BPP_OR_USER);
439 _bpp_set(hw_irq, BPP_IRQ_USER);
440 #undef _bpp_set
441
442 /* Apply settings */
443 s = splbpp();
444 bpp_setparams(sc, chw);
445 splx(s);
446 break;
447 case BPPIOCGPARAM:
448 *((struct hwstate *)data) = sc->sc_hwcurrent;
449 break;
450 case TIOCEXCL:
451 s = splbpp();
452 sc->sc_flags |= BPP_XCLUDE;
453 splx(s);
454 break;
455 case TIOCNXCL:
456 s = splbpp();
457 sc->sc_flags &= ~BPP_XCLUDE;
458 splx(s);
459 break;
460 case FIOASYNC:
461 mutex_enter(&proc_lock);
462 if (*(int *)data) {
463 if (sc->sc_asyncproc != NULL)
464 error = EBUSY;
465 else
466 sc->sc_asyncproc = p;
467 } else
468 sc->sc_asyncproc = NULL;
469 mutex_exit(&proc_lock);
470 break;
471 default:
472 break;
473 }
474
475 return error;
476 }
477
478 int
bpppoll(dev_t dev,int events,struct lwp * l)479 bpppoll(dev_t dev, int events, struct lwp *l)
480 {
481 struct bpp_softc *sc;
482 int revents = 0;
483
484 sc = device_lookup_private(&bpp_cd, BPPUNIT(dev));
485
486 if (events & (POLLIN | POLLRDNORM)) {
487 /* read is not yet implemented */
488 }
489
490 if (events & (POLLOUT | POLLWRNORM)) {
491 if ((sc->sc_flags & BPP_LOCKED) == 0)
492 revents |= (POLLOUT | POLLWRNORM);
493 }
494
495 if (revents == 0) {
496 if (events & (POLLIN | POLLRDNORM))
497 selrecord(l, &sc->sc_rsel);
498 if (events & (POLLOUT | POLLWRNORM))
499 selrecord(l, &sc->sc_wsel);
500 }
501
502 return revents;
503 }
504
505 static void
filt_bpprdetach(struct knote * kn)506 filt_bpprdetach(struct knote *kn)
507 {
508 struct bpp_softc *sc = kn->kn_hook;
509 int s;
510
511 s = splbpp();
512 selremove_knote(&sc->sc_rsel, kn);
513 splx(s);
514 }
515
516 static int
filt_bppread(struct knote * kn,long hint)517 filt_bppread(struct knote *kn, long hint)
518 {
519 /* XXX Read not yet implemented. */
520 return 0;
521 }
522
523 static const struct filterops bppread_filtops = {
524 .f_flags = FILTEROP_ISFD,
525 .f_attach = NULL,
526 .f_detach = filt_bpprdetach,
527 .f_event = filt_bppread,
528 };
529
530 static void
filt_bppwdetach(struct knote * kn)531 filt_bppwdetach(struct knote *kn)
532 {
533 struct bpp_softc *sc = kn->kn_hook;
534 int s;
535
536 s = splbpp();
537 selremove_knote(&sc->sc_wsel, kn);
538 splx(s);
539 }
540
541 static int
filt_bpfwrite(struct knote * kn,long hint)542 filt_bpfwrite(struct knote *kn, long hint)
543 {
544 struct bpp_softc *sc = kn->kn_hook;
545
546 if (sc->sc_flags & BPP_LOCKED)
547 return 0;
548
549 kn->kn_data = 0; /* XXXLUKEM (thorpej): what to put here? */
550 return 1;
551 }
552
553 static const struct filterops bppwrite_filtops = {
554 .f_flags = FILTEROP_ISFD,
555 .f_attach = NULL,
556 .f_detach = filt_bppwdetach,
557 .f_event = filt_bpfwrite,
558 };
559
560 int
bppkqfilter(dev_t dev,struct knote * kn)561 bppkqfilter(dev_t dev, struct knote *kn)
562 {
563 struct bpp_softc *sc;
564 struct selinfo *sip;
565 int s;
566
567 sc = device_lookup_private(&bpp_cd, BPPUNIT(dev));
568
569 switch (kn->kn_filter) {
570 case EVFILT_READ:
571 sip = &sc->sc_rsel;
572 kn->kn_fop = &bppread_filtops;
573 break;
574
575 case EVFILT_WRITE:
576 sip = &sc->sc_wsel;
577 kn->kn_fop = &bppwrite_filtops;
578 break;
579
580 default:
581 return EINVAL;
582 }
583
584 kn->kn_hook = sc;
585
586 s = splbpp();
587 selrecord_knote(sip, kn);
588 splx(s);
589
590 return 0;
591 }
592
593 int
bppintr(void * arg)594 bppintr(void *arg)
595 {
596 struct bpp_softc *sc = arg;
597 struct lsi64854_softc *lsi = &sc->sc_lsi64854;
598 uint16_t irq;
599
600 /* First handle any possible DMA interrupts */
601 if (lsi64854_pp_intr((void *)lsi) == -1)
602 sc->sc_error = 1;
603
604 irq = bus_space_read_2(lsi->sc_bustag, lsi->sc_regs, L64854_REG_ICR);
605 /* Ack all interrupts */
606 bus_space_write_2(lsi->sc_bustag, lsi->sc_regs, L64854_REG_ICR,
607 irq | BPP_ALLIRQ);
608
609 DPRINTF(("%s: %x\n", __func__, irq));
610 /* Did our device interrupt? */
611 if ((irq & BPP_ALLIRQ) == 0)
612 return 0;
613
614 if ((sc->sc_flags & BPP_LOCKED) != 0)
615 wakeup(sc);
616 else if ((sc->sc_flags & BPP_WANT) != 0) {
617 sc->sc_flags &= ~BPP_WANT;
618 wakeup(sc->sc_buf);
619 } else {
620 selnotify(&sc->sc_wsel, 0, 0);
621 if (sc->sc_asyncproc != NULL)
622 softint_schedule(sc->sc_sih);
623 }
624 return 1;
625 }
626
627 static void
bppsoftintr(void * cookie)628 bppsoftintr(void *cookie)
629 {
630 struct bpp_softc *sc = cookie;
631
632 mutex_enter(&proc_lock);
633 if (sc->sc_asyncproc)
634 psignal(sc->sc_asyncproc, SIGIO);
635 mutex_exit(&proc_lock);
636 }
637