ofw_syscons.c revision 183317
1193323Sed/*-
2193323Sed * Copyright (c) 2003 Peter Grehan
3193323Sed * All rights reserved.
4193323Sed *
5193323Sed * Redistribution and use in source and binary forms, with or without
6193323Sed * modification, are permitted provided that the following conditions
7193323Sed * are met:
8193323Sed * 1. Redistributions of source code must retain the above copyright
9193323Sed *    notice, this list of conditions and the following disclaimer.
10193323Sed * 2. Redistributions in binary form must reproduce the above copyright
11193323Sed *    notice, this list of conditions and the following disclaimer in the
12193323Sed *    documentation and/or other materials provided with the distribution.
13193323Sed *
14198090Srdivacky * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
15198090Srdivacky * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
16193323Sed * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
17193323Sed * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
18198090Srdivacky * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
19193323Sed * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
20193323Sed * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
21193323Sed * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
22193323Sed * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
23249423Sdim * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
24193323Sed * SUCH DAMAGE.
25193323Sed */
26193323Sed
27193323Sed#include <sys/cdefs.h>
28193323Sed__FBSDID("$FreeBSD: head/sys/powerpc/ofw/ofw_syscons.c 183317 2008-09-23 22:16:23Z sobomax $");
29193323Sed
30193323Sed#include <sys/param.h>
31193323Sed#include <sys/systm.h>
32193323Sed#include <sys/module.h>
33226633Sdim#include <sys/bus.h>
34226633Sdim#include <sys/kernel.h>
35226633Sdim#include <sys/sysctl.h>
36226633Sdim#include <sys/limits.h>
37226633Sdim#include <sys/conf.h>
38193323Sed#include <sys/cons.h>
39218893Sdim#include <sys/proc.h>
40198090Srdivacky#include <sys/fcntl.h>
41198090Srdivacky#include <sys/malloc.h>
42193323Sed#include <sys/fbio.h>
43198090Srdivacky#include <sys/consio.h>
44263508Sdim
45193323Sed#include <machine/bus.h>
46193323Sed#include <machine/sc_machdep.h>
47193323Sed
48223017Sdim#include <sys/rman.h>
49223017Sdim
50193323Sed#include <dev/fb/fbreg.h>
51223017Sdim#include <dev/syscons/syscons.h>
52193323Sed
53193323Sed#include <dev/ofw/openfirm.h>
54218893Sdim#include <dev/ofw/ofw_pci.h>
55218893Sdim#include <powerpc/ofw/ofw_syscons.h>
56193323Sed#include <machine/nexusvar.h>
57223017Sdim
58223017Sdimstatic int ofwfb_ignore_mmap_checks;
59193323SedSYSCTL_NODE(_hw, OID_AUTO, ofwfb, CTLFLAG_RD, 0, "ofwfb");
60193323SedSYSCTL_INT(_hw_ofwfb, OID_AUTO, relax_mmap, CTLFLAG_RW,
61218893Sdim    &ofwfb_ignore_mmap_checks, 0, "relax mmap bounds checking");
62218893Sdim
63193323Sedextern u_char dflt_font_16[];
64223017Sdimextern u_char dflt_font_14[];
65193323Sedextern u_char dflt_font_8[];
66198090Srdivacky
67198090Srdivackystatic int ofwfb_configure(int flags);
68218893Sdim
69218893Sdimstatic vi_probe_t ofwfb_probe;
70198090Srdivackystatic vi_init_t ofwfb_init;
71223017Sdimstatic vi_get_info_t ofwfb_get_info;
72193323Sedstatic vi_query_mode_t ofwfb_query_mode;
73193323Sedstatic vi_set_mode_t ofwfb_set_mode;
74218893Sdimstatic vi_save_font_t ofwfb_save_font;
75218893Sdimstatic vi_load_font_t ofwfb_load_font;
76193323Sedstatic vi_show_font_t ofwfb_show_font;
77223017Sdimstatic vi_save_palette_t ofwfb_save_palette;
78218893Sdimstatic vi_load_palette_t ofwfb_load_palette;
79193323Sedstatic vi_set_border_t ofwfb_set_border;
80263508Sdimstatic vi_save_state_t ofwfb_save_state;
81263508Sdimstatic vi_load_state_t ofwfb_load_state;
82263508Sdimstatic vi_set_win_org_t ofwfb_set_win_org;
83193323Sedstatic vi_read_hw_cursor_t ofwfb_read_hw_cursor;
84193323Sedstatic vi_set_hw_cursor_t ofwfb_set_hw_cursor;
85218893Sdimstatic vi_set_hw_cursor_shape_t ofwfb_set_hw_cursor_shape;
86218893Sdimstatic vi_blank_display_t ofwfb_blank_display;
87193323Sedstatic vi_mmap_t ofwfb_mmap;
88193323Sedstatic vi_ioctl_t ofwfb_ioctl;
89193323Sedstatic vi_clear_t ofwfb_clear;
90193323Sedstatic vi_fill_rect_t ofwfb_fill_rect;
91193724Sedstatic vi_bitblt_t ofwfb_bitblt;
92218893Sdimstatic vi_diag_t ofwfb_diag;
93193724Sedstatic vi_save_cursor_palette_t ofwfb_save_cursor_palette;
94243830Sdimstatic vi_load_cursor_palette_t ofwfb_load_cursor_palette;
95243830Sdimstatic vi_copy_t ofwfb_copy;
96243830Sdimstatic vi_putp_t ofwfb_putp;
97193724Sedstatic vi_putc_t ofwfb_putc;
98243830Sdimstatic vi_puts_t ofwfb_puts;
99243830Sdimstatic vi_putm_t ofwfb_putm;
100243830Sdim
101243830Sdimstatic video_switch_t ofwfbvidsw = {
102243830Sdim	.probe			= ofwfb_probe,
103243830Sdim	.init			= ofwfb_init,
104243830Sdim	.get_info		= ofwfb_get_info,
105243830Sdim	.query_mode		= ofwfb_query_mode,
106243830Sdim	.set_mode		= ofwfb_set_mode,
107243830Sdim	.save_font		= ofwfb_save_font,
108243830Sdim	.load_font		= ofwfb_load_font,
109193724Sed	.show_font		= ofwfb_show_font,
110218893Sdim	.save_palette		= ofwfb_save_palette,
111193724Sed	.load_palette		= ofwfb_load_palette,
112243830Sdim	.set_border		= ofwfb_set_border,
113243830Sdim	.save_state		= ofwfb_save_state,
114243830Sdim	.load_state		= ofwfb_load_state,
115263508Sdim	.set_win_org		= ofwfb_set_win_org,
116263508Sdim	.read_hw_cursor		= ofwfb_read_hw_cursor,
117243830Sdim	.set_hw_cursor		= ofwfb_set_hw_cursor,
118243830Sdim	.set_hw_cursor_shape	= ofwfb_set_hw_cursor_shape,
119243830Sdim	.blank_display		= ofwfb_blank_display,
120243830Sdim	.mmap			= ofwfb_mmap,
121243830Sdim	.ioctl			= ofwfb_ioctl,
122243830Sdim	.clear			= ofwfb_clear,
123243830Sdim	.fill_rect		= ofwfb_fill_rect,
124243830Sdim	.bitblt			= ofwfb_bitblt,
125243830Sdim	.diag			= ofwfb_diag,
126243830Sdim	.save_cursor_palette	= ofwfb_save_cursor_palette,
127243830Sdim	.load_cursor_palette	= ofwfb_load_cursor_palette,
128243830Sdim	.copy			= ofwfb_copy,
129243830Sdim	.putp			= ofwfb_putp,
130243830Sdim	.putc			= ofwfb_putc,
131243830Sdim	.puts			= ofwfb_puts,
132243830Sdim	.putm			= ofwfb_putm,
133243830Sdim};
134243830Sdim
135243830Sdim/*
136243830Sdim * bitmap depth-specific routines
137243830Sdim */
138193724Sedstatic vi_blank_display_t ofwfb_blank_display8;
139193724Sedstatic vi_putc_t ofwfb_putc8;
140198090Srdivackystatic vi_set_border_t ofwfb_set_border8;
141193724Sed
142193724Sedstatic vi_blank_display_t ofwfb_blank_display32;
143193724Sedstatic vi_putc_t ofwfb_putc32;
144193724Sedstatic vi_set_border_t ofwfb_set_border32;
145193323Sed
146193323SedVIDEO_DRIVER(ofwfb, ofwfbvidsw, ofwfb_configure);
147193323Sed
148193323Sedextern sc_rndr_sw_t txtrndrsw;
149193323SedRENDERER(ofwfb, 0, txtrndrsw, gfb_set);
150193323Sed
151243830SdimRENDERER_MODULE(ofwfb, gfb_set);
152198396Srdivacky
153193323Sed/*
154193323Sed * Define the iso6429-1983 colormap
155218893Sdim */
156193323Sedstatic struct {
157193323Sed	uint8_t	red;
158218893Sdim	uint8_t	green;
159203954Srdivacky	uint8_t	blue;
160193323Sed} ofwfb_cmap[16] = {		/*  #     R    G    B   Color */
161193323Sed				/*  -     -    -    -   ----- */
162263508Sdim	{ 0x00, 0x00, 0x00 },	/*  0     0    0    0   Black */
163234353Sdim	{ 0x00, 0x00, 0xaa },	/*  1     0    0  2/3   Blue  */
164193323Sed	{ 0x00, 0xaa, 0x00 },	/*  2     0  2/3    0   Green */
165193323Sed	{ 0x00, 0xaa, 0xaa },	/*  3     0  2/3  2/3   Cyan  */
166193323Sed	{ 0xaa, 0x00, 0x00 },	/*  4   2/3    0    0   Red   */
167193323Sed	{ 0xaa, 0x00, 0xaa },	/*  5   2/3    0  2/3   Magenta */
168263508Sdim	{ 0xaa, 0x55, 0x00 },	/*  6   2/3  1/3    0   Brown */
169263508Sdim	{ 0xaa, 0xaa, 0xaa },	/*  7   2/3  2/3  2/3   White */
170193323Sed        { 0x55, 0x55, 0x55 },	/*  8   1/3  1/3  1/3   Gray  */
171193323Sed	{ 0x55, 0x55, 0xff },	/*  9   1/3  1/3    1   Bright Blue  */
172218893Sdim	{ 0x55, 0xff, 0x55 },	/* 10   1/3    1  1/3   Bright Green */
173218893Sdim	{ 0x55, 0xff, 0xff },	/* 11   1/3    1    1   Bright Cyan  */
174234353Sdim	{ 0xff, 0x55, 0x55 },	/* 12     1  1/3  1/3   Bright Red   */
175193323Sed	{ 0xff, 0x55, 0xff },	/* 13     1  1/3    1   Bright Magenta */
176193323Sed	{ 0xff, 0xff, 0x80 },	/* 14     1    1  1/3   Bright Yellow */
177193323Sed	{ 0xff, 0xff, 0xff }	/* 15     1    1    1   Bright White */
178193323Sed};
179193323Sed
180193323Sed#define	TODO	printf("%s: unimplemented\n", __func__)
181193323Sed
182193323Sedstatic u_int16_t ofwfb_static_window[ROW*COL];
183193323Sed
184193323Sedstatic struct ofwfb_softc ofwfb_softc;
185193323Sed
186193323Sedstatic __inline int
187193323Sedofwfb_background(uint8_t attr)
188193323Sed{
189193323Sed	return (attr >> 4);
190193323Sed}
191193323Sed
192193323Sedstatic __inline int
193193323Sedofwfb_foreground(uint8_t attr)
194193323Sed{
195193323Sed	return (attr & 0x0f);
196193323Sed}
197193323Sed
198193323Sedstatic u_int
199193323Sedofwfb_pix32(int attr)
200193323Sed{
201193323Sed	u_int retval;
202193323Sed
203193323Sed	retval = (ofwfb_cmap[attr].blue  << 16) |
204239462Sdim		(ofwfb_cmap[attr].green << 8) |
205263508Sdim		ofwfb_cmap[attr].red;
206193323Sed
207193323Sed	return (retval);
208193323Sed}
209198090Srdivacky
210198090Srdivackystatic int
211193323Sedofwfb_configure(int flags)
212239462Sdim{
213239462Sdim	struct ofwfb_softc *sc;
214239462Sdim        phandle_t chosen;
215239462Sdim        ihandle_t stdout;
216239462Sdim	phandle_t node;
217239462Sdim	int depth;
218239462Sdim	int disable;
219239462Sdim	int len;
220239462Sdim	char type[16];
221218893Sdim	static int done = 0;
222207618Srdivacky
223207618Srdivacky	disable = 0;
224207618Srdivacky	TUNABLE_INT_FETCH("hw.syscons.disable", &disable);
225193323Sed	if (disable != 0)
226193323Sed		return (0);
227193323Sed
228193323Sed	if (done != 0)
229193323Sed		return (0);
230193323Sed	done = 1;
231193323Sed
232193323Sed	sc = &ofwfb_softc;
233193323Sed
234193323Sed	chosen = OF_finddevice("/chosen");
235193323Sed	OF_getprop(chosen, "stdout", &stdout, sizeof(stdout));
236193323Sed        node = OF_instance_to_package(stdout);
237193323Sed	if (node == -1) {
238193323Sed		/*
239193323Sed		 * The "/chosen/stdout" does not exist try
240193323Sed		 * using "screen" directly.
241193323Sed		 */
242193323Sed		node = OF_finddevice("screen");
243263508Sdim	}
244193323Sed	OF_getprop(node, "device_type", type, sizeof(type));
245193323Sed	if (strcmp(type, "display") != 0)
246198090Srdivacky		return (0);
247193323Sed
248193323Sed	/* Only support 8 and 32-bit framebuffers */
249193323Sed	OF_getprop(node, "depth", &depth, sizeof(depth));
250193323Sed	if (depth == 8) {
251203954Srdivacky		sc->sc_blank = ofwfb_blank_display8;
252234353Sdim		sc->sc_putc = ofwfb_putc8;
253263508Sdim		sc->sc_set_border = ofwfb_set_border8;
254193323Sed	} else if (depth == 32) {
255193323Sed		sc->sc_blank = ofwfb_blank_display32;
256193323Sed		sc->sc_putc = ofwfb_putc32;
257218893Sdim		sc->sc_set_border = ofwfb_set_border32;
258263508Sdim	} else
259263508Sdim		return (0);
260193323Sed
261193323Sed	sc->sc_depth = depth;
262193323Sed	sc->sc_node = node;
263193323Sed	sc->sc_console = 1;
264263508Sdim	OF_getprop(node, "height", &sc->sc_height, sizeof(sc->sc_height));
265218893Sdim	OF_getprop(node, "width", &sc->sc_width, sizeof(sc->sc_width));
266218893Sdim	OF_getprop(node, "linebytes", &sc->sc_stride, sizeof(sc->sc_stride));
267234353Sdim
268263508Sdim	/*
269193323Sed	 * XXX the physical address of the frame buffer is assumed to be
270193323Sed	 * BAT-mapped so it can be accessed directly
271193323Sed	 */
272193323Sed	OF_getprop(node, "address", &sc->sc_addr, sizeof(sc->sc_addr));
273193323Sed
274193323Sed	/*
275193323Sed	 * Get the PCI addresses of the adapter. The node may be the
276193323Sed	 * child of the PCI device: in that case, try the parent for
277193323Sed	 * the assigned-addresses property.
278193323Sed	 */
279193323Sed	len = OF_getprop(node, "assigned-addresses", sc->sc_pciaddrs,
280193323Sed	          sizeof(sc->sc_pciaddrs));
281193323Sed	if (len == -1) {
282193323Sed		len = OF_getprop(OF_parent(node), "assigned-addresses", sc->sc_pciaddrs,
283193323Sed		          sizeof(sc->sc_pciaddrs));
284193323Sed	}
285210299Sed
286210299Sed	if (len != -1) {
287193323Sed		sc->sc_num_pciaddrs = len / sizeof(struct ofw_pci_register);
288193323Sed	}
289263508Sdim
290210299Sed	ofwfb_init(0, &sc->sc_va, 0);
291193323Sed
292210299Sed	return (0);
293210299Sed}
294193323Sed
295193323Sedstatic int
296193323Sedofwfb_probe(int unit, video_adapter_t **adp, void *arg, int flags)
297193323Sed{
298193323Sed	TODO;
299193323Sed	return (0);
300193323Sed}
301193323Sed
302193323Sedstatic int
303193323Sedofwfb_init(int unit, video_adapter_t *adp, int flags)
304193323Sed{
305193323Sed	struct ofwfb_softc *sc;
306193323Sed	video_info_t *vi;
307193323Sed	char name[64];
308193323Sed	ihandle_t ih;
309263508Sdim	int i;
310263508Sdim	int cborder;
311263508Sdim	int font_height;
312263508Sdim	int retval;
313263508Sdim
314263508Sdim	sc = (struct ofwfb_softc *)adp;
315263508Sdim	vi = &adp->va_info;
316263508Sdim
317263508Sdim	vid_init_struct(adp, "ofwfb", -1, unit);
318263508Sdim
319263508Sdim	if (sc->sc_depth == 8) {
320263508Sdim		/*
321263508Sdim		 * Install the ISO6429 colormap - older OFW systems
322263508Sdim		 * don't do this by default
323263508Sdim		 */
324263508Sdim		memset(name, 0, sizeof(name));
325263508Sdim		OF_package_to_path(sc->sc_node, name, sizeof(name));
326263508Sdim		ih = OF_open(name);
327263508Sdim		for (i = 0; i < 16; i++) {
328218893Sdim			OF_call_method("color!", ih, 4, 1,
329263508Sdim				       ofwfb_cmap[i].red,
330193323Sed				       ofwfb_cmap[i].green,
331193323Sed				       ofwfb_cmap[i].blue,
332193323Sed				       i,
333193323Sed				       &retval);
334193323Sed		}
335218893Sdim	}
336263508Sdim
337263508Sdim	/* The default font size can be overridden by loader */
338263508Sdim	font_height = 16;
339263508Sdim	TUNABLE_INT_FETCH("hw.syscons.fsize", &font_height);
340263508Sdim	if (font_height == 8) {
341198090Srdivacky		sc->sc_font = dflt_font_8;
342207618Srdivacky		sc->sc_font_height = 8;
343207618Srdivacky	} else if (font_height == 14) {
344263508Sdim		sc->sc_font = dflt_font_14;
345263508Sdim		sc->sc_font_height = 14;
346263508Sdim	} else {
347263508Sdim		/* default is 8x16 */
348263508Sdim		sc->sc_font = dflt_font_16;
349263508Sdim		sc->sc_font_height = 16;
350263508Sdim	}
351193323Sed
352263508Sdim	/* The user can set a border in chars - default is 1 char width */
353263508Sdim	cborder = 1;
354193323Sed	TUNABLE_INT_FETCH("hw.syscons.border", &cborder);
355263508Sdim
356263508Sdim	vi->vi_cheight = sc->sc_font_height;
357193323Sed	vi->vi_width = sc->sc_width/8 - 2*cborder;
358193323Sed	vi->vi_height = sc->sc_height/sc->sc_font_height - 2*cborder;
359193323Sed	vi->vi_cwidth = 8;
360193323Sed
361193323Sed	/*
362193323Sed	 * Clamp width/height to syscons maximums
363193323Sed	 */
364193323Sed	if (vi->vi_width > COL)
365198090Srdivacky		vi->vi_width = COL;
366193323Sed	if (vi->vi_height > ROW)
367198090Srdivacky		vi->vi_height = ROW;
368198090Srdivacky
369263508Sdim	sc->sc_xmargin = (sc->sc_width - (vi->vi_width * vi->vi_cwidth)) / 2;
370193323Sed	sc->sc_ymargin = (sc->sc_height - (vi->vi_height * vi->vi_cheight))/2;
371193323Sed
372193323Sed	/*
373193323Sed	 * Avoid huge amounts of conditional code in syscons by
374193323Sed	 * defining a dummy h/w text display buffer.
375193323Sed	 */
376193323Sed	adp->va_window = (vm_offset_t) ofwfb_static_window;
377193323Sed
378193323Sed	/* Enable future font-loading and flag color support */
379193323Sed	adp->va_flags |= V_ADP_FONT | V_ADP_COLOR;
380193323Sed
381193323Sed	ofwfb_blank_display(&sc->sc_va, V_DISPLAY_ON);
382193323Sed
383193323Sed	ofwfb_set_mode(&sc->sc_va, 0);
384193323Sed
385193323Sed	vid_register(&sc->sc_va);
386193323Sed
387193323Sed	return (0);
388193323Sed}
389207618Srdivacky
390207618Srdivackystatic int
391207618Srdivackyofwfb_get_info(video_adapter_t *adp, int mode, video_info_t *info)
392193323Sed{
393193323Sed	bcopy(&adp->va_info, info, sizeof(*info));
394218893Sdim	return (0);
395193323Sed}
396193323Sed
397193323Sedstatic int
398193323Sedofwfb_query_mode(video_adapter_t *adp, video_info_t *info)
399193323Sed{
400193323Sed	TODO;
401193323Sed	return (0);
402193323Sed}
403193323Sed
404193323Sedstatic int
405198090Srdivackyofwfb_set_mode(video_adapter_t *adp, int mode)
406193323Sed{
407263508Sdim
408193323Sed	return (0);
409193323Sed}
410198090Srdivacky
411198090Srdivackystatic int
412193323Sedofwfb_save_font(video_adapter_t *adp, int page, int size, int width,
413193323Sed    u_char *data, int c, int count)
414193323Sed{
415193323Sed	TODO;
416193323Sed	return (0);
417193323Sed}
418198090Srdivacky
419218893Sdimstatic int
420193323Sedofwfb_load_font(video_adapter_t *adp, int page, int size, int width,
421193323Sed    u_char *data, int c, int count)
422193323Sed{
423193323Sed	struct ofwfb_softc *sc;
424193323Sed
425193323Sed	sc = (struct ofwfb_softc *)adp;
426193323Sed
427193323Sed	/*
428193323Sed	 * syscons code has already determined that current width/height
429193323Sed	 * are unchanged for this new font
430193323Sed	 */
431263508Sdim	sc->sc_font = data;
432263508Sdim	return (0);
433193323Sed}
434193323Sed
435193323Sedstatic int
436218893Sdimofwfb_show_font(video_adapter_t *adp, int page)
437193323Sed{
438193323Sed
439193323Sed	return (0);
440263508Sdim}
441198090Srdivacky
442193323Sedstatic int
443193323Sedofwfb_save_palette(video_adapter_t *adp, u_char *palette)
444193323Sed{
445193323Sed	/* TODO; */
446193323Sed	return (0);
447193323Sed}
448193323Sed
449193323Sedstatic int
450193323Sedofwfb_load_palette(video_adapter_t *adp, u_char *palette)
451193323Sed{
452193323Sed	/* TODO; */
453193323Sed	return (0);
454193323Sed}
455193323Sed
456263508Sdimstatic int
457193323Sedofwfb_set_border8(video_adapter_t *adp, int border)
458193323Sed{
459207618Srdivacky	struct ofwfb_softc *sc;
460207618Srdivacky	int i, j;
461193323Sed	uint8_t *addr;
462193323Sed	uint8_t bground;
463193323Sed
464193323Sed	sc = (struct ofwfb_softc *)adp;
465203954Srdivacky
466263508Sdim	bground = ofwfb_background(border);
467193323Sed
468193323Sed	/* Set top margin */
469193323Sed	addr = (uint8_t *) sc->sc_addr;
470193323Sed	for (i = 0; i < sc->sc_ymargin; i++) {
471193323Sed		for (j = 0; j < sc->sc_width; j++) {
472193323Sed			*(addr + j) = bground;
473193323Sed		}
474193323Sed		addr += sc->sc_stride;
475193323Sed	}
476193323Sed
477218893Sdim	/* bottom margin */
478263508Sdim	addr = (uint8_t *) sc->sc_addr + (sc->sc_height - sc->sc_ymargin)*sc->sc_stride;
479193323Sed	for (i = 0; i < sc->sc_ymargin; i++) {
480193323Sed		for (j = 0; j < sc->sc_width; j++) {
481263508Sdim			*(addr + j) = bground;
482218893Sdim		}
483218893Sdim		addr += sc->sc_stride;
484203954Srdivacky	}
485263508Sdim
486193323Sed	/* remaining left and right borders */
487193323Sed	addr = (uint8_t *) sc->sc_addr + sc->sc_ymargin*sc->sc_stride;
488193323Sed	for (i = 0; i < sc->sc_height - 2*sc->sc_xmargin; i++) {
489193323Sed		for (j = 0; j < sc->sc_xmargin; j++) {
490193323Sed			*(addr + j) = bground;
491193323Sed			*(addr + j + sc->sc_width - sc->sc_xmargin) = bground;
492193323Sed		}
493193323Sed		addr += sc->sc_stride;
494193323Sed	}
495193323Sed
496193323Sed	return (0);
497193323Sed}
498193323Sed
499193323Sedstatic int
500226633Sdimofwfb_set_border32(video_adapter_t *adp, int border)
501193323Sed{
502226633Sdim	/* XXX Be lazy for now and blank entire screen */
503226633Sdim	return (ofwfb_blank_display32(adp, border));
504193323Sed}
505193323Sed
506193323Sedstatic int
507193323Sedofwfb_set_border(video_adapter_t *adp, int border)
508226633Sdim{
509263508Sdim	struct ofwfb_softc *sc;
510193323Sed
511193323Sed	sc = (struct ofwfb_softc *)adp;
512193323Sed
513193323Sed	return ((*sc->sc_set_border)(adp, border));
514226633Sdim}
515226633Sdim
516263508Sdimstatic int
517263508Sdimofwfb_save_state(video_adapter_t *adp, void *p, size_t size)
518263508Sdim{
519263508Sdim	TODO;
520263508Sdim	return (0);
521263508Sdim}
522226633Sdim
523226633Sdimstatic int
524226633Sdimofwfb_load_state(video_adapter_t *adp, void *p)
525226633Sdim{
526193323Sed	TODO;
527193323Sed	return (0);
528193323Sed}
529193323Sed
530193323Sedstatic int
531263508Sdimofwfb_set_win_org(video_adapter_t *adp, off_t offset)
532193323Sed{
533193323Sed	TODO;
534193323Sed	return (0);
535193323Sed}
536193323Sed
537193323Sedstatic int
538193323Sedofwfb_read_hw_cursor(video_adapter_t *adp, int *col, int *row)
539193323Sed{
540193323Sed	*col = 0;
541193323Sed	*row = 0;
542198090Srdivacky
543263508Sdim	return (0);
544193323Sed}
545193323Sed
546193323Sedstatic int
547ofwfb_set_hw_cursor(video_adapter_t *adp, int col, int row)
548{
549
550	return (0);
551}
552
553static int
554ofwfb_set_hw_cursor_shape(video_adapter_t *adp, int base, int height,
555    int celsize, int blink)
556{
557	return (0);
558}
559
560static int
561ofwfb_blank_display8(video_adapter_t *adp, int mode)
562{
563	struct ofwfb_softc *sc;
564	int i;
565	uint8_t *addr;
566
567	sc = (struct ofwfb_softc *)adp;
568	addr = (uint8_t *) sc->sc_addr;
569
570	/* Could be done a lot faster e.g. 32-bits, or Altivec'd */
571	for (i = 0; i < sc->sc_stride*sc->sc_height; i++)
572		*(addr + i) = ofwfb_background(SC_NORM_ATTR);
573
574	return (0);
575}
576
577static int
578ofwfb_blank_display32(video_adapter_t *adp, int mode)
579{
580	struct ofwfb_softc *sc;
581	int i;
582	uint32_t *addr;
583
584	sc = (struct ofwfb_softc *)adp;
585	addr = (uint32_t *) sc->sc_addr;
586
587	for (i = 0; i < (sc->sc_stride/4)*sc->sc_height; i++)
588		*(addr + i) = ofwfb_pix32(ofwfb_background(SC_NORM_ATTR));
589
590	return (0);
591}
592
593static int
594ofwfb_blank_display(video_adapter_t *adp, int mode)
595{
596	struct ofwfb_softc *sc;
597
598	sc = (struct ofwfb_softc *)adp;
599
600	return ((*sc->sc_blank)(adp, mode));
601}
602
603static int
604ofwfb_mmap(video_adapter_t *adp, vm_offset_t offset, vm_paddr_t *paddr,
605    int prot)
606{
607	struct ofwfb_softc *sc;
608	int i;
609
610	sc = (struct ofwfb_softc *)adp;
611
612	if (sc->sc_num_pciaddrs == 0)
613		return (ENOMEM);
614
615	/*
616	 * Hack for Radeon...
617	 */
618	if (ofwfb_ignore_mmap_checks) {
619		*paddr = offset;
620		return (0);
621	}
622
623	/*
624	 * Make sure the requested address lies within the PCI device's assigned addrs
625	 */
626	for (i = 0; i < sc->sc_num_pciaddrs; i++)
627		if (offset >= sc->sc_pciaddrs[i].phys_lo &&
628		    offset < (sc->sc_pciaddrs[i].phys_lo + sc->sc_pciaddrs[i].size_lo)) {
629			*paddr = offset;
630			return (0);
631		}
632
633	/*
634	 * This might be a legacy VGA mem request: if so, just point it at the
635	 * framebuffer, since it shouldn't be touched
636	 */
637	if (offset < sc->sc_stride*sc->sc_height) {
638		*paddr = sc->sc_addr + offset;
639		return (0);
640	}
641
642	return (EINVAL);
643}
644
645static int
646ofwfb_ioctl(video_adapter_t *adp, u_long cmd, caddr_t data)
647{
648
649	return (0);
650}
651
652static int
653ofwfb_clear(video_adapter_t *adp)
654{
655	TODO;
656	return (0);
657}
658
659static int
660ofwfb_fill_rect(video_adapter_t *adp, int val, int x, int y, int cx, int cy)
661{
662	TODO;
663	return (0);
664}
665
666static int
667ofwfb_bitblt(video_adapter_t *adp, ...)
668{
669	TODO;
670	return (0);
671}
672
673static int
674ofwfb_diag(video_adapter_t *adp, int level)
675{
676	TODO;
677	return (0);
678}
679
680static int
681ofwfb_save_cursor_palette(video_adapter_t *adp, u_char *palette)
682{
683	TODO;
684	return (0);
685}
686
687static int
688ofwfb_load_cursor_palette(video_adapter_t *adp, u_char *palette)
689{
690	TODO;
691	return (0);
692}
693
694static int
695ofwfb_copy(video_adapter_t *adp, vm_offset_t src, vm_offset_t dst, int n)
696{
697	TODO;
698	return (0);
699}
700
701static int
702ofwfb_putp(video_adapter_t *adp, vm_offset_t off, uint32_t p, uint32_t a,
703    int size, int bpp, int bit_ltor, int byte_ltor)
704{
705	TODO;
706	return (0);
707}
708
709static int
710ofwfb_putc8(video_adapter_t *adp, vm_offset_t off, uint8_t c, uint8_t a)
711{
712	struct ofwfb_softc *sc;
713	int row;
714	int col;
715	int i;
716	uint32_t *addr;
717	u_char *p, fg, bg;
718	union {
719		uint32_t l;
720		uint8_t  c[4];
721	} ch1, ch2;
722
723
724	sc = (struct ofwfb_softc *)adp;
725        row = (off / adp->va_info.vi_width) * adp->va_info.vi_cheight;
726        col = (off % adp->va_info.vi_width) * adp->va_info.vi_cwidth;
727	p = sc->sc_font + c*sc->sc_font_height;
728	addr = (u_int32_t *)((int)sc->sc_addr
729		+ (row + sc->sc_ymargin)*sc->sc_stride
730		+ col + sc->sc_xmargin);
731
732	fg = ofwfb_foreground(a);
733	bg = ofwfb_background(a);
734
735	for (i = 0; i < sc->sc_font_height; i++) {
736		u_char fline = p[i];
737
738		/*
739		 * Assume that there is more background than foreground
740		 * in characters and init accordingly
741		 */
742		ch1.l = ch2.l = (bg << 24) | (bg << 16) | (bg << 8) | bg;
743
744		/*
745		 * Calculate 2 x 4-chars at a time, and then
746		 * write these out.
747		 */
748		if (fline & 0x80) ch1.c[0] = fg;
749		if (fline & 0x40) ch1.c[1] = fg;
750		if (fline & 0x20) ch1.c[2] = fg;
751		if (fline & 0x10) ch1.c[3] = fg;
752
753		if (fline & 0x08) ch2.c[0] = fg;
754		if (fline & 0x04) ch2.c[1] = fg;
755		if (fline & 0x02) ch2.c[2] = fg;
756		if (fline & 0x01) ch2.c[3] = fg;
757
758		addr[0] = ch1.l;
759		addr[1] = ch2.l;
760		addr += (sc->sc_stride / sizeof(u_int32_t));
761	}
762
763	return (0);
764}
765
766static int
767ofwfb_putc32(video_adapter_t *adp, vm_offset_t off, uint8_t c, uint8_t a)
768{
769	struct ofwfb_softc *sc;
770	int row;
771	int col;
772	int i, j, k;
773	uint32_t *addr;
774	u_char *p;
775
776	sc = (struct ofwfb_softc *)adp;
777        row = (off / adp->va_info.vi_width) * adp->va_info.vi_cheight;
778        col = (off % adp->va_info.vi_width) * adp->va_info.vi_cwidth;
779	p = sc->sc_font + c*sc->sc_font_height;
780	addr = (uint32_t *)sc->sc_addr
781		+ (row + sc->sc_ymargin)*(sc->sc_stride/4)
782		+ col + sc->sc_xmargin;
783
784	for (i = 0; i < sc->sc_font_height; i++) {
785		for (j = 0, k = 7; j < 8; j++, k--) {
786			if ((p[i] & (1 << k)) == 0)
787				*(addr + j) = ofwfb_pix32(ofwfb_background(a));
788			else
789				*(addr + j) = ofwfb_pix32(ofwfb_foreground(a));
790		}
791		addr += (sc->sc_stride/4);
792	}
793
794	return (0);
795}
796
797static int
798ofwfb_putc(video_adapter_t *adp, vm_offset_t off, uint8_t c, uint8_t a)
799{
800	struct ofwfb_softc *sc;
801
802	sc = (struct ofwfb_softc *)adp;
803
804	return ((*sc->sc_putc)(adp, off, c, a));
805}
806
807static int
808ofwfb_puts(video_adapter_t *adp, vm_offset_t off, u_int16_t *s, int len)
809{
810	int i;
811
812	for (i = 0; i < len; i++) {
813		ofwfb_putc(adp, off + i, s[i] & 0xff, (s[i] & 0xff00) >> 8);
814	}
815	return (0);
816}
817
818static int
819ofwfb_putm(video_adapter_t *adp, int x, int y, uint8_t *pixel_image,
820    uint32_t pixel_mask, int size, int width)
821{
822	struct ofwfb_softc *sc;
823
824	sc = (struct ofwfb_softc *)adp;
825
826	/* put mouse */
827
828	return (0);
829}
830
831/*
832 * Define the syscons nexus device attachment
833 */
834static void
835ofwfb_scidentify(driver_t *driver, device_t parent)
836{
837	device_t child;
838
839	/*
840	 * Add with a priority guaranteed to make it last on
841	 * the device list
842	 */
843	child = BUS_ADD_CHILD(parent, INT_MAX, SC_DRIVER_NAME, 0);
844	if (child != NULL)
845		nexus_set_device_type(child, "syscons");
846}
847
848static int
849ofwfb_scprobe(device_t dev)
850{
851	char *name;
852
853	name = nexus_get_name(dev);
854	if (strcmp(SC_DRIVER_NAME, name) != 0)
855		return (ENXIO);
856
857	device_set_desc(dev, "System console");
858	return (sc_probe_unit(device_get_unit(dev),
859	    device_get_flags(dev) | SC_AUTODETECT_KBD));
860}
861
862static int
863ofwfb_scattach(device_t dev)
864{
865	return (sc_attach_unit(device_get_unit(dev),
866	    device_get_flags(dev) | SC_AUTODETECT_KBD));
867}
868
869static device_method_t ofwfb_sc_methods[] = {
870  	DEVMETHOD(device_identify,	ofwfb_scidentify),
871	DEVMETHOD(device_probe,		ofwfb_scprobe),
872	DEVMETHOD(device_attach,	ofwfb_scattach),
873	{ 0, 0 }
874};
875
876static driver_t ofwfb_sc_driver = {
877	SC_DRIVER_NAME,
878	ofwfb_sc_methods,
879	sizeof(sc_softc_t),
880};
881
882static devclass_t	sc_devclass;
883
884DRIVER_MODULE(sc, nexus, ofwfb_sc_driver, sc_devclass, 0, 0);
885
886/*
887 * Define a stub keyboard driver in case one hasn't been
888 * compiled into the kernel
889 */
890#include <sys/kbio.h>
891#include <dev/kbd/kbdreg.h>
892
893static int dummy_kbd_configure(int flags);
894
895keyboard_switch_t dummysw;
896
897static int
898dummy_kbd_configure(int flags)
899{
900
901	return (0);
902}
903KEYBOARD_DRIVER(dummy, dummysw, dummy_kbd_configure);
904
905/*
906 * Utility routines from <dev/fb/fbreg.h>
907 */
908void
909ofwfb_bcopy(const void *s, void *d, size_t c)
910{
911	bcopy(s, d, c);
912}
913
914void
915ofwfb_bzero(void *d, size_t c)
916{
917	bzero(d, c);
918}
919
920void
921ofwfb_fillw(int pat, void *base, size_t cnt)
922{
923	u_int16_t *bptr = base;
924
925	while (cnt--)
926		*bptr++ = pat;
927}
928
929u_int16_t
930ofwfb_readw(u_int16_t *addr)
931{
932	return (*addr);
933}
934
935void
936ofwfb_writew(u_int16_t *addr, u_int16_t val)
937{
938	*addr = val;
939}
940