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