ofwfb.c revision 230440
1/*-
2 * Copyright (c) 2011 Nathan Whitehorn
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: user/ed/newcons/sys/dev/vt/hw/ofwfb/ofwfb.c 219888 2011-03-22 21:31:31Z ed $");
29
30#include <sys/param.h>
31#include <sys/kernel.h>
32#include <sys/systm.h>
33
34#include <dev/vt/vt.h>
35
36#include <vm/vm.h>
37#include <vm/pmap.h>
38
39#include <machine/bus.h>
40#ifdef __sparc64__
41#include <machine/bus_private.h>
42#endif
43
44#include <dev/ofw/openfirm.h>
45#include <dev/ofw/ofw_bus.h>
46#include <dev/ofw/ofw_pci.h>
47
48struct ofwfb_softc {
49	phandle_t	sc_node;
50
51	intptr_t	sc_addr;
52	int		sc_depth;
53	int		sc_stride;
54
55#ifdef __sparc64__
56	bus_space_tag_t	sc_memt;
57#endif
58};
59
60static vd_init_t	ofwfb_init;
61static vd_blank_t	ofwfb_blank;
62static vd_bitblt_t	ofwfb_bitblt;
63
64static const struct vt_driver vt_ofwfb_driver = {
65	.vd_init	= ofwfb_init,
66	.vd_blank	= ofwfb_blank,
67	.vd_bitblt	= ofwfb_bitblt,
68};
69
70static struct ofwfb_softc ofwfb_conssoftc;
71VT_CONSDEV_DECLARE(vt_ofwfb_driver, PIXEL_WIDTH(1920), PIXEL_HEIGHT(1200),
72    &ofwfb_conssoftc);
73/* XXX: hardcoded max size */
74
75static const uint32_t colormap[] = {
76	0x00000000,	/* Black */
77	0x00ff0000,	/* Red */
78	0x0000ff00,	/* Green */
79	0x00c0c000,	/* Brown */
80	0x000000ff,	/* Blue */
81	0x00c000c0,	/* Magenta */
82	0x0000c0c0,	/* Cyan */
83	0x00c0c0c0,	/* Light grey */
84	0x00808080,	/* Dark grey */
85	0x00ff8080,	/* Light red */
86	0x0080ff80,	/* Light green */
87	0x00ffff80,	/* Yellow */
88	0x008080ff,	/* Light blue */
89	0x00ff80ff,	/* Light magenta */
90	0x0080ffff,	/* Light cyan */
91	0x00ffffff, 	/* White */
92};
93
94static void
95ofwfb_blank(struct vt_device *vd, term_color_t color)
96{
97	struct ofwfb_softc *sc = vd->vd_softc;
98	u_int ofs;
99	uint32_t c;
100
101	switch (sc->sc_depth) {
102	case 8:
103		for (ofs = 0; ofs < sc->sc_stride*vd->vd_height; ofs++)
104			*(uint8_t *)(sc->sc_addr + ofs) = color;
105		break;
106	case 32:
107		c = colormap[color];
108		for (ofs = 0; ofs < sc->sc_stride*vd->vd_height; ofs++)
109			*(uint32_t *)(sc->sc_addr + 4*ofs) = c;
110		break;
111	default:
112		/* panic? */
113		break;
114	}
115}
116
117static void
118ofwfb_bitblt(struct vt_device *vd, const uint8_t *src,
119    vt_axis_t top, vt_axis_t left, unsigned int width, unsigned int height,
120    term_color_t fg, term_color_t bg)
121{
122	struct ofwfb_softc *sc = vd->vd_softc;
123	u_long line;
124	uint32_t fgc, bgc;
125	int c;
126	uint8_t b = 0;
127
128	fgc = colormap[fg];
129	bgc = colormap[bg];
130
131	line = (sc->sc_stride * top) + left * sc->sc_depth/8;
132	for (; height > 0; height--) {
133		line += sc->sc_stride;
134		for (c = 0; c < width; c++) {
135			if (c % 8 == 0)
136				b = *src++;
137			else
138				b <<= 1;
139			switch(sc->sc_depth) {
140			case 8:
141				*(uint8_t *)(sc->sc_addr + line + c) =
142				    b & 0x80 ? fg : bg;
143				break;
144			case 32:
145				*(uint32_t *)(sc->sc_addr + line + 4*c) =
146				    (b & 0x80) ? fgc : bgc;
147				break;
148			default:
149				/* panic? */
150				break;
151			}
152		}
153	}
154}
155
156static void
157ofwfb_initialize(struct vt_device *vd)
158{
159	struct ofwfb_softc *sc = vd->vd_softc;
160	char name[64];
161	ihandle_t ih;
162	int i;
163	cell_t retval;
164
165	/* Open display device, thereby initializing it */
166	memset(name, 0, sizeof(name));
167	OF_package_to_path(sc->sc_node, name, sizeof(name));
168	ih = OF_open(name);
169
170	if (sc->sc_depth == 8) {
171		/*
172		 * Install the color map
173		 */
174		for (i = 0; i < 16; i++) {
175			OF_call_method("color!", ih, 4, 1,
176			    (cell_t)((colormap[i] >> 16) & 0xff),
177			    (cell_t)((colormap[i] >> 8) & 0xff),
178			    (cell_t)((colormap[i] >> 0) & 0xff),
179			    (cell_t)i, &retval);
180		}
181        }
182
183	/* Clear the screen. */
184	ofwfb_blank(vd, TC_BLACK);
185}
186
187static int
188ofwfb_init(struct vt_device *vd)
189{
190	struct ofwfb_softc *sc = vd->vd_softc;
191	char type[64];
192	phandle_t chosen;
193	ihandle_t stdout;
194	phandle_t node;
195	uint32_t depth, height, width;
196	uint32_t fb_phys;
197#ifdef __sparc64__
198	static struct bus_space_tag ofwfb_memt[1];
199	bus_addr_t phys;
200	int space;
201#endif
202
203	chosen = OF_finddevice("/chosen");
204	OF_getprop(chosen, "stdout", &stdout, sizeof(stdout));
205	node = OF_instance_to_package(stdout);
206	if (node == -1) {
207		/*
208		 * The "/chosen/stdout" does not exist try
209		 * using "screen" directly.
210		 */
211		node = OF_finddevice("screen");
212	}
213	OF_getprop(node, "device_type", type, sizeof(type));
214	if (strcmp(type, "display") != 0)
215		return (CN_DEAD);
216
217	/* Keep track of the OF node */
218	sc->sc_node = node;
219
220	/* Only support 8 and 32-bit framebuffers */
221	OF_getprop(node, "depth", &depth, sizeof(depth));
222	sc->sc_depth = depth;
223
224	OF_getprop(node, "height", &height, sizeof(height));
225	OF_getprop(node, "width", &width, sizeof(width));
226	OF_getprop(node, "linebytes", &sc->sc_stride, sizeof(sc->sc_stride));
227
228	vd->vd_height = height;
229	vd->vd_width = width;
230
231	/*
232	 * Grab the physical address of the framebuffer, and then map it
233	 * into our memory space. If the MMU is not yet up, it will be
234	 * remapped for us when relocation turns on.
235	 */
236
237	 /* XXX We assume #address-cells is 1 at this point. */
238	OF_getprop(node, "address", &fb_phys, sizeof(fb_phys));
239
240#if defined(__powerpc__)
241	bus_space_map(&bs_be_tag, fb_phys, height * sc->sc_stride,
242	    BUS_SPACE_MAP_PREFETCHABLE, &sc->sc_addr);
243#elif defined(__sparc64__)
244	OF_decode_addr(node, 0, &space, &phys);
245	sc->sc_memt = &ofwfb_memt[0];
246	sc->sc_addr = sparc64_fake_bustag(space, fb_phys, sc->sc_memt);
247#else
248	#error Unsupported platform!
249#endif
250
251	ofwfb_initialize(vd);
252
253	return (CN_INTERNAL);
254}
255
256