Annotation of sys/arch/vax/vsa/lcspx.c, Revision 1.1.1.1
1.1 nbrk 1: /* $OpenBSD: lcspx.c,v 1.11 2006/11/29 12:13:54 miod Exp $ */
2: /*
3: * Copyright (c) 2006 Miodrag Vallat.
4: *
5: * Permission to use, copy, modify, and distribute this software for any
6: * purpose with or without fee is hereby granted, provided that the above
7: * copyright notice, this permission notice, and the disclaimer below
8: * appear in all copies.
9: *
10: * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
11: * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
12: * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR 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: * Copyright (c) 2004 Blaz Antonic
20: * All rights reserved.
21: *
22: * This software contains code written by Michael L. Hitch.
23: *
24: * Redistribution and use in source and binary forms, with or without
25: * modification, are permitted provided that the following conditions
26: * are met:
27: * 1. Redistributions of source code must retain the above copyright
28: * notice, this list of conditions and the following disclaimer.
29: * 2. Redistributions in binary form must reproduce the above copyright
30: * notice, this list of conditions and the following disclaimer in the
31: * documentation and/or other materials provided with the distribution.
32: * 3. All advertising materials mentioning features or use of this software
33: * must display the abovementioned copyrights
34: * 4. The name of the author may not be used to endorse or promote products
35: * derived from this software without specific prior written permission
36: *
37: * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
38: * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
39: * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
40: * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
41: * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
42: * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
43: * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
44: * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
45: * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
46: * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
47: */
48:
49: #include <sys/param.h>
50: #include <sys/device.h>
51: #include <sys/systm.h>
52: #include <sys/malloc.h>
53: #include <sys/conf.h>
54: #include <sys/kernel.h>
55:
56: #include <machine/nexus.h>
57: #include <machine/vsbus.h>
58: #include <machine/scb.h>
59: #include <machine/sid.h>
60: #include <machine/cpu.h>
61:
62: #include <uvm/uvm_extern.h>
63:
64: #include <dev/cons.h>
65:
66: #include <dev/wscons/wsconsio.h>
67: #include <dev/wscons/wsdisplayvar.h>
68: #include <dev/rasops/rasops.h>
69:
70: #include <dev/ic/bt463reg.h> /* actually it's a 459 here... */
71:
72: #define LCSPX_REG_ADDR 0x39302000 /* registers */
73: #define LCSPX_REG_SIZE 0x2000
74: #define LCSPX_REG1_ADDR 0x39b00000 /* more registers */
75: #define LCSPX_RAMDAC_ADDR 0x39b10000 /* RAMDAC */
76: #define LCSPX_RAMDAC_INTERLEAVE 0x00004000
77: #define LCSPX_FB_ADDR 0x38000000 /* frame buffer */
78:
79: #define LCSPX_WIDTH 1280
80: #define LCSPX_HEIGHT 1024
81: #define LCSPX_FBSIZE (LCSPX_WIDTH * LCSPX_HEIGHT)
82:
83: void lcspx_attach(struct device *, struct device *, void *);
84: int lcspx_vsbus_match(struct device *, void *, void *);
85: int lcspx_vxtbus_match(struct device *, void *, void *);
86:
87: struct lcspx_screen {
88: struct rasops_info ss_ri;
89: caddr_t ss_addr; /* frame buffer address */
90: volatile u_int8_t *ss_ramdac[4];
91: vaddr_t ss_reg;
92: u_int8_t ss_cmap[256 * 3];
93: };
94:
95: #define lcspx_reg_read(ss, reg) \
96: *(volatile u_int32_t *)((ss)->ss_reg + (reg))
97: #define lcspx_reg_write(ss, reg, val) \
98: *(volatile u_int32_t *)((ss)->ss_reg + (reg)) = (val)
99:
100: /* for console */
101: struct lcspx_screen lcspx_consscr;
102:
103: struct lcspx_softc {
104: struct device sc_dev;
105: struct lcspx_screen *sc_scr;
106: int sc_nscreens;
107: };
108:
109: struct cfattach lcspx_vsbus_ca = {
110: sizeof(struct lcspx_softc), lcspx_vsbus_match, lcspx_attach,
111: };
112:
113: struct cfattach lcspx_vxtbus_ca = {
114: sizeof(struct lcspx_softc), lcspx_vxtbus_match, lcspx_attach,
115: };
116:
117: struct cfdriver lcspx_cd = {
118: NULL, "lcspx", DV_DULL
119: };
120:
121: struct wsscreen_descr lcspx_stdscreen = {
122: "std",
123: };
124:
125: const struct wsscreen_descr *_lcspx_scrlist[] = {
126: &lcspx_stdscreen,
127: };
128:
129: const struct wsscreen_list lcspx_screenlist = {
130: sizeof(_lcspx_scrlist) / sizeof(struct wsscreen_descr *),
131: _lcspx_scrlist,
132: };
133:
134: int lcspx_ioctl(void *, u_long, caddr_t, int, struct proc *);
135: paddr_t lcspx_mmap(void *, off_t, int);
136: int lcspx_alloc_screen(void *, const struct wsscreen_descr *,
137: void **, int *, int *, long *);
138: void lcspx_free_screen(void *, void *);
139: int lcspx_show_screen(void *, void *, int,
140: void (*) (void *, int, int), void *);
141:
142: const struct wsdisplay_accessops lcspx_accessops = {
143: lcspx_ioctl,
144: lcspx_mmap,
145: lcspx_alloc_screen,
146: lcspx_free_screen,
147: lcspx_show_screen,
148: NULL, /* load_font */
149: NULL, /* scrollback */
150: NULL, /* getchar */
151: NULL /* burner */
152: };
153:
154: int lcspx_getcmap(struct lcspx_screen *, struct wsdisplay_cmap *);
155: void lcspx_loadcmap(struct lcspx_screen *, int, int);
156: int lcspx_putcmap(struct lcspx_screen *, struct wsdisplay_cmap *);
157: static __inline__
158: void lcspx_ramdac_wraddr(struct lcspx_screen *, u_int);
159: void lcspx_resetcmap(struct lcspx_screen *);
160: int lcspx_setup_screen(struct lcspx_screen *);
161:
162: int
163: lcspx_vsbus_match(struct device *parent, void *vcf, void *aux)
164: {
165: struct vsbus_softc *sc = (void *)parent;
166: struct vsbus_attach_args *va = aux;
167:
168: switch (vax_boardtype) {
169: default:
170: return (0);
171:
172: case VAX_BTYP_49:
173: if (va->va_paddr != LCSPX_REG_ADDR)
174: return (0);
175:
176: if ((vax_confdata & 0x12) != 0x02)
177: return (0);
178:
179: break;
180: }
181:
182: sc->sc_mask = 0x04; /* XXX - should be generated */
183: scb_fake(0x120, 0x15);
184: return (20);
185: }
186:
187: int
188: lcspx_vxtbus_match(struct device *parent, void *vcf, void *aux)
189: {
190: struct bp_conf *bp = aux;
191: int missing;
192: volatile u_int8_t *ch;
193:
194: if (strcmp(bp->type, lcspx_cd.cd_name) != 0)
195: return (0);
196:
197: /*
198: * Check for video memory at SPX address.
199: */
200: missing = 0;
201: ch = (volatile u_int8_t *)vax_map_physmem(LCSPX_FB_ADDR, 1);
202: *ch = 0x01;
203: if ((*ch & 0x01) == 0)
204: missing = 1;
205: else {
206: *ch = 0x00;
207: if ((*ch & 0x01) != 0)
208: missing = 1;
209: }
210: vax_unmap_physmem((vaddr_t)ch, 1);
211:
212: return (missing ? 0 : 1);
213: }
214:
215: void
216: lcspx_attach(struct device *parent, struct device *self, void *aux)
217: {
218: struct lcspx_softc *sc = (struct lcspx_softc *)self;
219: struct lcspx_screen *ss;
220: struct wsemuldisplaydev_attach_args aa;
221: int i, console;
222: extern struct consdev wsdisplay_cons;
223:
224: if (cn_tab == &wsdisplay_cons) {
225: if (vax_boardtype == VAX_BTYP_49)
226: console = (vax_confdata & 8) == 0;
227: else /* VXT2000 */
228: console = (vax_confdata & 2) != 0;
229: } else
230: console = 0;
231: if (console) {
232: ss = &lcspx_consscr;
233: sc->sc_nscreens = 1;
234: } else {
235: ss = malloc(sizeof(struct lcspx_screen), M_DEVBUF, M_NOWAIT);
236: if (ss == NULL) {
237: printf(": can not allocate memory\n");
238: return;
239: }
240: bzero(ss, sizeof(struct lcspx_screen));
241:
242: ss->ss_addr = (caddr_t)vax_map_physmem(LCSPX_FB_ADDR,
243: LCSPX_FBSIZE / VAX_NBPG);
244: if (ss->ss_addr == NULL) {
245: printf(": can not map frame buffer\n");
246: goto fail1;
247: }
248:
249: ss->ss_reg = vax_map_physmem(LCSPX_REG_ADDR,
250: LCSPX_REG_SIZE / VAX_NBPG);
251: if (ss->ss_reg == 0L) {
252: printf(": can not map registers\n");
253: goto fail2;
254: }
255:
256: for (i = 0; i < 4; i++) {
257: ss->ss_ramdac[i] = (volatile u_int8_t *)vax_map_physmem(
258: LCSPX_RAMDAC_ADDR + i * LCSPX_RAMDAC_INTERLEAVE, 1);
259: if (ss->ss_ramdac[i] == NULL) {
260: printf(": can not map RAMDAC registers\n");
261: goto fail3;
262: }
263: }
264:
265: if (lcspx_setup_screen(ss) != 0) {
266: printf(": initialization failed\n");
267: goto fail3;
268: }
269: }
270: sc->sc_scr = ss;
271:
272: printf("\n%s: 1280x1024x8 frame buffer\n", self->dv_xname);
273:
274: aa.console = console;
275: aa.scrdata = &lcspx_screenlist;
276: aa.accessops = &lcspx_accessops;
277: aa.accesscookie = sc;
278: aa.defaultscreens = 0;
279:
280: config_found(self, &aa, wsemuldisplaydevprint);
281: return;
282:
283: fail3:
284: for (i = 0; i < 4; i++)
285: if (ss->ss_ramdac[i] != NULL)
286: vax_unmap_physmem((vaddr_t)ss->ss_ramdac[i], 1);
287: vax_unmap_physmem(ss->ss_reg, LCSPX_REG_SIZE / VAX_NBPG);
288: fail2:
289: vax_unmap_physmem((vaddr_t)ss->ss_addr, LCSPX_FBSIZE / VAX_NBPG);
290: fail1:
291: free(ss, M_DEVBUF);
292: }
293:
294: static __inline__ void
295: lcspx_ramdac_wraddr(struct lcspx_screen *ss, u_int addr)
296: {
297: *(ss->ss_ramdac[BT463_REG_ADDR_LOW]) = addr & 0xff;
298: *(ss->ss_ramdac[BT463_REG_ADDR_HIGH]) = (addr >> 8) & 0xff;
299: }
300:
301: /*
302: * Initialize anything necessary for an emulating wsdisplay to work (i.e.
303: * pick a font, initialize a rasops structure, setup the accessops callbacks.)
304: */
305: int
306: lcspx_setup_screen(struct lcspx_screen *ss)
307: {
308: struct rasops_info *ri = &ss->ss_ri;
309:
310: bzero(ri, sizeof(*ri));
311: ri->ri_depth = 8;
312: ri->ri_width = LCSPX_WIDTH;
313: ri->ri_height = LCSPX_HEIGHT;
314: ri->ri_stride = LCSPX_WIDTH;
315: ri->ri_flg = RI_CLEAR | RI_CENTER;
316: ri->ri_bits = (void *)ss->ss_addr;
317: ri->ri_hw = ss;
318:
319: /*
320: * Enable all planes for reading and writing
321: */
322: lcspx_reg_write(ss, 0x1170, 0xffffffff);
323: lcspx_reg_write(ss, 0x1174, 0xffffffff);
324: lcspx_ramdac_wraddr(ss, 0x0204); /* plane mask */
325: *(ss->ss_ramdac[BT463_REG_IREG_DATA]) = 0xff;
326:
327: /*
328: * Ask for an unholy big display, rasops will trim this to more
329: * reasonable values.
330: */
331: if (rasops_init(ri, 160, 160) != 0)
332: return (-1);
333:
334: lcspx_resetcmap(ss);
335:
336: lcspx_stdscreen.ncols = ri->ri_cols;
337: lcspx_stdscreen.nrows = ri->ri_rows;
338: lcspx_stdscreen.textops = &ri->ri_ops;
339: lcspx_stdscreen.fontwidth = ri->ri_font->fontwidth;
340: lcspx_stdscreen.fontheight = ri->ri_font->fontheight;
341: lcspx_stdscreen.capabilities = ri->ri_caps;
342:
343: return (0);
344: }
345:
346: int
347: lcspx_ioctl(void *v, u_long cmd, caddr_t data, int flag, struct proc *p)
348: {
349: struct lcspx_softc *sc = v;
350: struct lcspx_screen *ss = sc->sc_scr;
351: struct wsdisplay_fbinfo *wdf;
352: struct wsdisplay_cmap *cm;
353: int error;
354:
355: switch (cmd) {
356: case WSDISPLAYIO_GTYPE:
357: *(u_int *)data = WSDISPLAY_TYPE_LCSPX;
358: break;
359:
360: case WSDISPLAYIO_GINFO:
361: wdf = (struct wsdisplay_fbinfo *)data;
362: wdf->height = LCSPX_HEIGHT;
363: wdf->width = LCSPX_WIDTH;
364: wdf->depth = 8;
365: wdf->cmsize = 256;
366: break;
367:
368: case WSDISPLAYIO_LINEBYTES:
369: *(u_int *)data = ss->ss_ri.ri_stride;
370: break;
371:
372: case WSDISPLAYIO_GETCMAP:
373: cm = (struct wsdisplay_cmap *)data;
374: error = lcspx_getcmap(ss, cm);
375: if (error != 0)
376: return (error);
377: break;
378: case WSDISPLAYIO_PUTCMAP:
379: cm = (struct wsdisplay_cmap *)data;
380: error = lcspx_putcmap(ss, cm);
381: if (error != 0)
382: return (error);
383: lcspx_loadcmap(ss, cm->index, cm->count);
384: break;
385:
386: case WSDISPLAYIO_GVIDEO:
387: case WSDISPLAYIO_SVIDEO:
388: break;
389:
390: default:
391: return (-1);
392: }
393:
394: return (0);
395: }
396:
397: paddr_t
398: lcspx_mmap(void *v, off_t offset, int prot)
399: {
400: if (offset >= LCSPX_FBSIZE || offset < 0)
401: return (-1);
402:
403: return (LCSPX_FB_ADDR + offset) >> PGSHIFT;
404: }
405:
406: int
407: lcspx_alloc_screen(void *v, const struct wsscreen_descr *type, void **cookiep,
408: int *curxp, int *curyp, long *defattrp)
409: {
410: struct lcspx_softc *sc = v;
411: struct lcspx_screen *ss = sc->sc_scr;
412: struct rasops_info *ri = &ss->ss_ri;
413:
414: if (sc->sc_nscreens > 0)
415: return (ENOMEM);
416:
417: *cookiep = ri;
418: *curxp = *curyp = 0;
419: ri->ri_ops.alloc_attr(ri, 0, 0, 0, defattrp);
420: sc->sc_nscreens++;
421:
422: return (0);
423: }
424:
425: void
426: lcspx_free_screen(void *v, void *cookie)
427: {
428: struct lcspx_softc *sc = v;
429:
430: sc->sc_nscreens--;
431: }
432:
433: int
434: lcspx_show_screen(void *v, void *cookie, int waitok,
435: void (*cb)(void *, int, int), void *cbarg)
436: {
437: return (0);
438: }
439:
440: /*
441: * Colormap handling routines
442: */
443:
444: int
445: lcspx_getcmap(struct lcspx_screen *ss, struct wsdisplay_cmap *cm)
446: {
447: u_int index = cm->index, count = cm->count, i;
448: int error;
449: u_int8_t ramp[256], *c, *r;
450:
451: if (index >= 256 || count > 256 - index)
452: return (EINVAL);
453:
454: /* extract reds */
455: c = ss->ss_cmap + 0 + index * 3;
456: for (i = count, r = ramp; i != 0; i--)
457: *r++ = *c, c += 3;
458: if ((error = copyout(ramp, cm->red, count)) != 0)
459: return (error);
460:
461: /* extract greens */
462: c = ss->ss_cmap + 1 + index * 3;
463: for (i = count, r = ramp; i != 0; i--)
464: *r++ = *c, c += 3;
465: if ((error = copyout(ramp, cm->green, count)) != 0)
466: return (error);
467:
468: /* extract blues */
469: c = ss->ss_cmap + 2 + index * 3;
470: for (i = count, r = ramp; i != 0; i--)
471: *r++ = *c, c += 3;
472: if ((error = copyout(ramp, cm->blue, count)) != 0)
473: return (error);
474:
475: return (0);
476: }
477:
478: int
479: lcspx_putcmap(struct lcspx_screen *ss, struct wsdisplay_cmap *cm)
480: {
481: u_int index = cm->index, count = cm->count;
482: int i, error;
483: u_int8_t r[256], g[256], b[256], *nr, *ng, *nb, *c;
484:
485: if (index >= 256 || count > 256 - index)
486: return (EINVAL);
487:
488: if ((error = copyin(cm->red, r, count)) != 0)
489: return (error);
490: if ((error = copyin(cm->green, g, count)) != 0)
491: return (error);
492: if ((error = copyin(cm->blue, b, count)) != 0)
493: return (error);
494:
495: nr = r, ng = g, nb = b;
496: c = ss->ss_cmap + index * 3;
497: for (i = count; i != 0; i--) {
498: *c++ = *nr++;
499: *c++ = *ng++;
500: *c++ = *nb++;
501: }
502:
503: return (0);
504: }
505:
506: void
507: lcspx_loadcmap(struct lcspx_screen *ss, int from, int count)
508: {
509: u_int8_t *cmap = ss->ss_cmap;
510: int i;
511:
512: cmap += from * 3;
513: for (i = from; i < from + count; i++) {
514: /*
515: * Reprogram the index every iteration, because the RAMDAC
516: * may not be in autoincrement mode. XXX fix this
517: */
518: lcspx_ramdac_wraddr(ss, i);
519: *(ss->ss_ramdac[BT463_REG_CMAP_DATA]) = *cmap++;
520: *(ss->ss_ramdac[BT463_REG_CMAP_DATA]) = *cmap++;
521: *(ss->ss_ramdac[BT463_REG_CMAP_DATA]) = *cmap++;
522: }
523: }
524:
525: void
526: lcspx_resetcmap(struct lcspx_screen *ss)
527: {
528: bcopy(rasops_cmap, ss->ss_cmap, sizeof(ss->ss_cmap));
529: lcspx_loadcmap(ss, 0, 256);
530: }
531:
532: /*
533: * Console support code
534: */
535:
536: int lcspxcnprobe(void);
537: void lcspxcninit(void);
538:
539: int
540: lcspxcnprobe()
541: {
542: extern vaddr_t virtual_avail;
543: volatile u_int8_t *ch;
544:
545: switch (vax_boardtype) {
546: case VAX_BTYP_49:
547: if ((vax_confdata & 8) != 0)
548: break; /* doesn't use graphics console */
549:
550: if ((vax_confdata & 0x12) != 0x02)
551: return (0);
552:
553: return (1);
554:
555: case VAX_BTYP_VXT:
556: if ((vax_confdata & 2) == 0)
557: break; /* doesn't use graphics console */
558:
559: /*
560: * Check for video memory at SPX address.
561: */
562: ioaccess(virtual_avail, LCSPX_FB_ADDR, 1);
563: ch = (volatile u_int8_t *)virtual_avail;
564: *ch = 0x01;
565: if ((*ch & 0x01) == 0)
566: break;
567: *ch = 0x00;
568: if ((*ch & 0x01) != 0)
569: break;
570:
571: return (1);
572:
573: default:
574: break;
575: }
576:
577: return (0);
578: }
579:
580: /*
581: * Called very early to setup the glass tty as console.
582: * Because it's called before the VM system is initialized, virtual memory
583: * for the framebuffer can be stolen directly without disturbing anything.
584: */
585: void
586: lcspxcninit()
587: {
588: struct lcspx_screen *ss = &lcspx_consscr;
589: extern vaddr_t virtual_avail;
590: int i;
591: long defattr;
592: struct rasops_info *ri;
593:
594: ss->ss_addr = (caddr_t)virtual_avail;
595: virtual_avail += LCSPX_FBSIZE;
596: ioaccess((vaddr_t)ss->ss_addr, LCSPX_FB_ADDR, LCSPX_FBSIZE / VAX_NBPG);
597:
598: ss->ss_reg = virtual_avail;
599: virtual_avail += LCSPX_REG_SIZE;
600: ioaccess(ss->ss_reg, LCSPX_REG_ADDR, LCSPX_REG_SIZE / VAX_NBPG);
601:
602: for (i = 0; i < 4; i++) {
603: ss->ss_ramdac[i] = (volatile u_int8_t *)virtual_avail;
604: virtual_avail += VAX_NBPG;
605: ioaccess((vaddr_t)ss->ss_ramdac[i],
606: LCSPX_RAMDAC_ADDR + i * LCSPX_RAMDAC_INTERLEAVE, 1);
607: }
608:
609: virtual_avail = round_page(virtual_avail);
610:
611: /* this had better not fail as we can't recover there */
612: if (lcspx_setup_screen(ss) != 0)
613: panic(__func__);
614:
615: ri = &ss->ss_ri;
616: ri->ri_ops.alloc_attr(ri, 0, 0, 0, &defattr);
617: wsdisplay_cnattach(&lcspx_stdscreen, ri, 0, 0, defattr);
618: }
CVSweb