rfx.c 13 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539
  1. /* $OpenBSD: rfx.c,v 1.12 2014/01/22 03:03:09 jsg Exp $ */
  2. /*
  3. * Copyright (c) 2004, Miodrag Vallat.
  4. * 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 ``AS IS'' AND ANY EXPRESS OR
  16. * 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 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)
  22. * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
  23. * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
  24. * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
  25. * POSSIBILITY OF SUCH DAMAGE.
  26. *
  27. */
  28. /*
  29. * Driver for the Vitec RasterFlex family of frame buffers.
  30. * It should support RasterFlex-24, RasterFlex-32 and RasterFlex-HR.
  31. */
  32. #include <sys/param.h>
  33. #include <sys/systm.h>
  34. #include <sys/buf.h>
  35. #include <sys/device.h>
  36. #include <sys/ioctl.h>
  37. #include <sys/malloc.h>
  38. #include <sys/mman.h>
  39. #include <sys/tty.h>
  40. #include <sys/conf.h>
  41. #include <uvm/uvm_extern.h>
  42. #include <machine/autoconf.h>
  43. #include <machine/pmap.h>
  44. #include <machine/cpu.h>
  45. #include <machine/conf.h>
  46. #include <machine/openfirm.h>
  47. #include <dev/wscons/wsconsio.h>
  48. #include <dev/wscons/wsdisplayvar.h>
  49. #include <dev/rasops/rasops.h>
  50. #include <machine/fbvar.h>
  51. #include <dev/sbus/sbusvar.h>
  52. #include <dev/ic/bt463reg.h>
  53. /*
  54. * Configuration structure
  55. */
  56. struct rfx_config {
  57. u_int16_t unknown;
  58. u_int16_t version;
  59. u_int32_t scanline;
  60. u_int32_t maxwidth; /* unsure */
  61. u_int32_t maxheight; /* unsure */
  62. u_int32_t width;
  63. u_int32_t height;
  64. };
  65. /*
  66. * In-memory offsets
  67. */
  68. #define RFX_RAMDAC_ADDR 0x00020000
  69. #define RFX_RAMDAC_SIZE 0x00000004
  70. #define RFX_CONTROL_ADDR 0x00040000
  71. #define RFX_CONTROL_SIZE 0x000000e0
  72. #define RFX_INIT_ADDR 0x00018000
  73. #define RFX_INIT_OFFSET 0x0000001c
  74. #define RFX_INIT_SIZE 0x00008000
  75. #define RFX_VRAM_ADDR 0x00100000
  76. /*
  77. * Control registers
  78. */
  79. #define RFX_VIDCTRL_REG 0x10
  80. #define RFX_VSYNC_ENABLE 0x00000001
  81. #define RFX_VIDEO_DISABLE 0x00000002
  82. /*
  83. * Shadow colormap
  84. */
  85. struct rfx_cmap {
  86. u_int8_t red[256];
  87. u_int8_t green[256];
  88. u_int8_t blue[256];
  89. };
  90. struct rfx_softc {
  91. struct sunfb sc_sunfb;
  92. bus_space_tag_t sc_bustag;
  93. bus_addr_t sc_paddr;
  94. struct intrhand sc_ih;
  95. struct rfx_cmap sc_cmap;
  96. volatile u_int8_t *sc_ramdac;
  97. volatile u_int32_t *sc_ctrl;
  98. int sc_nscreens;
  99. };
  100. void rfx_burner(void *, u_int, u_int);
  101. int rfx_ioctl(void *, u_long, caddr_t, int, struct proc *);
  102. paddr_t rfx_mmap(void *, off_t, int);
  103. int rfx_getcmap(struct rfx_cmap *, struct wsdisplay_cmap *);
  104. int rfx_initialize(struct rfx_softc *, struct sbus_attach_args *,
  105. struct rfx_config *);
  106. int rfx_intr(void *);
  107. void rfx_loadcmap(struct rfx_softc *, int, int);
  108. int rfx_putcmap(struct rfx_cmap *, struct wsdisplay_cmap *);
  109. void rfx_setcolor(void *, u_int, u_int8_t, u_int8_t, u_int8_t);
  110. struct wsdisplay_accessops rfx_accessops = {
  111. .ioctl = rfx_ioctl,
  112. .mmap = rfx_mmap,
  113. .burn_screen = rfx_burner
  114. };
  115. int rfxmatch(struct device *, void *, void *);
  116. void rfxattach(struct device *, struct device *, void *);
  117. #if defined(OpenBSD)
  118. struct cfattach rfx_ca = {
  119. sizeof (struct rfx_softc), rfxmatch, rfxattach
  120. };
  121. struct cfdriver rfx_cd = {
  122. NULL, "rfx", DV_DULL
  123. };
  124. #else
  125. CFATTACH_DECL(rfx, sizeof (struct rfx_softc), rfxmatch, rfxattach, NULL, NULL);
  126. #endif
  127. /*
  128. * Match a supported RasterFlex card.
  129. */
  130. int
  131. rfxmatch(struct device *parent, void *vcf, void *aux)
  132. {
  133. struct sbus_attach_args *sa = aux;
  134. const char *device = sa->sa_name;
  135. /* skip vendor name (could be CWARE, VITec, ...) */
  136. while (*device != ',' && *device != '\0')
  137. device++;
  138. if (*device == '\0')
  139. device = sa->sa_name;
  140. else
  141. device++;
  142. if (strncmp(device, "RasterFLEX", strlen("RasterFLEX")) != 0)
  143. return (0);
  144. /* RasterVideo and RasterFlex-TV are frame grabbers */
  145. if (strcmp(device, "RasterFLEX-TV") == 0)
  146. return (0);
  147. return (1);
  148. }
  149. /*
  150. * Attach and initialize a rfx display, as well as a child wsdisplay.
  151. */
  152. void
  153. rfxattach(struct device *parent, struct device *self, void *args)
  154. {
  155. struct rfx_softc *sc = (struct rfx_softc *)self;
  156. struct sbus_attach_args *sa = args;
  157. const char *device = sa->sa_name;
  158. struct rfx_config cf;
  159. bus_space_tag_t bt;
  160. bus_space_handle_t bh;
  161. int node, cflen, isconsole = 0;
  162. /* skip vendor name (could be CWARE, VITec, ...) */
  163. while (*device != ',' && *device != '\0')
  164. device++;
  165. if (*device == '\0')
  166. device = sa->sa_name;
  167. else
  168. device++;
  169. printf(": %s", device);
  170. if (sa->sa_nreg == 0) {
  171. printf("\n%s: no SBus registers!\n", self->dv_xname);
  172. return;
  173. }
  174. bt = sa->sa_bustag;
  175. node = sa->sa_node;
  176. isconsole = node == fbnode;
  177. /*
  178. * Parse configuration structure
  179. */
  180. cflen = getproplen(node, "configuration");
  181. if (cflen != sizeof cf) {
  182. printf(", unknown %d bytes conf. structure", cflen);
  183. /* fill in default values */
  184. cf.version = 0;
  185. cf.scanline = 2048;
  186. cf.width = 1152;
  187. cf.height = 900;
  188. } else {
  189. OF_getprop(node, "configuration", &cf, cflen);
  190. printf(", revision %d", cf.version);
  191. }
  192. /*
  193. * Map registers
  194. */
  195. sc->sc_bustag = bt;
  196. sc->sc_paddr = sbus_bus_addr(bt, sa->sa_slot, sa->sa_offset);
  197. if (sbus_bus_map(bt, sa->sa_slot, sa->sa_offset + RFX_RAMDAC_ADDR,
  198. RFX_RAMDAC_SIZE, BUS_SPACE_MAP_LINEAR, 0, &bh) != 0) {
  199. printf("\n%s: couldn't map ramdac registers\n", self->dv_xname);
  200. return;
  201. }
  202. sc->sc_ramdac = (u_int8_t *)bus_space_vaddr(bt, bh);
  203. if (sbus_bus_map(bt, sa->sa_slot, sa->sa_offset + RFX_CONTROL_ADDR,
  204. RFX_CONTROL_SIZE, BUS_SPACE_MAP_LINEAR, 0, &bh) != 0) {
  205. printf("\n%s: couldn't map control registers\n", self->dv_xname);
  206. return;
  207. }
  208. sc->sc_ctrl = (u_int32_t *)bus_space_vaddr(bt, bh);
  209. #if 0 /* not yet */
  210. sc->sc_ih.ih_fun = rfx_intr;
  211. sc->sc_ih.ih_arg = sc;
  212. intr_establish(ca->ca_ra.ra_intr[0].int_pri, &sc->sc_ih, IPL_FB);
  213. #endif
  214. /*
  215. * The following is an equivalent for
  216. * fb_setsize(&sc->sc_sunfb, 8, cf.width, cf.height,
  217. * node, ca->ca_bustype);
  218. * forcing the correct scan line value. Since the usual frame buffer
  219. * properties are missing on this card, no need to go through
  220. * fb_setsize()...
  221. */
  222. sc->sc_sunfb.sf_depth = 8;
  223. sc->sc_sunfb.sf_width = cf.width;
  224. sc->sc_sunfb.sf_height = cf.height;
  225. sc->sc_sunfb.sf_linebytes = cf.scanline;
  226. sc->sc_sunfb.sf_fbsize = cf.height * cf.scanline;
  227. printf(", %dx%d\n", sc->sc_sunfb.sf_width, sc->sc_sunfb.sf_height);
  228. if (sbus_bus_map(bt, sa->sa_slot, sa->sa_offset + RFX_VRAM_ADDR,
  229. round_page(sc->sc_sunfb.sf_fbsize), BUS_SPACE_MAP_LINEAR,
  230. 0, &bh) != 0) {
  231. printf("\n%s: couldn't map video memory\n", self->dv_xname);
  232. return;
  233. }
  234. sc->sc_sunfb.sf_ro.ri_bits = bus_space_vaddr(bt, bh);
  235. sc->sc_sunfb.sf_ro.ri_hw = sc;
  236. /*
  237. * If we are not the console, the frame buffer has not been
  238. * initialized by the PROM - do this ourselves.
  239. */
  240. if (!isconsole) {
  241. if (rfx_initialize(sc, sa, &cf) != 0)
  242. return;
  243. }
  244. fbwscons_init(&sc->sc_sunfb, 0, isconsole);
  245. bzero(&sc->sc_cmap, sizeof(sc->sc_cmap));
  246. fbwscons_setcolormap(&sc->sc_sunfb, rfx_setcolor);
  247. if (isconsole)
  248. fbwscons_console_init(&sc->sc_sunfb, -1);
  249. /* enable video */
  250. rfx_burner(sc, 1, 0);
  251. fbwscons_attach(&sc->sc_sunfb, &rfx_accessops, isconsole);
  252. }
  253. /*
  254. * Common wsdisplay operations
  255. */
  256. int
  257. rfx_ioctl(void *v, u_long cmd, caddr_t data, int flags, struct proc *p)
  258. {
  259. struct rfx_softc *sc = v;
  260. struct wsdisplay_cmap *cm;
  261. struct wsdisplay_fbinfo *wdf;
  262. int error;
  263. switch (cmd) {
  264. case WSDISPLAYIO_GTYPE:
  265. *(u_int *)data = WSDISPLAY_TYPE_RFLEX;
  266. break;
  267. case WSDISPLAYIO_GINFO:
  268. wdf = (struct wsdisplay_fbinfo *)data;
  269. wdf->height = sc->sc_sunfb.sf_height;
  270. wdf->width = sc->sc_sunfb.sf_width;
  271. wdf->depth = sc->sc_sunfb.sf_depth;
  272. wdf->cmsize = 256;
  273. break;
  274. case WSDISPLAYIO_LINEBYTES:
  275. *(u_int *)data = sc->sc_sunfb.sf_linebytes;
  276. break;
  277. case WSDISPLAYIO_GETCMAP:
  278. cm = (struct wsdisplay_cmap *)data;
  279. error = rfx_getcmap(&sc->sc_cmap, cm);
  280. if (error != 0)
  281. return (error);
  282. break;
  283. case WSDISPLAYIO_PUTCMAP:
  284. cm = (struct wsdisplay_cmap *)data;
  285. error = rfx_putcmap(&sc->sc_cmap, cm);
  286. if (error != 0)
  287. return (error);
  288. rfx_loadcmap(sc, cm->index, cm->count);
  289. break;
  290. case WSDISPLAYIO_SVIDEO:
  291. case WSDISPLAYIO_GVIDEO:
  292. break;
  293. default:
  294. return (-1);
  295. }
  296. return (0);
  297. }
  298. paddr_t
  299. rfx_mmap(void *v, off_t offset, int prot)
  300. {
  301. struct rfx_softc *sc = v;
  302. if (offset & PGOFSET)
  303. return (-1);
  304. if (offset >= 0 && offset < sc->sc_sunfb.sf_fbsize) {
  305. return (bus_space_mmap(sc->sc_bustag, sc->sc_paddr,
  306. RFX_VRAM_ADDR + offset, prot, BUS_SPACE_MAP_LINEAR));
  307. }
  308. return (-1);
  309. }
  310. void
  311. rfx_burner(void *v, u_int on, u_int flags)
  312. {
  313. struct rfx_softc *sc = v;
  314. if (on) {
  315. sc->sc_ctrl[RFX_VIDCTRL_REG] &= ~RFX_VIDEO_DISABLE;
  316. sc->sc_ctrl[RFX_VIDCTRL_REG] |= RFX_VSYNC_ENABLE;
  317. } else {
  318. sc->sc_ctrl[RFX_VIDCTRL_REG] |= RFX_VIDEO_DISABLE;
  319. if (flags & WSDISPLAY_BURN_VBLANK)
  320. sc->sc_ctrl[RFX_VIDCTRL_REG] &= ~RFX_VSYNC_ENABLE;
  321. }
  322. }
  323. /*
  324. * Colormap helper functions
  325. */
  326. void
  327. rfx_setcolor(void *v, u_int index, u_int8_t r, u_int8_t g, u_int8_t b)
  328. {
  329. struct rfx_softc *sc = v;
  330. sc->sc_cmap.red[index] = r;
  331. sc->sc_cmap.green[index] = g;
  332. sc->sc_cmap.blue[index] = b;
  333. rfx_loadcmap(sc, index, 1);
  334. }
  335. int
  336. rfx_getcmap(struct rfx_cmap *cm, struct wsdisplay_cmap *rcm)
  337. {
  338. u_int index = rcm->index, count = rcm->count;
  339. int error;
  340. if (index >= 256 || count > 256 - index)
  341. return (EINVAL);
  342. if ((error = copyout(cm->red + index, rcm->red, count)) != 0)
  343. return (error);
  344. if ((error = copyout(cm->green + index, rcm->green, count)) != 0)
  345. return (error);
  346. if ((error = copyout(cm->blue + index, rcm->blue, count)) != 0)
  347. return (error);
  348. return (0);
  349. }
  350. int
  351. rfx_putcmap(struct rfx_cmap *cm, struct wsdisplay_cmap *rcm)
  352. {
  353. u_int index = rcm->index, count = rcm->count;
  354. u_int8_t red[256], green[256], blue[256];
  355. int error;
  356. if (index >= 256 || count > 256 - index)
  357. return (EINVAL);
  358. if ((error = copyin(rcm->red, red, count)) != 0)
  359. return (error);
  360. if ((error = copyin(rcm->green, green, count)) != 0)
  361. return (error);
  362. if ((error = copyin(rcm->blue, blue, count)) != 0)
  363. return (error);
  364. bcopy(red, cm->red + index, count);
  365. bcopy(green, cm->green + index, count);
  366. bcopy(blue, cm->blue + index, count);
  367. return (0);
  368. }
  369. void
  370. rfx_loadcmap(struct rfx_softc *sc, int start, int ncolors)
  371. {
  372. u_int8_t *r, *g, *b;
  373. r = sc->sc_cmap.red + start;
  374. g = sc->sc_cmap.green + start;
  375. b = sc->sc_cmap.blue + start;
  376. start += BT463_IREG_CPALETTE_RAM;
  377. sc->sc_ramdac[BT463_REG_ADDR_LOW] = start & 0xff;
  378. sc->sc_ramdac[BT463_REG_ADDR_HIGH] = (start >> 8) & 0xff;
  379. while (ncolors-- != 0) {
  380. sc->sc_ramdac[BT463_REG_CMAP_DATA] = *r++;
  381. sc->sc_ramdac[BT463_REG_CMAP_DATA] = *g++;
  382. sc->sc_ramdac[BT463_REG_CMAP_DATA] = *b++;
  383. }
  384. }
  385. /*
  386. * Initialization code parser
  387. */
  388. int
  389. rfx_initialize(struct rfx_softc *sc, struct sbus_attach_args *sa,
  390. struct rfx_config *cf)
  391. {
  392. u_int32_t *data, offset, value;
  393. size_t cnt;
  394. bus_space_handle_t bh;
  395. int error;
  396. /*
  397. * Map the initialization data
  398. */
  399. if ((error = sbus_bus_map(sa->sa_bustag, sa->sa_slot, sa->sa_offset +
  400. RFX_INIT_ADDR, RFX_INIT_SIZE, BUS_SPACE_MAP_LINEAR, 0, &bh)) != 0) {
  401. printf("\n%s: couldn't map initialization data\n",
  402. sc->sc_sunfb.sf_dev.dv_xname);
  403. return error;
  404. }
  405. data = (u_int32_t *)bus_space_vaddr(sa->sa_bustag, bh);
  406. /*
  407. * Skip copyright notice
  408. */
  409. data += RFX_INIT_OFFSET / sizeof(u_int32_t);
  410. cnt = (RFX_INIT_SIZE - RFX_INIT_OFFSET) / sizeof(u_int32_t);
  411. cnt >>= 1;
  412. /*
  413. * Parse and apply settings
  414. */
  415. while (cnt != 0) {
  416. offset = *data++;
  417. value = *data++;
  418. if (offset == (u_int32_t)-1 && value == (u_int32_t)-1)
  419. break;
  420. /* Old PROM are little-endian */
  421. if (cf->version <= 1) {
  422. offset = letoh32(offset);
  423. value = letoh32(offset);
  424. }
  425. if (offset & (1U << 31)) {
  426. offset = (offset & ~(1U << 31)) - RFX_RAMDAC_ADDR;
  427. if (offset < RFX_RAMDAC_SIZE)
  428. sc->sc_ramdac[offset] = value >> 24;
  429. } else {
  430. offset -= RFX_CONTROL_ADDR;
  431. if (offset < RFX_CONTROL_SIZE)
  432. sc->sc_ctrl[offset >> 2] = value;
  433. }
  434. cnt--;
  435. }
  436. #ifdef DEBUG
  437. if (cnt != 0)
  438. printf("%s: incoherent initialization data!\n",
  439. sc->sc_sunfb.sf_dev.dv_xname);
  440. #endif
  441. bus_space_unmap(sa->sa_bustag, bh, RFX_INIT_SIZE);
  442. return 0;
  443. }