bpp.c 10 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407
  1. /* $OpenBSD: bpp.c,v 1.4 2015/02/10 21:56:09 miod Exp $ */
  2. /* $NetBSD: bpp.c,v 1.25 2005/12/11 12:23:44 christos Exp $ */
  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. #include <sys/param.h>
  32. #include <sys/ioctl.h>
  33. #include <sys/systm.h>
  34. #include <sys/kernel.h>
  35. #include <sys/errno.h>
  36. #include <sys/device.h>
  37. #include <sys/malloc.h>
  38. #include <sys/proc.h>
  39. #include <sys/vnode.h>
  40. #include <sys/conf.h>
  41. #include <machine/autoconf.h>
  42. #include <machine/bus.h>
  43. #include <machine/conf.h>
  44. #include <machine/intr.h>
  45. #include <dev/ic/lsi64854reg.h>
  46. #include <dev/ic/lsi64854var.h>
  47. #include <dev/sbus/sbusvar.h>
  48. #include <dev/sbus/bppreg.h>
  49. #define splbpp() spltty() /* XXX */
  50. #ifdef DEBUG
  51. #define DPRINTF(x) do { if (bppdebug) printf x ; } while (0)
  52. int bppdebug = 1;
  53. #else
  54. #define DPRINTF(x)
  55. #endif
  56. #if 0
  57. struct bpp_param {
  58. int bpp_dss; /* data setup to strobe */
  59. int bpp_dsw; /* data strobe width */
  60. int bpp_outputpins; /* Select/Autofeed/Init pins */
  61. int bpp_inputpins; /* Error/Select/Paperout pins */
  62. };
  63. #endif
  64. struct hwstate {
  65. u_int16_t hw_hcr; /* Hardware config register */
  66. u_int16_t hw_ocr; /* Operation config register */
  67. u_int8_t hw_tcr; /* Transfer Control register */
  68. u_int8_t hw_or; /* Output register */
  69. u_int16_t hw_irq; /* IRQ; polarity bits only */
  70. };
  71. struct bpp_softc {
  72. struct lsi64854_softc sc_lsi64854; /* base device */
  73. size_t sc_bufsz; /* temp buffer */
  74. caddr_t sc_buf;
  75. int sc_error; /* bottom-half error */
  76. int sc_flags;
  77. #define BPP_LOCKED 0x01 /* DMA in progress */
  78. #define BPP_WANT 0x02 /* Waiting for DMA */
  79. /* Hardware state */
  80. struct hwstate sc_hwstate;
  81. };
  82. int bppmatch(struct device *, void *, void *);
  83. void bppattach(struct device *, struct device *, void *);
  84. int bppintr (void *);
  85. void bpp_setparams(struct bpp_softc *, struct hwstate *);
  86. const struct cfattach bpp_ca = {
  87. sizeof(struct bpp_softc), bppmatch, bppattach
  88. };
  89. struct cfdriver bpp_cd = {
  90. NULL, "bpp", DV_DULL
  91. };
  92. #define BPPUNIT(dev) (minor(dev))
  93. int
  94. bppmatch(struct device *parent, void *vcf, void *aux)
  95. {
  96. struct sbus_attach_args *sa = aux;
  97. return (strcmp("SUNW,bpp", sa->sa_name) == 0);
  98. }
  99. void
  100. bppattach(struct device *parent, struct device *self, void *aux)
  101. {
  102. struct sbus_attach_args *sa = aux;
  103. struct bpp_softc *dsc = (void *)self;
  104. struct lsi64854_softc *sc = &dsc->sc_lsi64854;
  105. int burst, sbusburst;
  106. int node;
  107. node = sa->sa_node;
  108. sc->sc_bustag = sa->sa_bustag;
  109. sc->sc_dmatag = sa->sa_dmatag;
  110. /* Map device registers */
  111. if (sa->sa_npromvaddrs != 0) {
  112. if (sbus_bus_map(sa->sa_bustag, 0, sa->sa_promvaddrs[0],
  113. sa->sa_size, /* ???? */
  114. BUS_SPACE_MAP_PROMADDRESS, 0, &sc->sc_regs) != 0) {
  115. printf(": cannot map registers\n");
  116. return;
  117. }
  118. } else if (sbus_bus_map(sa->sa_bustag, sa->sa_slot, sa->sa_offset,
  119. sa->sa_size, 0, 0, &sc->sc_regs) != 0) {
  120. printf(": cannot map registers\n");
  121. return;
  122. }
  123. /* Check for the interrupt property */
  124. if (sa->sa_nintr == 0) {
  125. printf(": no interrupt property\n");
  126. return;
  127. }
  128. /*
  129. * Get transfer burst size from PROM and plug it into the
  130. * controller registers. This is needed on the Sun4m; do
  131. * others need it too?
  132. */
  133. sbusburst = ((struct sbus_softc *)parent)->sc_burst;
  134. if (sbusburst == 0)
  135. sbusburst = SBUS_BURST_32 - 1; /* 1->16 */
  136. burst = getpropint(node, "burst-sizes", -1);
  137. if (burst == -1)
  138. /* take SBus burst sizes */
  139. burst = sbusburst;
  140. /* Clamp at parent's burst sizes */
  141. burst &= sbusburst;
  142. sc->sc_burst = (burst & SBUS_BURST_32) ? 32 :
  143. (burst & SBUS_BURST_16) ? 16 : 0;
  144. /* Initialize the DMA channel */
  145. sc->sc_channel = L64854_CHANNEL_PP;
  146. if (lsi64854_attach(sc) != 0)
  147. return;
  148. /* Establish interrupt handler */
  149. sc->sc_intrchain = bppintr;
  150. sc->sc_intrchainarg = dsc;
  151. (void)bus_intr_establish(sa->sa_bustag, sa->sa_pri, IPL_TTY, 0,
  152. bppintr, sc, self->dv_xname);
  153. /* Allocate buffer XXX - should actually use dmamap_uio() */
  154. dsc->sc_bufsz = 1024;
  155. dsc->sc_buf = malloc(dsc->sc_bufsz, M_DEVBUF, M_NOWAIT);
  156. /* XXX read default state */
  157. {
  158. bus_space_handle_t h = sc->sc_regs;
  159. struct hwstate *hw = &dsc->sc_hwstate;
  160. int ack_rate = sa->sa_frequency/1000000;
  161. hw->hw_hcr = bus_space_read_2(sc->sc_bustag, h, L64854_REG_HCR);
  162. hw->hw_ocr = bus_space_read_2(sc->sc_bustag, h, L64854_REG_OCR);
  163. hw->hw_tcr = bus_space_read_1(sc->sc_bustag, h, L64854_REG_TCR);
  164. hw->hw_or = bus_space_read_1(sc->sc_bustag, h, L64854_REG_OR);
  165. DPRINTF(("bpp: hcr %x ocr %x tcr %x or %x\n",
  166. hw->hw_hcr, hw->hw_ocr, hw->hw_tcr, hw->hw_or));
  167. /* Set these to sane values */
  168. hw->hw_hcr = ((ack_rate<<BPP_HCR_DSS_SHFT)&BPP_HCR_DSS_MASK)
  169. | ((ack_rate<<BPP_HCR_DSW_SHFT)&BPP_HCR_DSW_MASK);
  170. hw->hw_ocr |= BPP_OCR_ACK_OP;
  171. }
  172. }
  173. void
  174. bpp_setparams(struct bpp_softc *sc, struct hwstate *hw)
  175. {
  176. u_int16_t irq;
  177. bus_space_tag_t t = sc->sc_lsi64854.sc_bustag;
  178. bus_space_handle_t h = sc->sc_lsi64854.sc_regs;
  179. bus_space_write_2(t, h, L64854_REG_HCR, hw->hw_hcr);
  180. bus_space_write_2(t, h, L64854_REG_OCR, hw->hw_ocr);
  181. bus_space_write_1(t, h, L64854_REG_TCR, hw->hw_tcr);
  182. bus_space_write_1(t, h, L64854_REG_OR, hw->hw_or);
  183. /* Only change IRP settings in interrupt status register */
  184. irq = bus_space_read_2(t, h, L64854_REG_ICR);
  185. irq &= ~BPP_ALLIRP;
  186. irq |= (hw->hw_irq & BPP_ALLIRP);
  187. bus_space_write_2(t, h, L64854_REG_ICR, irq);
  188. DPRINTF(("bpp_setparams: hcr %x ocr %x tcr %x or %x, irq %x\n",
  189. hw->hw_hcr, hw->hw_ocr, hw->hw_tcr, hw->hw_or, irq));
  190. }
  191. int
  192. bppopen(dev_t dev, int flags, int mode, struct proc *p)
  193. {
  194. int unit = BPPUNIT(dev);
  195. struct bpp_softc *sc;
  196. struct lsi64854_softc *lsi;
  197. u_int16_t irq;
  198. int s;
  199. if (unit >= bpp_cd.cd_ndevs)
  200. return (ENXIO);
  201. if ((sc = bpp_cd.cd_devs[unit]) == NULL)
  202. return (ENXIO);
  203. lsi = &sc->sc_lsi64854;
  204. /* Set default parameters */
  205. s = splbpp();
  206. bpp_setparams(sc, &sc->sc_hwstate);
  207. splx(s);
  208. /* Enable interrupts */
  209. irq = BPP_ERR_IRQ_EN;
  210. irq |= sc->sc_hwstate.hw_irq;
  211. bus_space_write_2(lsi->sc_bustag, lsi->sc_regs, L64854_REG_ICR, irq);
  212. return (0);
  213. }
  214. int
  215. bppclose(dev_t dev, int flags, int mode, struct proc *p)
  216. {
  217. struct bpp_softc *sc = bpp_cd.cd_devs[BPPUNIT(dev)];
  218. struct lsi64854_softc *lsi = &sc->sc_lsi64854;
  219. u_int16_t irq;
  220. /* Turn off all interrupt enables */
  221. irq = sc->sc_hwstate.hw_irq | BPP_ALLIRQ;
  222. irq &= ~BPP_ALLEN;
  223. bus_space_write_2(lsi->sc_bustag, lsi->sc_regs, L64854_REG_ICR, irq);
  224. sc->sc_flags = 0;
  225. return (0);
  226. }
  227. int
  228. bppwrite(dev_t dev, struct uio *uio, int flags)
  229. {
  230. struct bpp_softc *sc = bpp_cd.cd_devs[BPPUNIT(dev)];
  231. struct lsi64854_softc *lsi = &sc->sc_lsi64854;
  232. int error = 0;
  233. int s;
  234. /*
  235. * Wait until the DMA engine is free.
  236. */
  237. s = splbpp();
  238. while ((sc->sc_flags & BPP_LOCKED) != 0) {
  239. if ((flags & IO_NDELAY) != 0) {
  240. splx(s);
  241. return (EWOULDBLOCK);
  242. }
  243. sc->sc_flags |= BPP_WANT;
  244. error = tsleep(sc->sc_buf, PZERO | PCATCH, "bppwrite", 0);
  245. if (error != 0) {
  246. splx(s);
  247. return (error);
  248. }
  249. }
  250. sc->sc_flags |= BPP_LOCKED;
  251. splx(s);
  252. /*
  253. * Move data from user space into our private buffer
  254. * and start DMA.
  255. */
  256. while (uio->uio_resid > 0) {
  257. caddr_t bp = sc->sc_buf;
  258. size_t len = min(sc->sc_bufsz, uio->uio_resid);
  259. if ((error = uiomovei(bp, len, uio)) != 0)
  260. break;
  261. while (len > 0) {
  262. u_int8_t tcr;
  263. size_t size = len;
  264. DMA_SETUP(lsi, &bp, &len, 0, &size);
  265. #ifdef DEBUG
  266. if (bppdebug) {
  267. int i;
  268. printf("bpp: writing %ld : ", len);
  269. for (i=0; i<len; i++) printf("%c(0x%x)", bp[i], bp[i]);
  270. printf("\n");
  271. }
  272. #endif
  273. /* Clear direction control bit */
  274. tcr = bus_space_read_1(lsi->sc_bustag, lsi->sc_regs,
  275. L64854_REG_TCR);
  276. tcr &= ~BPP_TCR_DIR;
  277. bus_space_write_1(lsi->sc_bustag, lsi->sc_regs,
  278. L64854_REG_TCR, tcr);
  279. /* Enable DMA */
  280. s = splbpp();
  281. DMA_GO(lsi);
  282. error = tsleep(sc, PZERO | PCATCH, "bppdma", 0);
  283. splx(s);
  284. if (error != 0)
  285. goto out;
  286. /* Bail out if bottom half reported an error */
  287. if ((error = sc->sc_error) != 0)
  288. goto out;
  289. /*
  290. * DMA_INTR() does this part.
  291. *
  292. * len -= size;
  293. */
  294. }
  295. }
  296. out:
  297. DPRINTF(("bpp done %x\n", error));
  298. s = splbpp();
  299. sc->sc_flags &= ~BPP_LOCKED;
  300. if ((sc->sc_flags & BPP_WANT) != 0) {
  301. sc->sc_flags &= ~BPP_WANT;
  302. wakeup(sc->sc_buf);
  303. }
  304. splx(s);
  305. return (error);
  306. }
  307. int
  308. bppioctl(dev_t dev, u_long cmd, caddr_t data, int flag, struct proc *p)
  309. {
  310. int error = 0;
  311. switch(cmd) {
  312. default:
  313. error = ENODEV;
  314. break;
  315. }
  316. return (error);
  317. }
  318. int
  319. bppintr(void *arg)
  320. {
  321. struct bpp_softc *sc = arg;
  322. struct lsi64854_softc *lsi = &sc->sc_lsi64854;
  323. u_int16_t irq;
  324. /* First handle any possible DMA interrupts */
  325. if (DMA_INTR(lsi) == -1)
  326. sc->sc_error = 1;
  327. irq = bus_space_read_2(lsi->sc_bustag, lsi->sc_regs, L64854_REG_ICR);
  328. /* Ack all interrupts */
  329. bus_space_write_2(lsi->sc_bustag, lsi->sc_regs, L64854_REG_ICR,
  330. irq | BPP_ALLIRQ);
  331. DPRINTF(("bpp_intr: %x\n", irq));
  332. /* Did our device interrupt? */
  333. if ((irq & BPP_ALLIRQ) == 0)
  334. return (0);
  335. if ((sc->sc_flags & BPP_LOCKED) != 0)
  336. wakeup(sc);
  337. else if ((sc->sc_flags & BPP_WANT) != 0) {
  338. sc->sc_flags &= ~BPP_WANT;
  339. wakeup(sc->sc_buf);
  340. }
  341. return (1);
  342. }