1 /* $NetBSD: fb.c,v 1.29 2021/08/07 16:19:01 thorpej 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.29 2021/08/07 16:19:01 thorpej Exp $");
31
32 #include <sys/param.h>
33 #include <sys/device.h>
34 #include <sys/ioctl.h>
35 #include <sys/kmem.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
fb_match(device_t parent,cfdata_t cf,void * aux)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
fb_attach(device_t parent,device_t self,void * aux)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 = kmem_zalloc(sizeof(struct fb_devconfig), KM_SLEEP);
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();
159 }
160 sc->sc_dc = dc;
161
162 id = (*ctlreg >> 8) & 0xf;
163 aprint_normal(": %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, CFARGS_NONE);
172 }
173
174 int
fb_common_init(struct fb_devconfig * dc)175 fb_common_init(struct fb_devconfig *dc)
176 {
177 struct rasops_info *ri = &dc->dc_ri;
178 volatile uint16_t *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 default:
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 if (dc == &fb_console_dc)
205 ri->ri_flg |= RI_NO_AUTO;
206
207 rasops_init(ri, 24, 80);
208 rows = (height - 2) / ri->ri_font->fontheight;
209 cols = ((width - 2) / ri->ri_font->fontwidth) & ~7;
210 xoff = ((width - cols * ri->ri_font->fontwidth) / 2 / 8) & ~3;
211 yoff = (height - rows * ri->ri_font->fontheight) / 2;
212 rasops_reconfig(ri, rows, cols);
213
214 ri->ri_xorigin = xoff;
215 ri->ri_yorigin = yoff;
216 ri->ri_bits = dc->dc_fbbase + xoff + ri->ri_stride * yoff;
217
218 fb_stdscreen.nrows = ri->ri_rows;
219 fb_stdscreen.ncols = ri->ri_cols;
220 fb_stdscreen.textops = &ri->ri_ops;
221 fb_stdscreen.capabilities = ri->ri_caps;
222
223 return 0;
224 }
225
226 int
fb_is_console(void)227 fb_is_console(void)
228 {
229 volatile u_int *dipsw = (void *)DIP_SWITCH;
230
231 if (*dipsw & 7) /* XXX right? */
232 return 1;
233
234 return 0;
235 }
236
237 int
fb_ioctl(void * v,void * vs,u_long cmd,void * data,int flag,struct lwp * l)238 fb_ioctl(void *v, void *vs, u_long cmd, void *data, int flag, struct lwp *l)
239 {
240 struct fb_softc *sc = v;
241 struct fb_devconfig *dc = sc->sc_dc;
242 struct wsdisplay_fbinfo *wdf;
243
244 switch (cmd) {
245 case WSDISPLAYIO_GTYPE:
246 *(int *)data = WSDISPLAY_TYPE_UNKNOWN; /* XXX */
247 return 0;
248
249 case WSDISPLAYIO_GINFO:
250 wdf = (void *)data;
251 wdf->height = dc->dc_ri.ri_height;
252 wdf->width = dc->dc_ri.ri_width;
253 wdf->depth = dc->dc_ri.ri_depth;
254 wdf->cmsize = 2;
255 return 0;
256
257 case WSDISPLAYIO_LINEBYTES:
258 *(u_int *)data = dc->dc_ri.ri_stride;
259 return 0;
260
261 case WSDISPLAYIO_SVIDEO:
262 if (*(int *)data == WSDISPLAYIO_VIDEO_OFF) {
263 volatile u_short *ctlreg = NWB253_CTLREG;
264 *ctlreg = 0; /* stop crtc */
265 } else
266 fb253_init();
267 return 0;
268
269 case WSDISPLAYIO_GETCMAP:
270 case WSDISPLAYIO_PUTCMAP:
271 break;
272 }
273 return EPASSTHROUGH;
274 }
275
276 paddr_t
fb_mmap(void * v,void * vs,off_t offset,int prot)277 fb_mmap(void *v, void *vs, off_t offset, int prot)
278 {
279 struct fb_softc *sc = v;
280 struct fb_devconfig *dc = sc->sc_dc;
281
282 if (offset >= 2048 * 2048 / 8 || offset < 0)
283 return -1;
284
285 return mips_btop((int)dc->dc_fbbase + offset);
286 }
287
288 int
fb_alloc_screen(void * v,const struct wsscreen_descr * scrdesc,void ** cookiep,int * ccolp,int * crowp,long * attrp)289 fb_alloc_screen(void *v, const struct wsscreen_descr *scrdesc, void **cookiep,
290 int *ccolp, int *crowp, long *attrp)
291 {
292 struct fb_softc *sc = v;
293 struct rasops_info *ri = &sc->sc_dc->dc_ri;
294 long defattr;
295
296 if (sc->sc_nscreens > 0)
297 return ENOMEM;
298
299 *cookiep = ri;
300 *ccolp = *crowp = 0;
301 (*ri->ri_ops.allocattr)(ri, 0, 0, 0, &defattr);
302 *attrp = defattr;
303 sc->sc_nscreens++;
304
305 return 0;
306 }
307
308 void
fb_free_screen(void * v,void * cookie)309 fb_free_screen(void *v, void *cookie)
310 {
311 struct fb_softc *sc = v;
312
313 if (sc->sc_dc == &fb_console_dc)
314 panic("%s: console", __func__);
315
316 sc->sc_nscreens--;
317 }
318
319 int
fb_show_screen(void * v,void * cookie,int waitok,void (* cb)(void *,int,int),void * cbarg)320 fb_show_screen(void *v, void *cookie, int waitok, void (*cb)(void *, int, int),
321 void *cbarg)
322 {
323
324 return 0;
325 }
326
327 void
fb_cnattach(void)328 fb_cnattach(void)
329 {
330 struct fb_devconfig *dc = &fb_console_dc;
331 struct rasops_info *ri = &dc->dc_ri;
332 long defattr;
333
334 if (!fb_is_console())
335 return;
336
337 dc->dc_fbbase = NWB253_VRAM;
338 fb_common_init(dc);
339
340 (*ri->ri_ops.allocattr)(ri, 0, 0, 0, &defattr);
341 wsdisplay_cnattach(&fb_stdscreen, ri, 0, ri->ri_rows - 1, defattr);
342 }
343
344 static const uint8_t
345 nwp512_data1[] = {
346 0x00, 0x44,
347 0x01, 0x33,
348 0x02, 0x3c,
349 0x03, 0x38,
350 0x04, 0x84,
351 0x05, 0x03,
352 0x06, 0x80,
353 0x07, 0x80,
354 0x08, 0x10,
355 0x09, 0x07,
356 0x0a, 0x20,
357 0x0c, 0x00,
358 0x0d, 0x00,
359 0x1b, 0x03
360 };
361
362 static const uint8_t
363 nwp512_data2[] = {
364 0x1e, 0x08,
365 0x20, 0x08,
366 0x21, 0x0d
367 };
368
369 static const uint8_t
370 nwp518_data1[] = {
371 0x00, 0x52,
372 0x01, 0x40,
373 0x02, 0x4a,
374 0x03, 0x49,
375 0x04, 0x63,
376 0x05, 0x02,
377 0x06, 0x60,
378 0x07, 0x60,
379 0x08, 0x10,
380 0x09, 0x07,
381 0x0a, 0x20,
382 0x0c, 0x00,
383 0x0d, 0x00,
384 0x1b, 0x04
385 };
386
387 static const uint8_t
388 nwp518_data2[] = {
389 0x1e, 0x08,
390 0x20, 0x00,
391 0x21, 0x00
392 };
393
394 static const uint8_t
395 nwe501_data1[] = {
396 0x00, 0x4b,
397 0x01, 0x40,
398 0x02, 0x4a,
399 0x03, 0x43,
400 0x04, 0x64,
401 0x05, 0x02,
402 0x06, 0x60,
403 0x07, 0x60,
404 0x08, 0x10,
405 0x09, 0x07,
406 0x0a, 0x20,
407 0x0c, 0x00,
408 0x0d, 0x00,
409 0x1b, 0x04
410 };
411
412 static const uint8_t
413 nwe501_data2[] = {
414 0x1e, 0x08,
415 0x20, 0x00,
416 0x21, 0x00
417 };
418
419 static const uint8_t
420 *crtc_data[3][2] = {
421 { nwp512_data1, nwp512_data2 },
422 { nwp518_data1, nwp518_data2 },
423 { nwe501_data1, nwe501_data2 }
424 };
425
426 static void
fb253_init(void)427 fb253_init(void)
428 {
429 volatile uint16_t *ctlreg = NWB253_CTLREG;
430 volatile uint16_t *crtreg = NWB253_CRTREG;
431 int id = (*ctlreg >> 8) & 0xf;
432 const uint8_t *p;
433 int i;
434
435 *ctlreg = 0; /* stop crtc */
436 delay(10);
437
438 /* initialize crtc without R3{0,1,2} */
439 p = crtc_data[id][0];
440 for (i = 0; i < 28; i++) {
441 *crtreg++ = *p++;
442 delay(10);
443 }
444
445 *ctlreg = 0x02; /* start crtc */
446 delay(10);
447
448 /* set crtc control reg */
449 p = crtc_data[id][1];
450 for (i = 0; i < 6; i++) {
451 *crtreg++ = *p++;
452 delay(10);
453 }
454 }
455
456 #if 0
457 static struct wsdisplay_font newsrom8x16;
458 static struct wsdisplay_font newsrom12x24;
459 static char fontarea16[96][32];
460 static char fontarea24[96][96];
461
462 void
463 initfont(struct rasops_info *ri)
464 {
465 int c, x;
466
467 for (c = 0; c < 96; c++) {
468 x = ((c & 0x1f) | ((c & 0xe0) << 2)) << 7;
469 memcpy(fontarea16 + c, (char *)0xb8e00000 + x + 96, 32);
470 memcpy(fontarea24 + c, (char *)0xb8e00000 + x, 96);
471 }
472
473 newsrom8x16.name = "rom8x16";
474 newsrom8x16.firstchar = 32;
475 newsrom8x16.numchars = 96;
476 newsrom8x16.encoding = WSDISPLAY_FONTENC_ISO;
477 newsrom8x16.fontwidth = 8;
478 newsrom8x16.fontheight = 16;
479 newsrom8x16.stride = 2;
480 newsrom8x16.bitorder = WSDISPLAY_FONTORDER_L2R;
481 newsrom8x16.byteorder = WSDISPLAY_FONTORDER_L2R;
482 newsrom8x16.data = fontarea16;
483
484 newsrom12x24.name = "rom12x24";
485 newsrom12x24.firstchar = 32;
486 newsrom12x24.numchars = 96;
487 newsrom12x24.encoding = WSDISPLAY_FONTENC_ISO;
488 newsrom12x24.fontwidth = 12;
489 newsrom12x24.fontheight = 24;
490 newsrom12x24.stride = 4;
491 newsrom12x24.bitorder = WSDISPLAY_FONTORDER_L2R;
492 newsrom12x24.byteorder = WSDISPLAY_FONTORDER_L2R;
493 newsrom12x24.data = fontarea24;
494
495 ri->ri_font = &newsrom8x16;
496 ri->ri_font = &newsrom12x24;
497 ri->ri_wsfcookie = -1; /* not using wsfont */
498 }
499 #endif
500