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