vt_early_fb.c revision 266360
1/*-
2 * Copyright (c) 2013 The FreeBSD Foundation
3 * All rights reserved.
4 *
5 * This software was developed by Aleksandr Rybalko under sponsorship from the
6 * FreeBSD Foundation.
7 *
8 * Redistribution and use in source and binary forms, with or without
9 * modification, are permitted provided that the following conditions
10 * are met:
11 * 1. Redistributions of source code must retain the above copyright
12 *    notice, this list of conditions and the following disclaimer.
13 * 2. Redistributions in binary form must reproduce the above copyright
14 *    notice, this list of conditions and the following disclaimer in the
15 *    documentation and/or other materials provided with the distribution.
16 *
17 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
18 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
19 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
20 * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
21 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
22 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
23 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
24 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
25 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
26 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
27 * SUCH DAMAGE.
28 *
29 * $FreeBSD: stable/10/sys/dev/vt/hw/fb/vt_early_fb.c 266360 2014-05-17 21:31:58Z ian $
30 */
31
32#include <sys/cdefs.h>
33__FBSDID("$FreeBSD: stable/10/sys/dev/vt/hw/fb/vt_early_fb.c 266360 2014-05-17 21:31:58Z ian $");
34
35#include <sys/param.h>
36#include <sys/systm.h>
37#include <sys/kernel.h>
38#include <sys/fbio.h>
39
40#include "opt_platform.h"
41
42#ifdef	FDT
43#include <dev/fdt/fdt_common.h>
44#include <dev/ofw/ofw_bus.h>
45#include <dev/ofw/ofw_bus_subr.h>
46#include <dev/ofw/ofw_pci.h>
47#include <machine/fdt.h>
48#endif
49
50#include <dev/vt/vt.h>
51#include <dev/vt/hw/fb/vt_fb.h>
52#include <dev/vt/colors/vt_termcolors.h>
53
54static vd_init_t vt_efb_init;
55
56static struct vt_driver vt_fb_early_driver = {
57	.vd_init = vt_efb_init,
58	.vd_blank = vt_fb_blank,
59	.vd_bitbltchr = vt_fb_bitbltchr,
60	.vd_priority = VD_PRIORITY_GENERIC,
61};
62
63static struct fb_info info;
64VT_CONSDEV_DECLARE(vt_fb_early_driver,
65    MAX(80, PIXEL_WIDTH(VT_FB_DEFAULT_WIDTH)),
66    MAX(25, PIXEL_HEIGHT(VT_FB_DEFAULT_HEIGHT)), &info);
67
68static void
69#ifdef	FDT
70vt_efb_initialize(struct fb_info *info, phandle_t node)
71#else
72vt_efb_initialize(struct fb_info *info)
73#endif
74{
75#ifdef	FDT
76	char name[64];
77	cell_t retval;
78	ihandle_t ih;
79	int i;
80
81	/* Open display device, thereby initializing it */
82	memset(name, 0, sizeof(name));
83	OF_package_to_path(node, name, sizeof(name));
84	ih = OF_open(name);
85#endif
86
87	/*
88	 * Set up the color map
89	 */
90	switch (info->fb_depth) {
91	case 8:
92		vt_generate_vga_palette(info->fb_cmap, COLOR_FORMAT_RGB,
93		    0x7, 5, 0x7, 2, 0x3, 0);
94		break;
95	case 15:
96		vt_generate_vga_palette(info->fb_cmap, COLOR_FORMAT_RGB,
97		    0x1f, 10, 0x1f, 5, 0x1f, 0);
98		break;
99	case 16:
100		vt_generate_vga_palette(info->fb_cmap, COLOR_FORMAT_RGB,
101		    0x1f, 11, 0x3f, 5, 0x1f, 0);
102		break;
103	case 24:
104	case 32:
105#if BYTE_ORDER == BIG_ENDIAN
106		vt_generate_vga_palette(info->fb_cmap,
107		    COLOR_FORMAT_RGB, 255, 16, 255, 8, 255, 0);
108#else
109		vt_generate_vga_palette(info->fb_cmap,
110		    COLOR_FORMAT_RGB, 255, 0, 255, 8, 255, 16);
111#endif
112#ifdef	FDT
113		for (i = 0; i < 16; i++) {
114			OF_call_method("color!", ih, 4, 1,
115			    (cell_t)((info->fb_cmap[i] >> 16) & 0xff),
116			    (cell_t)((info->fb_cmap[i] >> 8) & 0xff),
117			    (cell_t)((info->fb_cmap[i] >> 0) & 0xff),
118			    (cell_t)i, &retval);
119		}
120#endif
121		break;
122
123	default:
124		panic("Unknown color space fb_depth %d", info->fb_depth);
125		break;
126        }
127}
128
129static int
130vt_efb_init(struct vt_device *vd)
131{
132	struct ofw_pci_register pciaddrs[8];
133	struct fb_info *info;
134	int i, len, n_pciaddrs;
135	phandle_t chosen, node;
136	ihandle_t stdout;
137	char type[64];
138
139	info = vd->vd_softc;
140
141	chosen = OF_finddevice("/chosen");
142	OF_getprop(chosen, "stdout", &stdout, sizeof(stdout));
143	node = OF_instance_to_package(stdout);
144	if (node == -1) {
145		/*
146		 * The "/chosen/stdout" does not exist try
147		 * using "screen" directly.
148		 */
149		node = OF_finddevice("screen");
150	}
151	OF_getprop(node, "device_type", type, sizeof(type));
152	if (strcmp(type, "display") != 0)
153		return (CN_DEAD);
154
155#define	GET(name, var)							\
156	if (OF_getproplen(node, (name)) != sizeof(info->fb_##var))	\
157		return (CN_DEAD);					\
158	OF_getencprop(node, (name), &info->fb_##var, sizeof(info->fb_##var)); \
159	if (info->fb_##var == 0)					\
160		return (CN_DEAD);
161
162	GET("height", height)
163	GET("width", width)
164	GET("depth", depth)
165	GET("linebytes", stride)
166#undef GET
167
168	info->fb_size = info->fb_height * info->fb_stride;
169
170	/*
171	 * Get the PCI addresses of the adapter, if present. The node may be the
172	 * child of the PCI device: in that case, try the parent for
173	 * the assigned-addresses property.
174	 */
175	len = OF_getprop(node, "assigned-addresses", pciaddrs,
176	    sizeof(pciaddrs));
177	if (len == -1) {
178		len = OF_getprop(OF_parent(node), "assigned-addresses",
179		    pciaddrs, sizeof(pciaddrs));
180        }
181        if (len == -1)
182                len = 0;
183	n_pciaddrs = len / sizeof(struct ofw_pci_register);
184
185	/*
186	 * Grab the physical address of the framebuffer, and then map it
187	 * into our memory space. If the MMU is not yet up, it will be
188	 * remapped for us when relocation turns on.
189	 */
190	if (OF_getproplen(node, "address") == sizeof(info->fb_pbase)) {
191	 	/* XXX We assume #address-cells is 1 at this point. */
192		OF_getencprop(node, "address", &info->fb_pbase,
193		    sizeof(info->fb_pbase));
194
195	#if defined(__powerpc__)
196		sc->sc_memt = &bs_be_tag;
197		bus_space_map(sc->sc_memt, info->fb_pbase, info->fb_size,
198		    BUS_SPACE_MAP_PREFETCHABLE, &info->fb_vbase);
199	#elif defined(__sparc64__)
200		OF_decode_addr(node, 0, &space, &phys);
201		sc->sc_memt = &vt_efb_memt[0];
202		info->addr = sparc64_fake_bustag(space, fb_phys, sc->sc_memt);
203	#else
204		bus_space_map(fdtbus_bs_tag, info->fb_pbase, info->fb_size,
205		    BUS_SPACE_MAP_PREFETCHABLE,
206		    (bus_space_handle_t *)&info->fb_vbase);
207	#endif
208	} else {
209		/*
210		 * Some IBM systems don't have an address property. Try to
211		 * guess the framebuffer region from the assigned addresses.
212		 * This is ugly, but there doesn't seem to be an alternative.
213		 * Linux does the same thing.
214		 */
215
216		info->fb_pbase = n_pciaddrs;
217		for (i = 0; i < n_pciaddrs; i++) {
218			/* If it is too small, not the framebuffer */
219			if (pciaddrs[i].size_lo < info->fb_size)
220				continue;
221			/* If it is not memory, it isn't either */
222			if (!(pciaddrs[i].phys_hi &
223			    OFW_PCI_PHYS_HI_SPACE_MEM32))
224				continue;
225
226			/* This could be the framebuffer */
227			info->fb_pbase = i;
228
229			/* If it is prefetchable, it certainly is */
230			if (pciaddrs[i].phys_hi & OFW_PCI_PHYS_HI_PREFETCHABLE)
231				break;
232		}
233
234		if (info->fb_pbase == n_pciaddrs) /* No candidates found */
235			return (CN_DEAD);
236
237	#if defined(__powerpc__)
238		OF_decode_addr(node, info->fb_pbase, &sc->sc_memt,
239		    &info->fb_vbase);
240	#elif defined(__sparc64__)
241		OF_decode_addr(node, info->fb_pbase, &space, &info->fb_pbase);
242		sc->sc_memt = &vt_efb_memt[0];
243		info->fb_vbase = sparc64_fake_bustag(space, info->fb_pbase,
244		    sc->sc_memt);
245	#else
246		bus_space_map(fdtbus_bs_tag, info->fb_pbase, info->fb_size,
247		    BUS_SPACE_MAP_PREFETCHABLE,
248		    (bus_space_handle_t *)&info->fb_vbase);
249	#endif
250        }
251
252
253	/* blank full size */
254	len = info->fb_size / 4;
255	for (i = 0; i < len; i++) {
256		((uint32_t *)info->fb_vbase)[i] = 0;
257	}
258
259	/* Get pixel storage size. */
260	info->fb_bpp = info->fb_stride / info->fb_width * 8;
261
262	/*
263	 * Early FB driver work with static window buffer 80x25, so reduce
264	 * size to 640x480.
265	 */
266	info->fb_width = VT_FB_DEFAULT_WIDTH;
267	info->fb_height = VT_FB_DEFAULT_HEIGHT;
268
269#ifdef	FDT
270	vt_efb_initialize(info, node);
271#else
272	vt_efb_initialize(info);
273#endif
274	fb_probe(info);
275	vt_fb_init(vd);
276
277
278	return (CN_INTERNAL);
279}
280