]> CyberLeo.Net >> Repos - FreeBSD/stable/9.git/blob - sys/dev/vt/hw/fb/vt_early_fb.c
MFC 219886, 226100, 226111, 226341, 242529, 259015, 259016, 259019, 259049,
[FreeBSD/stable/9.git] / sys / dev / vt / hw / fb / vt_early_fb.c
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$
30  */
31
32 #include <sys/cdefs.h>
33 __FBSDID("$FreeBSD$");
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 #endif
48
49 #include <dev/vt/vt.h>
50 #include <dev/vt/hw/fb/vt_fb.h>
51 #include <dev/vt/colors/vt_termcolors.h>
52
53 static vd_init_t vt_efb_init;
54
55 static struct vt_driver vt_fb_early_driver = {
56         .vd_init = vt_efb_init,
57         .vd_blank = vt_fb_blank,
58         .vd_bitbltchr = vt_fb_bitbltchr,
59         .vd_priority = VD_PRIORITY_GENERIC,
60 };
61
62 static struct fb_info info;
63 VT_CONSDEV_DECLARE(vt_fb_early_driver,
64     MAX(80, PIXEL_WIDTH(VT_FB_DEFAULT_WIDTH)),
65     MAX(25, PIXEL_HEIGHT(VT_FB_DEFAULT_HEIGHT)), &info);
66
67 static void
68 #ifdef  FDT
69 vt_efb_initialize(struct fb_info *info, phandle_t node)
70 #else
71 vt_efb_initialize(struct fb_info *info)
72 #endif
73 {
74 #ifdef  FDT
75         char name[64];
76         cell_t retval;
77         ihandle_t ih;
78         int i;
79
80         /* Open display device, thereby initializing it */
81         memset(name, 0, sizeof(name));
82         OF_package_to_path(node, name, sizeof(name));
83         ih = OF_open(name);
84 #endif
85
86         /*
87          * Set up the color map
88          */
89         switch (info->fb_depth) {
90         case 8:
91                 vt_generate_vga_palette(info->fb_cmap, COLOR_FORMAT_RGB,
92                     0x7, 5, 0x7, 2, 0x3, 0);
93                 break;
94         case 15:
95                 vt_generate_vga_palette(info->fb_cmap, COLOR_FORMAT_RGB,
96                     0x1f, 10, 0x1f, 5, 0x1f, 0);
97                 break;
98         case 16:
99                 vt_generate_vga_palette(info->fb_cmap, COLOR_FORMAT_RGB,
100                     0x1f, 11, 0x3f, 5, 0x1f, 0);
101                 break;
102         case 24:
103         case 32:
104 #if BYTE_ORDER == BIG_ENDIAN
105                 vt_generate_vga_palette(info->fb_cmap,
106                     COLOR_FORMAT_RGB, 255, 16, 255, 8, 255, 0);
107 #else
108                 vt_generate_vga_palette(info->fb_cmap,
109                     COLOR_FORMAT_RGB, 255, 0, 255, 8, 255, 16);
110 #endif
111 #ifdef  FDT
112                 for (i = 0; i < 16; i++) {
113                         OF_call_method("color!", ih, 4, 1,
114                             (cell_t)((info->fb_cmap[i] >> 16) & 0xff),
115                             (cell_t)((info->fb_cmap[i] >> 8) & 0xff),
116                             (cell_t)((info->fb_cmap[i] >> 0) & 0xff),
117                             (cell_t)i, &retval);
118                 }
119 #endif
120                 break;
121
122         default:
123                 panic("Unknown color space fb_depth %d", info->fb_depth);
124                 break;
125         }
126 }
127
128 static int
129 vt_efb_init(struct vt_device *vd)
130 {
131         struct ofw_pci_register pciaddrs[8];
132         struct fb_info *info;
133         int i, len, n_pciaddrs;
134         phandle_t chosen, node;
135         ihandle_t stdout;
136         char type[64];
137
138         info = vd->vd_softc;
139
140         chosen = OF_finddevice("/chosen");
141         OF_getprop(chosen, "stdout", &stdout, sizeof(stdout));
142         node = OF_instance_to_package(stdout);
143         if (node == -1) {
144                 /*
145                  * The "/chosen/stdout" does not exist try
146                  * using "screen" directly.
147                  */
148                 node = OF_finddevice("screen");
149         }
150         OF_getprop(node, "device_type", type, sizeof(type));
151         if (strcmp(type, "display") != 0)
152                 return (CN_DEAD);
153
154 #define GET(name, var)                                                  \
155         if (OF_getproplen(node, (name)) != sizeof(info->fb_##var))      \
156                 return (CN_DEAD);                                       \
157         OF_getencprop(node, (name), &info->fb_##var, sizeof(info->fb_##var)); \
158         if (info->fb_##var == 0)                                        \
159                 return (CN_DEAD);
160
161         GET("height", height)
162         GET("width", width)
163         GET("depth", depth)
164         GET("linebytes", stride)
165 #undef GET
166
167         info->fb_size = info->fb_height * info->fb_stride;
168
169         /*
170          * Get the PCI addresses of the adapter, if present. The node may be the
171          * child of the PCI device: in that case, try the parent for
172          * the assigned-addresses property.
173          */
174         len = OF_getprop(node, "assigned-addresses", pciaddrs,
175             sizeof(pciaddrs));
176         if (len == -1) {
177                 len = OF_getprop(OF_parent(node), "assigned-addresses",
178                     pciaddrs, sizeof(pciaddrs));
179         }
180         if (len == -1)
181                 len = 0;
182         n_pciaddrs = len / sizeof(struct ofw_pci_register);
183
184         /*
185          * Grab the physical address of the framebuffer, and then map it
186          * into our memory space. If the MMU is not yet up, it will be
187          * remapped for us when relocation turns on.
188          */
189         if (OF_getproplen(node, "address") == sizeof(info->fb_pbase)) {
190                 /* XXX We assume #address-cells is 1 at this point. */
191                 OF_getencprop(node, "address", &info->fb_pbase,
192                     sizeof(info->fb_pbase));
193
194         #if defined(__powerpc__)
195                 sc->sc_memt = &bs_be_tag;
196                 bus_space_map(sc->sc_memt, info->fb_pbase, info->fb_size,
197                     BUS_SPACE_MAP_PREFETCHABLE, &info->fb_vbase);
198         #elif defined(__sparc64__)
199                 OF_decode_addr(node, 0, &space, &phys);
200                 sc->sc_memt = &vt_efb_memt[0];
201                 info->addr = sparc64_fake_bustag(space, fb_phys, sc->sc_memt);
202         #else
203                 bus_space_map(fdtbus_bs_tag, info->fb_pbase, info->fb_size,
204                     BUS_SPACE_MAP_PREFETCHABLE,
205                     (bus_space_handle_t *)&info->fb_vbase);
206         #endif
207         } else {
208                 /*
209                  * Some IBM systems don't have an address property. Try to
210                  * guess the framebuffer region from the assigned addresses.
211                  * This is ugly, but there doesn't seem to be an alternative.
212                  * Linux does the same thing.
213                  */
214
215                 info->fb_pbase = n_pciaddrs;
216                 for (i = 0; i < n_pciaddrs; i++) {
217                         /* If it is too small, not the framebuffer */
218                         if (pciaddrs[i].size_lo < info->fb_size)
219                                 continue;
220                         /* If it is not memory, it isn't either */
221                         if (!(pciaddrs[i].phys_hi &
222                             OFW_PCI_PHYS_HI_SPACE_MEM32))
223                                 continue;
224
225                         /* This could be the framebuffer */
226                         info->fb_pbase = i;
227
228                         /* If it is prefetchable, it certainly is */
229                         if (pciaddrs[i].phys_hi & OFW_PCI_PHYS_HI_PREFETCHABLE)
230                                 break;
231                 }
232
233                 if (info->fb_pbase == n_pciaddrs) /* No candidates found */
234                         return (CN_DEAD);
235
236         #if defined(__powerpc__)
237                 OF_decode_addr(node, info->fb_pbase, &sc->sc_memt,
238                     &info->fb_vbase);
239         #elif defined(__sparc64__)
240                 OF_decode_addr(node, info->fb_pbase, &space, &info->fb_pbase);
241                 sc->sc_memt = &vt_efb_memt[0];
242                 info->fb_vbase = sparc64_fake_bustag(space, info->fb_pbase,
243                     sc->sc_memt);
244         #else
245                 bus_space_map(fdtbus_bs_tag, info->fb_pbase, info->fb_size,
246                     BUS_SPACE_MAP_PREFETCHABLE,
247                     (bus_space_handle_t *)&info->fb_vbase);
248         #endif
249         }
250
251
252         /* blank full size */
253         len = info->fb_size / 4;
254         for (i = 0; i < len; i++) {
255                 ((uint32_t *)info->fb_vbase)[i] = 0;
256         }
257
258         /* Get pixel storage size. */
259         info->fb_bpp = info->fb_stride / info->fb_width * 8;
260
261         /*
262          * Early FB driver work with static window buffer 80x25, so reduce
263          * size to 640x480.
264          */
265         info->fb_width = VT_FB_DEFAULT_WIDTH;
266         info->fb_height = VT_FB_DEFAULT_HEIGHT;
267
268 #ifdef  FDT
269         vt_efb_initialize(info, node);
270 #else
271         vt_efb_initialize(info);
272 #endif
273         fb_probe(info);
274         vt_fb_init(vd);
275
276
277         return (CN_INTERNAL);
278 }