xref: /freebsd/sys/powerpc/ofw/ofw_syscons.c (revision ce3adf4362fcca6a43e500b2531f0038adbfbd21)
1 /*-
2  * Copyright (c) 2003 Peter Grehan
3  * All rights reserved.
4  *
5  * Redistribution and use in source and binary forms, with or without
6  * modification, are permitted provided that the following conditions
7  * are met:
8  * 1. Redistributions of source code must retain the above copyright
9  *    notice, this list of conditions and the following disclaimer.
10  * 2. Redistributions in binary form must reproduce the above copyright
11  *    notice, this list of conditions and the following disclaimer in the
12  *    documentation and/or other materials provided with the distribution.
13  *
14  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
15  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
16  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
17  * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
18  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
19  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
20  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
21  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
22  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
23  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
24  * SUCH DAMAGE.
25  */
26 
27 #include <sys/cdefs.h>
28 __FBSDID("$FreeBSD$");
29 
30 #include <sys/param.h>
31 #include <sys/systm.h>
32 #include <sys/module.h>
33 #include <sys/bus.h>
34 #include <sys/kernel.h>
35 #include <sys/sysctl.h>
36 #include <sys/limits.h>
37 #include <sys/conf.h>
38 #include <sys/cons.h>
39 #include <sys/proc.h>
40 #include <sys/fcntl.h>
41 #include <sys/malloc.h>
42 #include <sys/fbio.h>
43 #include <sys/consio.h>
44 
45 #include <machine/bus.h>
46 #include <machine/sc_machdep.h>
47 #include <machine/vm.h>
48 
49 #include <sys/rman.h>
50 
51 #include <dev/fb/fbreg.h>
52 #include <dev/syscons/syscons.h>
53 
54 #include <dev/ofw/openfirm.h>
55 #include <dev/ofw/ofw_bus.h>
56 #include <dev/ofw/ofw_pci.h>
57 #include <powerpc/ofw/ofw_syscons.h>
58 
59 static int ofwfb_ignore_mmap_checks = 1;
60 static SYSCTL_NODE(_hw, OID_AUTO, ofwfb, CTLFLAG_RD, 0, "ofwfb");
61 SYSCTL_INT(_hw_ofwfb, OID_AUTO, relax_mmap, CTLFLAG_RW,
62     &ofwfb_ignore_mmap_checks, 0, "relaxed mmap bounds checking");
63 
64 extern u_char dflt_font_16[];
65 extern u_char dflt_font_14[];
66 extern u_char dflt_font_8[];
67 
68 static int ofwfb_configure(int flags);
69 
70 static vi_probe_t ofwfb_probe;
71 static vi_init_t ofwfb_init;
72 static vi_get_info_t ofwfb_get_info;
73 static vi_query_mode_t ofwfb_query_mode;
74 static vi_set_mode_t ofwfb_set_mode;
75 static vi_save_font_t ofwfb_save_font;
76 static vi_load_font_t ofwfb_load_font;
77 static vi_show_font_t ofwfb_show_font;
78 static vi_save_palette_t ofwfb_save_palette;
79 static vi_load_palette_t ofwfb_load_palette;
80 static vi_set_border_t ofwfb_set_border;
81 static vi_save_state_t ofwfb_save_state;
82 static vi_load_state_t ofwfb_load_state;
83 static vi_set_win_org_t ofwfb_set_win_org;
84 static vi_read_hw_cursor_t ofwfb_read_hw_cursor;
85 static vi_set_hw_cursor_t ofwfb_set_hw_cursor;
86 static vi_set_hw_cursor_shape_t ofwfb_set_hw_cursor_shape;
87 static vi_blank_display_t ofwfb_blank_display;
88 static vi_mmap_t ofwfb_mmap;
89 static vi_ioctl_t ofwfb_ioctl;
90 static vi_clear_t ofwfb_clear;
91 static vi_fill_rect_t ofwfb_fill_rect;
92 static vi_bitblt_t ofwfb_bitblt;
93 static vi_diag_t ofwfb_diag;
94 static vi_save_cursor_palette_t ofwfb_save_cursor_palette;
95 static vi_load_cursor_palette_t ofwfb_load_cursor_palette;
96 static vi_copy_t ofwfb_copy;
97 static vi_putp_t ofwfb_putp;
98 static vi_putc_t ofwfb_putc;
99 static vi_puts_t ofwfb_puts;
100 static vi_putm_t ofwfb_putm;
101 
102 static video_switch_t ofwfbvidsw = {
103 	.probe			= ofwfb_probe,
104 	.init			= ofwfb_init,
105 	.get_info		= ofwfb_get_info,
106 	.query_mode		= ofwfb_query_mode,
107 	.set_mode		= ofwfb_set_mode,
108 	.save_font		= ofwfb_save_font,
109 	.load_font		= ofwfb_load_font,
110 	.show_font		= ofwfb_show_font,
111 	.save_palette		= ofwfb_save_palette,
112 	.load_palette		= ofwfb_load_palette,
113 	.set_border		= ofwfb_set_border,
114 	.save_state		= ofwfb_save_state,
115 	.load_state		= ofwfb_load_state,
116 	.set_win_org		= ofwfb_set_win_org,
117 	.read_hw_cursor		= ofwfb_read_hw_cursor,
118 	.set_hw_cursor		= ofwfb_set_hw_cursor,
119 	.set_hw_cursor_shape	= ofwfb_set_hw_cursor_shape,
120 	.blank_display		= ofwfb_blank_display,
121 	.mmap			= ofwfb_mmap,
122 	.ioctl			= ofwfb_ioctl,
123 	.clear			= ofwfb_clear,
124 	.fill_rect		= ofwfb_fill_rect,
125 	.bitblt			= ofwfb_bitblt,
126 	.diag			= ofwfb_diag,
127 	.save_cursor_palette	= ofwfb_save_cursor_palette,
128 	.load_cursor_palette	= ofwfb_load_cursor_palette,
129 	.copy			= ofwfb_copy,
130 	.putp			= ofwfb_putp,
131 	.putc			= ofwfb_putc,
132 	.puts			= ofwfb_puts,
133 	.putm			= ofwfb_putm,
134 };
135 
136 /*
137  * bitmap depth-specific routines
138  */
139 static vi_blank_display_t ofwfb_blank_display8;
140 static vi_putc_t ofwfb_putc8;
141 static vi_putm_t ofwfb_putm8;
142 static vi_set_border_t ofwfb_set_border8;
143 
144 static vi_blank_display_t ofwfb_blank_display32;
145 static vi_putc_t ofwfb_putc32;
146 static vi_putm_t ofwfb_putm32;
147 static vi_set_border_t ofwfb_set_border32;
148 
149 VIDEO_DRIVER(ofwfb, ofwfbvidsw, ofwfb_configure);
150 
151 extern sc_rndr_sw_t txtrndrsw;
152 RENDERER(ofwfb, 0, txtrndrsw, gfb_set);
153 
154 RENDERER_MODULE(ofwfb, gfb_set);
155 
156 /*
157  * Define the iso6429-1983 colormap
158  */
159 static struct {
160 	uint8_t	red;
161 	uint8_t	green;
162 	uint8_t	blue;
163 } ofwfb_cmap[16] = {		/*  #     R    G    B   Color */
164 				/*  -     -    -    -   ----- */
165 	{ 0x00, 0x00, 0x00 },	/*  0     0    0    0   Black */
166 	{ 0x00, 0x00, 0xaa },	/*  1     0    0  2/3   Blue  */
167 	{ 0x00, 0xaa, 0x00 },	/*  2     0  2/3    0   Green */
168 	{ 0x00, 0xaa, 0xaa },	/*  3     0  2/3  2/3   Cyan  */
169 	{ 0xaa, 0x00, 0x00 },	/*  4   2/3    0    0   Red   */
170 	{ 0xaa, 0x00, 0xaa },	/*  5   2/3    0  2/3   Magenta */
171 	{ 0xaa, 0x55, 0x00 },	/*  6   2/3  1/3    0   Brown */
172 	{ 0xaa, 0xaa, 0xaa },	/*  7   2/3  2/3  2/3   White */
173         { 0x55, 0x55, 0x55 },	/*  8   1/3  1/3  1/3   Gray  */
174 	{ 0x55, 0x55, 0xff },	/*  9   1/3  1/3    1   Bright Blue  */
175 	{ 0x55, 0xff, 0x55 },	/* 10   1/3    1  1/3   Bright Green */
176 	{ 0x55, 0xff, 0xff },	/* 11   1/3    1    1   Bright Cyan  */
177 	{ 0xff, 0x55, 0x55 },	/* 12     1  1/3  1/3   Bright Red   */
178 	{ 0xff, 0x55, 0xff },	/* 13     1  1/3    1   Bright Magenta */
179 	{ 0xff, 0xff, 0x80 },	/* 14     1    1  1/3   Bright Yellow */
180 	{ 0xff, 0xff, 0xff }	/* 15     1    1    1   Bright White */
181 };
182 
183 #define	TODO	printf("%s: unimplemented\n", __func__)
184 
185 static u_int16_t ofwfb_static_window[ROW*COL];
186 
187 static struct ofwfb_softc ofwfb_softc;
188 
189 static __inline int
190 ofwfb_background(uint8_t attr)
191 {
192 	return (attr >> 4);
193 }
194 
195 static __inline int
196 ofwfb_foreground(uint8_t attr)
197 {
198 	return (attr & 0x0f);
199 }
200 
201 static u_int
202 ofwfb_pix32(int attr)
203 {
204 	u_int retval;
205 
206 	retval = (ofwfb_cmap[attr].blue  << 16) |
207 		(ofwfb_cmap[attr].green << 8) |
208 		ofwfb_cmap[attr].red;
209 
210 	return (retval);
211 }
212 
213 static int
214 ofwfb_configure(int flags)
215 {
216 	struct ofwfb_softc *sc;
217         phandle_t chosen;
218         ihandle_t stdout;
219 	phandle_t node;
220 	uint32_t fb_phys;
221 	int depth;
222 	int disable;
223 	int len;
224 	char type[16];
225 	static int done = 0;
226 
227 	disable = 0;
228 	TUNABLE_INT_FETCH("hw.syscons.disable", &disable);
229 	if (disable != 0)
230 		return (0);
231 
232 	if (done != 0)
233 		return (0);
234 	done = 1;
235 
236 	sc = &ofwfb_softc;
237 
238 	chosen = OF_finddevice("/chosen");
239 	OF_getprop(chosen, "stdout", &stdout, sizeof(stdout));
240         node = OF_instance_to_package(stdout);
241 	if (node == -1) {
242 		/*
243 		 * The "/chosen/stdout" does not exist try
244 		 * using "screen" directly.
245 		 */
246 		node = OF_finddevice("screen");
247 	}
248 	OF_getprop(node, "device_type", type, sizeof(type));
249 	if (strcmp(type, "display") != 0)
250 		return (0);
251 
252 	/* Only support 8 and 32-bit framebuffers */
253 	OF_getprop(node, "depth", &depth, sizeof(depth));
254 	if (depth == 8) {
255 		sc->sc_blank = ofwfb_blank_display8;
256 		sc->sc_putc = ofwfb_putc8;
257 		sc->sc_putm = ofwfb_putm8;
258 		sc->sc_set_border = ofwfb_set_border8;
259 	} else if (depth == 32) {
260 		sc->sc_blank = ofwfb_blank_display32;
261 		sc->sc_putc = ofwfb_putc32;
262 		sc->sc_putm = ofwfb_putm32;
263 		sc->sc_set_border = ofwfb_set_border32;
264 	} else
265 		return (0);
266 
267 	if (OF_getproplen(node, "height") != sizeof(sc->sc_height) ||
268 	    OF_getproplen(node, "width") != sizeof(sc->sc_width))
269 		return (0);
270 
271 	sc->sc_depth = depth;
272 	sc->sc_node = node;
273 	sc->sc_console = 1;
274 	OF_getprop(node, "height", &sc->sc_height, sizeof(sc->sc_height));
275 	OF_getprop(node, "width", &sc->sc_width, sizeof(sc->sc_width));
276 	OF_getprop(node, "linebytes", &sc->sc_stride, sizeof(sc->sc_stride));
277 
278 	/*
279 	 * Grab the physical address of the framebuffer, and then map it
280 	 * into our memory space. If the MMU is not yet up, it will be
281 	 * remapped for us when relocation turns on.
282 	 *
283 	 * XXX We assume #address-cells is 1 at this point.
284 	 */
285 	if (OF_getproplen(node, "address") != sizeof(fb_phys))
286 		return (0);
287 	OF_getprop(node, "address", &fb_phys, sizeof(fb_phys));
288 
289 	bus_space_map(&bs_be_tag, fb_phys, sc->sc_height * sc->sc_stride,
290 	    BUS_SPACE_MAP_PREFETCHABLE, &sc->sc_addr);
291 
292 	/*
293 	 * Get the PCI addresses of the adapter. The node may be the
294 	 * child of the PCI device: in that case, try the parent for
295 	 * the assigned-addresses property.
296 	 */
297 	len = OF_getprop(node, "assigned-addresses", sc->sc_pciaddrs,
298 	          sizeof(sc->sc_pciaddrs));
299 	if (len == -1) {
300 		len = OF_getprop(OF_parent(node), "assigned-addresses",
301 		    sc->sc_pciaddrs, sizeof(sc->sc_pciaddrs));
302 	}
303 
304 	if (len != -1) {
305 		sc->sc_num_pciaddrs = len / sizeof(struct ofw_pci_register);
306 	}
307 
308 	ofwfb_init(0, &sc->sc_va, 0);
309 
310 	return (0);
311 }
312 
313 static int
314 ofwfb_probe(int unit, video_adapter_t **adp, void *arg, int flags)
315 {
316 	TODO;
317 	return (0);
318 }
319 
320 static int
321 ofwfb_init(int unit, video_adapter_t *adp, int flags)
322 {
323 	struct ofwfb_softc *sc;
324 	video_info_t *vi;
325 	int cborder;
326 	int font_height;
327 
328 	sc = (struct ofwfb_softc *)adp;
329 	vi = &adp->va_info;
330 
331 	vid_init_struct(adp, "ofwfb", -1, unit);
332 
333 	/* The default font size can be overridden by loader */
334 	font_height = 16;
335 	TUNABLE_INT_FETCH("hw.syscons.fsize", &font_height);
336 	if (font_height == 8) {
337 		sc->sc_font = dflt_font_8;
338 		sc->sc_font_height = 8;
339 	} else if (font_height == 14) {
340 		sc->sc_font = dflt_font_14;
341 		sc->sc_font_height = 14;
342 	} else {
343 		/* default is 8x16 */
344 		sc->sc_font = dflt_font_16;
345 		sc->sc_font_height = 16;
346 	}
347 
348 	/* The user can set a border in chars - default is 1 char width */
349 	cborder = 1;
350 	TUNABLE_INT_FETCH("hw.syscons.border", &cborder);
351 
352 	vi->vi_cheight = sc->sc_font_height;
353 	vi->vi_width = sc->sc_width/8 - 2*cborder;
354 	vi->vi_height = sc->sc_height/sc->sc_font_height - 2*cborder;
355 	vi->vi_cwidth = 8;
356 
357 	/*
358 	 * Clamp width/height to syscons maximums
359 	 */
360 	if (vi->vi_width > COL)
361 		vi->vi_width = COL;
362 	if (vi->vi_height > ROW)
363 		vi->vi_height = ROW;
364 
365 	sc->sc_xmargin = (sc->sc_width - (vi->vi_width * vi->vi_cwidth)) / 2;
366 	sc->sc_ymargin = (sc->sc_height - (vi->vi_height * vi->vi_cheight))/2;
367 
368 	/*
369 	 * Avoid huge amounts of conditional code in syscons by
370 	 * defining a dummy h/w text display buffer.
371 	 */
372 	adp->va_window = (vm_offset_t) ofwfb_static_window;
373 
374 	/*
375 	 * Enable future font-loading and flag color support, as well as
376 	 * adding V_ADP_MODECHANGE so that we ofwfb_set_mode() gets called
377 	 * when the X server shuts down. This enables us to get the console
378 	 * back when X disappears.
379 	 */
380 	adp->va_flags |= V_ADP_FONT | V_ADP_COLOR | V_ADP_MODECHANGE;
381 
382 	ofwfb_set_mode(&sc->sc_va, 0);
383 
384 	vid_register(&sc->sc_va);
385 
386 	return (0);
387 }
388 
389 static int
390 ofwfb_get_info(video_adapter_t *adp, int mode, video_info_t *info)
391 {
392 	bcopy(&adp->va_info, info, sizeof(*info));
393 	return (0);
394 }
395 
396 static int
397 ofwfb_query_mode(video_adapter_t *adp, video_info_t *info)
398 {
399 	TODO;
400 	return (0);
401 }
402 
403 static int
404 ofwfb_set_mode(video_adapter_t *adp, int mode)
405 {
406 	struct ofwfb_softc *sc;
407 	char name[64];
408 	ihandle_t ih;
409 	int i, retval;
410 
411 	sc = (struct ofwfb_softc *)adp;
412 
413 	/*
414 	 * Open the display device, which will initialize it.
415 	 */
416 
417 	memset(name, 0, sizeof(name));
418 	OF_package_to_path(sc->sc_node, name, sizeof(name));
419 	ih = OF_open(name);
420 
421 	if (sc->sc_depth == 8) {
422 		/*
423 		 * Install the ISO6429 colormap - older OFW systems
424 		 * don't do this by default
425 		 */
426 		for (i = 0; i < 16; i++) {
427 			OF_call_method("color!", ih, 4, 1,
428 				       ofwfb_cmap[i].red,
429 				       ofwfb_cmap[i].green,
430 				       ofwfb_cmap[i].blue,
431 				       i,
432 				       &retval);
433 		}
434 	}
435 
436 	ofwfb_blank_display(&sc->sc_va, V_DISPLAY_ON);
437 
438 	return (0);
439 }
440 
441 static int
442 ofwfb_save_font(video_adapter_t *adp, int page, int size, int width,
443     u_char *data, int c, int count)
444 {
445 	TODO;
446 	return (0);
447 }
448 
449 static int
450 ofwfb_load_font(video_adapter_t *adp, int page, int size, int width,
451     u_char *data, int c, int count)
452 {
453 	struct ofwfb_softc *sc;
454 
455 	sc = (struct ofwfb_softc *)adp;
456 
457 	/*
458 	 * syscons code has already determined that current width/height
459 	 * are unchanged for this new font
460 	 */
461 	sc->sc_font = data;
462 	return (0);
463 }
464 
465 static int
466 ofwfb_show_font(video_adapter_t *adp, int page)
467 {
468 
469 	return (0);
470 }
471 
472 static int
473 ofwfb_save_palette(video_adapter_t *adp, u_char *palette)
474 {
475 	/* TODO; */
476 	return (0);
477 }
478 
479 static int
480 ofwfb_load_palette(video_adapter_t *adp, u_char *palette)
481 {
482 	/* TODO; */
483 	return (0);
484 }
485 
486 static int
487 ofwfb_set_border8(video_adapter_t *adp, int border)
488 {
489 	struct ofwfb_softc *sc;
490 	int i, j;
491 	uint8_t *addr;
492 	uint8_t bground;
493 
494 	sc = (struct ofwfb_softc *)adp;
495 
496 	bground = ofwfb_background(border);
497 
498 	/* Set top margin */
499 	addr = (uint8_t *) sc->sc_addr;
500 	for (i = 0; i < sc->sc_ymargin; i++) {
501 		for (j = 0; j < sc->sc_width; j++) {
502 			*(addr + j) = bground;
503 		}
504 		addr += sc->sc_stride;
505 	}
506 
507 	/* bottom margin */
508 	addr = (uint8_t *) sc->sc_addr + (sc->sc_height - sc->sc_ymargin)*sc->sc_stride;
509 	for (i = 0; i < sc->sc_ymargin; i++) {
510 		for (j = 0; j < sc->sc_width; j++) {
511 			*(addr + j) = bground;
512 		}
513 		addr += sc->sc_stride;
514 	}
515 
516 	/* remaining left and right borders */
517 	addr = (uint8_t *) sc->sc_addr + sc->sc_ymargin*sc->sc_stride;
518 	for (i = 0; i < sc->sc_height - 2*sc->sc_xmargin; i++) {
519 		for (j = 0; j < sc->sc_xmargin; j++) {
520 			*(addr + j) = bground;
521 			*(addr + j + sc->sc_width - sc->sc_xmargin) = bground;
522 		}
523 		addr += sc->sc_stride;
524 	}
525 
526 	return (0);
527 }
528 
529 static int
530 ofwfb_set_border32(video_adapter_t *adp, int border)
531 {
532 	/* XXX Be lazy for now and blank entire screen */
533 	return (ofwfb_blank_display32(adp, border));
534 }
535 
536 static int
537 ofwfb_set_border(video_adapter_t *adp, int border)
538 {
539 	struct ofwfb_softc *sc;
540 
541 	sc = (struct ofwfb_softc *)adp;
542 
543 	return ((*sc->sc_set_border)(adp, border));
544 }
545 
546 static int
547 ofwfb_save_state(video_adapter_t *adp, void *p, size_t size)
548 {
549 	TODO;
550 	return (0);
551 }
552 
553 static int
554 ofwfb_load_state(video_adapter_t *adp, void *p)
555 {
556 	TODO;
557 	return (0);
558 }
559 
560 static int
561 ofwfb_set_win_org(video_adapter_t *adp, off_t offset)
562 {
563 	TODO;
564 	return (0);
565 }
566 
567 static int
568 ofwfb_read_hw_cursor(video_adapter_t *adp, int *col, int *row)
569 {
570 	*col = 0;
571 	*row = 0;
572 
573 	return (0);
574 }
575 
576 static int
577 ofwfb_set_hw_cursor(video_adapter_t *adp, int col, int row)
578 {
579 
580 	return (0);
581 }
582 
583 static int
584 ofwfb_set_hw_cursor_shape(video_adapter_t *adp, int base, int height,
585     int celsize, int blink)
586 {
587 	return (0);
588 }
589 
590 static int
591 ofwfb_blank_display8(video_adapter_t *adp, int mode)
592 {
593 	struct ofwfb_softc *sc;
594 	int i;
595 	uint32_t *addr;
596 	uint32_t color;
597 	uint32_t end;
598 
599 	sc = (struct ofwfb_softc *)adp;
600 	addr = (uint32_t *) sc->sc_addr;
601 	end = (sc->sc_stride/4) * sc->sc_height;
602 
603 	/* Splat 4 pixels at once. */
604 	color = (ofwfb_background(SC_NORM_ATTR) << 24) |
605 	    (ofwfb_background(SC_NORM_ATTR) << 16) |
606 	    (ofwfb_background(SC_NORM_ATTR) << 8) |
607 	    (ofwfb_background(SC_NORM_ATTR));
608 
609 	for (i = 0; i < end; i++)
610 		*(addr + i) = color;
611 
612 	return (0);
613 }
614 
615 static int
616 ofwfb_blank_display32(video_adapter_t *adp, int mode)
617 {
618 	struct ofwfb_softc *sc;
619 	int i;
620 	uint32_t *addr;
621 
622 	sc = (struct ofwfb_softc *)adp;
623 	addr = (uint32_t *) sc->sc_addr;
624 
625 	for (i = 0; i < (sc->sc_stride/4)*sc->sc_height; i++)
626 		*(addr + i) = ofwfb_pix32(ofwfb_background(SC_NORM_ATTR));
627 
628 	return (0);
629 }
630 
631 static int
632 ofwfb_blank_display(video_adapter_t *adp, int mode)
633 {
634 	struct ofwfb_softc *sc;
635 
636 	sc = (struct ofwfb_softc *)adp;
637 
638 	return ((*sc->sc_blank)(adp, mode));
639 }
640 
641 static int
642 ofwfb_mmap(video_adapter_t *adp, vm_ooffset_t offset, vm_paddr_t *paddr,
643     int prot, vm_memattr_t *memattr)
644 {
645 	struct ofwfb_softc *sc;
646 	int i;
647 
648 	sc = (struct ofwfb_softc *)adp;
649 
650 	/*
651 	 * Make sure the requested address lies within the PCI device's
652 	 * assigned addrs
653 	 */
654 	for (i = 0; i < sc->sc_num_pciaddrs; i++)
655 	  if (offset >= sc->sc_pciaddrs[i].phys_lo &&
656 	    offset < (sc->sc_pciaddrs[i].phys_lo + sc->sc_pciaddrs[i].size_lo))
657 		{
658 			/*
659 			 * If this is a prefetchable BAR, we can (and should)
660 			 * enable write-combining.
661 			 */
662 			if (sc->sc_pciaddrs[i].phys_hi &
663 			    OFW_PCI_PHYS_HI_PREFETCHABLE)
664 				*memattr = VM_MEMATTR_WRITE_COMBINING;
665 
666 			*paddr = offset;
667 			return (0);
668 		}
669 
670 	/*
671 	 * Hack for Radeon...
672 	 */
673 	if (ofwfb_ignore_mmap_checks) {
674 		*paddr = offset;
675 		return (0);
676 	}
677 
678 	/*
679 	 * This might be a legacy VGA mem request: if so, just point it at the
680 	 * framebuffer, since it shouldn't be touched
681 	 */
682 	if (offset < sc->sc_stride*sc->sc_height) {
683 		*paddr = sc->sc_addr + offset;
684 		return (0);
685 	}
686 
687 	/*
688 	 * Error if we didn't have a better idea.
689 	 */
690 	if (sc->sc_num_pciaddrs == 0)
691 		return (ENOMEM);
692 
693 	return (EINVAL);
694 }
695 
696 static int
697 ofwfb_ioctl(video_adapter_t *adp, u_long cmd, caddr_t data)
698 {
699 
700 	return (0);
701 }
702 
703 static int
704 ofwfb_clear(video_adapter_t *adp)
705 {
706 	TODO;
707 	return (0);
708 }
709 
710 static int
711 ofwfb_fill_rect(video_adapter_t *adp, int val, int x, int y, int cx, int cy)
712 {
713 	TODO;
714 	return (0);
715 }
716 
717 static int
718 ofwfb_bitblt(video_adapter_t *adp, ...)
719 {
720 	TODO;
721 	return (0);
722 }
723 
724 static int
725 ofwfb_diag(video_adapter_t *adp, int level)
726 {
727 	TODO;
728 	return (0);
729 }
730 
731 static int
732 ofwfb_save_cursor_palette(video_adapter_t *adp, u_char *palette)
733 {
734 	TODO;
735 	return (0);
736 }
737 
738 static int
739 ofwfb_load_cursor_palette(video_adapter_t *adp, u_char *palette)
740 {
741 	TODO;
742 	return (0);
743 }
744 
745 static int
746 ofwfb_copy(video_adapter_t *adp, vm_offset_t src, vm_offset_t dst, int n)
747 {
748 	TODO;
749 	return (0);
750 }
751 
752 static int
753 ofwfb_putp(video_adapter_t *adp, vm_offset_t off, uint32_t p, uint32_t a,
754     int size, int bpp, int bit_ltor, int byte_ltor)
755 {
756 	TODO;
757 	return (0);
758 }
759 
760 static int
761 ofwfb_putc8(video_adapter_t *adp, vm_offset_t off, uint8_t c, uint8_t a)
762 {
763 	struct ofwfb_softc *sc;
764 	int row;
765 	int col;
766 	int i;
767 	uint32_t *addr;
768 	u_char *p, fg, bg;
769 	union {
770 		uint32_t l;
771 		uint8_t  c[4];
772 	} ch1, ch2;
773 
774 
775 	sc = (struct ofwfb_softc *)adp;
776         row = (off / adp->va_info.vi_width) * adp->va_info.vi_cheight;
777         col = (off % adp->va_info.vi_width) * adp->va_info.vi_cwidth;
778 	p = sc->sc_font + c*sc->sc_font_height;
779 	addr = (u_int32_t *)((uintptr_t)sc->sc_addr
780 		+ (row + sc->sc_ymargin)*sc->sc_stride
781 		+ col + sc->sc_xmargin);
782 
783 	fg = ofwfb_foreground(a);
784 	bg = ofwfb_background(a);
785 
786 	for (i = 0; i < sc->sc_font_height; i++) {
787 		u_char fline = p[i];
788 
789 		/*
790 		 * Assume that there is more background than foreground
791 		 * in characters and init accordingly
792 		 */
793 		ch1.l = ch2.l = (bg << 24) | (bg << 16) | (bg << 8) | bg;
794 
795 		/*
796 		 * Calculate 2 x 4-chars at a time, and then
797 		 * write these out.
798 		 */
799 		if (fline & 0x80) ch1.c[0] = fg;
800 		if (fline & 0x40) ch1.c[1] = fg;
801 		if (fline & 0x20) ch1.c[2] = fg;
802 		if (fline & 0x10) ch1.c[3] = fg;
803 
804 		if (fline & 0x08) ch2.c[0] = fg;
805 		if (fline & 0x04) ch2.c[1] = fg;
806 		if (fline & 0x02) ch2.c[2] = fg;
807 		if (fline & 0x01) ch2.c[3] = fg;
808 
809 		addr[0] = ch1.l;
810 		addr[1] = ch2.l;
811 		addr += (sc->sc_stride / sizeof(u_int32_t));
812 	}
813 
814 	return (0);
815 }
816 
817 static int
818 ofwfb_putc32(video_adapter_t *adp, vm_offset_t off, uint8_t c, uint8_t a)
819 {
820 	struct ofwfb_softc *sc;
821 	int row;
822 	int col;
823 	int i, j, k;
824 	uint32_t *addr;
825 	u_char *p;
826 
827 	sc = (struct ofwfb_softc *)adp;
828         row = (off / adp->va_info.vi_width) * adp->va_info.vi_cheight;
829         col = (off % adp->va_info.vi_width) * adp->va_info.vi_cwidth;
830 	p = sc->sc_font + c*sc->sc_font_height;
831 	addr = (uint32_t *)sc->sc_addr
832 		+ (row + sc->sc_ymargin)*(sc->sc_stride/4)
833 		+ col + sc->sc_xmargin;
834 
835 	for (i = 0; i < sc->sc_font_height; i++) {
836 		for (j = 0, k = 7; j < 8; j++, k--) {
837 			if ((p[i] & (1 << k)) == 0)
838 				*(addr + j) = ofwfb_pix32(ofwfb_background(a));
839 			else
840 				*(addr + j) = ofwfb_pix32(ofwfb_foreground(a));
841 		}
842 		addr += (sc->sc_stride/4);
843 	}
844 
845 	return (0);
846 }
847 
848 static int
849 ofwfb_putc(video_adapter_t *adp, vm_offset_t off, uint8_t c, uint8_t a)
850 {
851 	struct ofwfb_softc *sc;
852 
853 	sc = (struct ofwfb_softc *)adp;
854 
855 	return ((*sc->sc_putc)(adp, off, c, a));
856 }
857 
858 static int
859 ofwfb_puts(video_adapter_t *adp, vm_offset_t off, u_int16_t *s, int len)
860 {
861 	int i;
862 
863 	for (i = 0; i < len; i++) {
864 		ofwfb_putc(adp, off + i, s[i] & 0xff, (s[i] & 0xff00) >> 8);
865 	}
866 	return (0);
867 }
868 
869 static int
870 ofwfb_putm(video_adapter_t *adp, int x, int y, uint8_t *pixel_image,
871     uint32_t pixel_mask, int size, int width)
872 {
873 	struct ofwfb_softc *sc;
874 
875 	sc = (struct ofwfb_softc *)adp;
876 
877 	return ((*sc->sc_putm)(adp, x, y, pixel_image, pixel_mask, size,
878 	    width));
879 }
880 
881 static int
882 ofwfb_putm8(video_adapter_t *adp, int x, int y, uint8_t *pixel_image,
883     uint32_t pixel_mask, int size, int width)
884 {
885 	struct ofwfb_softc *sc;
886 	int i, j, k;
887 	uint8_t *addr;
888 	u_char fg, bg;
889 
890 	sc = (struct ofwfb_softc *)adp;
891 	addr = (u_int8_t *)((uintptr_t)sc->sc_addr
892 		+ (y + sc->sc_ymargin)*sc->sc_stride
893 		+ x + sc->sc_xmargin);
894 
895 	fg = ofwfb_foreground(SC_NORM_ATTR);
896 	bg = ofwfb_background(SC_NORM_ATTR);
897 
898 	for (i = 0; i < size && i+y < sc->sc_height - 2*sc->sc_ymargin; i++) {
899 		/*
900 		 * Calculate 2 x 4-chars at a time, and then
901 		 * write these out.
902 		 */
903 		for (j = 0, k = width; j < 8; j++, k--) {
904 			if (x + j >= sc->sc_width - 2*sc->sc_xmargin)
905 				continue;
906 
907 			if (pixel_image[i] & (1 << k))
908 				addr[j] = (addr[j] == fg) ? bg : fg;
909 		}
910 
911 		addr += (sc->sc_stride / sizeof(u_int8_t));
912 	}
913 
914 	return (0);
915 }
916 
917 static int
918 ofwfb_putm32(video_adapter_t *adp, int x, int y, uint8_t *pixel_image,
919     uint32_t pixel_mask, int size, int width)
920 {
921 	struct ofwfb_softc *sc;
922 	int i, j, k;
923 	uint32_t fg, bg;
924 	uint32_t *addr;
925 
926 	sc = (struct ofwfb_softc *)adp;
927 	addr = (uint32_t *)sc->sc_addr
928 		+ (y + sc->sc_ymargin)*(sc->sc_stride/4)
929 		+ x + sc->sc_xmargin;
930 
931 	fg = ofwfb_pix32(ofwfb_foreground(SC_NORM_ATTR));
932 	bg = ofwfb_pix32(ofwfb_background(SC_NORM_ATTR));
933 
934 	for (i = 0; i < size && i+y < sc->sc_height - 2*sc->sc_ymargin; i++) {
935 		for (j = 0, k = width; j < 8; j++, k--) {
936 			if (x + j >= sc->sc_width - 2*sc->sc_xmargin)
937 				continue;
938 
939 			if (pixel_image[i] & (1 << k))
940 				*(addr + j) = (*(addr + j) == fg) ? bg : fg;
941 		}
942 		addr += (sc->sc_stride/4);
943 	}
944 
945 	return (0);
946 }
947 
948 /*
949  * Define the syscons nexus device attachment
950  */
951 static void
952 ofwfb_scidentify(driver_t *driver, device_t parent)
953 {
954 	device_t child;
955 
956 	/*
957 	 * The Nintendo Wii doesn't have open firmware, so don't probe ofwfb
958 	 * because otherwise we will crash.
959 	 */
960 	if (strcmp(installed_platform(), "wii") == 0)
961 		return;
962 	/*
963 	 * Add with a priority guaranteed to make it last on
964 	 * the device list
965 	 */
966 	child = BUS_ADD_CHILD(parent, INT_MAX, SC_DRIVER_NAME, 0);
967 }
968 
969 static int
970 ofwfb_scprobe(device_t dev)
971 {
972 	int error;
973 
974 	device_set_desc(dev, "System console");
975 
976 	error = sc_probe_unit(device_get_unit(dev),
977 	    device_get_flags(dev) | SC_AUTODETECT_KBD);
978 	if (error != 0)
979 		return (error);
980 
981 	/* This is a fake device, so make sure we added it ourselves */
982 	return (BUS_PROBE_NOWILDCARD);
983 }
984 
985 static int
986 ofwfb_scattach(device_t dev)
987 {
988 	return (sc_attach_unit(device_get_unit(dev),
989 	    device_get_flags(dev) | SC_AUTODETECT_KBD));
990 }
991 
992 static device_method_t ofwfb_sc_methods[] = {
993   	DEVMETHOD(device_identify,	ofwfb_scidentify),
994 	DEVMETHOD(device_probe,		ofwfb_scprobe),
995 	DEVMETHOD(device_attach,	ofwfb_scattach),
996 	{ 0, 0 }
997 };
998 
999 static driver_t ofwfb_sc_driver = {
1000 	SC_DRIVER_NAME,
1001 	ofwfb_sc_methods,
1002 	sizeof(sc_softc_t),
1003 };
1004 
1005 static devclass_t	sc_devclass;
1006 
1007 DRIVER_MODULE(ofwfb, nexus, ofwfb_sc_driver, sc_devclass, 0, 0);
1008 
1009 /*
1010  * Define a stub keyboard driver in case one hasn't been
1011  * compiled into the kernel
1012  */
1013 #include <sys/kbio.h>
1014 #include <dev/kbd/kbdreg.h>
1015 
1016 static int dummy_kbd_configure(int flags);
1017 
1018 keyboard_switch_t dummysw;
1019 
1020 static int
1021 dummy_kbd_configure(int flags)
1022 {
1023 
1024 	return (0);
1025 }
1026 KEYBOARD_DRIVER(dummy, dummysw, dummy_kbd_configure);
1027 
1028 /*
1029  * Utility routines from <dev/fb/fbreg.h>
1030  */
1031 void
1032 ofwfb_bcopy(const void *s, void *d, size_t c)
1033 {
1034 	bcopy(s, d, c);
1035 }
1036 
1037 void
1038 ofwfb_bzero(void *d, size_t c)
1039 {
1040 	bzero(d, c);
1041 }
1042 
1043 void
1044 ofwfb_fillw(int pat, void *base, size_t cnt)
1045 {
1046 	u_int16_t *bptr = base;
1047 
1048 	while (cnt--)
1049 		*bptr++ = pat;
1050 }
1051 
1052 u_int16_t
1053 ofwfb_readw(u_int16_t *addr)
1054 {
1055 	return (*addr);
1056 }
1057 
1058 void
1059 ofwfb_writew(u_int16_t *addr, u_int16_t val)
1060 {
1061 	*addr = val;
1062 }
1063