]> CyberLeo.Net >> Repos - FreeBSD/releng/10.2.git/blob - sys/dev/vt/hw/ofwfb/ofwfb.c
- Copy stable/10@285827 to releng/10.2 in preparation for 10.2-RC1
[FreeBSD/releng/10.2.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 #include <sys/fbio.h>
34
35 #include <dev/vt/vt.h>
36 #include <dev/vt/hw/fb/vt_fb.h>
37 #include <dev/vt/colors/vt_termcolors.h>
38
39 #include <vm/vm.h>
40 #include <vm/pmap.h>
41
42 #include <machine/bus.h>
43 #ifdef __sparc64__
44 #include <machine/bus_private.h>
45 #endif
46
47 #include <dev/ofw/openfirm.h>
48 #include <dev/ofw/ofw_bus.h>
49 #include <dev/ofw/ofw_pci.h>
50
51 struct ofwfb_softc {
52         struct fb_info  fb;
53
54         phandle_t       sc_node;
55         ihandle_t       sc_handle;
56         bus_space_tag_t sc_memt;
57 };
58
59 static vd_probe_t       ofwfb_probe;
60 static vd_init_t        ofwfb_init;
61 static vd_bitblt_text_t ofwfb_bitblt_text;
62 static vd_bitblt_bmp_t  ofwfb_bitblt_bitmap;
63
64 static const struct vt_driver vt_ofwfb_driver = {
65         .vd_name        = "ofwfb",
66         .vd_probe       = ofwfb_probe,
67         .vd_init        = ofwfb_init,
68         .vd_blank       = vt_fb_blank,
69         .vd_bitblt_text = ofwfb_bitblt_text,
70         .vd_bitblt_bmp  = ofwfb_bitblt_bitmap,
71         .vd_fb_ioctl    = vt_fb_ioctl,
72         .vd_fb_mmap     = vt_fb_mmap,
73         .vd_priority    = VD_PRIORITY_GENERIC+1,
74 };
75
76 static struct ofwfb_softc ofwfb_conssoftc;
77 VT_DRIVER_DECLARE(vt_ofwfb, vt_ofwfb_driver);
78
79 static int
80 ofwfb_probe(struct vt_device *vd)
81 {
82         phandle_t chosen, node;
83         ihandle_t stdout;
84         char type[64];
85
86         chosen = OF_finddevice("/chosen");
87         OF_getprop(chosen, "stdout", &stdout, sizeof(stdout));
88         node = OF_instance_to_package(stdout);
89         if (node == -1) {
90                 /*
91                  * The "/chosen/stdout" does not exist try
92                  * using "screen" directly.
93                  */
94                 node = OF_finddevice("screen");
95         }
96         OF_getprop(node, "device_type", type, sizeof(type));
97         if (strcmp(type, "display") != 0)
98                 return (CN_DEAD);
99
100         /* Looks OK... */
101         return (CN_INTERNAL);
102 }
103
104 static void
105 ofwfb_bitblt_bitmap(struct vt_device *vd, const struct vt_window *vw,
106     const uint8_t *pattern, const uint8_t *mask,
107     unsigned int width, unsigned int height,
108     unsigned int x, unsigned int y, term_color_t fg, term_color_t bg)
109 {
110         struct fb_info *sc = vd->vd_softc;
111         u_long line;
112         uint32_t fgc, bgc;
113         int c, l;
114         uint8_t b, m;
115         union {
116                 uint32_t l;
117                 uint8_t  c[4];
118         } ch1, ch2;
119
120         fgc = sc->fb_cmap[fg];
121         bgc = sc->fb_cmap[bg];
122         b = m = 0;
123
124         line = (sc->fb_stride * y) + x * sc->fb_bpp/8;
125         if (mask == NULL && sc->fb_bpp == 8 && (width % 8 == 0)) {
126                 /* Don't try to put off screen pixels */
127                 if (((x + width) > vd->vd_width) || ((y + height) >
128                     vd->vd_height))
129                         return;
130
131                 for (; height > 0; height--) {
132                         for (c = 0; c < width; c += 8) {
133                                 b = *pattern++;
134
135                                 /*
136                                  * Assume that there is more background than
137                                  * foreground in characters and init accordingly
138                                  */
139                                 ch1.l = ch2.l = (bg << 24) | (bg << 16) |
140                                     (bg << 8) | bg;
141
142                                 /*
143                                  * Calculate 2 x 4-chars at a time, and then
144                                  * write these out.
145                                  */
146                                 if (b & 0x80) ch1.c[0] = fg;
147                                 if (b & 0x40) ch1.c[1] = fg;
148                                 if (b & 0x20) ch1.c[2] = fg;
149                                 if (b & 0x10) ch1.c[3] = fg;
150
151                                 if (b & 0x08) ch2.c[0] = fg;
152                                 if (b & 0x04) ch2.c[1] = fg;
153                                 if (b & 0x02) ch2.c[2] = fg;
154                                 if (b & 0x01) ch2.c[3] = fg;
155
156                                 *(uint32_t *)(sc->fb_vbase + line + c) = ch1.l;
157                                 *(uint32_t *)(sc->fb_vbase + line + c + 4) =
158                                     ch2.l;
159                         }
160                         line += sc->fb_stride;
161                 }
162         } else {
163                 for (l = 0;
164                     l < height && y + l < vw->vw_draw_area.tr_end.tp_row;
165                     l++) {
166                         for (c = 0;
167                             c < width && x + c < vw->vw_draw_area.tr_end.tp_col;
168                             c++) {
169                                 if (c % 8 == 0)
170                                         b = *pattern++;
171                                 else
172                                         b <<= 1;
173                                 if (mask != NULL) {
174                                         if (c % 8 == 0)
175                                                 m = *mask++;
176                                         else
177                                                 m <<= 1;
178                                         /* Skip pixel write, if mask not set. */
179                                         if ((m & 0x80) == 0)
180                                                 continue;
181                                 }
182                                 switch(sc->fb_bpp) {
183                                 case 8:
184                                         *(uint8_t *)(sc->fb_vbase + line + c) =
185                                             b & 0x80 ? fg : bg;
186                                         break;
187                                 case 32:
188                                         *(uint32_t *)(sc->fb_vbase + line + 4*c)
189                                             = (b & 0x80) ? fgc : bgc;
190                                         break;
191                                 default:
192                                         /* panic? */
193                                         break;
194                                 }
195                         }
196                         line += sc->fb_stride;
197                 }
198         }
199 }
200
201 void
202 ofwfb_bitblt_text(struct vt_device *vd, const struct vt_window *vw,
203     const term_rect_t *area)
204 {
205         unsigned int col, row, x, y;
206         struct vt_font *vf;
207         term_char_t c;
208         term_color_t fg, bg;
209         const uint8_t *pattern;
210
211         vf = vw->vw_font;
212
213         for (row = area->tr_begin.tp_row; row < area->tr_end.tp_row; ++row) {
214                 for (col = area->tr_begin.tp_col; col < area->tr_end.tp_col;
215                     ++col) {
216                         x = col * vf->vf_width +
217                             vw->vw_draw_area.tr_begin.tp_col;
218                         y = row * vf->vf_height +
219                             vw->vw_draw_area.tr_begin.tp_row;
220
221                         c = VTBUF_GET_FIELD(&vw->vw_buf, row, col);
222                         pattern = vtfont_lookup(vf, c);
223                         vt_determine_colors(c,
224                             VTBUF_ISCURSOR(&vw->vw_buf, row, col), &fg, &bg);
225
226                         ofwfb_bitblt_bitmap(vd, vw,
227                             pattern, NULL, vf->vf_width, vf->vf_height,
228                             x, y, fg, bg);
229                 }
230         }
231
232 #ifndef SC_NO_CUTPASTE
233         if (!vd->vd_mshown)
234                 return;
235
236         term_rect_t drawn_area;
237
238         drawn_area.tr_begin.tp_col = area->tr_begin.tp_col * vf->vf_width;
239         drawn_area.tr_begin.tp_row = area->tr_begin.tp_row * vf->vf_height;
240         drawn_area.tr_end.tp_col = area->tr_end.tp_col * vf->vf_width;
241         drawn_area.tr_end.tp_row = area->tr_end.tp_row * vf->vf_height;
242
243         if (vt_is_cursor_in_area(vd, &drawn_area)) {
244                 ofwfb_bitblt_bitmap(vd, vw,
245                     vd->vd_mcursor->map, vd->vd_mcursor->mask,
246                     vd->vd_mcursor->width, vd->vd_mcursor->height,
247                     vd->vd_mx_drawn + vw->vw_draw_area.tr_begin.tp_col,
248                     vd->vd_my_drawn + vw->vw_draw_area.tr_begin.tp_row,
249                     vd->vd_mcursor_fg, vd->vd_mcursor_bg);
250         }
251 #endif
252 }
253
254 static void
255 ofwfb_initialize(struct vt_device *vd)
256 {
257         struct ofwfb_softc *sc = vd->vd_softc;
258         int i;
259         cell_t retval;
260         uint32_t oldpix;
261
262         /*
263          * Set up the color map
264          */
265
266         switch (sc->fb.fb_bpp) {
267         case 8:
268                 vt_generate_cons_palette(sc->fb.fb_cmap, COLOR_FORMAT_RGB, 255,
269                     16, 255, 8, 255, 0);
270
271                 for (i = 0; i < 16; i++) {
272                         OF_call_method("color!", sc->sc_handle, 4, 1,
273                             (cell_t)((sc->fb.fb_cmap[i] >> 16) & 0xff),
274                             (cell_t)((sc->fb.fb_cmap[i] >> 8) & 0xff),
275                             (cell_t)((sc->fb.fb_cmap[i] >> 0) & 0xff),
276                             (cell_t)i, &retval);
277                 }
278                 break;
279
280         case 32:
281                 /*
282                  * We bypass the usual bus_space_() accessors here, mostly
283                  * for performance reasons. In particular, we don't want
284                  * any barrier operations that may be performed and handle
285                  * endianness slightly different. Figure out the host-view
286                  * endianness of the frame buffer.
287                  */
288                 oldpix = bus_space_read_4(sc->sc_memt, sc->fb.fb_vbase, 0);
289                 bus_space_write_4(sc->sc_memt, sc->fb.fb_vbase, 0, 0xff000000);
290                 if (*(uint8_t *)(sc->fb.fb_vbase) == 0xff)
291                         vt_generate_cons_palette(sc->fb.fb_cmap,
292                             COLOR_FORMAT_RGB, 255, 0, 255, 8, 255, 16);
293                 else
294                         vt_generate_cons_palette(sc->fb.fb_cmap,
295                             COLOR_FORMAT_RGB, 255, 16, 255, 8, 255, 0);
296                 bus_space_write_4(sc->sc_memt, sc->fb.fb_vbase, 0, oldpix);
297                 break;
298
299         default:
300                 panic("Unknown color space depth %d", sc->fb.fb_bpp);
301                 break;
302         }
303
304         sc->fb.fb_cmsize = 16;
305 }
306
307 static int
308 ofwfb_init(struct vt_device *vd)
309 {
310         struct ofwfb_softc *sc;
311         char type[64];
312         phandle_t chosen;
313         phandle_t node;
314         uint32_t depth, height, width, stride;
315         uint32_t fb_phys;
316         int i, len;
317 #ifdef __sparc64__
318         static struct bus_space_tag ofwfb_memt[1];
319         bus_addr_t phys;
320         int space;
321 #endif
322
323         /* Initialize softc */
324         vd->vd_softc = sc = &ofwfb_conssoftc;
325
326         chosen = OF_finddevice("/chosen");
327         OF_getprop(chosen, "stdout", &sc->sc_handle, sizeof(ihandle_t));
328         node = OF_instance_to_package(sc->sc_handle);
329         if (node == -1) {
330                 /*
331                  * The "/chosen/stdout" does not exist try
332                  * using "screen" directly.
333                  */
334                 node = OF_finddevice("screen");
335                 sc->sc_handle = OF_open("screen");
336         }
337         OF_getprop(node, "device_type", type, sizeof(type));
338         if (strcmp(type, "display") != 0)
339                 return (CN_DEAD);
340
341         /* Keep track of the OF node */
342         sc->sc_node = node;
343
344         /*
345          * Try to use a 32-bit framebuffer if possible. This may be
346          * unimplemented and fail. That's fine -- it just means we are
347          * stuck with the defaults.
348          */
349         OF_call_method("set-depth", sc->sc_handle, 1, 1, (cell_t)32, &i);
350
351         /* Make sure we have needed properties */
352         if (OF_getproplen(node, "height") != sizeof(height) ||
353             OF_getproplen(node, "width") != sizeof(width) ||
354             OF_getproplen(node, "depth") != sizeof(depth) ||
355             OF_getproplen(node, "linebytes") != sizeof(sc->fb.fb_stride))
356                 return (CN_DEAD);
357
358         /* Only support 8 and 32-bit framebuffers */
359         OF_getprop(node, "depth", &depth, sizeof(depth));
360         if (depth != 8 && depth != 32)
361                 return (CN_DEAD);
362         sc->fb.fb_bpp = sc->fb.fb_depth = depth;
363
364         OF_getprop(node, "height", &height, sizeof(height));
365         OF_getprop(node, "width", &width, sizeof(width));
366         OF_getprop(node, "linebytes", &stride, sizeof(stride));
367
368         sc->fb.fb_height = height;
369         sc->fb.fb_width = width;
370         sc->fb.fb_stride = stride;
371         sc->fb.fb_size = sc->fb.fb_height * sc->fb.fb_stride;
372
373         /*
374          * Grab the physical address of the framebuffer, and then map it
375          * into our memory space. If the MMU is not yet up, it will be
376          * remapped for us when relocation turns on.
377          */
378         if (OF_getproplen(node, "address") == sizeof(fb_phys)) {
379                 /* XXX We assume #address-cells is 1 at this point. */
380                 OF_getprop(node, "address", &fb_phys, sizeof(fb_phys));
381
382         #if defined(__powerpc__)
383                 sc->sc_memt = &bs_be_tag;
384                 bus_space_map(sc->sc_memt, fb_phys, sc->fb.fb_size,
385                     BUS_SPACE_MAP_PREFETCHABLE, &sc->fb.fb_vbase);
386         #elif defined(__sparc64__)
387                 OF_decode_addr(node, 0, &space, &phys);
388                 sc->sc_memt = &ofwfb_memt[0];
389                 sc->fb.fb_vbase =
390                     sparc64_fake_bustag(space, fb_phys, sc->sc_memt);
391         #elif defined(__arm__)
392                 sc->sc_memt = fdtbus_bs_tag;
393                 bus_space_map(sc->sc_memt, sc->fb.fb_pbase, sc->fb.fb_size,
394                     BUS_SPACE_MAP_PREFETCHABLE,
395                     (bus_space_handle_t *)&sc->fb.fb_vbase);
396         #else
397                 #error Unsupported platform!
398         #endif
399
400                 sc->fb.fb_pbase = fb_phys;
401         } else {
402                 /*
403                  * Some IBM systems don't have an address property. Try to
404                  * guess the framebuffer region from the assigned addresses.
405                  * This is ugly, but there doesn't seem to be an alternative.
406                  * Linux does the same thing.
407                  */
408
409                 struct ofw_pci_register pciaddrs[8];
410                 int num_pciaddrs = 0;
411
412                 /*
413                  * Get the PCI addresses of the adapter, if present. The node
414                  * may be the child of the PCI device: in that case, try the
415                  * parent for the assigned-addresses property.
416                  */
417                 len = OF_getprop(node, "assigned-addresses", pciaddrs,
418                     sizeof(pciaddrs));
419                 if (len == -1) {
420                         len = OF_getprop(OF_parent(node), "assigned-addresses",
421                             pciaddrs, sizeof(pciaddrs));
422                 }
423                 if (len == -1)
424                         len = 0;
425                 num_pciaddrs = len / sizeof(struct ofw_pci_register);
426
427                 fb_phys = num_pciaddrs;
428                 for (i = 0; i < num_pciaddrs; i++) {
429                         /* If it is too small, not the framebuffer */
430                         if (pciaddrs[i].size_lo < sc->fb.fb_stride * height)
431                                 continue;
432                         /* If it is not memory, it isn't either */
433                         if (!(pciaddrs[i].phys_hi &
434                             OFW_PCI_PHYS_HI_SPACE_MEM32))
435                                 continue;
436
437                         /* This could be the framebuffer */
438                         fb_phys = i;
439
440                         /* If it is prefetchable, it certainly is */
441                         if (pciaddrs[i].phys_hi & OFW_PCI_PHYS_HI_PREFETCHABLE)
442                                 break;
443                 }
444
445                 if (fb_phys == num_pciaddrs) /* No candidates found */
446                         return (CN_DEAD);
447
448         #if defined(__powerpc__)
449                 OF_decode_addr(node, fb_phys, &sc->sc_memt, &sc->fb.fb_vbase);
450                 sc->fb.fb_pbase = sc->fb.fb_vbase; /* 1:1 mapped */
451         #else
452                 /* No ability to interpret assigned-addresses otherwise */
453                 return (CN_DEAD);
454         #endif
455         }
456
457
458         ofwfb_initialize(vd);
459         vt_fb_init(vd);
460
461         return (CN_INTERNAL);
462 }
463