]> CyberLeo.Net >> Repos - FreeBSD/stable/9.git/blob - sys/dev/vt/hw/ofwfb/ofwfb.c
MFC 219886, 226100, 226111, 226341, 242529, 259015, 259016, 259019, 259049,
[FreeBSD/stable/9.git] / sys / dev / vt / hw / ofwfb / ofwfb.c
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$");
29
30 #include <sys/param.h>
31 #include <sys/kernel.h>
32 #include <sys/systm.h>
33
34 #include <dev/vt/vt.h>
35 #include <dev/vt/colors/vt_termcolors.h>
36
37 #include <vm/vm.h>
38 #include <vm/pmap.h>
39
40 #include <machine/bus.h>
41 #ifdef __sparc64__
42 #include <machine/bus_private.h>
43 #endif
44
45 #include <dev/ofw/openfirm.h>
46 #include <dev/ofw/ofw_bus.h>
47 #include <dev/ofw/ofw_pci.h>
48
49 struct ofwfb_softc {
50         phandle_t       sc_node;
51
52         intptr_t        sc_addr;
53         int             sc_depth;
54         int             sc_stride;
55
56         bus_space_tag_t sc_memt; 
57
58         uint32_t        sc_colormap[16];
59 };
60
61 static vd_init_t        ofwfb_init;
62 static vd_blank_t       ofwfb_blank;
63 static vd_bitbltchr_t   ofwfb_bitbltchr;
64
65 static const struct vt_driver vt_ofwfb_driver = {
66         .vd_init        = ofwfb_init,
67         .vd_blank       = ofwfb_blank,
68         .vd_bitbltchr   = ofwfb_bitbltchr,
69         .vd_priority    = VD_PRIORITY_GENERIC+1,
70 };
71
72 static struct ofwfb_softc ofwfb_conssoftc;
73 VT_CONSDEV_DECLARE(vt_ofwfb_driver, PIXEL_WIDTH(1920), PIXEL_HEIGHT(1200),
74     &ofwfb_conssoftc);
75 /* XXX: hardcoded max size */
76
77 static void
78 ofwfb_blank(struct vt_device *vd, term_color_t color)
79 {
80         struct ofwfb_softc *sc = vd->vd_softc;
81         u_int ofs, size;
82         uint32_t c;
83
84         size = sc->sc_stride * vd->vd_height;
85         switch (sc->sc_depth) {
86         case 8:
87                 c = (color << 24) | (color << 16) | (color << 8) | color;
88                 for (ofs = 0; ofs < size/4; ofs++)
89                         *(uint32_t *)(sc->sc_addr + 4*ofs) = c;
90                 break;
91         case 32:
92                 c = sc->sc_colormap[color];
93                 for (ofs = 0; ofs < size; ofs++)
94                         *(uint32_t *)(sc->sc_addr + 4*ofs) = c;
95                 break;
96         default:
97                 /* panic? */
98                 break;
99         }
100 }
101
102 static void
103 ofwfb_bitbltchr(struct vt_device *vd, const uint8_t *src, const uint8_t *mask,
104     int bpl, vt_axis_t top, vt_axis_t left, unsigned int width,
105     unsigned int height, term_color_t fg, term_color_t bg)
106 {
107         struct ofwfb_softc *sc = vd->vd_softc;
108         u_long line;
109         uint32_t fgc, bgc;
110         int c;
111         uint8_t b, m;
112
113         fgc = sc->sc_colormap[fg];
114         bgc = sc->sc_colormap[bg];
115         b = m = 0;
116
117         /* Don't try to put off screen pixels */
118         if (((left + width) > vd->vd_width) || ((top + height) >
119             vd->vd_height))
120                 return;
121
122         line = (sc->sc_stride * top) + left * sc->sc_depth/8;
123         for (; height > 0; height--) {
124                 for (c = 0; c < width; c++) {
125                         if (c % 8 == 0)
126                                 b = *src++;
127                         else
128                                 b <<= 1;
129                         if (mask != NULL) {
130                                 if (c % 8 == 0)
131                                         m = *mask++;
132                                 else
133                                         m <<= 1;
134                                 /* Skip pixel write, if mask has no bit set. */
135                                 if ((m & 0x80) == 0)
136                                         continue;
137                         }
138                         switch(sc->sc_depth) {
139                         case 8:
140                                 *(uint8_t *)(sc->sc_addr + line + c) =
141                                     b & 0x80 ? fg : bg;
142                                 break;
143                         case 32:
144                                 *(uint32_t *)(sc->sc_addr + line + 4*c) = 
145                                     (b & 0x80) ? fgc : bgc;
146                                 break;
147                         default:
148                                 /* panic? */
149                                 break;
150                         }
151                 }
152                 line += sc->sc_stride;
153         }
154 }
155
156 static void
157 ofwfb_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         uint32_t oldpix;
165
166         /* Open display device, thereby initializing it */
167         memset(name, 0, sizeof(name));
168         OF_package_to_path(sc->sc_node, name, sizeof(name));
169         ih = OF_open(name);
170
171         /*
172          * Set up the color map
173          */
174
175         switch (sc->sc_depth) {
176         case 8:
177                 vt_generate_vga_palette(sc->sc_colormap, COLOR_FORMAT_RGB, 255,
178                     0, 255, 8, 255, 16);
179
180                 for (i = 0; i < 16; i++) {
181                         OF_call_method("color!", ih, 4, 1,
182                             (cell_t)((sc->sc_colormap[i] >> 16) & 0xff),
183                             (cell_t)((sc->sc_colormap[i] >> 8) & 0xff),
184                             (cell_t)((sc->sc_colormap[i] >> 0) & 0xff),
185                             (cell_t)i, &retval);
186                 }
187                 break;
188
189         case 32:
190                 /*
191                  * We bypass the usual bus_space_() accessors here, mostly
192                  * for performance reasons. In particular, we don't want
193                  * any barrier operations that may be performed and handle
194                  * endianness slightly different. Figure out the host-view
195                  * endianness of the frame buffer.
196                  */
197                 oldpix = bus_space_read_4(sc->sc_memt, sc->sc_addr, 0);
198                 bus_space_write_4(sc->sc_memt, sc->sc_addr, 0, 0xff000000);
199                 if (*(uint8_t *)(sc->sc_addr) == 0xff)
200                         vt_generate_vga_palette(sc->sc_colormap,
201                             COLOR_FORMAT_RGB, 255, 16, 255, 8, 255, 0);
202                 else
203                         vt_generate_vga_palette(sc->sc_colormap,
204                             COLOR_FORMAT_RGB, 255, 0, 255, 8, 255, 16);
205                 bus_space_write_4(sc->sc_memt, sc->sc_addr, 0, oldpix);
206                 break;
207
208         default:
209                 panic("Unknown color space depth %d", sc->sc_depth);
210                 break;
211         }
212
213         /* Clear the screen. */
214         ofwfb_blank(vd, TC_BLACK);
215 }
216
217 static int
218 ofwfb_init(struct vt_device *vd)
219 {
220         struct ofwfb_softc *sc = vd->vd_softc;
221         char type[64];
222         phandle_t chosen;
223         ihandle_t stdout;
224         phandle_t node;
225         uint32_t depth, height, width;
226         struct ofw_pci_register pciaddrs[8];
227         int n_pciaddrs;
228         uint32_t fb_phys;
229         int i, len;
230 #ifdef __sparc64__
231         static struct bus_space_tag ofwfb_memt[1];
232         bus_addr_t phys;
233         int space;
234 #endif
235
236         chosen = OF_finddevice("/chosen");
237         OF_getprop(chosen, "stdout", &stdout, sizeof(stdout));
238         node = OF_instance_to_package(stdout);
239         if (node == -1) {
240                 /*
241                  * The "/chosen/stdout" does not exist try
242                  * using "screen" directly.
243                  */
244                 node = OF_finddevice("screen");
245         }
246         OF_getprop(node, "device_type", type, sizeof(type));
247         if (strcmp(type, "display") != 0)
248                 return (CN_DEAD);
249
250         /* Keep track of the OF node */
251         sc->sc_node = node;
252
253         /* Make sure we have needed properties */
254         if (OF_getproplen(node, "height") != sizeof(height) ||
255             OF_getproplen(node, "width") != sizeof(width) ||
256             OF_getproplen(node, "depth") != sizeof(depth) ||
257             OF_getproplen(node, "linebytes") != sizeof(sc->sc_stride))
258                 return (CN_DEAD);
259
260         /* Only support 8 and 32-bit framebuffers */
261         OF_getprop(node, "depth", &depth, sizeof(depth));
262         if (depth != 8 && depth != 32)
263                 return (CN_DEAD);
264         sc->sc_depth = depth;
265
266         OF_getprop(node, "height", &height, sizeof(height));
267         OF_getprop(node, "width", &width, sizeof(width));
268         OF_getprop(node, "linebytes", &sc->sc_stride, sizeof(sc->sc_stride));
269
270         vd->vd_height = height;
271         vd->vd_width = width;
272
273         /*
274          * Get the PCI addresses of the adapter, if present. The node may be the
275          * child of the PCI device: in that case, try the parent for
276          * the assigned-addresses property.
277          */
278         len = OF_getprop(node, "assigned-addresses", pciaddrs,
279             sizeof(pciaddrs));
280         if (len == -1) {
281                 len = OF_getprop(OF_parent(node), "assigned-addresses",
282                     pciaddrs, sizeof(pciaddrs));
283         }
284         if (len == -1)
285                 len = 0;
286         n_pciaddrs = len / sizeof(struct ofw_pci_register);
287
288         /*
289          * Grab the physical address of the framebuffer, and then map it
290          * into our memory space. If the MMU is not yet up, it will be
291          * remapped for us when relocation turns on.
292          */
293         if (OF_getproplen(node, "address") == sizeof(fb_phys)) {
294                 /* XXX We assume #address-cells is 1 at this point. */
295                 OF_getprop(node, "address", &fb_phys, sizeof(fb_phys));
296
297         #if defined(__powerpc__)
298                 sc->sc_memt = &bs_be_tag;
299                 bus_space_map(sc->sc_memt, fb_phys, height * sc->sc_stride,
300                     BUS_SPACE_MAP_PREFETCHABLE, &sc->sc_addr);
301         #elif defined(__sparc64__)
302                 OF_decode_addr(node, 0, &space, &phys);
303                 sc->sc_memt = &ofwfb_memt[0];
304                 sc->sc_addr = sparc64_fake_bustag(space, fb_phys, sc->sc_memt);
305         #else
306                 #error Unsupported platform!
307         #endif
308         } else {
309                 /*
310                  * Some IBM systems don't have an address property. Try to
311                  * guess the framebuffer region from the assigned addresses.
312                  * This is ugly, but there doesn't seem to be an alternative.
313                  * Linux does the same thing.
314                  */
315
316                 fb_phys = n_pciaddrs;
317                 for (i = 0; i < n_pciaddrs; i++) {
318                         /* If it is too small, not the framebuffer */
319                         if (pciaddrs[i].size_lo < sc->sc_stride*height)
320                                 continue;
321                         /* If it is not memory, it isn't either */
322                         if (!(pciaddrs[i].phys_hi &
323                             OFW_PCI_PHYS_HI_SPACE_MEM32))
324                                 continue;
325
326                         /* This could be the framebuffer */
327                         fb_phys = i;
328
329                         /* If it is prefetchable, it certainly is */
330                         if (pciaddrs[i].phys_hi & OFW_PCI_PHYS_HI_PREFETCHABLE)
331                                 break;
332                 }
333
334                 if (fb_phys == n_pciaddrs) /* No candidates found */
335                         return (CN_DEAD);
336
337         #if defined(__powerpc__)
338                 OF_decode_addr(node, fb_phys, &sc->sc_memt, &sc->sc_addr);
339         #elif defined(__sparc64__)
340                 OF_decode_addr(node, fb_phys, &space, &phys);
341                 sc->sc_memt = &ofwfb_memt[0];
342                 sc->sc_addr = sparc64_fake_bustag(space, phys, sc->sc_memt);
343         #endif
344         }
345
346         ofwfb_initialize(vd);
347
348         return (CN_INTERNAL);
349 }
350