vigra.c 13 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539
  1. /* $OpenBSD: vigra.c,v 1.12 2013/10/20 20:07:31 miod Exp $ */
  2. /*
  3. * Copyright (c) 2002, 2003, 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 Vigra VS series of SBus framebuffers.
  30. *
  31. * The VS10, VS11 and VS12 models are supported. VS10-EK is handled by the
  32. * regular cgthree driver.
  33. *
  34. * The monochrome VS14, 16 grays VS15, and color VS18 are not supported.
  35. */
  36. #include <sys/param.h>
  37. #include <sys/systm.h>
  38. #include <sys/buf.h>
  39. #include <sys/device.h>
  40. #include <sys/ioctl.h>
  41. #include <sys/malloc.h>
  42. #include <sys/mman.h>
  43. #include <sys/tty.h>
  44. #include <sys/conf.h>
  45. #include <uvm/uvm_extern.h>
  46. #include <machine/autoconf.h>
  47. #include <machine/bus.h>
  48. #include <machine/pmap.h>
  49. #include <machine/cpu.h>
  50. #include <machine/conf.h>
  51. #include <dev/wscons/wsconsio.h>
  52. #include <dev/wscons/wsdisplayvar.h>
  53. #include <dev/rasops/rasops.h>
  54. #include <machine/fbvar.h>
  55. #include <dev/sbus/sbusvar.h>
  56. /*
  57. * The hardware information below has been gathered through experiments, as
  58. * well as the debug information of the SunOS 4.x vigfb driver.
  59. */
  60. /*
  61. * Control and status registers
  62. */
  63. struct csregs {
  64. u_int32_t sosr;
  65. u_int32_t g3rr;
  66. u_int32_t bcr; /* board control register */
  67. u_int32_t spr;
  68. u_int32_t g3sr; /* ramdac status register */
  69. #define STATUS_INTR 0x0001
  70. u_int32_t imr; /* interrupt mode register */
  71. u_int32_t ewcr;
  72. u_int32_t ssr;
  73. };
  74. /*
  75. * G300 layout
  76. */
  77. struct g300dac {
  78. u_int32_t cmap[256];
  79. u_int32_t g3null;
  80. u_int32_t unused1[32];
  81. u_int32_t half_sync;
  82. u_int32_t back_porch;
  83. u_int32_t display;
  84. u_int32_t short_display;
  85. u_int32_t broad_pulse;
  86. u_int32_t vsync;
  87. u_int32_t vblank;
  88. u_int32_t vdisplay;
  89. u_int32_t line_time;
  90. u_int32_t tos1;
  91. u_int32_t mem_init;
  92. u_int32_t transfer_delay;
  93. u_int32_t unused2[19];
  94. u_int32_t mask;
  95. u_int32_t unused3[31];
  96. u_int32_t cr;
  97. u_int32_t unused4[31];
  98. u_int32_t tos2;
  99. u_int32_t unused5[31];
  100. u_int32_t boot_location;
  101. };
  102. /*
  103. * G335 layout
  104. */
  105. struct g335dac {
  106. u_int32_t boot_location;
  107. u_int32_t unused1[32];
  108. u_int32_t half_sync;
  109. u_int32_t back_porch;
  110. u_int32_t display;
  111. u_int32_t short_display;
  112. u_int32_t broad_pulse;
  113. u_int32_t vsync;
  114. u_int32_t vpre_equalize;
  115. u_int32_t vpost_equalize;
  116. u_int32_t vblank;
  117. u_int32_t vdisplay;
  118. u_int32_t line_time;
  119. u_int32_t tos1;
  120. u_int32_t mem_init;
  121. u_int32_t transfer_delay;
  122. u_int32_t unused2[17];
  123. u_int32_t mask;
  124. u_int32_t unused3[31];
  125. u_int32_t cra;
  126. u_int32_t unused4[15];
  127. u_int32_t crb;
  128. u_int32_t unused5[15];
  129. u_int32_t tos2;
  130. u_int32_t unused6[32];
  131. u_int32_t cursor_palette[3];
  132. u_int32_t unused7[28];
  133. u_int32_t checksum[3];
  134. u_int32_t unused8[4];
  135. u_int32_t cursor_position;
  136. u_int32_t unused9[56];
  137. u_int32_t cmap[256];
  138. u_int32_t cursor_store[512];
  139. };
  140. union dac {
  141. struct g300dac g300;
  142. struct g335dac g335;
  143. };
  144. /*
  145. * SBUS register mappings
  146. */
  147. #define VIGRA_REG_RAMDAC 1 /* either G300 or G335 */
  148. #define VIGRA_REG_CSR 2
  149. #define VIGRA_REG_VRAM 3
  150. #define VIGRA_NREG 4
  151. union vigracmap {
  152. u_char cm_map[256][4]; /* 256 R/G/B entries plus pad */
  153. u_int32_t cm_chip[256]; /* the way the chip gets loaded */
  154. };
  155. /* per-display variables */
  156. struct vigra_softc {
  157. struct sunfb sc_sunfb; /* common base part */
  158. bus_space_tag_t sc_bustag;
  159. bus_addr_t sc_paddr;
  160. volatile struct csregs *sc_regs;/* control registers */
  161. volatile union dac *sc_ramdac; /* ramdac registers */
  162. union vigracmap sc_cmap; /* current colormap */
  163. int sc_g300;
  164. void *sc_ih;
  165. int sc_nscreens;
  166. };
  167. int vigra_ioctl(void *, u_long, caddr_t, int, struct proc *);
  168. paddr_t vigra_mmap(void *, off_t, int);
  169. void vigra_setcolor(void *, u_int, u_int8_t, u_int8_t, u_int8_t);
  170. int vigra_getcmap(union vigracmap *, struct wsdisplay_cmap *, int);
  171. int vigra_putcmap(union vigracmap *, struct wsdisplay_cmap *, int);
  172. void vigra_loadcmap_immediate(struct vigra_softc *, int, int);
  173. static __inline__ void vigra_loadcmap_deferred(struct vigra_softc *,
  174. u_int, u_int);
  175. void vigra_burner(void *, u_int, u_int);
  176. int vigra_intr(void *);
  177. struct wsdisplay_accessops vigra_accessops = {
  178. .ioctl = vigra_ioctl,
  179. .mmap = vigra_mmap,
  180. .burn_screen = vigra_burner
  181. };
  182. int vigramatch(struct device *, void *, void *);
  183. void vigraattach(struct device *, struct device *, void *);
  184. struct cfattach vigra_ca = {
  185. sizeof (struct vigra_softc), vigramatch, vigraattach
  186. };
  187. struct cfdriver vigra_cd = {
  188. NULL, "vigra", DV_DULL
  189. };
  190. /*
  191. * Match a supported vigra card.
  192. */
  193. int
  194. vigramatch(struct device *parent, void *vcf, void *aux)
  195. {
  196. struct sbus_attach_args *sa = aux;
  197. if (strcmp("vs10", sa->sa_name) != 0 &&
  198. strcmp("vs11", sa->sa_name) != 0 &&
  199. strcmp("vs12", sa->sa_name) != 0)
  200. return (0);
  201. return (1);
  202. }
  203. /*
  204. * Attach and initialize a vigra display, as well as a child wsdisplay.
  205. */
  206. void
  207. vigraattach(struct device *parent, struct device *self, void *args)
  208. {
  209. struct vigra_softc *sc = (struct vigra_softc *)self;
  210. struct sbus_attach_args *sa = args;
  211. bus_space_tag_t bt;
  212. bus_space_handle_t bh;
  213. int node, isconsole = 0;
  214. char *nam;
  215. bt = sa->sa_bustag;
  216. node = sa->sa_node;
  217. nam = getpropstring(node, "model");
  218. if (*nam == '\0')
  219. nam = (char *)sa->sa_name;
  220. printf(": %s", nam);
  221. isconsole = node == fbnode;
  222. if (sa->sa_nreg < VIGRA_NREG) {
  223. printf("\n%s: expected %d registers, got %d",
  224. self->dv_xname, VIGRA_NREG, sa->sa_nreg);
  225. return;
  226. }
  227. /*
  228. * Check whether we are using an G300 or an G335 chip.
  229. * The VS10 and VS12 use the G300, while the VS11 uses a G335.
  230. */
  231. sc->sc_g300 = strncmp(nam, "VIGRA,vs11", strlen("VIGRA,vs11"));
  232. sc->sc_bustag = bt;
  233. if (sbus_bus_map(bt, sa->sa_reg[VIGRA_REG_CSR].sbr_slot,
  234. sa->sa_reg[VIGRA_REG_CSR].sbr_offset,
  235. sa->sa_reg[VIGRA_REG_CSR].sbr_size, BUS_SPACE_MAP_LINEAR, 0,
  236. &bh) != 0) {
  237. printf("\n%s: can't map control registers\n", self->dv_xname);
  238. return;
  239. }
  240. sc->sc_regs = bus_space_vaddr(bt, bh);
  241. if (sbus_bus_map(bt, sa->sa_reg[VIGRA_REG_RAMDAC].sbr_slot,
  242. sa->sa_reg[VIGRA_REG_RAMDAC].sbr_offset,
  243. sa->sa_reg[VIGRA_REG_RAMDAC].sbr_size, BUS_SPACE_MAP_LINEAR, 0,
  244. &bh) != 0) {
  245. printf("\n%s: can't map ramdac registers\n", self->dv_xname);
  246. return;
  247. }
  248. sc->sc_ramdac = bus_space_vaddr(bt, bh);
  249. /* enable video */
  250. vigra_burner(sc, 1, 0);
  251. fb_setsize(&sc->sc_sunfb, 8, 1152, 900, node, 0);
  252. if (sbus_bus_map(bt, sa->sa_reg[VIGRA_REG_VRAM].sbr_slot,
  253. sa->sa_reg[VIGRA_REG_VRAM].sbr_offset,
  254. round_page(sc->sc_sunfb.sf_fbsize), BUS_SPACE_MAP_LINEAR, 0,
  255. &bh) != 0) {
  256. printf("\n%s: can't map video memory\n", self->dv_xname);
  257. return;
  258. }
  259. sc->sc_sunfb.sf_ro.ri_bits = bus_space_vaddr(bt, bh);
  260. sc->sc_sunfb.sf_ro.ri_hw = sc;
  261. sc->sc_paddr = sbus_bus_addr(bt, sa->sa_reg[VIGRA_REG_VRAM].sbr_slot,
  262. sa->sa_reg[VIGRA_REG_VRAM].sbr_offset);
  263. printf(", %dx%d\n", sc->sc_sunfb.sf_width, sc->sc_sunfb.sf_height);
  264. if ((sc->sc_ih = bus_intr_establish(sa->sa_bustag, sa->sa_pri,
  265. IPL_TTY, 0, vigra_intr, sc, self->dv_xname)) == NULL) {
  266. printf("%s: couldn't establish interrupt, pri %d\n",
  267. self->dv_xname, INTLEV(sa->sa_pri));
  268. }
  269. fbwscons_init(&sc->sc_sunfb, 0, isconsole);
  270. fbwscons_setcolormap(&sc->sc_sunfb, vigra_setcolor);
  271. if (isconsole)
  272. fbwscons_console_init(&sc->sc_sunfb, -1);
  273. fbwscons_attach(&sc->sc_sunfb, &vigra_accessops, isconsole);
  274. }
  275. int
  276. vigra_ioctl(void *v, u_long cmd, caddr_t data, int flags, struct proc *p)
  277. {
  278. struct vigra_softc *sc = v;
  279. struct wsdisplay_cmap *cm;
  280. struct wsdisplay_fbinfo *wdf;
  281. int error;
  282. switch (cmd) {
  283. case WSDISPLAYIO_GTYPE:
  284. *(u_int *)data = WSDISPLAY_TYPE_UNKNOWN;
  285. break;
  286. case WSDISPLAYIO_GINFO:
  287. wdf = (struct wsdisplay_fbinfo *)data;
  288. wdf->height = sc->sc_sunfb.sf_height;
  289. wdf->width = sc->sc_sunfb.sf_width;
  290. wdf->depth = sc->sc_sunfb.sf_depth;
  291. wdf->cmsize = 256;
  292. break;
  293. case WSDISPLAYIO_LINEBYTES:
  294. *(u_int *)data = sc->sc_sunfb.sf_linebytes;
  295. break;
  296. case WSDISPLAYIO_GETCMAP:
  297. cm = (struct wsdisplay_cmap *)data;
  298. error = vigra_getcmap(&sc->sc_cmap, cm, sc->sc_g300);
  299. if (error)
  300. return (error);
  301. break;
  302. case WSDISPLAYIO_PUTCMAP:
  303. cm = (struct wsdisplay_cmap *)data;
  304. error = vigra_putcmap(&sc->sc_cmap, cm, sc->sc_g300);
  305. if (error)
  306. return (error);
  307. /* if we can handle interrupts, defer the update */
  308. if (sc->sc_ih != NULL)
  309. vigra_loadcmap_deferred(sc, cm->index, cm->count);
  310. else
  311. vigra_loadcmap_immediate(sc, cm->index, cm->count);
  312. break;
  313. case WSDISPLAYIO_SVIDEO:
  314. case WSDISPLAYIO_GVIDEO:
  315. break;
  316. case WSDISPLAYIO_GCURPOS:
  317. case WSDISPLAYIO_SCURPOS:
  318. case WSDISPLAYIO_GCURMAX:
  319. case WSDISPLAYIO_GCURSOR:
  320. case WSDISPLAYIO_SCURSOR:
  321. default:
  322. return (-1); /* not supported yet */
  323. }
  324. return (0);
  325. }
  326. /*
  327. * Return the address that would map the given device at the given
  328. * offset, allowing for the given protection, or return -1 for error.
  329. */
  330. paddr_t
  331. vigra_mmap(void *v, off_t offset, int prot)
  332. {
  333. struct vigra_softc *sc = v;
  334. if (offset & PGOFSET)
  335. return (-1);
  336. if (offset >= 0 && offset < sc->sc_sunfb.sf_fbsize) {
  337. return (bus_space_mmap(sc->sc_bustag, sc->sc_paddr,
  338. offset, prot, BUS_SPACE_MAP_LINEAR));
  339. }
  340. return (-1);
  341. }
  342. void
  343. vigra_setcolor(void *v, u_int index, u_int8_t r, u_int8_t g, u_int8_t b)
  344. {
  345. struct vigra_softc *sc = v;
  346. if (sc->sc_g300) {
  347. sc->sc_cmap.cm_map[index][3] = r;
  348. sc->sc_cmap.cm_map[index][2] = g;
  349. sc->sc_cmap.cm_map[index][1] = b;
  350. } else {
  351. sc->sc_cmap.cm_map[index][3] = b;
  352. sc->sc_cmap.cm_map[index][2] = g;
  353. sc->sc_cmap.cm_map[index][1] = r;
  354. }
  355. sc->sc_cmap.cm_map[index][0] = 0; /* no alpha channel */
  356. vigra_loadcmap_immediate(sc, index, 1);
  357. }
  358. int
  359. vigra_getcmap(union vigracmap *cm, struct wsdisplay_cmap *rcm, int g300)
  360. {
  361. u_int index = rcm->index, count = rcm->count, i;
  362. int error;
  363. if (index >= 256 || count > 256 - index)
  364. return (EINVAL);
  365. if (g300) {
  366. for (i = 0; i < count; i++) {
  367. if ((error = copyout(&cm->cm_map[index + i][3],
  368. &rcm->red[i], 1)) != 0)
  369. return (error);
  370. if ((error = copyout(&cm->cm_map[index + i][1],
  371. &rcm->blue[i], 1)) != 0)
  372. return (error);
  373. }
  374. } else {
  375. for (i = 0; i < count; i++) {
  376. if ((error = copyout(&cm->cm_map[index + i][1],
  377. &rcm->red[i], 1)) != 0)
  378. return (error);
  379. if ((error = copyout(&cm->cm_map[index + i][3],
  380. &rcm->blue[i], 1)) != 0)
  381. return (error);
  382. }
  383. }
  384. for (i = 0; i < count; i++) {
  385. if ((error = copyout(&cm->cm_map[index + i][2],
  386. &rcm->green[i], 1)) != 0)
  387. return (error);
  388. }
  389. return (0);
  390. }
  391. int
  392. vigra_putcmap(union vigracmap *cm, struct wsdisplay_cmap *rcm, int g300)
  393. {
  394. u_int index = rcm->index, count = rcm->count, i;
  395. int error;
  396. if (index >= 256 || count > 256 - index)
  397. return (EINVAL);
  398. if (g300) {
  399. for (i = 0; i < count; i++) {
  400. if ((error = copyin(&rcm->red[i],
  401. &cm->cm_map[index + i][3], 1)) != 0)
  402. return (error);
  403. if ((error = copyin(&rcm->blue[i],
  404. &cm->cm_map[index + i][1], 1)) != 0)
  405. return (error);
  406. }
  407. } else {
  408. for (i = 0; i < count; i++) {
  409. if ((error = copyin(&rcm->red[i],
  410. &cm->cm_map[index + i][1], 1)) != 0)
  411. return (error);
  412. if ((error = copyin(&rcm->blue[i],
  413. &cm->cm_map[index + i][3], 1)) != 0)
  414. return (error);
  415. }
  416. }
  417. for (i = 0; i < count; i++) {
  418. if ((error = copyin(&rcm->green[i],
  419. &cm->cm_map[index + i][2], 1)) != 0)
  420. return (error);
  421. cm->cm_map[index + i][0] = 0; /* no alpha channel */
  422. }
  423. return (0);
  424. }
  425. void
  426. vigra_loadcmap_immediate(struct vigra_softc *sc, int start, int ncolors)
  427. {
  428. u_int32_t *colp = &sc->sc_cmap.cm_chip[start];
  429. volatile u_int32_t *lutp;
  430. if (sc->sc_g300)
  431. lutp = &(sc->sc_ramdac->g300.cmap[start]);
  432. else
  433. lutp = &(sc->sc_ramdac->g335.cmap[start]);
  434. while (--ncolors >= 0)
  435. *lutp++ = *colp++;
  436. }
  437. static __inline__ void
  438. vigra_loadcmap_deferred(struct vigra_softc *sc, u_int start, u_int ncolors)
  439. {
  440. sc->sc_regs->imr = 1;
  441. }
  442. void
  443. vigra_burner(void *v, u_int on, u_int flags)
  444. {
  445. struct vigra_softc *sc = v;
  446. if (on) {
  447. sc->sc_regs->bcr = 0;
  448. } else {
  449. sc->sc_regs->bcr = 1;
  450. }
  451. }
  452. int
  453. vigra_intr(void *v)
  454. {
  455. struct vigra_softc *sc = v;
  456. if (sc->sc_regs->imr == 0 ||
  457. !ISSET(sc->sc_regs->g3sr, STATUS_INTR)) {
  458. /* Not expecting an interrupt, it's not for us. */
  459. return (0);
  460. }
  461. /* Acknowledge the interrupt and disable it. */
  462. sc->sc_regs->imr = 0;
  463. vigra_loadcmap_immediate(sc, 0, 256);
  464. return (1);
  465. }