The Design and Implementation of the FreeBSD Operating System, Second Edition
Now available: The Design and Implementation of the FreeBSD Operating System (Second Edition)


[ source navigation ] [ diff markup ] [ identifier search ] [ freetext search ] [ file search ] [ list types ] [ track identifier ]

FreeBSD/Linux Kernel Cross Reference
sys/dev/vt/hw/ofwfb/ofwfb.c

Version: -  FREEBSD  -  FREEBSD-13-STABLE  -  FREEBSD-13-0  -  FREEBSD-12-STABLE  -  FREEBSD-12-0  -  FREEBSD-11-STABLE  -  FREEBSD-11-0  -  FREEBSD-10-STABLE  -  FREEBSD-10-0  -  FREEBSD-9-STABLE  -  FREEBSD-9-0  -  FREEBSD-8-STABLE  -  FREEBSD-8-0  -  FREEBSD-7-STABLE  -  FREEBSD-7-0  -  FREEBSD-6-STABLE  -  FREEBSD-6-0  -  FREEBSD-5-STABLE  -  FREEBSD-5-0  -  FREEBSD-4-STABLE  -  FREEBSD-3-STABLE  -  FREEBSD22  -  l41  -  OPENBSD  -  linux-2.6  -  MK84  -  PLAN9  -  xnu-8792 
SearchContext: -  none  -  3  -  10 

    1 /*-
    2  * SPDX-License-Identifier: BSD-2-Clause-FreeBSD
    3  *
    4  * Copyright (c) 2011 Nathan Whitehorn
    5  * All rights reserved.
    6  *
    7  * Redistribution and use in source and binary forms, with or without
    8  * modification, are permitted provided that the following conditions
    9  * are met:
   10  * 1. Redistributions of source code must retain the above copyright
   11  *    notice, this list of conditions and the following disclaimer.
   12  * 2. Redistributions in binary form must reproduce the above copyright
   13  *    notice, this list of conditions and the following disclaimer in the
   14  *    documentation and/or other materials provided with the distribution.
   15  *
   16  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
   17  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
   18  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
   19  * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
   20  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
   21  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
   22  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
   23  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
   24  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
   25  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
   26  * SUCH DAMAGE.
   27  */
   28 
   29 #include <sys/cdefs.h>
   30 __FBSDID("$FreeBSD$");
   31 
   32 #include <sys/param.h>
   33 #include <sys/kernel.h>
   34 #include <sys/systm.h>
   35 #include <sys/fbio.h>
   36 
   37 #include <dev/vt/vt.h>
   38 #include <dev/vt/hw/fb/vt_fb.h>
   39 #include <dev/vt/colors/vt_termcolors.h>
   40 
   41 #include <vm/vm.h>
   42 #include <vm/pmap.h>
   43 
   44 #include <machine/bus.h>
   45 #include <machine/cpu.h>
   46 
   47 #include <dev/ofw/openfirm.h>
   48 #include <dev/ofw/ofw_bus.h>
   49 #include <dev/ofw/ofw_pci.h>
   50 #include <dev/ofw/ofw_subr.h>
   51 
   52 struct ofwfb_softc {
   53         struct fb_info  fb;
   54 
   55         phandle_t       sc_node;
   56         ihandle_t       sc_handle;
   57         bus_space_tag_t sc_memt;
   58         int             iso_palette;
   59         int             argb;
   60         int             endian_flip;
   61         uint32_t        vendor_id;
   62 };
   63 
   64 #define PCI_VID_NVIDIA  0x10de  /* NVIDIA Corporation */
   65 #define PCI_VID_ASPEED  0x1a03  /* ASPEED Technology, Inc. */
   66 
   67 static void ofwfb_initialize(struct vt_device *vd);
   68 static vd_probe_t       ofwfb_probe;
   69 static vd_init_t        ofwfb_init;
   70 static vd_bitblt_text_t ofwfb_bitblt_text;
   71 static vd_bitblt_bmp_t  ofwfb_bitblt_bitmap;
   72 
   73 static const struct vt_driver vt_ofwfb_driver = {
   74         .vd_name        = "ofwfb",
   75         .vd_probe       = ofwfb_probe,
   76         .vd_init        = ofwfb_init,
   77         .vd_blank       = vt_fb_blank,
   78         .vd_bitblt_text = ofwfb_bitblt_text,
   79         .vd_bitblt_bmp  = ofwfb_bitblt_bitmap,
   80         .vd_fb_ioctl    = vt_fb_ioctl,
   81         .vd_fb_mmap     = vt_fb_mmap,
   82         .vd_priority    = VD_PRIORITY_GENERIC+1,
   83 };
   84 
   85 static unsigned char ofw_colors[16] = {
   86         /* See "16-color Text Extension" Open Firmware document, page 4 */
   87         0, 4, 2, 6, 1, 5, 3, 7,
   88         8, 12, 10, 14, 9, 13, 11, 15
   89 };
   90 
   91 static struct ofwfb_softc ofwfb_conssoftc;
   92 VT_DRIVER_DECLARE(vt_ofwfb, vt_ofwfb_driver);
   93 
   94 static int
   95 ofwfb_probe(struct vt_device *vd)
   96 {
   97         int disabled;
   98         phandle_t chosen, node;
   99         ihandle_t stdout;
  100         char buf[64];
  101 
  102         disabled = 0;
  103         TUNABLE_INT_FETCH("hw.ofwfb.disable", &disabled);
  104         if (disabled)
  105                 return (CN_DEAD);
  106 
  107         chosen = OF_finddevice("/chosen");
  108         if (chosen == -1)
  109                 return (CN_DEAD);
  110 
  111         node = -1;
  112         if (OF_getencprop(chosen, "stdout", &stdout, sizeof(stdout)) ==
  113             sizeof(stdout))
  114                 node = OF_instance_to_package(stdout);
  115         if (node == -1)
  116                 if (OF_getprop(chosen, "stdout-path", buf, sizeof(buf)) > 0)
  117                         node = OF_finddevice(buf);
  118         if (node == -1) {
  119                 /*
  120                  * The "/chosen/stdout" does not exist try
  121                  * using "screen" directly.
  122                  */
  123                 node = OF_finddevice("screen");
  124         }
  125         OF_getprop(node, "device_type", buf, sizeof(buf));
  126         if (strcmp(buf, "display") != 0)
  127                 return (CN_DEAD);
  128 
  129         /* Looks OK... */
  130         return (CN_INTERNAL);
  131 }
  132 
  133 static void
  134 ofwfb_bitblt_bitmap(struct vt_device *vd, const struct vt_window *vw,
  135     const uint8_t *pattern, const uint8_t *mask,
  136     unsigned int width, unsigned int height,
  137     unsigned int x, unsigned int y, term_color_t fg, term_color_t bg)
  138 {
  139         struct fb_info *sc = vd->vd_softc;
  140         u_long line;
  141         uint32_t fgc, bgc;
  142         int c, l;
  143         uint8_t b, m;
  144         union {
  145                 uint32_t l;
  146                 uint8_t  c[4];
  147         } ch1, ch2;
  148 
  149 #ifdef __powerpc__
  150         /* Deal with unmapped framebuffers */
  151         if (sc->fb_flags & FB_FLAG_NOWRITE) {
  152                 if (pmap_bootstrapped) {
  153                         sc->fb_flags &= ~FB_FLAG_NOWRITE;
  154                         ofwfb_initialize(vd);
  155                         vd->vd_driver->vd_blank(vd, TC_BLACK);
  156                 } else {
  157                         return;
  158                 }
  159         }
  160 #endif
  161 
  162         fgc = sc->fb_cmap[fg];
  163         bgc = sc->fb_cmap[bg];
  164         b = m = 0;
  165 
  166         if (((struct ofwfb_softc *)vd->vd_softc)->iso_palette) {
  167                 fg = ofw_colors[fg];
  168                 bg = ofw_colors[bg];
  169         }
  170 
  171         line = (sc->fb_stride * y) + x * sc->fb_bpp/8;
  172         if (mask == NULL && sc->fb_bpp == 8 && (width % 8 == 0)) {
  173                 /* Don't try to put off screen pixels */
  174                 if (((x + width) > vd->vd_width) || ((y + height) >
  175                     vd->vd_height))
  176                         return;
  177 
  178                 for (; height > 0; height--) {
  179                         for (c = 0; c < width; c += 8) {
  180                                 b = *pattern++;
  181 
  182                                 /*
  183                                  * Assume that there is more background than
  184                                  * foreground in characters and init accordingly
  185                                  */
  186                                 ch1.l = ch2.l = (bg << 24) | (bg << 16) |
  187                                     (bg << 8) | bg;
  188 
  189                                 /*
  190                                  * Calculate 2 x 4-chars at a time, and then
  191                                  * write these out.
  192                                  */
  193                                 if (b & 0x80) ch1.c[0] = fg;
  194                                 if (b & 0x40) ch1.c[1] = fg;
  195                                 if (b & 0x20) ch1.c[2] = fg;
  196                                 if (b & 0x10) ch1.c[3] = fg;
  197 
  198                                 if (b & 0x08) ch2.c[0] = fg;
  199                                 if (b & 0x04) ch2.c[1] = fg;
  200                                 if (b & 0x02) ch2.c[2] = fg;
  201                                 if (b & 0x01) ch2.c[3] = fg;
  202 
  203                                 *(uint32_t *)(sc->fb_vbase + line + c) = ch1.l;
  204                                 *(uint32_t *)(sc->fb_vbase + line + c + 4) =
  205                                     ch2.l;
  206                         }
  207                         line += sc->fb_stride;
  208                 }
  209         } else {
  210                 for (l = 0;
  211                     l < height && y + l < vw->vw_draw_area.tr_end.tp_row;
  212                     l++) {
  213                         for (c = 0;
  214                             c < width && x + c < vw->vw_draw_area.tr_end.tp_col;
  215                             c++) {
  216                                 if (c % 8 == 0)
  217                                         b = *pattern++;
  218                                 else
  219                                         b <<= 1;
  220                                 if (mask != NULL) {
  221                                         if (c % 8 == 0)
  222                                                 m = *mask++;
  223                                         else
  224                                                 m <<= 1;
  225                                         /* Skip pixel write, if mask not set. */
  226                                         if ((m & 0x80) == 0)
  227                                                 continue;
  228                                 }
  229                                 switch(sc->fb_bpp) {
  230                                 case 8:
  231                                         *(uint8_t *)(sc->fb_vbase + line + c) =
  232                                             b & 0x80 ? fg : bg;
  233                                         break;
  234                                 case 32:
  235                                         *(uint32_t *)(sc->fb_vbase + line + 4*c)
  236                                             = (b & 0x80) ? fgc : bgc;
  237                                         break;
  238                                 default:
  239                                         /* panic? */
  240                                         break;
  241                                 }
  242                         }
  243                         line += sc->fb_stride;
  244                 }
  245         }
  246 }
  247 
  248 void
  249 ofwfb_bitblt_text(struct vt_device *vd, const struct vt_window *vw,
  250     const term_rect_t *area)
  251 {
  252         unsigned int col, row, x, y;
  253         struct vt_font *vf;
  254         term_char_t c;
  255         term_color_t fg, bg;
  256         const uint8_t *pattern;
  257 
  258         vf = vw->vw_font;
  259 
  260         for (row = area->tr_begin.tp_row; row < area->tr_end.tp_row; ++row) {
  261                 for (col = area->tr_begin.tp_col; col < area->tr_end.tp_col;
  262                     ++col) {
  263                         x = col * vf->vf_width +
  264                             vw->vw_draw_area.tr_begin.tp_col;
  265                         y = row * vf->vf_height +
  266                             vw->vw_draw_area.tr_begin.tp_row;
  267 
  268                         c = VTBUF_GET_FIELD(&vw->vw_buf, row, col);
  269                         pattern = vtfont_lookup(vf, c);
  270                         vt_determine_colors(c,
  271                             VTBUF_ISCURSOR(&vw->vw_buf, row, col), &fg, &bg);
  272 
  273                         ofwfb_bitblt_bitmap(vd, vw,
  274                             pattern, NULL, vf->vf_width, vf->vf_height,
  275                             x, y, fg, bg);
  276                 }
  277         }
  278 
  279 #ifndef SC_NO_CUTPASTE
  280         if (!vd->vd_mshown)
  281                 return;
  282 
  283         term_rect_t drawn_area;
  284 
  285         drawn_area.tr_begin.tp_col = area->tr_begin.tp_col * vf->vf_width;
  286         drawn_area.tr_begin.tp_row = area->tr_begin.tp_row * vf->vf_height;
  287         drawn_area.tr_end.tp_col = area->tr_end.tp_col * vf->vf_width;
  288         drawn_area.tr_end.tp_row = area->tr_end.tp_row * vf->vf_height;
  289 
  290         if (vt_is_cursor_in_area(vd, &drawn_area)) {
  291                 ofwfb_bitblt_bitmap(vd, vw,
  292                     vd->vd_mcursor->map, vd->vd_mcursor->mask,
  293                     vd->vd_mcursor->width, vd->vd_mcursor->height,
  294                     vd->vd_mx_drawn + vw->vw_draw_area.tr_begin.tp_col,
  295                     vd->vd_my_drawn + vw->vw_draw_area.tr_begin.tp_row,
  296                     vd->vd_mcursor_fg, vd->vd_mcursor_bg);
  297         }
  298 #endif
  299 }
  300 
  301 
  302 /*
  303  * Decode OpenFirmware/IEEE 1275-1994 "ranges" property
  304  *
  305  * XXX: this is similar to ofw_pcib_fill_ranges but cannot use it here because
  306  *      it's not possible to allocate memory at the moment this is funcion is
  307  *      used. Since there are other similar functions dealing with "ranges"
  308  *      property, a proper refactoring is suggested.
  309  */
  310 static uint64_t
  311 decode_pci_ranges_host_addr(phandle_t pcinode)
  312 {
  313         struct simplebus_range {
  314                 uint64_t bus;
  315                 uint64_t host;
  316                 uint64_t size;
  317         };
  318 
  319         struct simplebus_range ranges[4];
  320         int nranges, host_address_cells;
  321         pcell_t acells, scells;
  322         cell_t base_ranges[64];
  323 
  324         ssize_t nbase_ranges;
  325         int i, j, k;
  326 
  327         if (!OF_hasprop(pcinode, "ranges"))
  328                 return (0);
  329 
  330         if (OF_getencprop(pcinode, "#address-cells", &acells, sizeof(acells)) !=
  331             sizeof(acells))
  332                 return (0);
  333 
  334         if (OF_getencprop(pcinode, "#size-cells", &scells, sizeof(scells)) !=
  335                 sizeof(scells))
  336                 return (0);
  337 
  338         if (OF_searchencprop(OF_parent(pcinode), "#address-cells",
  339                 &host_address_cells, sizeof(host_address_cells)) !=
  340                 sizeof(host_address_cells))
  341                 return (0);
  342 
  343         nbase_ranges = OF_getproplen(pcinode, "ranges");
  344         nranges = nbase_ranges / sizeof(cell_t) / (acells + host_address_cells + scells);
  345 
  346         /* prevent buffer overflow during iteration */
  347         if (nranges > sizeof(ranges) / sizeof(ranges[0]))
  348                 nranges = sizeof(ranges) / sizeof(ranges[0]);
  349 
  350         /* decode range value and return the first valid address */
  351         OF_getencprop(pcinode, "ranges", base_ranges, nbase_ranges);
  352         for (i = 0, j = 0; i < nranges; i++) {
  353                 ranges[i].bus = 0;
  354                 for (k = 0; k < acells; k++) {
  355                         ranges[i].bus <<= 32;
  356                         ranges[i].bus |= base_ranges[j++];
  357                 }
  358 
  359                 ranges[i].host = 0;
  360                 for (k = 0; k < host_address_cells; k++) {
  361                         ranges[i].host <<= 32;
  362                         ranges[i].host |= base_ranges[j++];
  363                 }
  364                 ranges[i].size = 0;
  365                 for (k = 0; k < scells; k++) {
  366                         ranges[i].size <<= 32;
  367                         ranges[i].size |= base_ranges[j++];
  368                 }
  369 
  370                 if (ranges[i].host != 0)
  371                         return (ranges[i].host);
  372         }
  373 
  374         return (0);
  375 }
  376 
  377 static bus_addr_t
  378 find_pci_host_address(phandle_t node)
  379 {
  380         uint64_t addr;
  381 
  382         /*
  383          * According to IEEE STD 1275, if property "ranges" exists but has a
  384          * zero-length property value, the child address space is identical
  385          * to the parent address space.
  386          */
  387         while (node) {
  388                 if (OF_hasprop(node, "ranges")) {
  389                         addr = decode_pci_ranges_host_addr(node);
  390                         if (addr != 0)
  391                                 return ((bus_addr_t)addr);
  392                 }
  393                 node = OF_parent(node);
  394         }
  395 
  396         return (0);
  397 }
  398 
  399 static void
  400 ofwfb_initialize(struct vt_device *vd)
  401 {
  402         struct ofwfb_softc *sc = vd->vd_softc;
  403         int i, err, r, g, b;
  404         cell_t retval;
  405 
  406         sc->fb.fb_cmsize = 16;
  407 
  408         if (sc->fb.fb_flags & FB_FLAG_NOWRITE)
  409                 return;
  410 
  411         /*
  412          * Set up the color map
  413          */
  414 
  415         sc->iso_palette = 0;
  416         switch (sc->fb.fb_bpp) {
  417         case 8:
  418                 /*
  419                  * No color format issues here, since we are passing the RGB
  420                  * components separately to Open Firmware.
  421                  */
  422                 vt_config_cons_colors(&sc->fb, COLOR_FORMAT_RGB, 255,
  423                     16, 255, 8, 255, 0);
  424 
  425                 for (i = 0; i < 16; i++) {
  426                         err = OF_call_method("color!", sc->sc_handle, 4, 1,
  427                             (cell_t)((sc->fb.fb_cmap[i] >> 16) & 0xff),
  428                             (cell_t)((sc->fb.fb_cmap[i] >> 8) & 0xff),
  429                             (cell_t)((sc->fb.fb_cmap[i] >> 0) & 0xff),
  430                             (cell_t)i, &retval);
  431                         if (err)
  432                                 break;
  433                 }
  434                 if (i != 16)
  435                         sc->iso_palette = 1;
  436 
  437                 break;
  438 
  439         case 32:
  440                 /*
  441                  * There are two main color formats in use.
  442                  * ARGB32 is used mainly on hardware that was designed for
  443                  * LE systems, and RGBA32 is used mainly on hardware designed
  444                  * for BE systems.
  445                  *
  446                  * PowerMacs use either, depending on the video card option.
  447                  * NVidia cards tend to be RGBA32, and ATI cards tend to be ARGB32.
  448                  *
  449                  * There is no good way to determine the correct option, as this
  450                  * is independent of endian swapping.
  451                  */
  452                 if (sc->vendor_id == PCI_VID_NVIDIA)
  453                         sc->argb = 0;
  454                 else
  455                         sc->argb = 1;
  456 
  457                 TUNABLE_INT_FETCH("hw.ofwfb.argb32_pixel", &sc->argb);
  458                 if (sc->endian_flip) {
  459                         if (sc->argb)
  460                                 r = 8, g = 16, b = 24;
  461                         else
  462                                 r = 24, g = 16, b = 8;
  463                 } else {
  464                         if (sc->argb)
  465                                 r = 16, g = 8, b = 0;
  466                         else
  467                                 r = 0, g = 8, b = 16;
  468                 }
  469                 vt_config_cons_colors(&sc->fb,
  470                     COLOR_FORMAT_RGB, 255, r, 255, g, 255, b);
  471                 break;
  472 
  473         default:
  474                 panic("Unknown color space depth %d", sc->fb.fb_bpp);
  475                 break;
  476         }
  477 }
  478 
  479 static int
  480 ofwfb_init(struct vt_device *vd)
  481 {
  482         struct ofwfb_softc *sc;
  483         char buf[64];
  484         phandle_t chosen;
  485         phandle_t node;
  486         pcell_t depth, height, width, stride;
  487         uint32_t vendor_id = 0;
  488         cell_t adr[2];
  489         uint64_t user_phys;
  490         bus_addr_t fb_phys;
  491         bus_size_t fb_phys_size;
  492         int i, j, len;
  493 
  494         /* Initialize softc */
  495         vd->vd_softc = sc = &ofwfb_conssoftc;
  496 
  497         node = -1;
  498         chosen = OF_finddevice("/chosen");
  499         if (OF_getencprop(chosen, "stdout", &sc->sc_handle,
  500             sizeof(ihandle_t)) == sizeof(ihandle_t))
  501                 node = OF_instance_to_package(sc->sc_handle);
  502         if (node == -1)
  503                 /* Try "/chosen/stdout-path" now */
  504                 if (OF_getprop(chosen, "stdout-path", buf, sizeof(buf)) > 0) {
  505                         node = OF_finddevice(buf);
  506                         if (node != -1)
  507                                 sc->sc_handle = OF_open(buf);
  508                 }
  509         if (node == -1) {
  510                 /*
  511                  * The "/chosen/stdout" does not exist try
  512                  * using "screen" directly.
  513                  */
  514                 node = OF_finddevice("screen");
  515                 sc->sc_handle = OF_open("screen");
  516         }
  517         OF_getprop(node, "device_type", buf, sizeof(buf));
  518         if (strcmp(buf, "display") != 0)
  519                 return (CN_DEAD);
  520 
  521         /*
  522          * Retrieve vendor-id from /chosen parent node, usually pointing to
  523          * video card device. This is used to select pixel format later on
  524          * ofwfb_initialize()
  525          */
  526         if (OF_getencprop(OF_parent(node), "vendor-id", &vendor_id,
  527             sizeof(vendor_id)) == sizeof(vendor_id))
  528                 sc->vendor_id = vendor_id;
  529 
  530         /* Keep track of the OF node */
  531         sc->sc_node = node;
  532 
  533         /*
  534          * Try to use a 32-bit framebuffer if possible. This may be
  535          * unimplemented and fail. That's fine -- it just means we are
  536          * stuck with the defaults.
  537          */
  538         OF_call_method("set-depth", sc->sc_handle, 1, 1, (cell_t)32, &i);
  539 
  540         /* Make sure we have needed properties */
  541         if (OF_getproplen(node, "height") != sizeof(height) ||
  542             OF_getproplen(node, "width") != sizeof(width) ||
  543             OF_getproplen(node, "depth") != sizeof(depth))
  544                 return (CN_DEAD);
  545 
  546         /* Only support 8 and 32-bit framebuffers */
  547         OF_getencprop(node, "depth", &depth, sizeof(depth));
  548         if (depth != 8 && depth != 32)
  549                 return (CN_DEAD);
  550         sc->fb.fb_bpp = sc->fb.fb_depth = depth;
  551 
  552         OF_getencprop(node, "height", &height, sizeof(height));
  553         OF_getencprop(node, "width", &width, sizeof(width));
  554         if (OF_getencprop(node, "linebytes", &stride, sizeof(stride)) !=
  555             sizeof(stride))
  556                 stride = width*depth/8;
  557 
  558 
  559         sc->fb.fb_height = height;
  560         sc->fb.fb_width = width;
  561         sc->fb.fb_stride = stride;
  562         sc->fb.fb_size = sc->fb.fb_height * sc->fb.fb_stride;
  563         sc->endian_flip = 0;
  564 
  565 #if defined(__powerpc__)
  566         if (OF_hasprop(node, "little-endian")) {
  567                 sc->sc_memt = &bs_le_tag;
  568 #if BYTE_ORDER == BIG_ENDIAN
  569                 sc->endian_flip = 1;
  570 #endif
  571         } else if (OF_hasprop(node, "big-endian")) {
  572                 sc->sc_memt = &bs_be_tag;
  573 #if BYTE_ORDER == LITTLE_ENDIAN
  574                 sc->endian_flip = 1;
  575 #endif
  576         }
  577         else {
  578                 /* Assume the framebuffer is in native endian. */
  579 #if BYTE_ORDER == BIG_ENDIAN
  580                 sc->sc_memt = &bs_be_tag;
  581 #else
  582                 sc->sc_memt = &bs_le_tag;
  583 #endif
  584         }
  585 #elif defined(__arm__)
  586         sc->sc_memt = fdtbus_bs_tag;
  587 #else
  588         #error Unsupported platform!
  589 #endif
  590 
  591 
  592         /*
  593          * Grab the physical address of the framebuffer, and then map it
  594          * into our memory space. If the MMU is not yet up, it will be
  595          * remapped for us when relocation turns on.
  596          *
  597          * The ASPEED driver on recent petitboot versions doesn't expose the
  598          * physical address of framebuffer anymore for security. So it should
  599          * retrieve the address from PCI device properties.
  600          */
  601         user_phys = 0;
  602         TUNABLE_UINT64_FETCH("hw.ofwfb.physaddr", &user_phys);
  603 
  604         if (user_phys)
  605                 sc->fb.fb_pbase = (vm_paddr_t)user_phys;
  606         else if (sc->vendor_id == PCI_VID_ASPEED)
  607                 sc->fb.fb_pbase = find_pci_host_address(node);
  608         else if (OF_hasprop(node, "address")) {
  609 
  610                 switch (OF_getproplen(node, "address")) {
  611                 case 4:
  612                         OF_getencprop(node, "address", adr, 4);
  613                         fb_phys = adr[0];
  614                         break;
  615                 case 8:
  616                         OF_getencprop(node, "address", adr, 8);
  617                         fb_phys = ((uint64_t)adr[0] << 32) | adr[1];
  618                         break;
  619                 default:
  620                         /* Bad property? */
  621                         return (CN_DEAD);
  622                 }
  623 
  624                 sc->fb.fb_pbase = (vm_paddr_t)fb_phys;
  625         } else {
  626 #if defined(__powerpc__)
  627                 /*
  628                  * Some IBM systems don't have an address property. Try to
  629                  * guess the framebuffer region from the assigned addresses.
  630                  * This is ugly, but there doesn't seem to be an alternative.
  631                  * Linux does the same thing.
  632                  */
  633 
  634                 struct ofw_pci_register pciaddrs[8];
  635                 int num_pciaddrs = 0;
  636 
  637                 /*
  638                  * Get the PCI addresses of the adapter, if present. The node
  639                  * may be the child of the PCI device: in that case, try the
  640                  * parent for the assigned-addresses property.
  641                  */
  642                 len = OF_getencprop(node, "assigned-addresses",
  643                     (pcell_t *)pciaddrs, sizeof(pciaddrs));
  644                 if (len == -1) {
  645                         len = OF_getencprop(OF_parent(node), "assigned-addresses",
  646                             (pcell_t *)pciaddrs, sizeof(pciaddrs));
  647                 }
  648                 if (len == -1)
  649                         len = 0;
  650                 num_pciaddrs = len / sizeof(struct ofw_pci_register);
  651 
  652                 j = num_pciaddrs;
  653                 for (i = 0; i < num_pciaddrs; i++) {
  654                         /* If it is too small, not the framebuffer */
  655                         if (pciaddrs[i].size_lo < sc->fb.fb_stride * height)
  656                                 continue;
  657                         /* If it is not memory, it isn't either */
  658                         if (!(pciaddrs[i].phys_hi &
  659                             OFW_PCI_PHYS_HI_SPACE_MEM32))
  660                                 continue;
  661 
  662                         /* This could be the framebuffer */
  663                         j = i;
  664 
  665                         /* If it is prefetchable, it certainly is */
  666                         if (pciaddrs[i].phys_hi & OFW_PCI_PHYS_HI_PREFETCHABLE)
  667                                 break;
  668                 }
  669 
  670                 if (j == num_pciaddrs) /* No candidates found */
  671                         return (CN_DEAD);
  672 
  673                 if (ofw_reg_to_paddr(node, j, &fb_phys, &fb_phys_size, NULL) < 0)
  674                         return (CN_DEAD);
  675 
  676                 sc->fb.fb_pbase = (vm_paddr_t)fb_phys;
  677 #else
  678                 /* No ability to interpret assigned-addresses otherwise */
  679                 return (CN_DEAD);
  680 #endif
  681         }
  682 
  683         if (!sc->fb.fb_pbase)
  684                 return (CN_DEAD);
  685 
  686         bus_space_map(sc->sc_memt, sc->fb.fb_pbase, sc->fb.fb_size,
  687             BUS_SPACE_MAP_PREFETCHABLE,
  688             (bus_space_handle_t *)&sc->fb.fb_vbase);
  689 
  690         #if defined(__powerpc__)
  691         /*
  692          * If we are running on PowerPC in real mode (supported only on AIM
  693          * CPUs), the frame buffer may be inaccessible (real mode does not
  694          * necessarily cover all RAM) and may also be mapped with the wrong
  695          * cache properties (all real mode accesses are assumed cacheable).
  696          * Just don't write to it for the time being.
  697          */
  698         if (!(cpu_features & PPC_FEATURE_BOOKE) && !(mfmsr() & PSL_DR))
  699                 sc->fb.fb_flags |= FB_FLAG_NOWRITE;
  700         #endif
  701         ofwfb_initialize(vd);
  702         vt_fb_init(vd);
  703 
  704         return (CN_INTERNAL);
  705 }

Cache object: f91205908ce58436787ae4ce532d86f9


[ source navigation ] [ diff markup ] [ identifier search ] [ freetext search ] [ file search ] [ list types ] [ track identifier ]


This page is part of the FreeBSD/Linux Linux Kernel Cross-Reference, and was automatically generated using a modified version of the LXR engine.