Annotation of sys/dev/pcmcia/cfxga.c, Revision 1.1.1.1
1.1 nbrk 1: /* $OpenBSD: cfxga.c,v 1.14 2006/11/29 19:11:17 miod Exp $ */
2:
3: /*
4: * Copyright (c) 2005, 2006, Matthieu Herrb and Miodrag Vallat
5: *
6: * Permission to use, copy, modify, and distribute this software for any
7: * purpose with or without fee is hereby granted, provided that the above
8: * copyright notice and this permission notice appear in all copies.
9: *
10: * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHORS DISCLAIM ALL WARRANTIES
11: * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
12: * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR
13: * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
14: * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
15: * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
16: * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
17: */
18:
19: /*
20: * Display driver for the Colorgraphic CompactFlash ``VoyagerVGA'' card.
21: * based upon the Epson S1D13806 graphics chip.
22: *
23: * Our goals are:
24: * - to provide a somewhat usable emulation mode for extra text display.
25: * - to let an application (such as an X server) map the controller registers
26: * in order to do its own display game.
27: *
28: * Driving this card is somewhat a challenge since:
29: * - its video memory is not directly accessible.
30: * - no operation can make use of DMA.
31: */
32:
33: #include <sys/param.h>
34: #include <sys/kernel.h>
35: #include <sys/device.h>
36: #include <sys/systm.h>
37: #include <sys/malloc.h>
38: #include <sys/conf.h>
39:
40: #include <dev/pcmcia/pcmciavar.h>
41: #include <dev/pcmcia/pcmciareg.h>
42:
43: #include <dev/wscons/wsconsio.h>
44: #include <dev/wscons/wsdisplayvar.h>
45: #include <dev/rasops/rasops.h>
46:
47: #include <dev/pcmcia/cfxgareg.h>
48:
49: /*
50: #define CFXGADEBUG
51: #define ENABLE_8BIT_MODES
52: */
53:
54: #ifdef CFXGADEBUG
55: #define DPRINTF(arg) printf arg
56: #else
57: #define DPRINTF(arg)
58: #endif
59:
60: struct cfxga_screen;
61:
62: #define CFXGA_MODE_640x480x16 0
63: #define CFXGA_MODE_800x600x16 1
64: #ifdef ENABLE_8BIT_MODES
65: #define CFXGA_MODE_640x480x8 2
66: #define CFXGA_MODE_800x600x8 3
67: #define CFXGA_NMODES 4
68: #else
69: #define CFXGA_NMODES 2
70: #endif
71:
72: struct cfxga_softc {
73: struct device sc_dev;
74: struct pcmcia_function *sc_pf;
75: int sc_state;
76: #define CS_MAPPED 0x0001
77: #define CS_RESET 0x0002
78:
79: struct pcmcia_mem_handle sc_pmemh;
80: int sc_memwin;
81: bus_addr_t sc_offset;
82:
83: int sc_mode;
84:
85: int sc_nscreens;
86: LIST_HEAD(, cfxga_screen) sc_scr;
87: struct cfxga_screen *sc_active;
88:
89: /* wsdisplay glue */
90: struct wsscreen_descr sc_wsd[CFXGA_NMODES];
91: struct wsscreen_list sc_wsl;
92: struct wsscreen_descr *sc_scrlist[CFXGA_NMODES];
93: struct wsdisplay_emulops sc_ops;
94: struct device *sc_wsdisplay;
95: };
96:
97: int cfxga_match(struct device *, void *, void *);
98: void cfxga_attach(struct device *, struct device *, void *);
99: int cfxga_detach(struct device *, int);
100: int cfxga_activate(struct device *, enum devact);
101:
102: struct cfattach cfxga_ca = {
103: sizeof(struct cfxga_softc), cfxga_match, cfxga_attach,
104: cfxga_detach, cfxga_activate
105: };
106:
107: struct cfdriver cfxga_cd = {
108: NULL, "cfxga", DV_DULL
109: };
110:
111: int cfxga_alloc_screen(void *, const struct wsscreen_descr *, void **,
112: int *, int *, long *);
113: void cfxga_burner(void *, u_int, u_int);
114: void cfxga_free_screen(void *, void *);
115: int cfxga_ioctl(void *, u_long, caddr_t, int, struct proc *);
116: paddr_t cfxga_mmap(void *, off_t, int);
117: int cfxga_show_screen(void *, void *, int, void (*)(void *, int, int),
118: void *);
119:
120: struct wsdisplay_accessops cfxga_accessops = {
121: cfxga_ioctl,
122: cfxga_mmap,
123: cfxga_alloc_screen,
124: cfxga_free_screen,
125: cfxga_show_screen,
126: NULL,
127: NULL,
128: NULL,
129: cfxga_burner
130: };
131:
132: /*
133: * Per-screen structure
134: */
135:
136: struct cfxga_screen {
137: LIST_ENTRY(cfxga_screen) scr_link;
138: struct cfxga_softc *scr_sc; /* parent reference */
139: struct rasops_info scr_ri; /* raster op glue */
140: struct wsdisplay_charcell *scr_mem; /* backing memory */
141: };
142:
143: void cfxga_copycols(void *, int, int, int, int);
144: void cfxga_copyrows(void *, int, int, int);
145: void cfxga_do_cursor(struct rasops_info *);
146: void cfxga_erasecols(void *, int, int, int, long);
147: void cfxga_eraserows(void *, int, int, long);
148: void cfxga_putchar(void *, int, int, u_int, long);
149:
150: int cfxga_install_function(struct pcmcia_function *);
151: void cfxga_remove_function(struct pcmcia_function *);
152:
153: int cfxga_expand_char(struct cfxga_screen *, u_int, int, int, long);
154: int cfxga_repaint_screen(struct cfxga_screen *);
155: void cfxga_reset_video(struct cfxga_softc *);
156: void cfxga_reset_and_repaint(struct cfxga_softc *);
157: int cfxga_solid_fill(struct cfxga_screen *, int, int, int, int, int32_t);
158: int cfxga_standalone_rop(struct cfxga_screen *, u_int,
159: int, int, int, int, int, int);
160: int cfxga_synchronize(struct cfxga_softc *);
161: u_int cfxga_wait(struct cfxga_softc *, u_int, u_int);
162:
163: #define cfxga_clear_screen(scr) \
164: cfxga_solid_fill(scr, 0, 0, scr->scr_ri.ri_width, \
165: scr->scr_ri.ri_height, scr->scr_ri.ri_devcmap[WSCOL_BLACK])
166:
167: #define cfxga_read_1(sc, addr) \
168: bus_space_read_1((sc)->sc_pmemh.memt, (sc)->sc_pmemh.memh, \
169: (sc)->sc_offset + (addr))
170: #define cfxga_read_2(sc, addr) \
171: bus_space_read_2((sc)->sc_pmemh.memt, (sc)->sc_pmemh.memh, \
172: (sc)->sc_offset + (addr))
173: #define cfxga_write_1(sc, addr, val) \
174: bus_space_write_1((sc)->sc_pmemh.memt, (sc)->sc_pmemh.memh, \
175: (sc)->sc_offset + (addr), (val))
176: #define cfxga_write_2(sc, addr, val) \
177: bus_space_write_2((sc)->sc_pmemh.memt, (sc)->sc_pmemh.memh, \
178: (sc)->sc_offset + (addr), (val))
179:
180: #define cfxga_stop_memory_blt(sc) \
181: (void)cfxga_read_2(sc, CFREG_BITBLT_DATA)
182:
183: const char *cfxga_modenames[CFXGA_NMODES] = {
184: "640x480x16",
185: "800x600x16",
186: #ifdef ENABLE_8BIT_MODES
187: "640x480x8",
188: "800x600x8"
189: #endif
190: };
191:
192: /*
193: * This card is very poorly engineered, specificationwise. It does not
194: * provide any CIS information, and has no vendor/product numbers as
195: * well: as such, there is no easy way to differentiate it from any
196: * other cheapo PCMCIA card.
197: *
198: * The best we can do is probe for a chip ID. This is not perfect but better
199: * than matching blindly. Of course this requires us to play some nasty games
200: * behind the PCMCIA framework to be able to do this probe, and correctly fail
201: * if this is not the card we are looking for.
202: *
203: * In shorter words: some card designers ought to be shot, as a service
204: * to the community.
205: */
206:
207: /*
208: * Create the necessary pcmcia function structures to alleviate the lack
209: * of any CIS information on this device.
210: * Actually, we hijack the fake function created by the pcmcia framework.
211: */
212: int
213: cfxga_install_function(struct pcmcia_function *pf)
214: {
215: struct pcmcia_config_entry *cfe;
216:
217: /* Get real. */
218: pf->pf_flags &= ~PFF_FAKE;
219:
220: /* Tell the pcmcia framework where the CCR is. */
221: pf->ccr_base = 0x800;
222: pf->ccr_mask = 0x67;
223:
224: /* Create a simple cfe. */
225: cfe = (struct pcmcia_config_entry *)malloc(sizeof *cfe,
226: M_DEVBUF, M_NOWAIT);
227: if (cfe == NULL) {
228: DPRINTF(("%s: cfe allocation failed\n", __func__));
229: return (ENOMEM);
230: }
231:
232: bzero(cfe, sizeof *cfe);
233: cfe->number = 42; /* have to put some value... */
234: cfe->flags = PCMCIA_CFE_IO16;
235: cfe->iftype = PCMCIA_IFTYPE_MEMORY;
236:
237: SIMPLEQ_INSERT_TAIL(&pf->cfe_head, cfe, cfe_list);
238:
239: pcmcia_function_init(pf, cfe);
240: return (0);
241: }
242:
243: /*
244: * Undo the changes done above.
245: * Such a function is necessary since we need a full-blown pcmcia world
246: * set up in order to do the device probe, but if we don't match the card,
247: * leaving this state will cause trouble during other probes.
248: */
249: void
250: cfxga_remove_function(struct pcmcia_function *pf)
251: {
252: struct pcmcia_config_entry *cfe;
253:
254: /* we are the first and only entry... */
255: cfe = SIMPLEQ_FIRST(&pf->cfe_head);
256: SIMPLEQ_REMOVE_HEAD(&pf->cfe_head, cfe_list);
257: free(cfe, M_DEVBUF);
258:
259: /* And we're a figment of the kernel's imagination again. */
260: pf->pf_flags |= PFF_FAKE;
261: }
262:
263: int
264: cfxga_match(struct device *parent, void *match, void *aux)
265: {
266: struct pcmcia_attach_args *pa = aux;
267: struct pcmcia_function *pf = pa->pf;
268: struct pcmcia_mem_handle h;
269: int rc;
270: int win;
271: bus_addr_t ptr;
272: u_int8_t id = 0;
273:
274: if (pa->product != PCMCIA_PRODUCT_INVALID ||
275: pa->manufacturer != PCMCIA_VENDOR_INVALID)
276: return (0);
277:
278: /* Only a card with no CIS will have a fake function... */
279: if ((pf->pf_flags & PFF_FAKE) == 0)
280: return (0);
281:
282: if (cfxga_install_function(pf) != 0)
283: return (0);
284:
285: if (pcmcia_function_enable(pf) != 0) {
286: DPRINTF(("%s: function enable failed\n"));
287: return (0);
288: }
289:
290: rc = pcmcia_mem_alloc(pf, CFXGA_MEM_RANGE, &h);
291: if (rc != 0)
292: goto out;
293:
294: rc = pcmcia_mem_map(pf, PCMCIA_MEM_ATTR, 0, CFXGA_MEM_RANGE,
295: &h, &ptr, &win);
296: if (rc != 0)
297: goto out2;
298:
299: id = (bus_space_read_1(h.memt, h.memh, ptr + CFREG_REV) &
300: CR_PRODUCT_MASK) >> CR_PRODUCT_SHIFT;
301:
302: pcmcia_mem_unmap(pa->pf, win);
303: out2:
304: pcmcia_mem_free(pa->pf, &h);
305: out:
306: pcmcia_function_disable(pf);
307: cfxga_remove_function(pf);
308:
309: /*
310: * Be sure to return a value greater than pccom's if we match,
311: * otherwise it can win due to the way config(8) will order devices...
312: */
313: return (id == PRODUCT_S1D13806 ? 10 : 0);
314: }
315:
316: int
317: cfxga_activate(struct device *dev, enum devact act)
318: {
319: struct cfxga_softc *sc = (void *)dev;
320:
321: switch (act) {
322: case DVACT_ACTIVATE:
323: if (pcmcia_function_enable(sc->sc_pf) != 0) {
324: printf("%s: function enable failed\n",
325: sc->sc_dev.dv_xname);
326: } else {
327: cfxga_reset_and_repaint(sc);
328: }
329: break;
330: case DVACT_DEACTIVATE:
331: pcmcia_function_disable(sc->sc_pf);
332: break;
333: }
334: return (0);
335: }
336:
337: void
338: cfxga_attach(struct device *parent, struct device *self, void *aux)
339: {
340: struct cfxga_softc *sc = (void *)self;
341: struct pcmcia_attach_args *pa = aux;
342: struct pcmcia_function *pf = pa->pf;
343: struct wsemuldisplaydev_attach_args waa;
344: struct wsscreen_descr *wsd;
345: u_int i;
346:
347: LIST_INIT(&sc->sc_scr);
348: sc->sc_nscreens = 0;
349: sc->sc_pf = pf;
350:
351: if (cfxga_install_function(pf) != 0) {
352: printf(": pcmcia function setup failed\n");
353: return;
354: }
355:
356: if (pcmcia_function_enable(pf)) {
357: printf(": function enable failed\n");
358: return;
359: }
360:
361: if (pcmcia_mem_alloc(pf, CFXGA_MEM_RANGE, &sc->sc_pmemh) != 0) {
362: printf(": can't allocate memory space\n");
363: return;
364: }
365:
366: if (pcmcia_mem_map(pf, PCMCIA_MEM_ATTR, 0, CFXGA_MEM_RANGE,
367: &sc->sc_pmemh, &sc->sc_offset, &sc->sc_memwin) != 0) {
368: printf(": can't map frame buffer registers\n");
369: pcmcia_mem_free(pf, &sc->sc_pmemh);
370: return;
371: }
372:
373: SET(sc->sc_state, CS_MAPPED);
374:
375: printf("\n");
376:
377: sc->sc_mode = WSDISPLAYIO_MODE_EMUL;
378:
379: /*
380: * We actually defer real initialization to the creation of the
381: * first wsdisplay screen, since we do not know which mode to pick
382: * yet.
383: */
384:
385: for (wsd = sc->sc_wsd, i = 0; i < CFXGA_NMODES; wsd++, i++) {
386: strlcpy(wsd->name, cfxga_modenames[i], sizeof(wsd->name));
387: wsd->textops = &sc->sc_ops;
388: sc->sc_scrlist[i] = wsd;
389: }
390: sc->sc_wsl.nscreens = CFXGA_NMODES;
391: sc->sc_wsl.screens = (const struct wsscreen_descr **)sc->sc_scrlist;
392:
393: waa.console = 0;
394: waa.scrdata = &sc->sc_wsl;
395: waa.accessops = &cfxga_accessops;
396: waa.accesscookie = sc;
397: waa.defaultscreens = 1;
398:
399: if ((sc->sc_wsdisplay =
400: config_found(self, &waa, wsemuldisplaydevprint)) == NULL) {
401: /* otherwise wscons will do this */
402: if (sc->sc_active != NULL)
403: cfxga_clear_screen(sc->sc_active);
404: else
405: cfxga_burner(sc, 0, 0);
406: }
407: }
408:
409: int
410: cfxga_detach(struct device *dev, int flags)
411: {
412: struct cfxga_softc *sc = (void *)dev;
413:
414: /*
415: * Detach all children, and hope wsdisplay detach code is correct...
416: */
417: if (sc->sc_wsdisplay != NULL) {
418: config_detach(sc->sc_wsdisplay, DETACH_FORCE);
419: /* sc->sc_wsdisplay = NULL; */
420: }
421:
422: if (ISSET(sc->sc_state, CS_MAPPED)) {
423: pcmcia_mem_unmap(sc->sc_pf, sc->sc_memwin);
424: pcmcia_mem_free(sc->sc_pf, &sc->sc_pmemh);
425: /* CLR(sc->sc_state, CS_MAPPED); */
426: }
427:
428: return (0);
429: }
430:
431: /*
432: * Wscons operations
433: */
434:
435: int
436: cfxga_alloc_screen(void *v, const struct wsscreen_descr *type, void **cookiep,
437: int *curxp, int *curyp, long *attrp)
438: {
439: struct cfxga_softc *sc = v;
440: struct cfxga_screen *scr;
441: struct rasops_info *ri;
442: u_int mode, width, height, depth, scrsize;
443:
444: scr = malloc(sizeof *scr, M_DEVBUF, cold ? M_NOWAIT : M_WAITOK);
445: if (scr == NULL)
446: return (ENOMEM);
447: bzero(scr, sizeof *scr);
448:
449: mode = type - sc->sc_wsd;
450: #ifdef DIAGNOSTIC
451: if (mode >= CFXGA_NMODES)
452: mode = CFXGA_MODE_640x480x16;
453: #endif
454: switch (mode) {
455: default:
456: case CFXGA_MODE_640x480x16:
457: width = 640;
458: height = 480;
459: depth = 16;
460: break;
461: case CFXGA_MODE_800x600x16:
462: width = 800;
463: height = 600;
464: depth = 16;
465: break;
466: #ifdef ENABLE_8BIT_MODES
467: case CFXGA_MODE_640x480x8:
468: width = 640;
469: height = 480;
470: depth = 8;
471: break;
472: case CFXGA_MODE_800x600x8:
473: width = 800;
474: height = 600;
475: depth = 8;
476: break;
477: #endif
478: }
479:
480: ri = &scr->scr_ri;
481: ri->ri_hw = (void *)scr;
482: ri->ri_bits = NULL;
483: ri->ri_depth = depth;
484: ri->ri_width = width;
485: ri->ri_height = height;
486: ri->ri_stride = width * depth / 8;
487: ri->ri_flg = 0;
488:
489: /* swap B and R at 16 bpp */
490: if (depth == 16) {
491: ri->ri_rnum = 5;
492: ri->ri_rpos = 11;
493: ri->ri_gnum = 6;
494: ri->ri_gpos = 5;
495: ri->ri_bnum = 5;
496: ri->ri_bpos = 0;
497: }
498:
499: if (type->nrows == 0) /* first screen creation */
500: rasops_init(ri, 100, 100);
501: else
502: rasops_init(ri, type->nrows, type->ncols);
503:
504: /*
505: * Allocate backing store to remember non-visible screen contents in
506: * emulation mode.
507: */
508: scrsize = ri->ri_rows * ri->ri_cols * sizeof(struct wsdisplay_charcell);
509: scr->scr_mem = malloc(scrsize, M_DEVBUF, cold ? M_NOWAIT : M_WAITOK);
510: if (scr->scr_mem == NULL) {
511: free(scr, M_DEVBUF);
512: return (ENOMEM);
513: }
514: bzero(scr->scr_mem, scrsize);
515:
516: ri->ri_ops.copycols = cfxga_copycols;
517: ri->ri_ops.copyrows = cfxga_copyrows;
518: ri->ri_ops.erasecols = cfxga_erasecols;
519: ri->ri_ops.eraserows = cfxga_eraserows;
520: ri->ri_ops.putchar = cfxga_putchar;
521: ri->ri_do_cursor = cfxga_do_cursor;
522:
523: /*
524: * Finish initializing our screen descriptions, now that we know
525: * the actual console emulation parameters.
526: */
527: if (type->nrows == 0) {
528: struct wsscreen_descr *wsd = (struct wsscreen_descr *)type;
529:
530: wsd->nrows = ri->ri_rows;
531: wsd->ncols = ri->ri_cols;
532: bcopy(&ri->ri_ops, &sc->sc_ops, sizeof(sc->sc_ops));
533: wsd->fontwidth = ri->ri_font->fontwidth;
534: wsd->fontheight = ri->ri_font->fontheight;
535: wsd->capabilities = ri->ri_caps;
536: }
537:
538: scr->scr_sc = sc;
539: LIST_INSERT_HEAD(&sc->sc_scr, scr, scr_link);
540: sc->sc_nscreens++;
541:
542: ri->ri_ops.alloc_attr(ri, 0, 0, 0, attrp);
543:
544: *cookiep = ri;
545: *curxp = *curyp = 0;
546:
547: return (0);
548: }
549:
550: void
551: cfxga_burner(void *v, u_int on, u_int flags)
552: {
553: struct cfxga_softc *sc = (void *)v;
554: u_int8_t mode;
555:
556: mode = cfxga_read_1(sc, CFREG_MODE) & LCD_MODE_SWIVEL_BIT_0;
557:
558: if (on)
559: cfxga_write_1(sc, CFREG_MODE, mode | MODE_CRT);
560: else
561: cfxga_write_1(sc, CFREG_MODE, mode | MODE_NO_DISPLAY);
562: }
563:
564: void
565: cfxga_free_screen(void *v, void *cookie)
566: {
567: struct cfxga_softc *sc = v;
568: struct rasops_info *ri = cookie;
569: struct cfxga_screen *scr = ri->ri_hw;
570:
571: LIST_REMOVE(scr, scr_link);
572: sc->sc_nscreens--;
573:
574: if (scr == sc->sc_active) {
575: sc->sc_active = NULL;
576: cfxga_burner(sc, 0, 0);
577: }
578:
579: free(scr->scr_mem, M_DEVBUF);
580: free(scr, M_DEVBUF);
581: }
582:
583: int
584: cfxga_ioctl(void *v, u_long cmd, caddr_t data, int flag, struct proc *p)
585: {
586: struct cfxga_softc *sc = v;
587: struct cfxga_screen *scr;
588: struct wsdisplay_fbinfo *wdf;
589: int mode;
590:
591: switch (cmd) {
592: case WSDISPLAYIO_GTYPE:
593: *(u_int *)data = WSDISPLAY_TYPE_CFXGA;
594: break;
595:
596: case WSDISPLAYIO_GINFO:
597: wdf = (struct wsdisplay_fbinfo *)data;
598: scr = sc->sc_active;
599: if (scr == NULL) {
600: /* try later...after running wsconscfg to add screens */
601: wdf->height = wdf->width = wdf->depth = wdf->cmsize = 0;
602: } else {
603: wdf->height = scr->scr_ri.ri_height;
604: wdf->width = scr->scr_ri.ri_width;
605: wdf->depth = scr->scr_ri.ri_depth;
606: wdf->cmsize = scr->scr_ri.ri_depth <= 8 ?
607: (1 << scr->scr_ri.ri_depth) : 0;
608: }
609: break;
610:
611: case WSDISPLAYIO_SMODE:
612: mode = *(u_int *)data;
613: if (mode == sc->sc_mode)
614: break;
615: switch (mode) {
616: case WSDISPLAYIO_MODE_EMUL:
617: cfxga_reset_and_repaint(sc);
618: break;
619: case WSDISPLAYIO_MODE_MAPPED:
620: break;
621: default:
622: return (EINVAL);
623: }
624: sc->sc_mode = mode;
625: break;
626:
627: /* these operations are handled by the wscons code... */
628: case WSDISPLAYIO_GVIDEO:
629: case WSDISPLAYIO_SVIDEO:
630: break;
631:
632: /* these operations are not supported... */
633: case WSDISPLAYIO_GETCMAP:
634: case WSDISPLAYIO_PUTCMAP:
635: case WSDISPLAYIO_LINEBYTES:
636: case WSDISPLAYIO_GCURPOS:
637: case WSDISPLAYIO_SCURPOS:
638: case WSDISPLAYIO_GCURMAX:
639: case WSDISPLAYIO_GCURSOR:
640: case WSDISPLAYIO_SCURSOR:
641: default:
642: return (-1);
643: }
644:
645: return (0);
646: }
647:
648: paddr_t
649: cfxga_mmap(void *v, off_t off, int prot)
650: {
651: return (-1);
652: }
653:
654: int
655: cfxga_show_screen(void *v, void *cookie, int waitok,
656: void (*cb)(void *, int, int), void *cbarg)
657: {
658: struct cfxga_softc *sc = v;
659: struct rasops_info *ri = cookie;
660: struct cfxga_screen *scr = ri->ri_hw, *old;
661:
662: old = sc->sc_active;
663: if (old == scr)
664: return (0);
665:
666: sc->sc_active = scr;
667: cfxga_reset_and_repaint(sc); /* will turn video on if scr != NULL */
668:
669: return (0);
670: }
671:
672: /*
673: * Real frame buffer operations
674: */
675:
676: void
677: cfxga_reset_video(struct cfxga_softc *sc)
678: {
679: struct cfxga_screen *scr = sc->sc_active;
680: struct rasops_info *ri;
681: #ifdef ENABLE_8BIT_MODES
682: const u_int8_t *cmap;
683: u_int i;
684: #endif
685:
686: /*
687: * Reset controller
688: */
689:
690: /* need to write to both REV and MISC at the same time */
691: cfxga_write_2(sc, CFREG_REV, 0x80 | (CM_REGSEL << 8));
692: delay(25000); /* maintain reset for a short while */
693: /* need to write to both REV and MISC at the same time */
694: cfxga_write_2(sc, CFREG_REV, 0 | (CM_MEMSEL << 8));
695: delay(25000);
696: /* stop any pending blt operation */
697: cfxga_write_2(sc, CFREG_BITBLT_CONTROL, 0);
698: cfxga_stop_memory_blt(sc);
699: cfxga_write_1(sc, CFREG_MODE, 0); /* disable all displays */
700:
701: /*
702: * Setup common video mode parameters.
703: */
704:
705: cfxga_write_2(sc, CFREG_MEMCLK, MEMCLK_SRC_CLK3);
706: #if 0
707: cfxga_write_1(sc, CFREG_LCD_PCLK, LCD_PCLK_SRC_CLKI | LCD_PCLK_DIV_1);
708: cfxga_write_1(sc, CFREG_MPLUG_CLK,
709: MPLUG_PCLK_SRC_CLKI2 | MPLUG_PCLK_DIV_1);
710: #endif
711: cfxga_write_2(sc, CFREG_CRTTV_PCLK, CRT_PCLK_SRC_CLKI | CRT_PCLK_DIV_1);
712: cfxga_write_2(sc, CFREG_WSTATE, WSTATE_MCLK);
713:
714: /* MEMCNF and DRAM_RFRSH need to be programmed at the same time */
715: cfxga_write_2(sc, CFREG_MEMCNF,
716: MEMCNF_SDRAM_INIT | (DRAM_RFRSH_50MHZ << 8));
717: delay(250);
718: cfxga_write_2(sc, CFREG_DRAM_TIMING, DRAM_TIMING_50MHZ);
719:
720: /*
721: * Setup mode-dependent parameters.
722: */
723: if (scr == NULL)
724: return;
725:
726: ri = &scr->scr_ri;
727: switch (scr->scr_ri.ri_width) {
728: default:
729: case 640:
730: cfxga_write_1(sc, CFREG_CRT_HWIDTH, (640 / 8) - 1);
731: /* HNDISP and HSTART need to be programmed at the same time */
732: cfxga_write_2(sc, CFREG_CRT_HNDISP, 23 | (2 << 8));
733: cfxga_write_1(sc, CFREG_CRT_HPULSE, 4);
734: cfxga_write_2(sc, CFREG_CRT_VHEIGHT, 480 - 1);
735: /* VNDISP and VSTART need to be programmed at the same time */
736: cfxga_write_2(sc, CFREG_CRT_VNDISP, 39 | (8 << 8));
737: cfxga_write_1(sc, CFREG_CRT_VPULSE, 2);
738: break;
739: case 800:
740: cfxga_write_1(sc, CFREG_CRT_HWIDTH, (800 / 8) - 1);
741: /* HNDISP and HSTART need to be programmed at the same time */
742: cfxga_write_2(sc, CFREG_CRT_HNDISP, 27 | (2 << 8));
743: cfxga_write_1(sc, CFREG_CRT_HPULSE, 4);
744: cfxga_write_2(sc, CFREG_CRT_VHEIGHT, 600 - 1);
745: /* VNDISP and VSTART need to be programmed at the same time */
746: cfxga_write_2(sc, CFREG_CRT_VNDISP, 25 | (8 << 8));
747: cfxga_write_1(sc, CFREG_CRT_VPULSE, 2);
748: break;
749: }
750: cfxga_write_1(sc, CFREG_CRT_MODE,
751: ri->ri_depth == 16 ? CRT_MODE_16BPP : CRT_MODE_8BPP);
752: cfxga_write_2(sc, CFREG_CRT_START_LOW, 0);
753: cfxga_write_1(sc, CFREG_CRT_START_HIGH, 0);
754: cfxga_write_2(sc, CFREG_CRT_MEMORY, ri->ri_width * ri->ri_depth / 16);
755: cfxga_write_1(sc, CFREG_CRT_PANNING, 0);
756: cfxga_write_1(sc, CFREG_CRT_FIFO_THRESHOLD_HIGH, 0);
757: cfxga_write_1(sc, CFREG_CRT_FIFO_THRESHOLD_LOW, 0);
758: cfxga_write_1(sc, CFREG_CRT_CURSOR_CONTROL, CURSOR_INACTIVE);
759:
760: #ifdef ENABLE_8BIT_MODES
761: /*
762: * On 8bpp video modes, program the LUT
763: */
764: if (ri->ri_depth == 8) {
765: #if 0
766: /* Wait for retrace */
767: while ((cfxga_read_1(sc, CFREG_CRT_VNDISP) &
768: CRT_VNDISP_STATUS) == 0)
769: delay(1);
770: #endif
771: cfxga_write_1(sc, CFREG_LUT_MODE, LUT_CRT);
772: cfxga_write_1(sc, CFREG_LUT_ADDRESS, 0); /* autoincrements */
773: cmap = rasops_cmap;
774: for (i = 256 * 3; i != 0; i--)
775: cfxga_write_1(sc, CFREG_LUT_DATA, *cmap++ & 0xf0);
776: }
777: #endif
778:
779: cfxga_write_1(sc, CFREG_TV_CONTROL,
780: TV_LUMINANCE_FILTER | TV_SVIDEO_OUTPUT | TV_NTSC_OUTPUT);
781:
782: cfxga_write_1(sc, CFREG_POWER_CONF, POWERSAVE_MBO);
783: cfxga_write_1(sc, CFREG_WATCHDOG, 0);
784:
785: cfxga_write_1(sc, CFREG_MODE, MODE_CRT);
786: delay(25000);
787: }
788:
789: void
790: cfxga_reset_and_repaint(struct cfxga_softc *sc)
791: {
792: cfxga_reset_video(sc);
793:
794: if (sc->sc_active != NULL)
795: cfxga_repaint_screen(sc->sc_active);
796: else
797: cfxga_burner(sc, 0, 0);
798: }
799:
800: /*
801: * Wait for the blitter to be in a given state.
802: */
803: u_int
804: cfxga_wait(struct cfxga_softc *sc, u_int mask, u_int result)
805: {
806: u_int tries;
807:
808: for (tries = 10000; tries != 0; tries--) {
809: if ((cfxga_read_1(sc, CFREG_BITBLT_CONTROL) & mask) == result)
810: break;
811: delay(10);
812: }
813:
814: return (tries);
815: }
816:
817: /*
818: * Wait for all pending blitter operations to be complete.
819: * Returns non-zero if the blitter got stuck.
820: */
821: int
822: cfxga_synchronize(struct cfxga_softc *sc)
823: {
824: /* Wait for previous operations to complete */
825: if (cfxga_wait(sc, BITBLT_ACTIVE, 0) == 0) {
826: DPRINTF(("%s: not ready\n", __func__));
827: if (ISSET(sc->sc_state, CS_RESET))
828: return (EAGAIN);
829: else {
830: DPRINTF(("%s: resetting...\n", sc->sc_dev.dv_xname));
831: SET(sc->sc_state, CS_RESET);
832: cfxga_reset_and_repaint(sc);
833: CLR(sc->sc_state, CS_RESET);
834: }
835: }
836: cfxga_stop_memory_blt(sc);
837: return (0);
838: }
839:
840: /*
841: * Display a character.
842: */
843: int
844: cfxga_expand_char(struct cfxga_screen *scr, u_int uc, int x, int y, long attr)
845: {
846: struct cfxga_softc *sc = scr->scr_sc;
847: struct rasops_info *ri = &scr->scr_ri;
848: struct wsdisplay_font *font = ri->ri_font;
849: u_int pos, sts, fifo_avail, chunk;
850: u_int8_t *fontbits;
851: int bg, fg, ul;
852: u_int i;
853: int rc;
854:
855: pos = (y * ri->ri_width + x) * ri->ri_depth / 8;
856: fontbits = (u_int8_t *)(font->data + (uc - font->firstchar) *
857: ri->ri_fontscale);
858: ri->ri_ops.unpack_attr(ri, attr, &fg, &bg, &ul);
859:
860: /* Wait for previous operations to complete */
861: if ((rc = cfxga_synchronize(sc)) != 0)
862: return (rc);
863:
864: cfxga_write_2(sc, CFREG_COLOR_EXPANSION,
865: ((font->fontwidth - 1) & 7) | (OP_COLOR_EXPANSION << 8));
866: cfxga_write_2(sc, CFREG_BITBLT_SRC_LOW, font->fontwidth <= 8 ? 0 : 1);
867: cfxga_write_2(sc, CFREG_BITBLT_SRC_HIGH, 0);
868: cfxga_write_2(sc, CFREG_BITBLT_DST_LOW, pos);
869: cfxga_write_2(sc, CFREG_BITBLT_DST_HIGH, pos >> 16);
870: cfxga_write_2(sc, CFREG_BITBLT_OFFSET,
871: ri->ri_width * ri->ri_depth / 16);
872: cfxga_write_2(sc, CFREG_BITBLT_WIDTH, font->fontwidth - 1);
873: cfxga_write_2(sc, CFREG_BITBLT_HEIGHT, font->fontheight - 1);
874: cfxga_write_2(sc, CFREG_BITBLT_FG, ri->ri_devcmap[fg]);
875: cfxga_write_2(sc, CFREG_BITBLT_BG, ri->ri_devcmap[bg]);
876: cfxga_write_2(sc, CFREG_BITBLT_CONTROL, BITBLT_ACTIVE |
877: (ri->ri_depth > 8 ? BITBLT_COLOR_16 : BITBLT_COLOR_8));
878:
879: if (cfxga_wait(sc, BITBLT_ACTIVE, BITBLT_ACTIVE) == 0)
880: goto fail; /* unlikely */
881: fifo_avail = 0;
882:
883: for (i = font->fontheight; i != 0; i--) {
884: /*
885: * Find out how much words we can feed before
886: * a FIFO check is needed.
887: */
888: if (fifo_avail == 0) {
889: sts = cfxga_read_1(sc, CFREG_BITBLT_CONTROL);
890: if ((sts & BITBLT_FIFO_NOT_EMPTY) == 0)
891: fifo_avail = font->fontwidth <= 8 ? 2 : 1;
892: else if ((sts & BITBLT_FIFO_HALF_FULL) == 0)
893: fifo_avail = font->fontwidth <= 8 ? 1 : 0;
894: else {
895: /*
896: * Let the cheap breathe for a short while.
897: * If this is not enough to free some FIFO
898: * entries, abort the operation.
899: */
900: if (cfxga_wait(sc, BITBLT_FIFO_FULL, 0) == 0)
901: goto fail;
902: }
903: }
904:
905: if (font->fontwidth <= 8) {
906: chunk = *fontbits;
907: if (ul && i == 1)
908: chunk = 0xff;
909: } else {
910: chunk = *(u_int16_t *)fontbits;
911: if (ul && i == 1)
912: chunk = 0xffff;
913: }
914: cfxga_write_2(sc, CFREG_BITBLT_DATA, chunk);
915: fontbits += font->stride;
916: fifo_avail--;
917: }
918:
919: return (0);
920:
921: fail:
922: DPRINTF(("%s: abort\n", __func__));
923: cfxga_write_2(sc, CFREG_BITBLT_CONTROL, 0);
924: cfxga_stop_memory_blt(sc);
925: return (EINTR);
926: }
927:
928: /*
929: * Copy a memory bitmap to the frame buffer.
930: *
931: * This is slow - we only use this to repaint the whole frame buffer on
932: * screen switches.
933: */
934: int
935: cfxga_repaint_screen(struct cfxga_screen *scr)
936: {
937: struct wsdisplay_charcell *cell = scr->scr_mem;
938: struct rasops_info *ri = &scr->scr_ri;
939: int x, y, cx, cy, lx, ly;
940: int fg, bg;
941: int rc;
942:
943: cfxga_clear_screen(scr);
944:
945: cx = ri->ri_font->fontwidth;
946: cy = ri->ri_font->fontheight;
947:
948: for (ly = 0, y = ri->ri_yorigin; ly < ri->ri_rows; ly++, y += cy) {
949: for (lx = 0, x = ri->ri_xorigin; lx < ri->ri_cols;
950: lx++, x += cx) {
951: if (cell->uc == 0 || cell->uc == ' ') {
952: ri->ri_ops.unpack_attr(ri, cell->attr,
953: &fg, &bg, NULL);
954: rc = cfxga_solid_fill(scr, x, y, cx, cy,
955: ri->ri_devcmap[bg]);
956: } else {
957: rc = cfxga_expand_char(scr, cell->uc,
958: x, y, cell->attr);
959: }
960: cell++;
961: if (rc != 0)
962: return (rc);
963: }
964: }
965:
966: return (0);
967: }
968:
969: /*
970: * Perform a solid fill operation.
971: */
972: int
973: cfxga_solid_fill(struct cfxga_screen *scr, int x, int y, int cx, int cy,
974: int32_t srccolor)
975: {
976: struct cfxga_softc *sc = scr->scr_sc;
977: struct rasops_info *ri = &scr->scr_ri;
978: u_int pos;
979: int rc;
980:
981: pos = (y * ri->ri_width + x) * ri->ri_depth / 8;
982:
983: /* Wait for previous operations to complete */
984: if ((rc = cfxga_synchronize(sc)) != 0)
985: return (rc);
986:
987: cfxga_write_2(sc, CFREG_BITBLT_ROP, 0 | (OP_SOLID_FILL << 8));
988: cfxga_write_2(sc, CFREG_BITBLT_SRC_LOW, pos);
989: cfxga_write_2(sc, CFREG_BITBLT_SRC_HIGH, pos >> 16);
990: cfxga_write_2(sc, CFREG_BITBLT_DST_LOW, pos);
991: cfxga_write_2(sc, CFREG_BITBLT_DST_HIGH, pos >> 16);
992: cfxga_write_2(sc, CFREG_BITBLT_OFFSET,
993: ri->ri_width * ri->ri_depth / 16);
994: cfxga_write_2(sc, CFREG_BITBLT_WIDTH, cx - 1);
995: cfxga_write_2(sc, CFREG_BITBLT_HEIGHT, cy - 1);
996: cfxga_write_2(sc, CFREG_BITBLT_FG, (u_int16_t)srccolor);
997: cfxga_write_2(sc, CFREG_BITBLT_CONTROL, BITBLT_ACTIVE |
998: (ri->ri_depth > 8 ? BITBLT_COLOR_16 : BITBLT_COLOR_8));
999:
1000: return (0);
1001: }
1002:
1003: /*
1004: * Perform an internal frame buffer operation.
1005: */
1006: int
1007: cfxga_standalone_rop(struct cfxga_screen *scr, u_int rop, int sx, int sy,
1008: int dx, int dy, int cx, int cy)
1009: {
1010: struct cfxga_softc *sc = scr->scr_sc;
1011: struct rasops_info *ri = &scr->scr_ri;
1012: u_int srcpos, dstpos;
1013: u_int opcode;
1014: int rc;
1015:
1016: srcpos = (sy * ri->ri_width + sx) * ri->ri_depth / 8;
1017: dstpos = (dy * ri->ri_width + dx) * ri->ri_depth / 8;
1018:
1019: if (dstpos <= srcpos)
1020: opcode = (OP_MOVE_POSITIVE_ROP << 8) | rop;
1021: else
1022: opcode = (OP_MOVE_NEGATIVE_ROP << 8) | rop;
1023:
1024: /* Wait for previous operations to complete */
1025: if ((rc = cfxga_synchronize(sc)) != 0)
1026: return (rc);
1027:
1028: cfxga_write_2(sc, CFREG_BITBLT_ROP, opcode);
1029: cfxga_write_2(sc, CFREG_BITBLT_SRC_LOW, srcpos);
1030: cfxga_write_2(sc, CFREG_BITBLT_SRC_HIGH, srcpos >> 16);
1031: cfxga_write_2(sc, CFREG_BITBLT_DST_LOW, dstpos);
1032: cfxga_write_2(sc, CFREG_BITBLT_DST_HIGH, dstpos >> 16);
1033: cfxga_write_2(sc, CFREG_BITBLT_OFFSET,
1034: ri->ri_width * ri->ri_depth / 16);
1035: cfxga_write_2(sc, CFREG_BITBLT_WIDTH, cx - 1);
1036: cfxga_write_2(sc, CFREG_BITBLT_HEIGHT, cy - 1);
1037: cfxga_write_2(sc, CFREG_BITBLT_CONTROL, BITBLT_ACTIVE |
1038: (ri->ri_depth > 8 ? BITBLT_COLOR_16 : BITBLT_COLOR_8));
1039:
1040: return (0);
1041: }
1042:
1043: /*
1044: * Text console raster operations.
1045: *
1046: * We shadow all these operations on a memory copy of the frame buffer.
1047: * Since we are running in emulation mode only, this could be optimized
1048: * by only storing actual character cell values (a la mda).
1049: */
1050:
1051: void
1052: cfxga_copycols(void *cookie, int row, int src, int dst, int num)
1053: {
1054: struct rasops_info *ri = cookie;
1055: struct cfxga_screen *scr = ri->ri_hw;
1056: int sx, dx, y, cx, cy;
1057:
1058: /* Copy columns in backing store. */
1059: ovbcopy(scr->scr_mem + row * ri->ri_cols + src,
1060: scr->scr_mem + row * ri->ri_cols + dst,
1061: num * sizeof(struct wsdisplay_charcell));
1062:
1063: if (scr != scr->scr_sc->sc_active)
1064: return;
1065:
1066: sx = src * ri->ri_font->fontwidth + ri->ri_xorigin;
1067: dx = dst * ri->ri_font->fontwidth + ri->ri_xorigin;
1068: y = row * ri->ri_font->fontheight + ri->ri_yorigin;
1069: cx = num * ri->ri_font->fontwidth;
1070: cy = ri->ri_font->fontheight;
1071: cfxga_standalone_rop(scr, ROP_SRC, sx, y, dx, y, cx, cy);
1072: }
1073:
1074: void
1075: cfxga_copyrows(void *cookie, int src, int dst, int num)
1076: {
1077: struct rasops_info *ri = cookie;
1078: struct cfxga_screen *scr = ri->ri_hw;
1079: int x, sy, dy, cx, cy;
1080:
1081: /* Copy rows in backing store. */
1082: ovbcopy(scr->scr_mem + src * ri->ri_cols,
1083: scr->scr_mem + dst * ri->ri_cols,
1084: num * ri->ri_cols * sizeof(struct wsdisplay_charcell));
1085:
1086: if (scr != scr->scr_sc->sc_active)
1087: return;
1088:
1089: x = ri->ri_xorigin;
1090: sy = src * ri->ri_font->fontheight + ri->ri_yorigin;
1091: dy = dst * ri->ri_font->fontheight + ri->ri_yorigin;
1092: cx = ri->ri_emuwidth;
1093: cy = num * ri->ri_font->fontheight;
1094: cfxga_standalone_rop(scr, ROP_SRC, x, sy, x, dy, cx, cy);
1095: }
1096:
1097: void
1098: cfxga_do_cursor(struct rasops_info *ri)
1099: {
1100: struct cfxga_screen *scr = ri->ri_hw;
1101: int x, y, cx, cy;
1102:
1103: if (scr != scr->scr_sc->sc_active)
1104: return;
1105:
1106: x = ri->ri_ccol * ri->ri_font->fontwidth + ri->ri_xorigin;
1107: y = ri->ri_crow * ri->ri_font->fontheight + ri->ri_yorigin;
1108: cx = ri->ri_font->fontwidth;
1109: cy = ri->ri_font->fontheight;
1110: cfxga_standalone_rop(scr, ROP_ONES ^ ROP_SRC /* i.e. not SRC */,
1111: x, y, x, y, cx, cy);
1112: }
1113:
1114: void
1115: cfxga_erasecols(void *cookie, int row, int col, int num, long attr)
1116: {
1117: struct rasops_info *ri = cookie;
1118: struct cfxga_screen *scr = ri->ri_hw;
1119: int fg, bg;
1120: int x, y, cx, cy;
1121:
1122: /* Erase columns in backing store. */
1123: for (x = col; x < col + num; x++) {
1124: scr->scr_mem[row * ri->ri_cols + x].uc = 0;
1125: scr->scr_mem[row * ri->ri_cols + x].attr = attr;
1126: }
1127:
1128: if (scr != scr->scr_sc->sc_active)
1129: return;
1130:
1131: ri->ri_ops.unpack_attr(cookie, attr, &fg, &bg, NULL);
1132: x = col * ri->ri_font->fontwidth + ri->ri_xorigin;
1133: y = row * ri->ri_font->fontheight + ri->ri_yorigin;
1134: cx = num * ri->ri_font->fontwidth;
1135: cy = ri->ri_font->fontheight;
1136: cfxga_solid_fill(scr, x, y, cx, cy, ri->ri_devcmap[bg]);
1137: }
1138:
1139: void
1140: cfxga_eraserows(void *cookie, int row, int num, long attr)
1141: {
1142: struct rasops_info *ri = cookie;
1143: struct cfxga_screen *scr = ri->ri_hw;
1144: int fg, bg;
1145: int x, y, cx, cy;
1146:
1147: /* Erase rows in backing store. */
1148: for (x = 0; x < ri->ri_cols; x++) {
1149: scr->scr_mem[row * ri->ri_cols + x].uc = 0;
1150: scr->scr_mem[row * ri->ri_cols + x].attr = attr;
1151: }
1152: for (y = 1; y < num; y++)
1153: ovbcopy(scr->scr_mem + row * ri->ri_cols,
1154: scr->scr_mem + (row + y) * ri->ri_cols,
1155: ri->ri_cols * sizeof(struct wsdisplay_charcell));
1156:
1157: if (scr != scr->scr_sc->sc_active)
1158: return;
1159:
1160: ri->ri_ops.unpack_attr(cookie, attr, &fg, &bg, NULL);
1161: x = ri->ri_xorigin;
1162: y = row * ri->ri_font->fontheight + ri->ri_yorigin;
1163: cx = ri->ri_emuwidth;
1164: cy = num * ri->ri_font->fontheight;
1165: cfxga_solid_fill(scr, x, y, cx, cy, ri->ri_devcmap[bg]);
1166: }
1167:
1168: void
1169: cfxga_putchar(void *cookie, int row, int col, u_int uc, long attr)
1170: {
1171: struct rasops_info *ri = cookie;
1172: struct cfxga_screen *scr = ri->ri_hw;
1173: int x, y;
1174:
1175: scr->scr_mem[row * ri->ri_cols + col].uc = uc;
1176: scr->scr_mem[row * ri->ri_cols + col].attr = attr;
1177:
1178: if (scr != scr->scr_sc->sc_active)
1179: return;
1180:
1181: x = col * ri->ri_font->fontwidth + ri->ri_xorigin;
1182: y = row * ri->ri_font->fontheight + ri->ri_yorigin;
1183:
1184: if (uc == ' ') {
1185: int cx, cy, fg, bg;
1186:
1187: ri->ri_ops.unpack_attr(cookie, attr, &fg, &bg, NULL);
1188: cx = ri->ri_font->fontwidth;
1189: cy = ri->ri_font->fontheight;
1190: cfxga_solid_fill(scr, x, y, cx, cy, ri->ri_devcmap[bg]);
1191: } else {
1192: cfxga_expand_char(scr, uc, x, y, attr);
1193: }
1194: }
CVSweb