cgsix.c 27 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014
  1. /* $OpenBSD: cgsix.c,v 1.59 2013/10/20 20:07:30 miod Exp $ */
  2. /*
  3. * Copyright (c) 2001 Jason L. Wright (jason@thought.net)
  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. * Effort sponsored in part by the Defense Advanced Research Projects
  28. * Agency (DARPA) and Air Force Research Laboratory, Air Force
  29. * Materiel Command, USAF, under agreement number F30602-01-2-0537.
  30. *
  31. */
  32. #include <sys/param.h>
  33. #include <sys/systm.h>
  34. #include <sys/kernel.h>
  35. #include <sys/errno.h>
  36. #include <sys/device.h>
  37. #include <sys/ioctl.h>
  38. #include <sys/malloc.h>
  39. #include <machine/bus.h>
  40. #include <machine/intr.h>
  41. #include <machine/autoconf.h>
  42. #include <machine/openfirm.h>
  43. #include <dev/sbus/sbusvar.h>
  44. #include <dev/wscons/wsconsio.h>
  45. #include <dev/wscons/wsdisplayvar.h>
  46. #include <dev/rasops/rasops.h>
  47. #include <machine/fbvar.h>
  48. #include <dev/sbus/cgsixreg.h>
  49. #include <dev/ic/bt458reg.h>
  50. int cgsix_ioctl(void *, u_long, caddr_t, int, struct proc *);
  51. paddr_t cgsix_mmap(void *, off_t, int);
  52. int cgsix_is_console(int);
  53. int cg6_bt_getcmap(union bt_cmap *, struct wsdisplay_cmap *);
  54. int cg6_bt_putcmap(union bt_cmap *, struct wsdisplay_cmap *);
  55. void cgsix_loadcmap_immediate(struct cgsix_softc *, u_int, u_int);
  56. void cgsix_loadcmap_deferred(struct cgsix_softc *, u_int, u_int);
  57. void cgsix_setcolor(void *, u_int, u_int8_t, u_int8_t, u_int8_t);
  58. void cgsix_reset(struct cgsix_softc *, u_int32_t);
  59. void cgsix_hardreset(struct cgsix_softc *);
  60. void cgsix_burner(void *, u_int, u_int);
  61. int cgsix_intr(void *);
  62. void cgsix_ras_init(struct cgsix_softc *);
  63. int cgsix_ras_copyrows(void *, int, int, int);
  64. int cgsix_ras_copycols(void *, int, int, int, int);
  65. int cgsix_ras_erasecols(void *, int, int, int, long int);
  66. int cgsix_ras_eraserows(void *, int, int, long int);
  67. int cgsix_ras_do_cursor(struct rasops_info *);
  68. int cgsix_setcursor(struct cgsix_softc *, struct wsdisplay_cursor *);
  69. int cgsix_updatecursor(struct cgsix_softc *, u_int);
  70. struct wsdisplay_accessops cgsix_accessops = {
  71. .ioctl = cgsix_ioctl,
  72. .mmap = cgsix_mmap,
  73. .burn_screen = cgsix_burner
  74. };
  75. int cgsixmatch(struct device *, void *, void *);
  76. void cgsixattach(struct device *, struct device *, void *);
  77. struct cfattach cgsix_ca = {
  78. sizeof (struct cgsix_softc), cgsixmatch, cgsixattach
  79. };
  80. struct cfdriver cgsix_cd = {
  81. NULL, "cgsix", DV_DULL
  82. };
  83. int
  84. cgsixmatch(struct device *parent, void *vcf, void *aux)
  85. {
  86. struct cfdata *cf = vcf;
  87. struct sbus_attach_args *sa = aux;
  88. return (strcmp(cf->cf_driver->cd_name, sa->sa_name) == 0);
  89. }
  90. void
  91. cgsixattach(struct device *parent, struct device *self, void *aux)
  92. {
  93. struct cgsix_softc *sc = (struct cgsix_softc *)self;
  94. struct sbus_attach_args *sa = aux;
  95. int node, console;
  96. u_int32_t fhc, rev;
  97. const char *nam;
  98. node = sa->sa_node;
  99. sc->sc_bustag = sa->sa_bustag;
  100. sc->sc_paddr = sbus_bus_addr(sa->sa_bustag, sa->sa_slot, sa->sa_offset);
  101. if (sa->sa_nreg != 1) {
  102. printf(": expected %d registers, got %d\n", 1, sa->sa_nreg);
  103. goto fail;
  104. }
  105. fb_setsize(&sc->sc_sunfb, 8, 1152, 900, node, 0);
  106. /*
  107. * Map just BT, FHC, FBC, THC, and video RAM.
  108. */
  109. if (sbus_bus_map(sa->sa_bustag, sa->sa_reg[0].sbr_slot,
  110. sa->sa_reg[0].sbr_offset + CGSIX_BT_OFFSET,
  111. CGSIX_BT_SIZE, 0, 0, &sc->sc_bt_regs) != 0) {
  112. printf(": cannot map bt registers\n");
  113. goto fail_bt;
  114. }
  115. if (sbus_bus_map(sa->sa_bustag, sa->sa_reg[0].sbr_slot,
  116. sa->sa_reg[0].sbr_offset + CGSIX_FHC_OFFSET,
  117. CGSIX_FHC_SIZE, 0, 0, &sc->sc_fhc_regs) != 0) {
  118. printf(": cannot map fhc registers\n");
  119. goto fail_fhc;
  120. }
  121. if (sbus_bus_map(sa->sa_bustag, sa->sa_reg[0].sbr_slot,
  122. sa->sa_reg[0].sbr_offset + CGSIX_THC_OFFSET,
  123. CGSIX_THC_SIZE, 0, 0, &sc->sc_thc_regs) != 0) {
  124. printf(": cannot map thc registers\n");
  125. goto fail_thc;
  126. }
  127. if (sbus_bus_map(sa->sa_bustag, sa->sa_reg[0].sbr_slot,
  128. sa->sa_reg[0].sbr_offset + CGSIX_VID_OFFSET,
  129. sc->sc_sunfb.sf_fbsize, BUS_SPACE_MAP_LINEAR,
  130. 0, &sc->sc_vid_regs) != 0) {
  131. printf(": cannot map vid registers\n");
  132. goto fail_vid;
  133. }
  134. if (sbus_bus_map(sa->sa_bustag, sa->sa_reg[0].sbr_slot,
  135. sa->sa_reg[0].sbr_offset + CGSIX_TEC_OFFSET,
  136. CGSIX_TEC_SIZE, 0, 0, &sc->sc_tec_regs) != 0) {
  137. printf(": cannot map tec registers\n");
  138. goto fail_tec;
  139. }
  140. if (sbus_bus_map(sa->sa_bustag, sa->sa_reg[0].sbr_slot,
  141. sa->sa_reg[0].sbr_offset + CGSIX_FBC_OFFSET,
  142. CGSIX_FBC_SIZE, 0, 0, &sc->sc_fbc_regs) != 0) {
  143. printf(": cannot map fbc registers\n");
  144. goto fail_fbc;
  145. }
  146. if ((sc->sc_ih = bus_intr_establish(sa->sa_bustag, sa->sa_pri,
  147. IPL_TTY, 0, cgsix_intr, sc, self->dv_xname)) == NULL) {
  148. printf(": couldn't establish interrupt, pri %d\n%s",
  149. INTLEV(sa->sa_pri), self->dv_xname);
  150. }
  151. /* if prom didn't initialize us, do it the hard way */
  152. if (OF_getproplen(node, "width") != sizeof(u_int32_t))
  153. cgsix_hardreset(sc);
  154. nam = getpropstring(node, "model");
  155. if (*nam == '\0')
  156. nam = sa->sa_name;
  157. printf(": %s", nam);
  158. console = cgsix_is_console(node);
  159. fhc = FHC_READ(sc);
  160. rev = (fhc & FHC_REV_MASK) >> FHC_REV_SHIFT;
  161. cgsix_reset(sc, rev);
  162. cgsix_burner(sc, 1, 0);
  163. sc->sc_sunfb.sf_ro.ri_bits = (void *)bus_space_vaddr(sc->sc_bustag,
  164. sc->sc_vid_regs);
  165. sc->sc_sunfb.sf_ro.ri_hw = sc;
  166. printf(", %dx%d, rev %d\n", sc->sc_sunfb.sf_width,
  167. sc->sc_sunfb.sf_height, rev);
  168. fbwscons_init(&sc->sc_sunfb, 0, console);
  169. fbwscons_setcolormap(&sc->sc_sunfb, cgsix_setcolor);
  170. /*
  171. * Old rev. cg6 cards do not like the current acceleration code.
  172. *
  173. * Some hints from Sun point out at timing and cache problems, which
  174. * will be investigated later.
  175. */
  176. if (rev < 5)
  177. sc->sc_sunfb.sf_dev.dv_cfdata->cf_flags |= CG6_CFFLAG_NOACCEL;
  178. if ((sc->sc_sunfb.sf_dev.dv_cfdata->cf_flags & CG6_CFFLAG_NOACCEL)
  179. == 0) {
  180. sc->sc_sunfb.sf_ro.ri_ops.copyrows = cgsix_ras_copyrows;
  181. sc->sc_sunfb.sf_ro.ri_ops.copycols = cgsix_ras_copycols;
  182. sc->sc_sunfb.sf_ro.ri_ops.eraserows = cgsix_ras_eraserows;
  183. sc->sc_sunfb.sf_ro.ri_ops.erasecols = cgsix_ras_erasecols;
  184. sc->sc_sunfb.sf_ro.ri_do_cursor = cgsix_ras_do_cursor;
  185. cgsix_ras_init(sc);
  186. }
  187. if (console)
  188. fbwscons_console_init(&sc->sc_sunfb, -1);
  189. fbwscons_attach(&sc->sc_sunfb, &cgsix_accessops, console);
  190. return;
  191. fail_fbc:
  192. bus_space_unmap(sa->sa_bustag, sc->sc_tec_regs, CGSIX_TEC_SIZE);
  193. fail_tec:
  194. bus_space_unmap(sa->sa_bustag, sc->sc_vid_regs, sc->sc_sunfb.sf_fbsize);
  195. fail_vid:
  196. bus_space_unmap(sa->sa_bustag, sc->sc_thc_regs, CGSIX_THC_SIZE);
  197. fail_thc:
  198. bus_space_unmap(sa->sa_bustag, sc->sc_fhc_regs, CGSIX_FHC_SIZE);
  199. fail_fhc:
  200. bus_space_unmap(sa->sa_bustag, sc->sc_bt_regs, CGSIX_BT_SIZE);
  201. fail_bt:
  202. fail:
  203. return;
  204. }
  205. int
  206. cgsix_ioctl(void *v, u_long cmd, caddr_t data, int flags, struct proc *p)
  207. {
  208. struct cgsix_softc *sc = v;
  209. struct wsdisplay_cmap *cm;
  210. struct wsdisplay_fbinfo *wdf;
  211. struct wsdisplay_cursor *curs;
  212. struct wsdisplay_curpos *pos;
  213. u_char r[2], g[2], b[2];
  214. int error, s;
  215. u_int mode;
  216. switch (cmd) {
  217. case WSDISPLAYIO_GTYPE:
  218. *(u_int *)data = WSDISPLAY_TYPE_SUNCG6;
  219. break;
  220. case WSDISPLAYIO_SMODE:
  221. mode = *(u_int *)data;
  222. if ((sc->sc_sunfb.sf_dev.dv_cfdata->cf_flags &
  223. CG6_CFFLAG_NOACCEL) == 0) {
  224. if (sc->sc_mode != WSDISPLAYIO_MODE_EMUL &&
  225. mode == WSDISPLAYIO_MODE_EMUL)
  226. cgsix_ras_init(sc);
  227. }
  228. sc->sc_mode = mode;
  229. break;
  230. case WSDISPLAYIO_GINFO:
  231. wdf = (void *)data;
  232. wdf->height = sc->sc_sunfb.sf_height;
  233. wdf->width = sc->sc_sunfb.sf_width;
  234. wdf->depth = sc->sc_sunfb.sf_depth;
  235. wdf->cmsize = 256;
  236. break;
  237. case WSDISPLAYIO_LINEBYTES:
  238. *(u_int *)data = sc->sc_sunfb.sf_linebytes;
  239. break;
  240. case WSDISPLAYIO_GETCMAP:
  241. cm = (struct wsdisplay_cmap *)data;
  242. error = cg6_bt_getcmap(&sc->sc_cmap, cm);
  243. if (error)
  244. return (error);
  245. break;
  246. case WSDISPLAYIO_PUTCMAP:
  247. cm = (struct wsdisplay_cmap *)data;
  248. error = cg6_bt_putcmap(&sc->sc_cmap, cm);
  249. if (error)
  250. return (error);
  251. /* if we can handle interrupts, defer the update */
  252. if (sc->sc_ih != NULL)
  253. cgsix_loadcmap_deferred(sc, cm->index, cm->count);
  254. else
  255. cgsix_loadcmap_immediate(sc, cm->index, cm->count);
  256. break;
  257. case WSDISPLAYIO_SCURSOR:
  258. curs = (struct wsdisplay_cursor *)data;
  259. return (cgsix_setcursor(sc, curs));
  260. case WSDISPLAYIO_GCURSOR:
  261. curs = (struct wsdisplay_cursor *)data;
  262. if (curs->which & WSDISPLAY_CURSOR_DOCUR)
  263. curs->enable = sc->sc_curs_enabled;
  264. if (curs->which & WSDISPLAY_CURSOR_DOPOS) {
  265. curs->pos.x = sc->sc_curs_pos.x;
  266. curs->pos.y = sc->sc_curs_pos.y;
  267. }
  268. if (curs->which & WSDISPLAY_CURSOR_DOHOT) {
  269. curs->hot.x = sc->sc_curs_hot.x;
  270. curs->hot.y = sc->sc_curs_hot.y;
  271. }
  272. if (curs->which & WSDISPLAY_CURSOR_DOCMAP) {
  273. curs->cmap.index = 0;
  274. curs->cmap.count = 2;
  275. r[0] = sc->sc_curs_fg >> 16;
  276. g[0] = sc->sc_curs_fg >> 8;
  277. b[0] = sc->sc_curs_fg >> 0;
  278. r[1] = sc->sc_curs_bg >> 16;
  279. g[1] = sc->sc_curs_bg >> 8;
  280. b[1] = sc->sc_curs_bg >> 0;
  281. error = copyout(r, curs->cmap.red, sizeof(r));
  282. if (error)
  283. return (error);
  284. error = copyout(g, curs->cmap.green, sizeof(g));
  285. if (error)
  286. return (error);
  287. error = copyout(b, curs->cmap.blue, sizeof(b));
  288. if (error)
  289. return (error);
  290. }
  291. if (curs->which & WSDISPLAY_CURSOR_DOSHAPE) {
  292. size_t l;
  293. curs->size.x = sc->sc_curs_size.x;
  294. curs->size.y = sc->sc_curs_size.y;
  295. l = (sc->sc_curs_size.x * sc->sc_curs_size.y) / NBBY;
  296. error = copyout(sc->sc_curs_image, curs->image, l);
  297. if (error)
  298. return (error);
  299. error = copyout(sc->sc_curs_mask, curs->mask, l);
  300. if (error)
  301. return (error);
  302. }
  303. break;
  304. case WSDISPLAYIO_GCURPOS:
  305. pos = (struct wsdisplay_curpos *)data;
  306. pos->x = sc->sc_curs_pos.x;
  307. pos->y = sc->sc_curs_pos.y;
  308. break;
  309. case WSDISPLAYIO_SCURPOS:
  310. pos = (struct wsdisplay_curpos *)data;
  311. s = spltty();
  312. sc->sc_curs_pos.x = pos->x;
  313. sc->sc_curs_pos.y = pos->y;
  314. cgsix_updatecursor(sc, WSDISPLAY_CURSOR_DOPOS);
  315. splx(s);
  316. break;
  317. case WSDISPLAYIO_GCURMAX:
  318. pos = (struct wsdisplay_curpos *)data;
  319. pos->x = pos->y = 32;
  320. break;
  321. case WSDISPLAYIO_SVIDEO:
  322. case WSDISPLAYIO_GVIDEO:
  323. break;
  324. default:
  325. return -1; /* not supported */
  326. }
  327. return (0);
  328. }
  329. int
  330. cgsix_setcursor(struct cgsix_softc *sc, struct wsdisplay_cursor *curs)
  331. {
  332. u_int8_t r[2], g[2], b[2], image[128], mask[128];
  333. int s, error;
  334. size_t imcount;
  335. /*
  336. * Do stuff that can generate errors first, then we'll blast it
  337. * all at once.
  338. */
  339. if (curs->which & WSDISPLAY_CURSOR_DOCMAP) {
  340. if (curs->cmap.count < 2)
  341. return (EINVAL);
  342. error = copyin(curs->cmap.red, r, sizeof(r));
  343. if (error)
  344. return (error);
  345. error = copyin(curs->cmap.green, g, sizeof(g));
  346. if (error)
  347. return (error);
  348. error = copyin(curs->cmap.blue, b, sizeof(b));
  349. if (error)
  350. return (error);
  351. }
  352. if (curs->which & WSDISPLAY_CURSOR_DOSHAPE) {
  353. if (curs->size.x > CG6_MAX_CURSOR ||
  354. curs->size.y > CG6_MAX_CURSOR)
  355. return (EINVAL);
  356. imcount = (curs->size.x * curs->size.y) / NBBY;
  357. error = copyin(curs->image, image, imcount);
  358. if (error)
  359. return (error);
  360. error = copyin(curs->mask, mask, imcount);
  361. if (error)
  362. return (error);
  363. }
  364. /*
  365. * Ok, everything is in kernel space and sane, update state.
  366. */
  367. s = spltty();
  368. if (curs->which & WSDISPLAY_CURSOR_DOCUR)
  369. sc->sc_curs_enabled = curs->enable;
  370. if (curs->which & WSDISPLAY_CURSOR_DOPOS) {
  371. sc->sc_curs_pos.x = curs->pos.x;
  372. sc->sc_curs_pos.y = curs->pos.y;
  373. }
  374. if (curs->which & WSDISPLAY_CURSOR_DOHOT) {
  375. sc->sc_curs_hot.x = curs->hot.x;
  376. sc->sc_curs_hot.y = curs->hot.y;
  377. }
  378. if (curs->which & WSDISPLAY_CURSOR_DOCMAP) {
  379. sc->sc_curs_fg = ((r[0] << 16) | (g[0] << 8) | (b[0] << 0));
  380. sc->sc_curs_bg = ((r[1] << 16) | (g[1] << 8) | (b[1] << 0));
  381. }
  382. if (curs->which & WSDISPLAY_CURSOR_DOSHAPE) {
  383. sc->sc_curs_size.x = curs->size.x;
  384. sc->sc_curs_size.y = curs->size.y;
  385. bcopy(image, sc->sc_curs_image, imcount);
  386. bcopy(mask, sc->sc_curs_mask, imcount);
  387. }
  388. cgsix_updatecursor(sc, curs->which);
  389. splx(s);
  390. return (0);
  391. }
  392. int
  393. cgsix_updatecursor(struct cgsix_softc *sc, u_int which)
  394. {
  395. if (which & WSDISPLAY_CURSOR_DOCMAP) {
  396. BT_WRITE(sc, BT_ADDR, BT_OV1 << 24);
  397. BT_WRITE(sc, BT_OMAP,
  398. ((sc->sc_curs_fg & 0x00ff0000) >> 16) << 24);
  399. BT_WRITE(sc, BT_OMAP,
  400. ((sc->sc_curs_fg & 0x0000ff00) >> 8) << 24);
  401. BT_WRITE(sc, BT_OMAP,
  402. ((sc->sc_curs_fg & 0x000000ff) >> 0) << 24);
  403. BT_WRITE(sc, BT_ADDR, BT_OV3 << 24);
  404. BT_WRITE(sc, BT_OMAP,
  405. ((sc->sc_curs_bg & 0x00ff0000) >> 16) << 24);
  406. BT_WRITE(sc, BT_OMAP,
  407. ((sc->sc_curs_bg & 0x0000ff00) >> 8) << 24);
  408. BT_WRITE(sc, BT_OMAP,
  409. ((sc->sc_curs_bg & 0x000000ff) >> 0) << 24);
  410. }
  411. if (which & (WSDISPLAY_CURSOR_DOPOS | WSDISPLAY_CURSOR_DOHOT)) {
  412. u_int32_t x, y;
  413. x = sc->sc_curs_pos.x + CG6_MAX_CURSOR - sc->sc_curs_hot.x;
  414. y = sc->sc_curs_pos.y + CG6_MAX_CURSOR - sc->sc_curs_hot.y;
  415. THC_WRITE(sc, CG6_THC_CURSXY,
  416. ((x & 0xffff) << 16) | (y & 0xffff));
  417. }
  418. if (which & WSDISPLAY_CURSOR_DOCUR) {
  419. u_int32_t c;
  420. /* Enable or disable the cursor overlay planes */
  421. if (sc->sc_curs_enabled) {
  422. BT_WRITE(sc, BT_ADDR, BT_CR << 24);
  423. c = BT_READ(sc, BT_CTRL);
  424. c |= (BTCR_DISPENA_OV0 | BTCR_DISPENA_OV1) << 24;
  425. BT_WRITE(sc, BT_CTRL, c);
  426. } else {
  427. BT_WRITE(sc, BT_ADDR, BT_CR << 24);
  428. c = BT_READ(sc, BT_CTRL);
  429. c &= ~((BTCR_DISPENA_OV0 | BTCR_DISPENA_OV1) << 24);
  430. BT_WRITE(sc, BT_CTRL, c);
  431. THC_WRITE(sc, CG6_THC_CURSXY, THC_CURSOFF);
  432. }
  433. }
  434. return (0);
  435. }
  436. struct mmo {
  437. off_t mo_uaddr;
  438. bus_size_t mo_size;
  439. bus_size_t mo_physoff;
  440. };
  441. paddr_t
  442. cgsix_mmap(void *v, off_t off, int prot)
  443. {
  444. struct cgsix_softc *sc = v;
  445. struct mmo *mo;
  446. bus_addr_t u;
  447. bus_size_t sz;
  448. static struct mmo mmo[] = {
  449. { CG6_USER_RAM, 0, CGSIX_VID_OFFSET },
  450. /* do not actually know how big most of these are! */
  451. { CG6_USER_FBC, 1, CGSIX_FBC_OFFSET },
  452. { CG6_USER_TEC, 1, CGSIX_TEC_OFFSET },
  453. { CG6_USER_BTREGS, 8192 /* XXX */, CGSIX_BT_OFFSET },
  454. { CG6_USER_FHC, 1, CGSIX_FHC_OFFSET },
  455. { CG6_USER_THC, CGSIX_THC_SIZE, CGSIX_THC_OFFSET },
  456. { CG6_USER_ROM, 65536, CGSIX_ROM_OFFSET },
  457. { CG6_USER_DHC, 1, CGSIX_DHC_OFFSET },
  458. };
  459. #define NMMO (sizeof mmo / sizeof *mmo)
  460. if (off & PGOFSET || off < 0)
  461. return (-1);
  462. switch (sc->sc_mode) {
  463. case WSDISPLAYIO_MODE_MAPPED:
  464. for (mo = mmo; mo < &mmo[NMMO]; mo++) {
  465. if (off < mo->mo_uaddr)
  466. continue;
  467. u = off - mo->mo_uaddr;
  468. sz = mo->mo_size ? mo->mo_size : sc->sc_sunfb.sf_fbsize;
  469. if (u < sz) {
  470. return (bus_space_mmap(sc->sc_bustag,
  471. sc->sc_paddr, u + mo->mo_physoff,
  472. prot, BUS_SPACE_MAP_LINEAR));
  473. }
  474. }
  475. break;
  476. case WSDISPLAYIO_MODE_DUMBFB:
  477. /* Allow mapping as a dumb framebuffer from offset 0 */
  478. if (off >= 0 && off < sc->sc_sunfb.sf_fbsize)
  479. return (bus_space_mmap(sc->sc_bustag, sc->sc_paddr,
  480. off + CGSIX_VID_OFFSET, prot,
  481. BUS_SPACE_MAP_LINEAR));
  482. break;
  483. }
  484. return (-1);
  485. }
  486. int
  487. cgsix_is_console(int node)
  488. {
  489. extern int fbnode;
  490. return (fbnode == node);
  491. }
  492. int
  493. cg6_bt_getcmap(union bt_cmap *bcm, struct wsdisplay_cmap *rcm)
  494. {
  495. u_int index = rcm->index, count = rcm->count, i;
  496. int error;
  497. if (index >= 256 || count > 256 - index)
  498. return (EINVAL);
  499. for (i = 0; i < count; i++) {
  500. if ((error = copyout(&bcm->cm_map[index + i][0],
  501. &rcm->red[i], 1)) != 0)
  502. return (error);
  503. if ((error = copyout(&bcm->cm_map[index + i][1],
  504. &rcm->green[i], 1)) != 0)
  505. return (error);
  506. if ((error = copyout(&bcm->cm_map[index + i][2],
  507. &rcm->blue[i], 1)) != 0)
  508. return (error);
  509. }
  510. return (0);
  511. }
  512. int
  513. cg6_bt_putcmap(union bt_cmap *bcm, struct wsdisplay_cmap *rcm)
  514. {
  515. u_int index = rcm->index, count = rcm->count, i;
  516. int error;
  517. if (index >= 256 || count > 256 - index)
  518. return (EINVAL);
  519. for (i = 0; i < count; i++) {
  520. if ((error = copyin(&rcm->red[i],
  521. &bcm->cm_map[index + i][0], 1)) != 0)
  522. return (error);
  523. if ((error = copyin(&rcm->green[i],
  524. &bcm->cm_map[index + i][1], 1)) != 0)
  525. return (error);
  526. if ((error = copyin(&rcm->blue[i],
  527. &bcm->cm_map[index + i][2], 1)) != 0)
  528. return (error);
  529. }
  530. return (0);
  531. }
  532. void
  533. cgsix_loadcmap_deferred(struct cgsix_softc *sc, u_int start, u_int ncolors)
  534. {
  535. u_int32_t thcm;
  536. thcm = THC_READ(sc, CG6_THC_MISC);
  537. thcm &= ~THC_MISC_RESET;
  538. thcm |= THC_MISC_INTEN;
  539. THC_WRITE(sc, CG6_THC_MISC, thcm);
  540. }
  541. void
  542. cgsix_loadcmap_immediate(struct cgsix_softc *sc, u_int start, u_int ncolors)
  543. {
  544. u_int cstart;
  545. u_int32_t v;
  546. int count;
  547. cstart = BT_D4M3(start);
  548. count = BT_D4M3(start + ncolors - 1) - BT_D4M3(start) + 3;
  549. BT_WRITE(sc, BT_ADDR, BT_D4M4(start) << 24);
  550. while (--count >= 0) {
  551. v = sc->sc_cmap.cm_chip[cstart];
  552. BT_WRITE(sc, BT_CMAP, v << 0);
  553. BT_WRITE(sc, BT_CMAP, v << 8);
  554. BT_WRITE(sc, BT_CMAP, v << 16);
  555. BT_WRITE(sc, BT_CMAP, v << 24);
  556. cstart++;
  557. }
  558. }
  559. void
  560. cgsix_setcolor(void *v, u_int index, u_int8_t r, u_int8_t g, u_int8_t b)
  561. {
  562. struct cgsix_softc *sc = v;
  563. union bt_cmap *bcm = &sc->sc_cmap;
  564. bcm->cm_map[index][0] = r;
  565. bcm->cm_map[index][1] = g;
  566. bcm->cm_map[index][2] = b;
  567. cgsix_loadcmap_immediate(sc, index, 1);
  568. }
  569. void
  570. cgsix_reset(struct cgsix_softc *sc, u_int32_t fhcrev)
  571. {
  572. u_int32_t fhc;
  573. /* hide the cursor, just in case */
  574. THC_WRITE(sc, CG6_THC_CURSXY, THC_CURSOFF);
  575. TEC_WRITE(sc, CG6_TEC_MV, 0);
  576. TEC_WRITE(sc, CG6_TEC_CLIP, 0);
  577. TEC_WRITE(sc, CG6_TEC_VDC, 0);
  578. /* take core of hardware bugs in old revisions */
  579. if (fhcrev < 5) {
  580. /*
  581. * Keep current resolution; set cpu to 68020, set test
  582. * window (size 1Kx1K), and for rev 1, disable dest cache.
  583. */
  584. fhc = FHC_READ(sc);
  585. fhc &= FHC_RES_MASK;
  586. fhc |= FHC_CPU_68020 | FHC_TEST |
  587. (11 << FHC_TESTX_SHIFT) | (11 << FHC_TESTY_SHIFT);
  588. if (fhcrev < 2)
  589. fhc |= FHC_DST_DISABLE;
  590. FHC_WRITE(sc, fhc);
  591. }
  592. /* enable cursor overlays in brooktree DAC */
  593. BT_WRITE(sc, BT_ADDR, BT_CR << 24);
  594. BT_WRITE(sc, BT_CTRL, BT_READ(sc, BT_CTRL) |
  595. ((BTCR_DISPENA_OV1 | BTCR_DISPENA_OV0) << 24));
  596. }
  597. void
  598. cgsix_hardreset(struct cgsix_softc *sc)
  599. {
  600. u_int32_t fhc, rev;
  601. /* enable all of the bit planes */
  602. BT_WRITE(sc, BT_ADDR, BT_RMR << 24);
  603. BT_BARRIER(sc, BT_ADDR, BUS_SPACE_BARRIER_WRITE);
  604. BT_WRITE(sc, BT_CTRL, 0xff << 24);
  605. BT_BARRIER(sc, BT_CTRL, BUS_SPACE_BARRIER_WRITE);
  606. /* no bit planes should blink */
  607. BT_WRITE(sc, BT_ADDR, BT_BMR << 24);
  608. BT_BARRIER(sc, BT_ADDR, BUS_SPACE_BARRIER_WRITE);
  609. BT_WRITE(sc, BT_CTRL, 0x00 << 24);
  610. BT_BARRIER(sc, BT_CTRL, BUS_SPACE_BARRIER_WRITE);
  611. /*
  612. * enable the RAMDAC, disable blink, disable overlay 0 and 1,
  613. * use 4:1 multiplexor.
  614. */
  615. BT_WRITE(sc, BT_ADDR, BT_CR << 24);
  616. BT_BARRIER(sc, BT_ADDR, BUS_SPACE_BARRIER_WRITE);
  617. BT_WRITE(sc, BT_CTRL,
  618. (BTCR_MPLX_4 | BTCR_RAMENA | BTCR_BLINK_6464) << 24);
  619. BT_BARRIER(sc, BT_CTRL, BUS_SPACE_BARRIER_WRITE);
  620. /* disable the D/A read pins */
  621. BT_WRITE(sc, BT_ADDR, BT_CTR << 24);
  622. BT_BARRIER(sc, BT_ADDR, BUS_SPACE_BARRIER_WRITE);
  623. BT_WRITE(sc, BT_CTRL, 0x00 << 24);
  624. BT_BARRIER(sc, BT_CTRL, BUS_SPACE_BARRIER_WRITE);
  625. /* configure thc */
  626. THC_WRITE(sc, CG6_THC_MISC, THC_MISC_RESET | THC_MISC_INTR |
  627. THC_MISC_CYCLS);
  628. THC_WRITE(sc, CG6_THC_MISC, THC_MISC_INTR | THC_MISC_CYCLS);
  629. THC_WRITE(sc, CG6_THC_HSYNC1, 0x10009);
  630. THC_WRITE(sc, CG6_THC_HSYNC2, 0x570000);
  631. THC_WRITE(sc, CG6_THC_HSYNC3, 0x15005d);
  632. THC_WRITE(sc, CG6_THC_VSYNC1, 0x10005);
  633. THC_WRITE(sc, CG6_THC_VSYNC2, 0x2403a8);
  634. THC_WRITE(sc, CG6_THC_REFRESH, 0x16b);
  635. THC_WRITE(sc, CG6_THC_MISC, THC_MISC_RESET | THC_MISC_INTR |
  636. THC_MISC_CYCLS);
  637. THC_WRITE(sc, CG6_THC_MISC, THC_MISC_INTR | THC_MISC_CYCLS);
  638. /* configure fhc (1152x900) */
  639. fhc = FHC_READ(sc);
  640. rev = (fhc & FHC_REV_MASK) >> FHC_REV_SHIFT;
  641. fhc = FHC_RES_1152 | FHC_CPU_68020 | FHC_TEST;
  642. if (rev < 1)
  643. fhc |= FHC_FROP_DISABLE;
  644. if (rev < 2)
  645. fhc |= FHC_DST_DISABLE;
  646. FHC_WRITE(sc, fhc);
  647. }
  648. void
  649. cgsix_burner(void *vsc, u_int on, u_int flags)
  650. {
  651. struct cgsix_softc *sc = vsc;
  652. int s;
  653. u_int32_t thcm;
  654. s = splhigh();
  655. thcm = THC_READ(sc, CG6_THC_MISC);
  656. if (on)
  657. thcm |= THC_MISC_VIDEN | THC_MISC_SYNCEN;
  658. else {
  659. thcm &= ~THC_MISC_VIDEN;
  660. if (flags & WSDISPLAY_BURN_VBLANK)
  661. thcm &= ~THC_MISC_SYNCEN;
  662. }
  663. THC_WRITE(sc, CG6_THC_MISC, thcm);
  664. splx(s);
  665. }
  666. int
  667. cgsix_intr(void *vsc)
  668. {
  669. struct cgsix_softc *sc = vsc;
  670. u_int32_t thcm;
  671. thcm = THC_READ(sc, CG6_THC_MISC);
  672. if ((thcm & (THC_MISC_INTEN | THC_MISC_INTR)) !=
  673. (THC_MISC_INTEN | THC_MISC_INTR)) {
  674. /* Not expecting an interrupt, it's not for us. */
  675. return (0);
  676. }
  677. /* Acknowledge the interrupt and disable it. */
  678. thcm &= ~(THC_MISC_RESET | THC_MISC_INTEN);
  679. thcm |= THC_MISC_INTR;
  680. THC_WRITE(sc, CG6_THC_MISC, thcm);
  681. cgsix_loadcmap_immediate(sc, 0, 256);
  682. return (1);
  683. }
  684. void
  685. cgsix_ras_init(struct cgsix_softc *sc)
  686. {
  687. u_int32_t m;
  688. CG6_DRAIN(sc);
  689. m = FBC_READ(sc, CG6_FBC_MODE);
  690. m &= ~FBC_MODE_MASK;
  691. m |= FBC_MODE_VAL;
  692. FBC_WRITE(sc, CG6_FBC_MODE, m);
  693. }
  694. int
  695. cgsix_ras_copyrows(void *cookie, int src, int dst, int n)
  696. {
  697. struct rasops_info *ri = cookie;
  698. struct cgsix_softc *sc = ri->ri_hw;
  699. if (dst == src)
  700. return 0;
  701. if (src < 0) {
  702. n += src;
  703. src = 0;
  704. }
  705. if (src + n > ri->ri_rows)
  706. n = ri->ri_rows - src;
  707. if (dst < 0) {
  708. n += dst;
  709. dst = 0;
  710. }
  711. if (dst + n > ri->ri_rows)
  712. n = ri->ri_rows - dst;
  713. if (n <= 0)
  714. return 0;
  715. n *= ri->ri_font->fontheight;
  716. src *= ri->ri_font->fontheight;
  717. dst *= ri->ri_font->fontheight;
  718. FBC_WRITE(sc, CG6_FBC_CLIP, 0);
  719. FBC_WRITE(sc, CG6_FBC_S, 0);
  720. FBC_WRITE(sc, CG6_FBC_OFFX, 0);
  721. FBC_WRITE(sc, CG6_FBC_OFFY, 0);
  722. FBC_WRITE(sc, CG6_FBC_CLIPMINX, 0);
  723. FBC_WRITE(sc, CG6_FBC_CLIPMINY, 0);
  724. FBC_WRITE(sc, CG6_FBC_CLIPMAXX, ri->ri_width - 1);
  725. FBC_WRITE(sc, CG6_FBC_CLIPMAXY, ri->ri_height - 1);
  726. FBC_WRITE(sc, CG6_FBC_ALU, FBC_ALU_COPY);
  727. FBC_WRITE(sc, CG6_FBC_X0, ri->ri_xorigin);
  728. FBC_WRITE(sc, CG6_FBC_Y0, ri->ri_yorigin + src);
  729. FBC_WRITE(sc, CG6_FBC_X1, ri->ri_xorigin + ri->ri_emuwidth - 1);
  730. FBC_WRITE(sc, CG6_FBC_Y1, ri->ri_yorigin + src + n - 1);
  731. FBC_WRITE(sc, CG6_FBC_X2, ri->ri_xorigin);
  732. FBC_WRITE(sc, CG6_FBC_Y2, ri->ri_yorigin + dst);
  733. FBC_WRITE(sc, CG6_FBC_X3, ri->ri_xorigin + ri->ri_emuwidth - 1);
  734. FBC_WRITE(sc, CG6_FBC_Y3, ri->ri_yorigin + dst + n - 1);
  735. CG6_BLIT_WAIT(sc);
  736. CG6_DRAIN(sc);
  737. return 0;
  738. }
  739. int
  740. cgsix_ras_copycols(void *cookie, int row, int src, int dst, int n)
  741. {
  742. struct rasops_info *ri = cookie;
  743. struct cgsix_softc *sc = ri->ri_hw;
  744. if (dst == src)
  745. return 0;
  746. if ((row < 0) || (row >= ri->ri_rows))
  747. return 0;
  748. if (src < 0) {
  749. n += src;
  750. src = 0;
  751. }
  752. if (src + n > ri->ri_cols)
  753. n = ri->ri_cols - src;
  754. if (dst < 0) {
  755. n += dst;
  756. dst = 0;
  757. }
  758. if (dst + n > ri->ri_cols)
  759. n = ri->ri_cols - dst;
  760. if (n <= 0)
  761. return 0;
  762. n *= ri->ri_font->fontwidth;
  763. src *= ri->ri_font->fontwidth;
  764. dst *= ri->ri_font->fontwidth;
  765. row *= ri->ri_font->fontheight;
  766. FBC_WRITE(sc, CG6_FBC_CLIP, 0);
  767. FBC_WRITE(sc, CG6_FBC_S, 0);
  768. FBC_WRITE(sc, CG6_FBC_OFFX, 0);
  769. FBC_WRITE(sc, CG6_FBC_OFFY, 0);
  770. FBC_WRITE(sc, CG6_FBC_CLIPMINX, 0);
  771. FBC_WRITE(sc, CG6_FBC_CLIPMINY, 0);
  772. FBC_WRITE(sc, CG6_FBC_CLIPMAXX, ri->ri_width - 1);
  773. FBC_WRITE(sc, CG6_FBC_CLIPMAXY, ri->ri_height - 1);
  774. FBC_WRITE(sc, CG6_FBC_ALU, FBC_ALU_COPY);
  775. FBC_WRITE(sc, CG6_FBC_X0, ri->ri_xorigin + src);
  776. FBC_WRITE(sc, CG6_FBC_Y0, ri->ri_yorigin + row);
  777. FBC_WRITE(sc, CG6_FBC_X1, ri->ri_xorigin + src + n - 1);
  778. FBC_WRITE(sc, CG6_FBC_Y1,
  779. ri->ri_yorigin + row + ri->ri_font->fontheight - 1);
  780. FBC_WRITE(sc, CG6_FBC_X2, ri->ri_xorigin + dst);
  781. FBC_WRITE(sc, CG6_FBC_Y2, ri->ri_yorigin + row);
  782. FBC_WRITE(sc, CG6_FBC_X3, ri->ri_xorigin + dst + n - 1);
  783. FBC_WRITE(sc, CG6_FBC_Y3,
  784. ri->ri_yorigin + row + ri->ri_font->fontheight - 1);
  785. CG6_BLIT_WAIT(sc);
  786. CG6_DRAIN(sc);
  787. return 0;
  788. }
  789. int
  790. cgsix_ras_erasecols(void *cookie, int row, int col, int n, long int attr)
  791. {
  792. struct rasops_info *ri = cookie;
  793. struct cgsix_softc *sc = ri->ri_hw;
  794. int fg, bg;
  795. if ((row < 0) || (row >= ri->ri_rows))
  796. return 0;
  797. if (col < 0) {
  798. n += col;
  799. col = 0;
  800. }
  801. if (col + n > ri->ri_cols)
  802. n = ri->ri_cols - col;
  803. if (n <= 0)
  804. return 0;
  805. n *= ri->ri_font->fontwidth;
  806. col *= ri->ri_font->fontwidth;
  807. row *= ri->ri_font->fontheight;
  808. ri->ri_ops.unpack_attr(cookie, attr, &fg, &bg, NULL);
  809. FBC_WRITE(sc, CG6_FBC_CLIP, 0);
  810. FBC_WRITE(sc, CG6_FBC_S, 0);
  811. FBC_WRITE(sc, CG6_FBC_OFFX, 0);
  812. FBC_WRITE(sc, CG6_FBC_OFFY, 0);
  813. FBC_WRITE(sc, CG6_FBC_CLIPMINX, 0);
  814. FBC_WRITE(sc, CG6_FBC_CLIPMINY, 0);
  815. FBC_WRITE(sc, CG6_FBC_CLIPMAXX, ri->ri_width - 1);
  816. FBC_WRITE(sc, CG6_FBC_CLIPMAXY, ri->ri_height - 1);
  817. FBC_WRITE(sc, CG6_FBC_ALU, FBC_ALU_FILL);
  818. FBC_WRITE(sc, CG6_FBC_FG, ri->ri_devcmap[bg]);
  819. FBC_WRITE(sc, CG6_FBC_ARECTY, ri->ri_yorigin + row);
  820. FBC_WRITE(sc, CG6_FBC_ARECTX, ri->ri_xorigin + col);
  821. FBC_WRITE(sc, CG6_FBC_ARECTY,
  822. ri->ri_yorigin + row + ri->ri_font->fontheight - 1);
  823. FBC_WRITE(sc, CG6_FBC_ARECTX, ri->ri_xorigin + col + n - 1);
  824. CG6_DRAW_WAIT(sc);
  825. CG6_DRAIN(sc);
  826. return 0;
  827. }
  828. int
  829. cgsix_ras_eraserows(void *cookie, int row, int n, long int attr)
  830. {
  831. struct rasops_info *ri = cookie;
  832. struct cgsix_softc *sc = ri->ri_hw;
  833. int fg, bg;
  834. if (row < 0) {
  835. n += row;
  836. row = 0;
  837. }
  838. if (row + n > ri->ri_rows)
  839. n = ri->ri_rows - row;
  840. if (n <= 0)
  841. return 0;
  842. ri->ri_ops.unpack_attr(cookie, attr, &fg, &bg, NULL);
  843. FBC_WRITE(sc, CG6_FBC_CLIP, 0);
  844. FBC_WRITE(sc, CG6_FBC_S, 0);
  845. FBC_WRITE(sc, CG6_FBC_OFFX, 0);
  846. FBC_WRITE(sc, CG6_FBC_OFFY, 0);
  847. FBC_WRITE(sc, CG6_FBC_CLIPMINX, 0);
  848. FBC_WRITE(sc, CG6_FBC_CLIPMINY, 0);
  849. FBC_WRITE(sc, CG6_FBC_CLIPMAXX, ri->ri_width - 1);
  850. FBC_WRITE(sc, CG6_FBC_CLIPMAXY, ri->ri_height - 1);
  851. FBC_WRITE(sc, CG6_FBC_ALU, FBC_ALU_FILL);
  852. FBC_WRITE(sc, CG6_FBC_FG, ri->ri_devcmap[bg]);
  853. if ((n == ri->ri_rows) && (ri->ri_flg & RI_FULLCLEAR)) {
  854. FBC_WRITE(sc, CG6_FBC_ARECTY, 0);
  855. FBC_WRITE(sc, CG6_FBC_ARECTX, 0);
  856. FBC_WRITE(sc, CG6_FBC_ARECTY, ri->ri_height - 1);
  857. FBC_WRITE(sc, CG6_FBC_ARECTX, ri->ri_width - 1);
  858. } else {
  859. row *= ri->ri_font->fontheight;
  860. FBC_WRITE(sc, CG6_FBC_ARECTY, ri->ri_yorigin + row);
  861. FBC_WRITE(sc, CG6_FBC_ARECTX, ri->ri_xorigin);
  862. FBC_WRITE(sc, CG6_FBC_ARECTY,
  863. ri->ri_yorigin + row + (n * ri->ri_font->fontheight) - 1);
  864. FBC_WRITE(sc, CG6_FBC_ARECTX,
  865. ri->ri_xorigin + ri->ri_emuwidth - 1);
  866. }
  867. CG6_DRAW_WAIT(sc);
  868. CG6_DRAIN(sc);
  869. return 0;
  870. }
  871. int
  872. cgsix_ras_do_cursor(struct rasops_info *ri)
  873. {
  874. struct cgsix_softc *sc = ri->ri_hw;
  875. int row, col;
  876. row = ri->ri_crow * ri->ri_font->fontheight;
  877. col = ri->ri_ccol * ri->ri_font->fontwidth;
  878. FBC_WRITE(sc, CG6_FBC_CLIP, 0);
  879. FBC_WRITE(sc, CG6_FBC_S, 0);
  880. FBC_WRITE(sc, CG6_FBC_OFFX, 0);
  881. FBC_WRITE(sc, CG6_FBC_OFFY, 0);
  882. FBC_WRITE(sc, CG6_FBC_CLIPMINX, 0);
  883. FBC_WRITE(sc, CG6_FBC_CLIPMINY, 0);
  884. FBC_WRITE(sc, CG6_FBC_CLIPMAXX, ri->ri_width - 1);
  885. FBC_WRITE(sc, CG6_FBC_CLIPMAXY, ri->ri_height - 1);
  886. FBC_WRITE(sc, CG6_FBC_ALU, FBC_ALU_FLIP);
  887. FBC_WRITE(sc, CG6_FBC_ARECTY, ri->ri_yorigin + row);
  888. FBC_WRITE(sc, CG6_FBC_ARECTX, ri->ri_xorigin + col);
  889. FBC_WRITE(sc, CG6_FBC_ARECTY,
  890. ri->ri_yorigin + row + ri->ri_font->fontheight - 1);
  891. FBC_WRITE(sc, CG6_FBC_ARECTX,
  892. ri->ri_xorigin + col + ri->ri_font->fontwidth - 1);
  893. CG6_DRAW_WAIT(sc);
  894. CG6_DRAIN(sc);
  895. return 0;
  896. }