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