fb.c revision 1.6 1 /* $NetBSD: fb.c,v 1.6 2000/11/14 15:32:03 tsubai Exp $ */
2
3 /*-
4 * Copyright (c) 2000 Tsubai Masanari. 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 * 3. The name of the author may not be used to endorse or promote products
15 * derived from this software without specific prior written permission.
16 *
17 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
18 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
19 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
20 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
21 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
22 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
23 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
24 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
25 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
26 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
27 */
28
29 #include <sys/param.h>
30 #include <sys/device.h>
31 #include <sys/ioctl.h>
32 #include <sys/malloc.h>
33 #include <sys/systm.h>
34
35 #include <uvm/uvm_extern.h>
36
37 #include <machine/adrsmap.h>
38 #include <machine/autoconf.h>
39
40 #include <dev/wscons/wsconsio.h>
41 #include <dev/wscons/wsdisplayvar.h>
42 #include <dev/rasops/rasops.h>
43
44 struct fb_devconfig {
45 u_char *dc_fbbase; /* VRAM base address */
46 struct rasops_info dc_ri;
47 };
48
49 struct fb_softc {
50 struct device sc_dev;
51 struct fb_devconfig *sc_dc;
52 int sc_nscreens;
53 };
54
55 int fb_match(struct device *, struct cfdata *, void *);
56 void fb_attach(struct device *, struct device *, void *);
57
58 int fb_common_init(struct fb_devconfig *);
59 int fb_is_console(void);
60
61 int fb_ioctl(void *, u_long, caddr_t, int, struct proc *);
62 paddr_t fb_mmap(void *, off_t, int);
63 int fb_alloc_screen(void *, const struct wsscreen_descr *, void **, int *,
64 int *, long *);
65 void fb_free_screen(void *, void *);
66 int fb_show_screen(void *, void *, int, void (*)(void *, int, int), void *);
67
68 void fb_cnattach(void);
69
70 static void fb253_init(int);
71
72 struct cfattach fb_ca = {
73 sizeof(struct fb_softc), fb_match, fb_attach,
74 };
75
76 struct fb_devconfig fb_console_dc;
77
78 struct wsdisplay_accessops fb_accessops = {
79 fb_ioctl,
80 fb_mmap,
81 fb_alloc_screen,
82 fb_free_screen,
83 fb_show_screen,
84 NULL /* load_font */
85 };
86
87 struct wsscreen_descr fb_stdscreen = {
88 "std",
89 0, 0,
90 0,
91 0, 0,
92 WSSCREEN_REVERSE
93 };
94
95 const struct wsscreen_descr *fb_scrlist[] = {
96 &fb_stdscreen
97 };
98
99 struct wsscreen_list fb_screenlist = {
100 sizeof(fb_scrlist) / sizeof(fb_scrlist[0]), fb_scrlist
101 };
102
103 #define NWB253_VRAM ((u_char *) 0x88000000)
104 #define NWB253_CTLREG ((u_short *)0xb8ff0000)
105 #define NWB253_CRTREG ((u_short *)0xb8fe0000)
106
107 static char *devname[8] = { "NWB-512", "NWB-518", "NWE-501" }; /* XXX ? */
108
109 int
110 fb_match(parent, match, aux)
111 struct device *parent;
112 struct cfdata *match;
113 void *aux;
114 {
115 struct confargs *ca = aux;
116
117 if (strcmp(ca->ca_name, "fb") != 0)
118 return 0;
119
120 if (badaddr(NWB253_CTLREG, 2) || badaddr(NWB253_CRTREG, 2))
121 return 0;
122 if ((*(volatile u_short *)NWB253_CTLREG & 7) != 4)
123 return 0;
124
125 return 1;
126 }
127
128 void
129 fb_attach(parent, self, aux)
130 struct device *parent, *self;
131 void *aux;
132 {
133 struct fb_softc *sc = (void *)self;
134 struct wsemuldisplaydev_attach_args waa;
135 struct fb_devconfig *dc;
136 struct rasops_info *ri;
137 int console;
138 volatile u_short *ctlreg = NWB253_CTLREG;
139 int id;
140
141 console = fb_is_console();
142
143 if (console) {
144 dc = &fb_console_dc;
145 ri = &dc->dc_ri;
146 sc->sc_nscreens = 1;
147 } else {
148 dc = malloc(sizeof(struct fb_devconfig), M_DEVBUF, M_WAITOK);
149 bzero(dc, sizeof(struct fb_devconfig));
150
151 dc->dc_fbbase = NWB253_VRAM;
152 fb_common_init(dc);
153 ri = &dc->dc_ri;
154
155 /* clear screen */
156 (*ri->ri_ops.eraserows)(ri, 0, ri->ri_rows, 0);
157
158 fb253_init(id);
159 }
160 sc->sc_dc = dc;
161
162 id = (*ctlreg >> 8) & 0xf;
163 printf(": %s, %d x %d, %dbpp\n", devname[id],
164 ri->ri_width, ri->ri_height, ri->ri_depth);
165
166 waa.console = console;
167 waa.scrdata = &fb_screenlist;
168 waa.accessops = &fb_accessops;
169 waa.accesscookie = sc;
170
171 config_found(self, &waa, wsemuldisplaydevprint);
172 }
173
174 int
175 fb_common_init(dc)
176 struct fb_devconfig *dc;
177 {
178 struct rasops_info *ri = &dc->dc_ri;
179 volatile u_short *ctlreg = NWB253_CTLREG;
180 int id;
181 int width, height, xoff, yoff, cols, rows;
182
183 id = (*ctlreg >> 8) & 0xf;
184
185 /* initialize rasops */
186 switch (id) {
187 case 0:
188 width = 816;
189 height = 1024;
190 break;
191 case 1:
192 case 2:
193 width = 1024;
194 height = 768;
195 break;
196 }
197
198 ri->ri_width = width;
199 ri->ri_height = height;
200 ri->ri_depth = 1;
201 ri->ri_stride = 2048 / 8;
202 ri->ri_bits = dc->dc_fbbase;
203 ri->ri_flg = RI_FULLCLEAR;
204
205 rasops_init(ri, 24, 80);
206 rows = (height - 2) / ri->ri_font->fontheight;
207 cols = ((width - 2) / ri->ri_font->fontwidth) & ~7;
208 xoff = ((width - cols * ri->ri_font->fontwidth) / 2 / 8) & ~3;
209 yoff = (height - rows * ri->ri_font->fontheight) / 2;
210 rasops_reconfig(ri, rows, cols);
211
212 ri->ri_xorigin = xoff;
213 ri->ri_yorigin = yoff;
214 ri->ri_bits = dc->dc_fbbase + xoff + ri->ri_stride * yoff;
215
216 fb_stdscreen.nrows = ri->ri_rows;
217 fb_stdscreen.ncols = ri->ri_cols;
218 fb_stdscreen.textops = &ri->ri_ops;
219 fb_stdscreen.capabilities = ri->ri_caps;
220
221 return 0;
222 }
223
224 int
225 fb_is_console()
226 {
227 volatile u_int *dipsw = (void *)DIP_SWITCH;
228
229 if (*dipsw & 7) /* XXX right? */
230 return 1;
231
232 return 0;
233 }
234
235 int
236 fb_ioctl(v, cmd, data, flag, p)
237 void *v;
238 u_long cmd;
239 caddr_t data;
240 int flag;
241 struct proc *p;
242 {
243 struct fb_softc *sc = v;
244 struct fb_devconfig *dc = sc->sc_dc;
245 struct wsdisplay_fbinfo *wdf;
246
247 switch (cmd) {
248 case WSDISPLAYIO_GTYPE:
249 *(int *)data = WSDISPLAY_TYPE_UNKNOWN; /* XXX */
250 return 0;
251
252 case WSDISPLAYIO_GINFO:
253 wdf = (void *)data;
254 wdf->height = dc->dc_ri.ri_height;
255 wdf->width = dc->dc_ri.ri_width;
256 wdf->depth = dc->dc_ri.ri_depth;
257 wdf->cmsize = 2;
258 return 0;
259
260 case WSDISPLAYIO_SVIDEO:
261 if (*(int *)data == WSDISPLAYIO_VIDEO_OFF) {
262 volatile u_short *ctlreg = NWB253_CTLREG;
263 *ctlreg = 0; /* stop crtc */
264 } else {
265 volatile u_short *ctlreg = NWB253_CTLREG;
266 int id = (*ctlreg >> 8) & 0xf;
267 fb253_init(id);
268 }
269 return 0;
270
271 case WSDISPLAYIO_GETCMAP:
272 case WSDISPLAYIO_PUTCMAP:
273 }
274 return -1;
275 }
276
277 paddr_t
278 fb_mmap(v, offset, prot)
279 void *v;
280 off_t offset;
281 int prot;
282 {
283 struct fb_softc *sc = v;
284 struct fb_devconfig *dc = sc->sc_dc;
285 struct rasops_info *ri = &dc->dc_ri;
286
287 if (offset >= 2048 * 2048 / 8 || offset < 0)
288 return -1;
289
290 return mips_btop((int)dc->dc_fbbase + offset);
291 }
292
293 int
294 fb_alloc_screen(v, scrdesc, cookiep, ccolp, crowp, attrp)
295 void *v;
296 const struct wsscreen_descr *scrdesc;
297 void **cookiep;
298 int *ccolp, *crowp;
299 long *attrp;
300 {
301 struct fb_softc *sc = v;
302 struct rasops_info *ri = &sc->sc_dc->dc_ri;
303 long defattr;
304
305 if (sc->sc_nscreens > 0)
306 return ENOMEM;
307
308 *cookiep = ri;
309 *ccolp = *crowp = 0;
310 (*ri->ri_ops.alloc_attr)(ri, 0, 0, 0, &defattr);
311 *attrp = defattr;
312 sc->sc_nscreens++;
313
314 return 0;
315 }
316
317 void
318 fb_free_screen(v, cookie)
319 void *v;
320 void *cookie;
321 {
322 struct fb_softc *sc = v;
323
324 if (sc->sc_dc == &fb_console_dc)
325 panic("fb_free_screen: console");
326
327 sc->sc_nscreens--;
328 }
329
330 int
331 fb_show_screen(v, cookie, waitok, cb, cbarg)
332 void *v;
333 void *cookie;
334 int waitok;
335 void (*cb)(void *, int, int);
336 void *cbarg;
337 {
338 return 0;
339 }
340
341 void
342 fb_cnattach()
343 {
344 struct fb_devconfig *dc = &fb_console_dc;
345 struct rasops_info *ri = &dc->dc_ri;
346 long defattr;
347
348 if (!fb_is_console())
349 return;
350
351 dc->dc_fbbase = NWB253_VRAM;
352 fb_common_init(dc);
353
354 (*ri->ri_ops.alloc_attr)(ri, 0, 0, 0, &defattr);
355 wsdisplay_cnattach(&fb_stdscreen, ri, 0, ri->ri_rows - 1, defattr);
356 }
357
358 static u_char
359 nwp512_data1[] = {
360 0x00, 0x44,
361 0x01, 0x33,
362 0x02, 0x3c,
363 0x03, 0x38,
364 0x04, 0x84,
365 0x05, 0x03,
366 0x06, 0x80,
367 0x07, 0x80,
368 0x08, 0x10,
369 0x09, 0x07,
370 0x0a, 0x20,
371 0x0c, 0x00,
372 0x0d, 0x00,
373 0x1b, 0x03
374 };
375
376 static u_char
377 nwp512_data2[] = {
378 0x1e, 0x08,
379 0x20, 0x08,
380 0x21, 0x0d
381 };
382
383 static u_char
384 nwp518_data1[] = {
385 0x00, 0x52,
386 0x01, 0x40,
387 0x02, 0x4a,
388 0x03, 0x49,
389 0x04, 0x63,
390 0x05, 0x02,
391 0x06, 0x60,
392 0x07, 0x60,
393 0x08, 0x10,
394 0x09, 0x07,
395 0x0a, 0x20,
396 0x0c, 0x00,
397 0x0d, 0x00,
398 0x1b, 0x04
399 };
400
401 static u_char
402 nwp518_data2[] = {
403 0x1e, 0x08,
404 0x20, 0x00,
405 0x21, 0x00
406 };
407
408 static u_char
409 nwe501_data1[] = {
410 0x00, 0x4b,
411 0x01, 0x40,
412 0x02, 0x4a,
413 0x03, 0x43,
414 0x04, 0x64,
415 0x05, 0x02,
416 0x06, 0x60,
417 0x07, 0x60,
418 0x08, 0x10,
419 0x09, 0x07,
420 0x0a, 0x20,
421 0x0c, 0x00,
422 0x0d, 0x00,
423 0x1b, 0x04
424 };
425
426 static u_char
427 nwe501_data2[] = {
428 0x1e, 0x08,
429 0x20, 0x00,
430 0x21, 0x00
431 };
432
433 static u_char
434 *crtc_data[3][2] = {
435 { nwp512_data1, nwp512_data2 },
436 { nwp518_data1, nwp518_data2 },
437 { nwe501_data1, nwe501_data2 }
438 };
439
440 static void
441 fb253_init(id)
442 int id;
443 {
444 volatile u_short *ctlreg = NWB253_CTLREG;
445 volatile u_short *crtreg = NWB253_CRTREG;
446 u_char *p;
447 int i;
448
449 *ctlreg = 0; /* stop crtc */
450 delay(10);
451
452 /* initialize crtc without R3{0,1,2} */
453 p = crtc_data[id][0];
454 for (i = 0; i < 28; i++) {
455 *crtreg++ = *p++;
456 delay(10);
457 }
458
459 *ctlreg = 0x02; /* start crtc */
460 delay(10);
461
462 /* set crtc control reg */
463 p = crtc_data[id][1];
464 for (i = 0; i < 6; i++) {
465 *crtreg++ = *p++;
466 delay(10);
467 }
468 }
469
470 #if 0
471 static struct wsdisplay_font newsrom8x16;
472 static struct wsdisplay_font newsrom12x24;
473 static char fontarea16[96][32];
474 static char fontarea24[96][96];
475
476 void
477 initfont(ri)
478 struct rasops_info *ri;
479 {
480 int c, x;
481
482 for (c = 0; c < 96; c++) {
483 x = ((c & 0x1f) | ((c & 0xe0) << 2)) << 7;
484 bcopy((char *)0xb8e00000 + x + 96, fontarea16 + c, 32);
485 bcopy((char *)0xb8e00000 + x, fontarea24 + c, 96);
486 }
487
488 newsrom8x16.name = "rom8x16";
489 newsrom8x16.firstchar = 32;
490 newsrom8x16.numchars = 96;
491 newsrom8x16.encoding = WSDISPLAY_FONTENC_ISO;
492 newsrom8x16.fontwidth = 8;
493 newsrom8x16.fontheight = 16;
494 newsrom8x16.stride = 2;
495 newsrom8x16.bitorder = WSDISPLAY_FONTORDER_L2R;
496 newsrom8x16.byteorder = WSDISPLAY_FONTORDER_L2R;
497 newsrom8x16.data = fontarea16;
498
499 newsrom12x24.name = "rom12x24";
500 newsrom12x24.firstchar = 32;
501 newsrom12x24.numchars = 96;
502 newsrom12x24.encoding = WSDISPLAY_FONTENC_ISO;
503 newsrom12x24.fontwidth = 12;
504 newsrom12x24.fontheight = 24;
505 newsrom12x24.stride = 4;
506 newsrom12x24.bitorder = WSDISPLAY_FONTORDER_L2R;
507 newsrom12x24.byteorder = WSDISPLAY_FONTORDER_L2R;
508 newsrom12x24.data = fontarea24;
509
510 ri->ri_font = &newsrom8x16;
511 ri->ri_font = &newsrom12x24;
512 ri->ri_wsfcookie = -1; /* not using wsfont */
513 }
514 #endif
515