xref: /freebsd/sys/dev/vt/hw/ofwfb/ofwfb.c (revision b93028d8cd3aafc883b5f0ecec65a8a2a30af7f3)
1a7435285SWarner Losh /*-
24d846d26SWarner Losh  * SPDX-License-Identifier: BSD-2-Clause
3718cf2ccSPedro F. Giffuni  *
427cf7d04SAleksandr Rybalko  * Copyright (c) 2011 Nathan Whitehorn
527cf7d04SAleksandr Rybalko  * All rights reserved.
627cf7d04SAleksandr Rybalko  *
727cf7d04SAleksandr Rybalko  * Redistribution and use in source and binary forms, with or without
827cf7d04SAleksandr Rybalko  * modification, are permitted provided that the following conditions
927cf7d04SAleksandr Rybalko  * are met:
1027cf7d04SAleksandr Rybalko  * 1. Redistributions of source code must retain the above copyright
1127cf7d04SAleksandr Rybalko  *    notice, this list of conditions and the following disclaimer.
1227cf7d04SAleksandr Rybalko  * 2. Redistributions in binary form must reproduce the above copyright
1327cf7d04SAleksandr Rybalko  *    notice, this list of conditions and the following disclaimer in the
1427cf7d04SAleksandr Rybalko  *    documentation and/or other materials provided with the distribution.
1527cf7d04SAleksandr Rybalko  *
1627cf7d04SAleksandr Rybalko  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
1727cf7d04SAleksandr Rybalko  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
1827cf7d04SAleksandr Rybalko  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
1927cf7d04SAleksandr Rybalko  * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
2027cf7d04SAleksandr Rybalko  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
2127cf7d04SAleksandr Rybalko  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
2227cf7d04SAleksandr Rybalko  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
2327cf7d04SAleksandr Rybalko  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
2427cf7d04SAleksandr Rybalko  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
2527cf7d04SAleksandr Rybalko  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
2627cf7d04SAleksandr Rybalko  * SUCH DAMAGE.
2727cf7d04SAleksandr Rybalko  */
2827cf7d04SAleksandr Rybalko 
2927cf7d04SAleksandr Rybalko #include <sys/param.h>
3027cf7d04SAleksandr Rybalko #include <sys/kernel.h>
3127cf7d04SAleksandr Rybalko #include <sys/systm.h>
3200cf40b0SNathan Whitehorn #include <sys/fbio.h>
3327cf7d04SAleksandr Rybalko 
3427cf7d04SAleksandr Rybalko #include <dev/vt/vt.h>
3500cf40b0SNathan Whitehorn #include <dev/vt/hw/fb/vt_fb.h>
3627cf7d04SAleksandr Rybalko #include <dev/vt/colors/vt_termcolors.h>
3727cf7d04SAleksandr Rybalko 
3827cf7d04SAleksandr Rybalko #include <vm/vm.h>
3927cf7d04SAleksandr Rybalko #include <vm/pmap.h>
4027cf7d04SAleksandr Rybalko 
4127cf7d04SAleksandr Rybalko #include <machine/bus.h>
424f75b930SNathan Whitehorn #include <machine/cpu.h>
4327cf7d04SAleksandr Rybalko 
4427cf7d04SAleksandr Rybalko #include <dev/ofw/openfirm.h>
4527cf7d04SAleksandr Rybalko #include <dev/ofw/ofw_bus.h>
4627cf7d04SAleksandr Rybalko #include <dev/ofw/ofw_pci.h>
4750b7c1f5SAlfredo Dal'Ava Junior #include <dev/ofw/ofw_subr.h>
4827cf7d04SAleksandr Rybalko 
4927cf7d04SAleksandr Rybalko struct ofwfb_softc {
5000cf40b0SNathan Whitehorn 	struct fb_info	fb;
5100cf40b0SNathan Whitehorn 
5227cf7d04SAleksandr Rybalko 	phandle_t	sc_node;
53232490c6SNathan Whitehorn 	ihandle_t	sc_handle;
5400cf40b0SNathan Whitehorn 	bus_space_tag_t	sc_memt;
5525023a8aSNathan Whitehorn 	int		iso_palette;
5650b7c1f5SAlfredo Dal'Ava Junior 	int		argb;
5750b7c1f5SAlfredo Dal'Ava Junior 	int		endian_flip;
5850b7c1f5SAlfredo Dal'Ava Junior 	uint32_t	vendor_id;
5927cf7d04SAleksandr Rybalko };
6027cf7d04SAleksandr Rybalko 
61b042d10cSAlfredo Dal'Ava Junior #define PCI_VID_NVIDIA	0x10de	/* NVIDIA Corporation */
62b042d10cSAlfredo Dal'Ava Junior #define PCI_VID_ASPEED	0x1a03	/* ASPEED Technology, Inc. */
6350b7c1f5SAlfredo Dal'Ava Junior 
64bb0455d7SNathan Whitehorn static void ofwfb_initialize(struct vt_device *vd);
65bdf49e39SNathan Whitehorn static vd_probe_t	ofwfb_probe;
6627cf7d04SAleksandr Rybalko static vd_init_t	ofwfb_init;
675a7d2743SJean-Sébastien Pédron static vd_bitblt_text_t	ofwfb_bitblt_text;
68631bb572SJean-Sébastien Pédron static vd_bitblt_bmp_t	ofwfb_bitblt_bitmap;
69*b93028d8SEmmanuel Vadot static vd_bitblt_argb_t	ofwfb_bitblt_argb;
7027cf7d04SAleksandr Rybalko 
7127cf7d04SAleksandr Rybalko static const struct vt_driver vt_ofwfb_driver = {
72ac7073a9SAleksandr Rybalko 	.vd_name	= "ofwfb",
73bdf49e39SNathan Whitehorn 	.vd_probe	= ofwfb_probe,
7427cf7d04SAleksandr Rybalko 	.vd_init	= ofwfb_init,
7500cf40b0SNathan Whitehorn 	.vd_blank	= vt_fb_blank,
765a7d2743SJean-Sébastien Pédron 	.vd_bitblt_text	= ofwfb_bitblt_text,
77631bb572SJean-Sébastien Pédron 	.vd_bitblt_bmp	= ofwfb_bitblt_bitmap,
78*b93028d8SEmmanuel Vadot 	.vd_bitblt_argb	= ofwfb_bitblt_argb,
79232490c6SNathan Whitehorn 	.vd_fb_ioctl	= vt_fb_ioctl,
80232490c6SNathan Whitehorn 	.vd_fb_mmap	= vt_fb_mmap,
8127cf7d04SAleksandr Rybalko 	.vd_priority	= VD_PRIORITY_GENERIC+1,
8227cf7d04SAleksandr Rybalko };
8327cf7d04SAleksandr Rybalko 
8425023a8aSNathan Whitehorn static unsigned char ofw_colors[16] = {
8525023a8aSNathan Whitehorn 	/* See "16-color Text Extension" Open Firmware document, page 4 */
8625023a8aSNathan Whitehorn 	0, 4, 2, 6, 1, 5, 3, 7,
8725023a8aSNathan Whitehorn 	8, 12, 10, 14, 9, 13, 11, 15
8825023a8aSNathan Whitehorn };
8925023a8aSNathan Whitehorn 
9027cf7d04SAleksandr Rybalko static struct ofwfb_softc ofwfb_conssoftc;
91bdf49e39SNathan Whitehorn VT_DRIVER_DECLARE(vt_ofwfb, vt_ofwfb_driver);
92bdf49e39SNathan Whitehorn 
93bdf49e39SNathan Whitehorn static int
94bdf49e39SNathan Whitehorn ofwfb_probe(struct vt_device *vd)
95bdf49e39SNathan Whitehorn {
9635f29427SLeandro Lupori 	int disabled;
97bdf49e39SNathan Whitehorn 	phandle_t chosen, node;
98bdf49e39SNathan Whitehorn 	ihandle_t stdout;
99529f0e6cSJustin Hibbits 	char buf[64];
100bdf49e39SNathan Whitehorn 
10135f29427SLeandro Lupori 	disabled = 0;
10235f29427SLeandro Lupori 	TUNABLE_INT_FETCH("hw.ofwfb.disable", &disabled);
10335f29427SLeandro Lupori 	if (disabled)
10435f29427SLeandro Lupori 		return (CN_DEAD);
10535f29427SLeandro Lupori 
106bdf49e39SNathan Whitehorn 	chosen = OF_finddevice("/chosen");
107223d42a4SNathan Whitehorn 	if (chosen == -1)
108223d42a4SNathan Whitehorn 		return (CN_DEAD);
109223d42a4SNathan Whitehorn 
110223d42a4SNathan Whitehorn 	node = -1;
111043577b7SLeandro Lupori 	if (OF_getencprop(chosen, "stdout", &stdout, sizeof(stdout)) ==
112223d42a4SNathan Whitehorn 	    sizeof(stdout))
113bdf49e39SNathan Whitehorn 		node = OF_instance_to_package(stdout);
1141dbd2e8cSJustin Hibbits 	if (node == -1)
115529f0e6cSJustin Hibbits 		if (OF_getprop(chosen, "stdout-path", buf, sizeof(buf)) > 0)
116529f0e6cSJustin Hibbits 			node = OF_finddevice(buf);
117bdf49e39SNathan Whitehorn 	if (node == -1) {
118bdf49e39SNathan Whitehorn 		/*
119bdf49e39SNathan Whitehorn 		 * The "/chosen/stdout" does not exist try
120bdf49e39SNathan Whitehorn 		 * using "screen" directly.
121bdf49e39SNathan Whitehorn 		 */
122bdf49e39SNathan Whitehorn 		node = OF_finddevice("screen");
123bdf49e39SNathan Whitehorn 	}
124529f0e6cSJustin Hibbits 	OF_getprop(node, "device_type", buf, sizeof(buf));
125529f0e6cSJustin Hibbits 	if (strcmp(buf, "display") != 0)
126bdf49e39SNathan Whitehorn 		return (CN_DEAD);
127bdf49e39SNathan Whitehorn 
128bdf49e39SNathan Whitehorn 	/* Looks OK... */
129bdf49e39SNathan Whitehorn 	return (CN_INTERNAL);
130bdf49e39SNathan Whitehorn }
13127cf7d04SAleksandr Rybalko 
13227cf7d04SAleksandr Rybalko static void
1335a7d2743SJean-Sébastien Pédron ofwfb_bitblt_bitmap(struct vt_device *vd, const struct vt_window *vw,
1345a7d2743SJean-Sébastien Pédron     const uint8_t *pattern, const uint8_t *mask,
1355a7d2743SJean-Sébastien Pédron     unsigned int width, unsigned int height,
1365a7d2743SJean-Sébastien Pédron     unsigned int x, unsigned int y, term_color_t fg, term_color_t bg)
13727cf7d04SAleksandr Rybalko {
13800cf40b0SNathan Whitehorn 	struct fb_info *sc = vd->vd_softc;
13927cf7d04SAleksandr Rybalko 	u_long line;
14027cf7d04SAleksandr Rybalko 	uint32_t fgc, bgc;
14184d623c6SJean-Sébastien Pédron 	int c, l;
14227cf7d04SAleksandr Rybalko 	uint8_t b, m;
143015ac42eSNathan Whitehorn 	union {
144015ac42eSNathan Whitehorn 		uint32_t l;
145015ac42eSNathan Whitehorn 		uint8_t	 c[4];
146015ac42eSNathan Whitehorn 	} ch1, ch2;
14727cf7d04SAleksandr Rybalko 
148bb0455d7SNathan Whitehorn #ifdef __powerpc__
149bb0455d7SNathan Whitehorn 	/* Deal with unmapped framebuffers */
150bb0455d7SNathan Whitehorn 	if (sc->fb_flags & FB_FLAG_NOWRITE) {
151bb0455d7SNathan Whitehorn 		if (pmap_bootstrapped) {
152bb0455d7SNathan Whitehorn 			sc->fb_flags &= ~FB_FLAG_NOWRITE;
153bb0455d7SNathan Whitehorn 			ofwfb_initialize(vd);
1544f75b930SNathan Whitehorn 			vd->vd_driver->vd_blank(vd, TC_BLACK);
155bb0455d7SNathan Whitehorn 		} else {
156bb0455d7SNathan Whitehorn 			return;
157bb0455d7SNathan Whitehorn 		}
158bb0455d7SNathan Whitehorn 	}
159bb0455d7SNathan Whitehorn #endif
160bb0455d7SNathan Whitehorn 
16100cf40b0SNathan Whitehorn 	fgc = sc->fb_cmap[fg];
16200cf40b0SNathan Whitehorn 	bgc = sc->fb_cmap[bg];
16327cf7d04SAleksandr Rybalko 	b = m = 0;
16427cf7d04SAleksandr Rybalko 
16525023a8aSNathan Whitehorn 	if (((struct ofwfb_softc *)vd->vd_softc)->iso_palette) {
16625023a8aSNathan Whitehorn 		fg = ofw_colors[fg];
16725023a8aSNathan Whitehorn 		bg = ofw_colors[bg];
16825023a8aSNathan Whitehorn 	}
16925023a8aSNathan Whitehorn 
17084d623c6SJean-Sébastien Pédron 	line = (sc->fb_stride * y) + x * sc->fb_bpp/8;
17184d623c6SJean-Sébastien Pédron 	if (mask == NULL && sc->fb_bpp == 8 && (width % 8 == 0)) {
17227cf7d04SAleksandr Rybalko 		/* Don't try to put off screen pixels */
1735a7d2743SJean-Sébastien Pédron 		if (((x + width) > vd->vd_width) || ((y + height) >
17427cf7d04SAleksandr Rybalko 		    vd->vd_height))
17527cf7d04SAleksandr Rybalko 			return;
17627cf7d04SAleksandr Rybalko 
177015ac42eSNathan Whitehorn 		for (; height > 0; height--) {
178015ac42eSNathan Whitehorn 			for (c = 0; c < width; c += 8) {
1795a7d2743SJean-Sébastien Pédron 				b = *pattern++;
180015ac42eSNathan Whitehorn 
181015ac42eSNathan Whitehorn 				/*
182015ac42eSNathan Whitehorn 				 * Assume that there is more background than
183015ac42eSNathan Whitehorn 				 * foreground in characters and init accordingly
184015ac42eSNathan Whitehorn 				 */
185015ac42eSNathan Whitehorn 				ch1.l = ch2.l = (bg << 24) | (bg << 16) |
186015ac42eSNathan Whitehorn 				    (bg << 8) | bg;
187015ac42eSNathan Whitehorn 
188015ac42eSNathan Whitehorn 				/*
189015ac42eSNathan Whitehorn 				 * Calculate 2 x 4-chars at a time, and then
190015ac42eSNathan Whitehorn 				 * write these out.
191015ac42eSNathan Whitehorn 				 */
192015ac42eSNathan Whitehorn 				if (b & 0x80) ch1.c[0] = fg;
193015ac42eSNathan Whitehorn 				if (b & 0x40) ch1.c[1] = fg;
194015ac42eSNathan Whitehorn 				if (b & 0x20) ch1.c[2] = fg;
195015ac42eSNathan Whitehorn 				if (b & 0x10) ch1.c[3] = fg;
196015ac42eSNathan Whitehorn 
197015ac42eSNathan Whitehorn 				if (b & 0x08) ch2.c[0] = fg;
198015ac42eSNathan Whitehorn 				if (b & 0x04) ch2.c[1] = fg;
199015ac42eSNathan Whitehorn 				if (b & 0x02) ch2.c[2] = fg;
200015ac42eSNathan Whitehorn 				if (b & 0x01) ch2.c[3] = fg;
201015ac42eSNathan Whitehorn 
20200cf40b0SNathan Whitehorn 				*(uint32_t *)(sc->fb_vbase + line + c) = ch1.l;
20300cf40b0SNathan Whitehorn 				*(uint32_t *)(sc->fb_vbase + line + c + 4) =
204015ac42eSNathan Whitehorn 				    ch2.l;
205015ac42eSNathan Whitehorn 			}
20600cf40b0SNathan Whitehorn 			line += sc->fb_stride;
207015ac42eSNathan Whitehorn 		}
208015ac42eSNathan Whitehorn 	} else {
20984d623c6SJean-Sébastien Pédron 		for (l = 0;
21084d623c6SJean-Sébastien Pédron 		    l < height && y + l < vw->vw_draw_area.tr_end.tp_row;
21184d623c6SJean-Sébastien Pédron 		    l++) {
21284d623c6SJean-Sébastien Pédron 			for (c = 0;
21384d623c6SJean-Sébastien Pédron 			    c < width && x + c < vw->vw_draw_area.tr_end.tp_col;
21484d623c6SJean-Sébastien Pédron 			    c++) {
21527cf7d04SAleksandr Rybalko 				if (c % 8 == 0)
2165a7d2743SJean-Sébastien Pédron 					b = *pattern++;
21727cf7d04SAleksandr Rybalko 				else
21827cf7d04SAleksandr Rybalko 					b <<= 1;
21927cf7d04SAleksandr Rybalko 				if (mask != NULL) {
22027cf7d04SAleksandr Rybalko 					if (c % 8 == 0)
22127cf7d04SAleksandr Rybalko 						m = *mask++;
22227cf7d04SAleksandr Rybalko 					else
22327cf7d04SAleksandr Rybalko 						m <<= 1;
224015ac42eSNathan Whitehorn 					/* Skip pixel write, if mask not set. */
22527cf7d04SAleksandr Rybalko 					if ((m & 0x80) == 0)
22627cf7d04SAleksandr Rybalko 						continue;
22727cf7d04SAleksandr Rybalko 				}
22800cf40b0SNathan Whitehorn 				switch(sc->fb_bpp) {
22927cf7d04SAleksandr Rybalko 				case 8:
23000cf40b0SNathan Whitehorn 					*(uint8_t *)(sc->fb_vbase + line + c) =
23127cf7d04SAleksandr Rybalko 					    b & 0x80 ? fg : bg;
23227cf7d04SAleksandr Rybalko 					break;
23327cf7d04SAleksandr Rybalko 				case 32:
23400cf40b0SNathan Whitehorn 					*(uint32_t *)(sc->fb_vbase + line + 4*c)
235015ac42eSNathan Whitehorn 					    = (b & 0x80) ? fgc : bgc;
23627cf7d04SAleksandr Rybalko 					break;
23727cf7d04SAleksandr Rybalko 				default:
23827cf7d04SAleksandr Rybalko 					/* panic? */
23927cf7d04SAleksandr Rybalko 					break;
24027cf7d04SAleksandr Rybalko 				}
24127cf7d04SAleksandr Rybalko 			}
24200cf40b0SNathan Whitehorn 			line += sc->fb_stride;
24327cf7d04SAleksandr Rybalko 		}
24427cf7d04SAleksandr Rybalko 	}
245015ac42eSNathan Whitehorn }
24627cf7d04SAleksandr Rybalko 
247*b93028d8SEmmanuel Vadot static int
248*b93028d8SEmmanuel Vadot ofwfb_bitblt_argb(struct vt_device *vd, const struct vt_window *vw,
249*b93028d8SEmmanuel Vadot     const uint8_t *argb,
250*b93028d8SEmmanuel Vadot     unsigned int width, unsigned int height,
251*b93028d8SEmmanuel Vadot     unsigned int x, unsigned int y)
252*b93028d8SEmmanuel Vadot {
253*b93028d8SEmmanuel Vadot 
254*b93028d8SEmmanuel Vadot 	return (EOPNOTSUPP);
255*b93028d8SEmmanuel Vadot }
256*b93028d8SEmmanuel Vadot 
2575a7d2743SJean-Sébastien Pédron void
2585a7d2743SJean-Sébastien Pédron ofwfb_bitblt_text(struct vt_device *vd, const struct vt_window *vw,
2595a7d2743SJean-Sébastien Pédron     const term_rect_t *area)
2605a7d2743SJean-Sébastien Pédron {
2615a7d2743SJean-Sébastien Pédron 	unsigned int col, row, x, y;
2625a7d2743SJean-Sébastien Pédron 	struct vt_font *vf;
2635a7d2743SJean-Sébastien Pédron 	term_char_t c;
2645a7d2743SJean-Sébastien Pédron 	term_color_t fg, bg;
2655a7d2743SJean-Sébastien Pédron 	const uint8_t *pattern;
2665a7d2743SJean-Sébastien Pédron 
2675a7d2743SJean-Sébastien Pédron 	vf = vw->vw_font;
2685a7d2743SJean-Sébastien Pédron 
2695a7d2743SJean-Sébastien Pédron 	for (row = area->tr_begin.tp_row; row < area->tr_end.tp_row; ++row) {
2705a7d2743SJean-Sébastien Pédron 		for (col = area->tr_begin.tp_col; col < area->tr_end.tp_col;
2715a7d2743SJean-Sébastien Pédron 		    ++col) {
27283fbb296SJean-Sébastien Pédron 			x = col * vf->vf_width +
27383fbb296SJean-Sébastien Pédron 			    vw->vw_draw_area.tr_begin.tp_col;
27483fbb296SJean-Sébastien Pédron 			y = row * vf->vf_height +
27583fbb296SJean-Sébastien Pédron 			    vw->vw_draw_area.tr_begin.tp_row;
2765a7d2743SJean-Sébastien Pédron 
2775a7d2743SJean-Sébastien Pédron 			c = VTBUF_GET_FIELD(&vw->vw_buf, row, col);
2785a7d2743SJean-Sébastien Pédron 			pattern = vtfont_lookup(vf, c);
2795a7d2743SJean-Sébastien Pédron 			vt_determine_colors(c,
2805a7d2743SJean-Sébastien Pédron 			    VTBUF_ISCURSOR(&vw->vw_buf, row, col), &fg, &bg);
2815a7d2743SJean-Sébastien Pédron 
2825a7d2743SJean-Sébastien Pédron 			ofwfb_bitblt_bitmap(vd, vw,
2835a7d2743SJean-Sébastien Pédron 			    pattern, NULL, vf->vf_width, vf->vf_height,
2845a7d2743SJean-Sébastien Pédron 			    x, y, fg, bg);
2855a7d2743SJean-Sébastien Pédron 		}
2865a7d2743SJean-Sébastien Pédron 	}
2875a7d2743SJean-Sébastien Pédron 
2885a7d2743SJean-Sébastien Pédron #ifndef SC_NO_CUTPASTE
2895a7d2743SJean-Sébastien Pédron 	if (!vd->vd_mshown)
2905a7d2743SJean-Sébastien Pédron 		return;
2915a7d2743SJean-Sébastien Pédron 
2925a7d2743SJean-Sébastien Pédron 	term_rect_t drawn_area;
2935a7d2743SJean-Sébastien Pédron 
29484d623c6SJean-Sébastien Pédron 	drawn_area.tr_begin.tp_col = area->tr_begin.tp_col * vf->vf_width;
29584d623c6SJean-Sébastien Pédron 	drawn_area.tr_begin.tp_row = area->tr_begin.tp_row * vf->vf_height;
29684d623c6SJean-Sébastien Pédron 	drawn_area.tr_end.tp_col = area->tr_end.tp_col * vf->vf_width;
29784d623c6SJean-Sébastien Pédron 	drawn_area.tr_end.tp_row = area->tr_end.tp_row * vf->vf_height;
2985a7d2743SJean-Sébastien Pédron 
2995a7d2743SJean-Sébastien Pédron 	if (vt_is_cursor_in_area(vd, &drawn_area)) {
3005a7d2743SJean-Sébastien Pédron 		ofwfb_bitblt_bitmap(vd, vw,
3015a7d2743SJean-Sébastien Pédron 		    vd->vd_mcursor->map, vd->vd_mcursor->mask,
3025a7d2743SJean-Sébastien Pédron 		    vd->vd_mcursor->width, vd->vd_mcursor->height,
30384d623c6SJean-Sébastien Pédron 		    vd->vd_mx_drawn + vw->vw_draw_area.tr_begin.tp_col,
30484d623c6SJean-Sébastien Pédron 		    vd->vd_my_drawn + vw->vw_draw_area.tr_begin.tp_row,
3055a7d2743SJean-Sébastien Pédron 		    vd->vd_mcursor_fg, vd->vd_mcursor_bg);
3065a7d2743SJean-Sébastien Pédron 	}
3075a7d2743SJean-Sébastien Pédron #endif
3085a7d2743SJean-Sébastien Pédron }
3095a7d2743SJean-Sébastien Pédron 
310b042d10cSAlfredo Dal'Ava Junior 
311b042d10cSAlfredo Dal'Ava Junior /*
312b042d10cSAlfredo Dal'Ava Junior  * Decode OpenFirmware/IEEE 1275-1994 "ranges" property
313b042d10cSAlfredo Dal'Ava Junior  *
314b042d10cSAlfredo Dal'Ava Junior  * XXX: this is similar to ofw_pcib_fill_ranges but cannot use it here because
315b042d10cSAlfredo Dal'Ava Junior  *      it's not possible to allocate memory at the moment this is funcion is
316b042d10cSAlfredo Dal'Ava Junior  *      used. Since there are other similar functions dealing with "ranges"
317b042d10cSAlfredo Dal'Ava Junior  *      property, a proper refactoring is suggested.
318b042d10cSAlfredo Dal'Ava Junior  */
319b042d10cSAlfredo Dal'Ava Junior static uint64_t
320b042d10cSAlfredo Dal'Ava Junior decode_pci_ranges_host_addr(phandle_t pcinode)
321b042d10cSAlfredo Dal'Ava Junior {
322b042d10cSAlfredo Dal'Ava Junior 	struct simplebus_range {
323b042d10cSAlfredo Dal'Ava Junior 		uint64_t bus;
324b042d10cSAlfredo Dal'Ava Junior 		uint64_t host;
325b042d10cSAlfredo Dal'Ava Junior 		uint64_t size;
326b042d10cSAlfredo Dal'Ava Junior 	};
327b042d10cSAlfredo Dal'Ava Junior 
328b042d10cSAlfredo Dal'Ava Junior 	struct simplebus_range ranges[4];
329b042d10cSAlfredo Dal'Ava Junior 	int nranges, host_address_cells;
330b042d10cSAlfredo Dal'Ava Junior 	pcell_t acells, scells;
331b042d10cSAlfredo Dal'Ava Junior 	cell_t base_ranges[64];
332b042d10cSAlfredo Dal'Ava Junior 
333b042d10cSAlfredo Dal'Ava Junior 	ssize_t nbase_ranges;
334b042d10cSAlfredo Dal'Ava Junior 	int i, j, k;
335b042d10cSAlfredo Dal'Ava Junior 
336b042d10cSAlfredo Dal'Ava Junior 	if (!OF_hasprop(pcinode, "ranges"))
337b042d10cSAlfredo Dal'Ava Junior 		return (0);
338b042d10cSAlfredo Dal'Ava Junior 
339b042d10cSAlfredo Dal'Ava Junior 	if (OF_getencprop(pcinode, "#address-cells", &acells, sizeof(acells)) !=
340b042d10cSAlfredo Dal'Ava Junior 	    sizeof(acells))
341b042d10cSAlfredo Dal'Ava Junior 		return (0);
342b042d10cSAlfredo Dal'Ava Junior 
343b042d10cSAlfredo Dal'Ava Junior 	if (OF_getencprop(pcinode, "#size-cells", &scells, sizeof(scells)) !=
344b042d10cSAlfredo Dal'Ava Junior 		sizeof(scells))
345b042d10cSAlfredo Dal'Ava Junior 		return (0);
346b042d10cSAlfredo Dal'Ava Junior 
347b042d10cSAlfredo Dal'Ava Junior 	if (OF_searchencprop(OF_parent(pcinode), "#address-cells",
348b042d10cSAlfredo Dal'Ava Junior 		&host_address_cells, sizeof(host_address_cells)) !=
349b042d10cSAlfredo Dal'Ava Junior 		sizeof(host_address_cells))
350b042d10cSAlfredo Dal'Ava Junior 		return (0);
351b042d10cSAlfredo Dal'Ava Junior 
352b042d10cSAlfredo Dal'Ava Junior 	nbase_ranges = OF_getproplen(pcinode, "ranges");
353b042d10cSAlfredo Dal'Ava Junior 	nranges = nbase_ranges / sizeof(cell_t) / (acells + host_address_cells + scells);
354b042d10cSAlfredo Dal'Ava Junior 
355b042d10cSAlfredo Dal'Ava Junior 	/* prevent buffer overflow during iteration */
356b042d10cSAlfredo Dal'Ava Junior 	if (nranges > sizeof(ranges) / sizeof(ranges[0]))
357b042d10cSAlfredo Dal'Ava Junior 		nranges = sizeof(ranges) / sizeof(ranges[0]);
358b042d10cSAlfredo Dal'Ava Junior 
359b042d10cSAlfredo Dal'Ava Junior 	/* decode range value and return the first valid address */
360b042d10cSAlfredo Dal'Ava Junior 	OF_getencprop(pcinode, "ranges", base_ranges, nbase_ranges);
361b042d10cSAlfredo Dal'Ava Junior 	for (i = 0, j = 0; i < nranges; i++) {
362b042d10cSAlfredo Dal'Ava Junior 		ranges[i].bus = 0;
363b042d10cSAlfredo Dal'Ava Junior 		for (k = 0; k < acells; k++) {
364b042d10cSAlfredo Dal'Ava Junior 			ranges[i].bus <<= 32;
365b042d10cSAlfredo Dal'Ava Junior 			ranges[i].bus |= base_ranges[j++];
366b042d10cSAlfredo Dal'Ava Junior 		}
367b042d10cSAlfredo Dal'Ava Junior 
368b042d10cSAlfredo Dal'Ava Junior 		ranges[i].host = 0;
369b042d10cSAlfredo Dal'Ava Junior 		for (k = 0; k < host_address_cells; k++) {
370b042d10cSAlfredo Dal'Ava Junior 			ranges[i].host <<= 32;
371b042d10cSAlfredo Dal'Ava Junior 			ranges[i].host |= base_ranges[j++];
372b042d10cSAlfredo Dal'Ava Junior 		}
373b042d10cSAlfredo Dal'Ava Junior 		ranges[i].size = 0;
374b042d10cSAlfredo Dal'Ava Junior 		for (k = 0; k < scells; k++) {
375b042d10cSAlfredo Dal'Ava Junior 			ranges[i].size <<= 32;
376b042d10cSAlfredo Dal'Ava Junior 			ranges[i].size |= base_ranges[j++];
377b042d10cSAlfredo Dal'Ava Junior 		}
378b042d10cSAlfredo Dal'Ava Junior 
379b042d10cSAlfredo Dal'Ava Junior 		if (ranges[i].host != 0)
380b042d10cSAlfredo Dal'Ava Junior 			return (ranges[i].host);
381b042d10cSAlfredo Dal'Ava Junior 	}
382b042d10cSAlfredo Dal'Ava Junior 
383b042d10cSAlfredo Dal'Ava Junior 	return (0);
384b042d10cSAlfredo Dal'Ava Junior }
385b042d10cSAlfredo Dal'Ava Junior 
386b042d10cSAlfredo Dal'Ava Junior static bus_addr_t
387b042d10cSAlfredo Dal'Ava Junior find_pci_host_address(phandle_t node)
388b042d10cSAlfredo Dal'Ava Junior {
389b042d10cSAlfredo Dal'Ava Junior 	uint64_t addr;
390b042d10cSAlfredo Dal'Ava Junior 
391b042d10cSAlfredo Dal'Ava Junior 	/*
392b042d10cSAlfredo Dal'Ava Junior 	 * According to IEEE STD 1275, if property "ranges" exists but has a
393b042d10cSAlfredo Dal'Ava Junior 	 * zero-length property value, the child address space is identical
394b042d10cSAlfredo Dal'Ava Junior 	 * to the parent address space.
395b042d10cSAlfredo Dal'Ava Junior 	 */
396b042d10cSAlfredo Dal'Ava Junior 	while (node) {
397b042d10cSAlfredo Dal'Ava Junior 		if (OF_hasprop(node, "ranges")) {
398b042d10cSAlfredo Dal'Ava Junior 			addr = decode_pci_ranges_host_addr(node);
399b042d10cSAlfredo Dal'Ava Junior 			if (addr != 0)
400b042d10cSAlfredo Dal'Ava Junior 				return ((bus_addr_t)addr);
401b042d10cSAlfredo Dal'Ava Junior 		}
402b042d10cSAlfredo Dal'Ava Junior 		node = OF_parent(node);
403b042d10cSAlfredo Dal'Ava Junior 	}
404b042d10cSAlfredo Dal'Ava Junior 
405b042d10cSAlfredo Dal'Ava Junior 	return (0);
406b042d10cSAlfredo Dal'Ava Junior }
407b042d10cSAlfredo Dal'Ava Junior 
40827cf7d04SAleksandr Rybalko static void
40927cf7d04SAleksandr Rybalko ofwfb_initialize(struct vt_device *vd)
41027cf7d04SAleksandr Rybalko {
41127cf7d04SAleksandr Rybalko 	struct ofwfb_softc *sc = vd->vd_softc;
412b9f3b63aSLeandro Lupori 	int i, err, r, g, b;
41327cf7d04SAleksandr Rybalko 	cell_t retval;
41427cf7d04SAleksandr Rybalko 
415bb0455d7SNathan Whitehorn 	sc->fb.fb_cmsize = 16;
416bb0455d7SNathan Whitehorn 
417bb0455d7SNathan Whitehorn 	if (sc->fb.fb_flags & FB_FLAG_NOWRITE)
418bb0455d7SNathan Whitehorn 		return;
419bb0455d7SNathan Whitehorn 
42027cf7d04SAleksandr Rybalko 	/*
42127cf7d04SAleksandr Rybalko 	 * Set up the color map
42227cf7d04SAleksandr Rybalko 	 */
42327cf7d04SAleksandr Rybalko 
42425023a8aSNathan Whitehorn 	sc->iso_palette = 0;
42500cf40b0SNathan Whitehorn 	switch (sc->fb.fb_bpp) {
42627cf7d04SAleksandr Rybalko 	case 8:
42750b7c1f5SAlfredo Dal'Ava Junior 		/*
42850b7c1f5SAlfredo Dal'Ava Junior 		 * No color format issues here, since we are passing the RGB
42950b7c1f5SAlfredo Dal'Ava Junior 		 * components separately to Open Firmware.
43050b7c1f5SAlfredo Dal'Ava Junior 		 */
431b9f3b63aSLeandro Lupori 		vt_config_cons_colors(&sc->fb, COLOR_FORMAT_RGB, 255,
43219e2ce2dSJean-Sébastien Pédron 		    16, 255, 8, 255, 0);
43327cf7d04SAleksandr Rybalko 
43427cf7d04SAleksandr Rybalko 		for (i = 0; i < 16; i++) {
43525023a8aSNathan Whitehorn 			err = OF_call_method("color!", sc->sc_handle, 4, 1,
43600cf40b0SNathan Whitehorn 			    (cell_t)((sc->fb.fb_cmap[i] >> 16) & 0xff),
43700cf40b0SNathan Whitehorn 			    (cell_t)((sc->fb.fb_cmap[i] >> 8) & 0xff),
43800cf40b0SNathan Whitehorn 			    (cell_t)((sc->fb.fb_cmap[i] >> 0) & 0xff),
43927cf7d04SAleksandr Rybalko 			    (cell_t)i, &retval);
44025023a8aSNathan Whitehorn 			if (err)
44125023a8aSNathan Whitehorn 				break;
44227cf7d04SAleksandr Rybalko 		}
44325023a8aSNathan Whitehorn 		if (i != 16)
44425023a8aSNathan Whitehorn 			sc->iso_palette = 1;
44525023a8aSNathan Whitehorn 
44627cf7d04SAleksandr Rybalko 		break;
44727cf7d04SAleksandr Rybalko 
44827cf7d04SAleksandr Rybalko 	case 32:
44927cf7d04SAleksandr Rybalko 		/*
45050b7c1f5SAlfredo Dal'Ava Junior 		 * There are two main color formats in use.
45150b7c1f5SAlfredo Dal'Ava Junior 		 * ARGB32 is used mainly on hardware that was designed for
45250b7c1f5SAlfredo Dal'Ava Junior 		 * LE systems, and RGBA32 is used mainly on hardware designed
45350b7c1f5SAlfredo Dal'Ava Junior 		 * for BE systems.
45450b7c1f5SAlfredo Dal'Ava Junior 		 *
45550b7c1f5SAlfredo Dal'Ava Junior 		 * PowerMacs use either, depending on the video card option.
45650b7c1f5SAlfredo Dal'Ava Junior 		 * NVidia cards tend to be RGBA32, and ATI cards tend to be ARGB32.
45750b7c1f5SAlfredo Dal'Ava Junior 		 *
45850b7c1f5SAlfredo Dal'Ava Junior 		 * There is no good way to determine the correct option, as this
45950b7c1f5SAlfredo Dal'Ava Junior 		 * is independent of endian swapping.
46027cf7d04SAleksandr Rybalko 		 */
461b042d10cSAlfredo Dal'Ava Junior 		if (sc->vendor_id == PCI_VID_NVIDIA)
46250b7c1f5SAlfredo Dal'Ava Junior 			sc->argb = 0;
46350b7c1f5SAlfredo Dal'Ava Junior 		else
46450b7c1f5SAlfredo Dal'Ava Junior 			sc->argb = 1;
46550b7c1f5SAlfredo Dal'Ava Junior 
46650b7c1f5SAlfredo Dal'Ava Junior 		TUNABLE_INT_FETCH("hw.ofwfb.argb32_pixel", &sc->argb);
46750b7c1f5SAlfredo Dal'Ava Junior 		if (sc->endian_flip) {
46850b7c1f5SAlfredo Dal'Ava Junior 			if (sc->argb)
469b9f3b63aSLeandro Lupori 				r = 8, g = 16, b = 24;
47019e2ce2dSJean-Sébastien Pédron 			else
471b9f3b63aSLeandro Lupori 				r = 24, g = 16, b = 8;
47250b7c1f5SAlfredo Dal'Ava Junior 		} else {
47350b7c1f5SAlfredo Dal'Ava Junior 			if (sc->argb)
474b9f3b63aSLeandro Lupori 				r = 16, g = 8, b = 0;
47550b7c1f5SAlfredo Dal'Ava Junior 			else
476b9f3b63aSLeandro Lupori 				r = 0, g = 8, b = 16;
47750b7c1f5SAlfredo Dal'Ava Junior 		}
478b9f3b63aSLeandro Lupori 		vt_config_cons_colors(&sc->fb,
479b9f3b63aSLeandro Lupori 		    COLOR_FORMAT_RGB, 255, r, 255, g, 255, b);
48027cf7d04SAleksandr Rybalko 		break;
48127cf7d04SAleksandr Rybalko 
48227cf7d04SAleksandr Rybalko 	default:
48300cf40b0SNathan Whitehorn 		panic("Unknown color space depth %d", sc->fb.fb_bpp);
48427cf7d04SAleksandr Rybalko 		break;
48527cf7d04SAleksandr Rybalko         }
48627cf7d04SAleksandr Rybalko }
48727cf7d04SAleksandr Rybalko 
48827cf7d04SAleksandr Rybalko static int
48927cf7d04SAleksandr Rybalko ofwfb_init(struct vt_device *vd)
49027cf7d04SAleksandr Rybalko {
491bdf49e39SNathan Whitehorn 	struct ofwfb_softc *sc;
492529f0e6cSJustin Hibbits 	char buf[64];
49327cf7d04SAleksandr Rybalko 	phandle_t chosen;
49427cf7d04SAleksandr Rybalko 	phandle_t node;
495043577b7SLeandro Lupori 	pcell_t depth, height, width, stride;
49650b7c1f5SAlfredo Dal'Ava Junior 	uint32_t vendor_id = 0;
49750b7c1f5SAlfredo Dal'Ava Junior 	cell_t adr[2];
49850b7c1f5SAlfredo Dal'Ava Junior 	uint64_t user_phys;
49950b7c1f5SAlfredo Dal'Ava Junior 	bus_addr_t fb_phys;
50050b7c1f5SAlfredo Dal'Ava Junior 	bus_size_t fb_phys_size;
50150b7c1f5SAlfredo Dal'Ava Junior 	int i, j, len;
50227cf7d04SAleksandr Rybalko 
503bdf49e39SNathan Whitehorn 	/* Initialize softc */
504bdf49e39SNathan Whitehorn 	vd->vd_softc = sc = &ofwfb_conssoftc;
505bdf49e39SNathan Whitehorn 
5062cc27fc0SJustin Hibbits 	node = -1;
50727cf7d04SAleksandr Rybalko 	chosen = OF_finddevice("/chosen");
508043577b7SLeandro Lupori 	if (OF_getencprop(chosen, "stdout", &sc->sc_handle,
5092cc27fc0SJustin Hibbits 	    sizeof(ihandle_t)) == sizeof(ihandle_t))
510232490c6SNathan Whitehorn 		node = OF_instance_to_package(sc->sc_handle);
511529f0e6cSJustin Hibbits 	if (node == -1)
512529f0e6cSJustin Hibbits 		/* Try "/chosen/stdout-path" now */
513529f0e6cSJustin Hibbits 		if (OF_getprop(chosen, "stdout-path", buf, sizeof(buf)) > 0) {
514529f0e6cSJustin Hibbits 			node = OF_finddevice(buf);
515529f0e6cSJustin Hibbits 			if (node != -1)
516529f0e6cSJustin Hibbits 				sc->sc_handle = OF_open(buf);
517529f0e6cSJustin Hibbits 		}
51827cf7d04SAleksandr Rybalko 	if (node == -1) {
51927cf7d04SAleksandr Rybalko 		/*
52027cf7d04SAleksandr Rybalko 		 * The "/chosen/stdout" does not exist try
52127cf7d04SAleksandr Rybalko 		 * using "screen" directly.
52227cf7d04SAleksandr Rybalko 		 */
52327cf7d04SAleksandr Rybalko 		node = OF_finddevice("screen");
524232490c6SNathan Whitehorn 		sc->sc_handle = OF_open("screen");
52527cf7d04SAleksandr Rybalko 	}
526529f0e6cSJustin Hibbits 	OF_getprop(node, "device_type", buf, sizeof(buf));
527529f0e6cSJustin Hibbits 	if (strcmp(buf, "display") != 0)
52827cf7d04SAleksandr Rybalko 		return (CN_DEAD);
52927cf7d04SAleksandr Rybalko 
53050b7c1f5SAlfredo Dal'Ava Junior 	/*
53150b7c1f5SAlfredo Dal'Ava Junior 	 * Retrieve vendor-id from /chosen parent node, usually pointing to
53250b7c1f5SAlfredo Dal'Ava Junior 	 * video card device. This is used to select pixel format later on
53350b7c1f5SAlfredo Dal'Ava Junior 	 * ofwfb_initialize()
53450b7c1f5SAlfredo Dal'Ava Junior 	 */
53550b7c1f5SAlfredo Dal'Ava Junior 	if (OF_getencprop(OF_parent(node), "vendor-id", &vendor_id,
53650b7c1f5SAlfredo Dal'Ava Junior 	    sizeof(vendor_id)) == sizeof(vendor_id))
53750b7c1f5SAlfredo Dal'Ava Junior 		sc->vendor_id = vendor_id;
53850b7c1f5SAlfredo Dal'Ava Junior 
53927cf7d04SAleksandr Rybalko 	/* Keep track of the OF node */
54027cf7d04SAleksandr Rybalko 	sc->sc_node = node;
54127cf7d04SAleksandr Rybalko 
542232490c6SNathan Whitehorn 	/*
543232490c6SNathan Whitehorn 	 * Try to use a 32-bit framebuffer if possible. This may be
544232490c6SNathan Whitehorn 	 * unimplemented and fail. That's fine -- it just means we are
545232490c6SNathan Whitehorn 	 * stuck with the defaults.
546232490c6SNathan Whitehorn 	 */
547232490c6SNathan Whitehorn 	OF_call_method("set-depth", sc->sc_handle, 1, 1, (cell_t)32, &i);
548232490c6SNathan Whitehorn 
54927cf7d04SAleksandr Rybalko 	/* Make sure we have needed properties */
55027cf7d04SAleksandr Rybalko 	if (OF_getproplen(node, "height") != sizeof(height) ||
55127cf7d04SAleksandr Rybalko 	    OF_getproplen(node, "width") != sizeof(width) ||
552452a74bfSNathan Whitehorn 	    OF_getproplen(node, "depth") != sizeof(depth))
55327cf7d04SAleksandr Rybalko 		return (CN_DEAD);
55427cf7d04SAleksandr Rybalko 
55527cf7d04SAleksandr Rybalko 	/* Only support 8 and 32-bit framebuffers */
556043577b7SLeandro Lupori 	OF_getencprop(node, "depth", &depth, sizeof(depth));
55727cf7d04SAleksandr Rybalko 	if (depth != 8 && depth != 32)
55827cf7d04SAleksandr Rybalko 		return (CN_DEAD);
559232490c6SNathan Whitehorn 	sc->fb.fb_bpp = sc->fb.fb_depth = depth;
56027cf7d04SAleksandr Rybalko 
561043577b7SLeandro Lupori 	OF_getencprop(node, "height", &height, sizeof(height));
562043577b7SLeandro Lupori 	OF_getencprop(node, "width", &width, sizeof(width));
563043577b7SLeandro Lupori 	if (OF_getencprop(node, "linebytes", &stride, sizeof(stride)) !=
564452a74bfSNathan Whitehorn 	    sizeof(stride))
565452a74bfSNathan Whitehorn 		stride = width*depth/8;
56627cf7d04SAleksandr Rybalko 
56750b7c1f5SAlfredo Dal'Ava Junior 
56800cf40b0SNathan Whitehorn 	sc->fb.fb_height = height;
56900cf40b0SNathan Whitehorn 	sc->fb.fb_width = width;
57000cf40b0SNathan Whitehorn 	sc->fb.fb_stride = stride;
57100cf40b0SNathan Whitehorn 	sc->fb.fb_size = sc->fb.fb_height * sc->fb.fb_stride;
57250b7c1f5SAlfredo Dal'Ava Junior 	sc->endian_flip = 0;
57350b7c1f5SAlfredo Dal'Ava Junior 
57450b7c1f5SAlfredo Dal'Ava Junior #if defined(__powerpc__)
57550b7c1f5SAlfredo Dal'Ava Junior 	if (OF_hasprop(node, "little-endian")) {
57650b7c1f5SAlfredo Dal'Ava Junior 		sc->sc_memt = &bs_le_tag;
57750b7c1f5SAlfredo Dal'Ava Junior #if BYTE_ORDER == BIG_ENDIAN
57850b7c1f5SAlfredo Dal'Ava Junior 		sc->endian_flip = 1;
57950b7c1f5SAlfredo Dal'Ava Junior #endif
58050b7c1f5SAlfredo Dal'Ava Junior         } else if (OF_hasprop(node, "big-endian")) {
58150b7c1f5SAlfredo Dal'Ava Junior 		sc->sc_memt = &bs_be_tag;
58250b7c1f5SAlfredo Dal'Ava Junior #if BYTE_ORDER == LITTLE_ENDIAN
58350b7c1f5SAlfredo Dal'Ava Junior 		sc->endian_flip = 1;
58450b7c1f5SAlfredo Dal'Ava Junior #endif
58550b7c1f5SAlfredo Dal'Ava Junior 	}
58650b7c1f5SAlfredo Dal'Ava Junior 	else {
58750b7c1f5SAlfredo Dal'Ava Junior 		/* Assume the framebuffer is in native endian. */
58850b7c1f5SAlfredo Dal'Ava Junior #if BYTE_ORDER == BIG_ENDIAN
58950b7c1f5SAlfredo Dal'Ava Junior 		sc->sc_memt = &bs_be_tag;
59050b7c1f5SAlfredo Dal'Ava Junior #else
59150b7c1f5SAlfredo Dal'Ava Junior 		sc->sc_memt = &bs_le_tag;
59250b7c1f5SAlfredo Dal'Ava Junior #endif
59350b7c1f5SAlfredo Dal'Ava Junior 	}
59450b7c1f5SAlfredo Dal'Ava Junior #elif defined(__arm__)
59550b7c1f5SAlfredo Dal'Ava Junior 	sc->sc_memt = fdtbus_bs_tag;
59650b7c1f5SAlfredo Dal'Ava Junior #else
59750b7c1f5SAlfredo Dal'Ava Junior 	#error Unsupported platform!
59850b7c1f5SAlfredo Dal'Ava Junior #endif
59950b7c1f5SAlfredo Dal'Ava Junior 
60027cf7d04SAleksandr Rybalko 
60127cf7d04SAleksandr Rybalko 	/*
60227cf7d04SAleksandr Rybalko 	 * Grab the physical address of the framebuffer, and then map it
60327cf7d04SAleksandr Rybalko 	 * into our memory space. If the MMU is not yet up, it will be
60427cf7d04SAleksandr Rybalko 	 * remapped for us when relocation turns on.
605b042d10cSAlfredo Dal'Ava Junior 	 *
606b042d10cSAlfredo Dal'Ava Junior 	 * The ASPEED driver on recent petitboot versions doesn't expose the
607b042d10cSAlfredo Dal'Ava Junior 	 * physical address of framebuffer anymore for security. So it should
608b042d10cSAlfredo Dal'Ava Junior 	 * retrieve the address from PCI device properties.
60927cf7d04SAleksandr Rybalko 	 */
61050b7c1f5SAlfredo Dal'Ava Junior 	user_phys = 0;
61150b7c1f5SAlfredo Dal'Ava Junior 	TUNABLE_UINT64_FETCH("hw.ofwfb.physaddr", &user_phys);
612b042d10cSAlfredo Dal'Ava Junior 
613b042d10cSAlfredo Dal'Ava Junior 	if (user_phys)
614b042d10cSAlfredo Dal'Ava Junior 		sc->fb.fb_pbase = (vm_paddr_t)user_phys;
615b042d10cSAlfredo Dal'Ava Junior 	else if (sc->vendor_id == PCI_VID_ASPEED)
616b042d10cSAlfredo Dal'Ava Junior 		sc->fb.fb_pbase = find_pci_host_address(node);
61750b7c1f5SAlfredo Dal'Ava Junior 	else if (OF_hasprop(node, "address")) {
61827cf7d04SAleksandr Rybalko 
61950b7c1f5SAlfredo Dal'Ava Junior 		switch (OF_getproplen(node, "address")) {
62050b7c1f5SAlfredo Dal'Ava Junior 		case 4:
62150b7c1f5SAlfredo Dal'Ava Junior 			OF_getencprop(node, "address", adr, 4);
62250b7c1f5SAlfredo Dal'Ava Junior 			fb_phys = adr[0];
62350b7c1f5SAlfredo Dal'Ava Junior 			break;
62450b7c1f5SAlfredo Dal'Ava Junior 		case 8:
62550b7c1f5SAlfredo Dal'Ava Junior 			OF_getencprop(node, "address", adr, 8);
62650b7c1f5SAlfredo Dal'Ava Junior 			fb_phys = ((uint64_t)adr[0] << 32) | adr[1];
62750b7c1f5SAlfredo Dal'Ava Junior 			break;
62850b7c1f5SAlfredo Dal'Ava Junior 		default:
62950b7c1f5SAlfredo Dal'Ava Junior 			/* Bad property? */
63050b7c1f5SAlfredo Dal'Ava Junior 			return (CN_DEAD);
63150b7c1f5SAlfredo Dal'Ava Junior 		}
632f051baa0SNathan Whitehorn 
63350b7c1f5SAlfredo Dal'Ava Junior 		sc->fb.fb_pbase = (vm_paddr_t)fb_phys;
63427cf7d04SAleksandr Rybalko 	} else {
63550b7c1f5SAlfredo Dal'Ava Junior #if defined(__powerpc__)
63627cf7d04SAleksandr Rybalko 		/*
63727cf7d04SAleksandr Rybalko 		 * Some IBM systems don't have an address property. Try to
63827cf7d04SAleksandr Rybalko 		 * guess the framebuffer region from the assigned addresses.
63927cf7d04SAleksandr Rybalko 		 * This is ugly, but there doesn't seem to be an alternative.
64027cf7d04SAleksandr Rybalko 		 * Linux does the same thing.
64127cf7d04SAleksandr Rybalko 		 */
64227cf7d04SAleksandr Rybalko 
643232490c6SNathan Whitehorn 		struct ofw_pci_register pciaddrs[8];
644232490c6SNathan Whitehorn 		int num_pciaddrs = 0;
645232490c6SNathan Whitehorn 
646232490c6SNathan Whitehorn 		/*
647232490c6SNathan Whitehorn 		 * Get the PCI addresses of the adapter, if present. The node
648232490c6SNathan Whitehorn 		 * may be the child of the PCI device: in that case, try the
649232490c6SNathan Whitehorn 		 * parent for the assigned-addresses property.
650232490c6SNathan Whitehorn 		 */
651043577b7SLeandro Lupori 		len = OF_getencprop(node, "assigned-addresses",
652043577b7SLeandro Lupori 		    (pcell_t *)pciaddrs, sizeof(pciaddrs));
653232490c6SNathan Whitehorn 		if (len == -1) {
654043577b7SLeandro Lupori 			len = OF_getencprop(OF_parent(node), "assigned-addresses",
655043577b7SLeandro Lupori 			    (pcell_t *)pciaddrs, sizeof(pciaddrs));
656232490c6SNathan Whitehorn 		}
657232490c6SNathan Whitehorn 		if (len == -1)
658232490c6SNathan Whitehorn 			len = 0;
659232490c6SNathan Whitehorn 		num_pciaddrs = len / sizeof(struct ofw_pci_register);
660232490c6SNathan Whitehorn 
66150b7c1f5SAlfredo Dal'Ava Junior 		j = num_pciaddrs;
662232490c6SNathan Whitehorn 		for (i = 0; i < num_pciaddrs; i++) {
66327cf7d04SAleksandr Rybalko 			/* If it is too small, not the framebuffer */
664232490c6SNathan Whitehorn 			if (pciaddrs[i].size_lo < sc->fb.fb_stride * height)
66527cf7d04SAleksandr Rybalko 				continue;
66627cf7d04SAleksandr Rybalko 			/* If it is not memory, it isn't either */
667232490c6SNathan Whitehorn 			if (!(pciaddrs[i].phys_hi &
66827cf7d04SAleksandr Rybalko 			    OFW_PCI_PHYS_HI_SPACE_MEM32))
66927cf7d04SAleksandr Rybalko 				continue;
67027cf7d04SAleksandr Rybalko 
67127cf7d04SAleksandr Rybalko 			/* This could be the framebuffer */
67250b7c1f5SAlfredo Dal'Ava Junior 			j = i;
67327cf7d04SAleksandr Rybalko 
67427cf7d04SAleksandr Rybalko 			/* If it is prefetchable, it certainly is */
675232490c6SNathan Whitehorn 			if (pciaddrs[i].phys_hi & OFW_PCI_PHYS_HI_PREFETCHABLE)
67627cf7d04SAleksandr Rybalko 				break;
67727cf7d04SAleksandr Rybalko 		}
67827cf7d04SAleksandr Rybalko 
67950b7c1f5SAlfredo Dal'Ava Junior 		if (j == num_pciaddrs) /* No candidates found */
68027cf7d04SAleksandr Rybalko 			return (CN_DEAD);
68127cf7d04SAleksandr Rybalko 
68250b7c1f5SAlfredo Dal'Ava Junior 		if (ofw_reg_to_paddr(node, j, &fb_phys, &fb_phys_size, NULL) < 0)
68350b7c1f5SAlfredo Dal'Ava Junior 			return (CN_DEAD);
68450b7c1f5SAlfredo Dal'Ava Junior 
68550b7c1f5SAlfredo Dal'Ava Junior 		sc->fb.fb_pbase = (vm_paddr_t)fb_phys;
686232490c6SNathan Whitehorn #else
687232490c6SNathan Whitehorn 		/* No ability to interpret assigned-addresses otherwise */
688232490c6SNathan Whitehorn 		return (CN_DEAD);
68927cf7d04SAleksandr Rybalko #endif
69027cf7d04SAleksandr Rybalko         }
69127cf7d04SAleksandr Rybalko 
69250b7c1f5SAlfredo Dal'Ava Junior 	if (!sc->fb.fb_pbase)
69350b7c1f5SAlfredo Dal'Ava Junior 		return (CN_DEAD);
69450b7c1f5SAlfredo Dal'Ava Junior 
69550b7c1f5SAlfredo Dal'Ava Junior 	bus_space_map(sc->sc_memt, sc->fb.fb_pbase, sc->fb.fb_size,
69650b7c1f5SAlfredo Dal'Ava Junior 	    BUS_SPACE_MAP_PREFETCHABLE,
69750b7c1f5SAlfredo Dal'Ava Junior 	    (bus_space_handle_t *)&sc->fb.fb_vbase);
69850b7c1f5SAlfredo Dal'Ava Junior 
6994f75b930SNathan Whitehorn 	#if defined(__powerpc__)
7004f75b930SNathan Whitehorn 	/*
7014f75b930SNathan Whitehorn 	 * If we are running on PowerPC in real mode (supported only on AIM
7024f75b930SNathan Whitehorn 	 * CPUs), the frame buffer may be inaccessible (real mode does not
7034f75b930SNathan Whitehorn 	 * necessarily cover all RAM) and may also be mapped with the wrong
7044f75b930SNathan Whitehorn 	 * cache properties (all real mode accesses are assumed cacheable).
7054f75b930SNathan Whitehorn 	 * Just don't write to it for the time being.
7064f75b930SNathan Whitehorn 	 */
7074f75b930SNathan Whitehorn 	if (!(cpu_features & PPC_FEATURE_BOOKE) && !(mfmsr() & PSL_DR))
7084f75b930SNathan Whitehorn 		sc->fb.fb_flags |= FB_FLAG_NOWRITE;
7094f75b930SNathan Whitehorn 	#endif
71027cf7d04SAleksandr Rybalko 	ofwfb_initialize(vd);
71100cf40b0SNathan Whitehorn 	vt_fb_init(vd);
71227cf7d04SAleksandr Rybalko 
71327cf7d04SAleksandr Rybalko 	return (CN_INTERNAL);
71427cf7d04SAleksandr Rybalko }
715