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