vt_early_fb.c revision 265397
1257726Sray/*-
2257726Sray * Copyright (c) 2013 The FreeBSD Foundation
3257726Sray * All rights reserved.
4257726Sray *
5257726Sray * This software was developed by Aleksandr Rybalko under sponsorship from the
6257726Sray * FreeBSD Foundation.
7257726Sray *
8257726Sray * Redistribution and use in source and binary forms, with or without
9257726Sray * modification, are permitted provided that the following conditions
10257726Sray * are met:
11257726Sray * 1. Redistributions of source code must retain the above copyright
12257726Sray *    notice, this list of conditions and the following disclaimer.
13257726Sray * 2. Redistributions in binary form must reproduce the above copyright
14257726Sray *    notice, this list of conditions and the following disclaimer in the
15257726Sray *    documentation and/or other materials provided with the distribution.
16257726Sray *
17257726Sray * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
18257726Sray * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
19257726Sray * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
20257726Sray * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
21257726Sray * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
22257726Sray * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
23257726Sray * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
24257726Sray * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
25257726Sray * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
26257726Sray * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
27257726Sray * SUCH DAMAGE.
28257726Sray *
29257726Sray * $FreeBSD: head/sys/dev/vt/hw/fb/vt_early_fb.c 265397 2014-05-05 21:48:19Z ray $
30257726Sray */
31257726Sray
32257726Sray#include <sys/cdefs.h>
33257726Sray__FBSDID("$FreeBSD: head/sys/dev/vt/hw/fb/vt_early_fb.c 265397 2014-05-05 21:48:19Z ray $");
34257726Sray
35257726Sray#include <sys/param.h>
36257726Sray#include <sys/systm.h>
37257726Sray#include <sys/kernel.h>
38257726Sray#include <sys/fbio.h>
39257726Sray
40257726Sray#include "opt_platform.h"
41257726Sray
42257726Sray#ifdef	FDT
43257726Sray#include <dev/fdt/fdt_common.h>
44257726Sray#include <dev/ofw/ofw_bus.h>
45257726Sray#include <dev/ofw/ofw_bus_subr.h>
46257726Sray#include <dev/ofw/ofw_pci.h>
47264182Srpaulo#include <machine/fdt.h>
48257726Sray#endif
49257726Sray
50257726Sray#include <dev/vt/vt.h>
51257726Sray#include <dev/vt/hw/fb/vt_fb.h>
52257726Sray#include <dev/vt/colors/vt_termcolors.h>
53257726Sray
54257726Sraystatic vd_init_t vt_efb_init;
55265397Sraystatic vd_probe_t vt_efb_probe;
56257726Sray
57257726Sraystatic struct vt_driver vt_fb_early_driver = {
58265397Sray	.vd_name = "efb",
59265397Sray	.vd_probe = vt_efb_probe,
60257726Sray	.vd_init = vt_efb_init,
61257726Sray	.vd_blank = vt_fb_blank,
62257726Sray	.vd_bitbltchr = vt_fb_bitbltchr,
63257726Sray	.vd_priority = VD_PRIORITY_GENERIC,
64257726Sray};
65257726Sray
66265397Sraystatic struct fb_info local_info;
67265397SrayVT_DRIVER_DECLARE(vt_efb, vt_fb_early_driver);
68257726Sray
69257726Sraystatic void
70257726Sray#ifdef	FDT
71257726Srayvt_efb_initialize(struct fb_info *info, phandle_t node)
72257726Sray#else
73257726Srayvt_efb_initialize(struct fb_info *info)
74257726Sray#endif
75257726Sray{
76257726Sray#ifdef	FDT
77257726Sray	char name[64];
78257726Sray	cell_t retval;
79257726Sray	ihandle_t ih;
80257726Sray	int i;
81257726Sray
82257726Sray	/* Open display device, thereby initializing it */
83257726Sray	memset(name, 0, sizeof(name));
84257726Sray	OF_package_to_path(node, name, sizeof(name));
85257726Sray	ih = OF_open(name);
86257726Sray#endif
87257726Sray
88257726Sray	/*
89257726Sray	 * Set up the color map
90257726Sray	 */
91257726Sray	switch (info->fb_depth) {
92257726Sray	case 8:
93257726Sray		vt_generate_vga_palette(info->fb_cmap, COLOR_FORMAT_RGB,
94257726Sray		    0x7, 5, 0x7, 2, 0x3, 0);
95257726Sray		break;
96257726Sray	case 15:
97257726Sray		vt_generate_vga_palette(info->fb_cmap, COLOR_FORMAT_RGB,
98257726Sray		    0x1f, 10, 0x1f, 5, 0x1f, 0);
99257726Sray		break;
100257726Sray	case 16:
101257726Sray		vt_generate_vga_palette(info->fb_cmap, COLOR_FORMAT_RGB,
102257726Sray		    0x1f, 11, 0x3f, 5, 0x1f, 0);
103257726Sray		break;
104257726Sray	case 24:
105257726Sray	case 32:
106257726Sray#if BYTE_ORDER == BIG_ENDIAN
107257726Sray		vt_generate_vga_palette(info->fb_cmap,
108257726Sray		    COLOR_FORMAT_RGB, 255, 16, 255, 8, 255, 0);
109257726Sray#else
110257726Sray		vt_generate_vga_palette(info->fb_cmap,
111257726Sray		    COLOR_FORMAT_RGB, 255, 0, 255, 8, 255, 16);
112257726Sray#endif
113257726Sray#ifdef	FDT
114257726Sray		for (i = 0; i < 16; i++) {
115257726Sray			OF_call_method("color!", ih, 4, 1,
116257726Sray			    (cell_t)((info->fb_cmap[i] >> 16) & 0xff),
117257726Sray			    (cell_t)((info->fb_cmap[i] >> 8) & 0xff),
118257726Sray			    (cell_t)((info->fb_cmap[i] >> 0) & 0xff),
119257726Sray			    (cell_t)i, &retval);
120257726Sray		}
121257726Sray#endif
122257726Sray		break;
123257726Sray
124257726Sray	default:
125257726Sray		panic("Unknown color space fb_depth %d", info->fb_depth);
126257726Sray		break;
127257726Sray        }
128257726Sray}
129257726Sray
130265397Sraystatic phandle_t
131265397Srayvt_efb_get_fbnode()
132257726Sray{
133257726Sray	phandle_t chosen, node;
134257726Sray	ihandle_t stdout;
135257726Sray	char type[64];
136257726Sray
137257726Sray	chosen = OF_finddevice("/chosen");
138257726Sray	OF_getprop(chosen, "stdout", &stdout, sizeof(stdout));
139257726Sray	node = OF_instance_to_package(stdout);
140265397Sray	if (node != -1) {
141265397Sray		/* The "/chosen/stdout" present. */
142265397Sray		OF_getprop(node, "device_type", type, sizeof(type));
143265397Sray		/* Check if it has "display" type. */
144265397Sray		if (strcmp(type, "display") == 0)
145265397Sray			return (node);
146257726Sray	}
147265397Sray	/* Try device with name "screen". */
148265397Sray	node = OF_finddevice("screen");
149265397Sray
150265397Sray	return (node);
151265397Sray}
152265397Sray
153265397Sraystatic int
154265397Srayvt_efb_probe(struct vt_device *vd)
155265397Sray{
156265397Sray	phandle_t node;
157265397Sray
158265397Sray	node = vt_efb_get_fbnode();
159265397Sray	if (node == -1)
160257726Sray		return (CN_DEAD);
161257726Sray
162265397Sray	if ((OF_getproplen(node, "height") <= 0) ||
163265397Sray	    (OF_getproplen(node, "width") <= 0) ||
164265397Sray	    (OF_getproplen(node, "depth") <= 0) ||
165265397Sray	    (OF_getproplen(node, "linebytes") <= 0))
166265397Sray		return (CN_DEAD);
167265397Sray
168265397Sray	return (CN_INTERNAL);
169265397Sray}
170265397Sray
171265397Sraystatic int
172265397Srayvt_efb_init(struct vt_device *vd)
173265397Sray{
174265397Sray	struct ofw_pci_register pciaddrs[8];
175265397Sray	struct fb_info *info;
176265397Sray	int i, len, n_pciaddrs;
177265397Sray	phandle_t node;
178265397Sray
179265397Sray	if (vd->vd_softc == NULL)
180265397Sray		vd->vd_softc = (void *)&local_info;
181265397Sray
182265397Sray	info = vd->vd_softc;
183265397Sray
184265397Sray	node = vt_efb_get_fbnode();
185265397Sray	if (node == -1)
186265397Sray		return (CN_DEAD);
187265397Sray
188257726Sray#define	GET(name, var)							\
189257726Sray	if (OF_getproplen(node, (name)) != sizeof(info->fb_##var))	\
190257726Sray		return (CN_DEAD);					\
191257726Sray	OF_getencprop(node, (name), &info->fb_##var, sizeof(info->fb_##var)); \
192257726Sray	if (info->fb_##var == 0)					\
193257726Sray		return (CN_DEAD);
194257726Sray
195257726Sray	GET("height", height)
196257726Sray	GET("width", width)
197257726Sray	GET("depth", depth)
198257726Sray	GET("linebytes", stride)
199257726Sray#undef GET
200257726Sray
201257726Sray	info->fb_size = info->fb_height * info->fb_stride;
202257726Sray
203257726Sray	/*
204257726Sray	 * Get the PCI addresses of the adapter, if present. The node may be the
205257726Sray	 * child of the PCI device: in that case, try the parent for
206257726Sray	 * the assigned-addresses property.
207257726Sray	 */
208257726Sray	len = OF_getprop(node, "assigned-addresses", pciaddrs,
209257726Sray	    sizeof(pciaddrs));
210257726Sray	if (len == -1) {
211257726Sray		len = OF_getprop(OF_parent(node), "assigned-addresses",
212257726Sray		    pciaddrs, sizeof(pciaddrs));
213257726Sray        }
214257726Sray        if (len == -1)
215257726Sray                len = 0;
216257726Sray	n_pciaddrs = len / sizeof(struct ofw_pci_register);
217257726Sray
218257726Sray	/*
219257726Sray	 * Grab the physical address of the framebuffer, and then map it
220257726Sray	 * into our memory space. If the MMU is not yet up, it will be
221257726Sray	 * remapped for us when relocation turns on.
222257726Sray	 */
223257726Sray	if (OF_getproplen(node, "address") == sizeof(info->fb_pbase)) {
224257726Sray	 	/* XXX We assume #address-cells is 1 at this point. */
225257726Sray		OF_getencprop(node, "address", &info->fb_pbase,
226257726Sray		    sizeof(info->fb_pbase));
227257726Sray
228257726Sray	#if defined(__powerpc__)
229257726Sray		sc->sc_memt = &bs_be_tag;
230257726Sray		bus_space_map(sc->sc_memt, info->fb_pbase, info->fb_size,
231257726Sray		    BUS_SPACE_MAP_PREFETCHABLE, &info->fb_vbase);
232257726Sray	#elif defined(__sparc64__)
233257726Sray		OF_decode_addr(node, 0, &space, &phys);
234257726Sray		sc->sc_memt = &vt_efb_memt[0];
235257726Sray		info->addr = sparc64_fake_bustag(space, fb_phys, sc->sc_memt);
236257726Sray	#else
237257726Sray		bus_space_map(fdtbus_bs_tag, info->fb_pbase, info->fb_size,
238257726Sray		    BUS_SPACE_MAP_PREFETCHABLE,
239257726Sray		    (bus_space_handle_t *)&info->fb_vbase);
240257726Sray	#endif
241257726Sray	} else {
242257726Sray		/*
243257726Sray		 * Some IBM systems don't have an address property. Try to
244257726Sray		 * guess the framebuffer region from the assigned addresses.
245257726Sray		 * This is ugly, but there doesn't seem to be an alternative.
246257726Sray		 * Linux does the same thing.
247257726Sray		 */
248257726Sray
249257726Sray		info->fb_pbase = n_pciaddrs;
250257726Sray		for (i = 0; i < n_pciaddrs; i++) {
251257726Sray			/* If it is too small, not the framebuffer */
252257726Sray			if (pciaddrs[i].size_lo < info->fb_size)
253257726Sray				continue;
254257726Sray			/* If it is not memory, it isn't either */
255257726Sray			if (!(pciaddrs[i].phys_hi &
256257726Sray			    OFW_PCI_PHYS_HI_SPACE_MEM32))
257257726Sray				continue;
258257726Sray
259257726Sray			/* This could be the framebuffer */
260257726Sray			info->fb_pbase = i;
261257726Sray
262257726Sray			/* If it is prefetchable, it certainly is */
263257726Sray			if (pciaddrs[i].phys_hi & OFW_PCI_PHYS_HI_PREFETCHABLE)
264257726Sray				break;
265257726Sray		}
266257726Sray
267257726Sray		if (info->fb_pbase == n_pciaddrs) /* No candidates found */
268257726Sray			return (CN_DEAD);
269257726Sray
270257726Sray	#if defined(__powerpc__)
271257726Sray		OF_decode_addr(node, info->fb_pbase, &sc->sc_memt,
272257726Sray		    &info->fb_vbase);
273257726Sray	#elif defined(__sparc64__)
274257726Sray		OF_decode_addr(node, info->fb_pbase, &space, &info->fb_pbase);
275257726Sray		sc->sc_memt = &vt_efb_memt[0];
276257726Sray		info->fb_vbase = sparc64_fake_bustag(space, info->fb_pbase,
277257726Sray		    sc->sc_memt);
278257726Sray	#else
279257726Sray		bus_space_map(fdtbus_bs_tag, info->fb_pbase, info->fb_size,
280257726Sray		    BUS_SPACE_MAP_PREFETCHABLE,
281257726Sray		    (bus_space_handle_t *)&info->fb_vbase);
282257726Sray	#endif
283257726Sray        }
284257726Sray
285257726Sray	/* blank full size */
286257726Sray	len = info->fb_size / 4;
287257726Sray	for (i = 0; i < len; i++) {
288257726Sray		((uint32_t *)info->fb_vbase)[i] = 0;
289257726Sray	}
290257726Sray
291257726Sray	/* Get pixel storage size. */
292257726Sray	info->fb_bpp = info->fb_stride / info->fb_width * 8;
293257726Sray
294257726Sray	/*
295257726Sray	 * Early FB driver work with static window buffer 80x25, so reduce
296257726Sray	 * size to 640x480.
297257726Sray	 */
298257726Sray	info->fb_width = VT_FB_DEFAULT_WIDTH;
299257726Sray	info->fb_height = VT_FB_DEFAULT_HEIGHT;
300257726Sray
301257726Sray#ifdef	FDT
302257726Sray	vt_efb_initialize(info, node);
303257726Sray#else
304257726Sray	vt_efb_initialize(info);
305257726Sray#endif
306257726Sray	fb_probe(info);
307257726Sray	vt_fb_init(vd);
308257726Sray
309257726Sray	return (CN_INTERNAL);
310257726Sray}
311