uboot/arch/x86/lib/fsp/fsp_graphics.c
<<
>>
Prefs
   1// SPDX-License-Identifier: GPL-2.0+
   2/*
   3 * Copyright (C) 2017, Bin Meng <bmeng.cn@gmail.com>
   4 */
   5
   6#define LOG_CATEGORY UCLASS_VIDEO
   7
   8#include <common.h>
   9#include <dm.h>
  10#include <init.h>
  11#include <log.h>
  12#include <vbe.h>
  13#include <video.h>
  14#include <acpi/acpi_table.h>
  15#include <asm/fsp/fsp_support.h>
  16#include <asm/global_data.h>
  17#include <asm/intel_opregion.h>
  18#include <asm/mtrr.h>
  19#include <dm/acpi.h>
  20
  21DECLARE_GLOBAL_DATA_PTR;
  22
  23struct pixel {
  24        u8 pos;
  25        u8 size;
  26};
  27
  28static const struct fsp_framebuffer {
  29        struct pixel red;
  30        struct pixel green;
  31        struct pixel blue;
  32        struct pixel rsvd;
  33} fsp_framebuffer_format_map[] = {
  34        [pixel_rgbx_8bpc] = { {0, 8}, {8, 8}, {16, 8}, {24, 8} },
  35        [pixel_bgrx_8bpc] = { {16, 8}, {8, 8}, {0, 8}, {24, 8} },
  36};
  37
  38static int save_vesa_mode(struct vesa_mode_info *vesa)
  39{
  40        const struct hob_graphics_info *ginfo;
  41        const struct fsp_framebuffer *fbinfo;
  42
  43        ginfo = fsp_get_graphics_info(gd->arch.hob_list, NULL);
  44
  45        /*
  46         * If there is no graphics info structure, bail out and keep
  47         * running on the serial console.
  48         *
  49         * Note: on some platforms (eg: Braswell), the FSP will not produce
  50         * the graphics info HOB unless you plug some cables to the display
  51         * interface (eg: HDMI) on the board.
  52         */
  53        if (!ginfo) {
  54                debug("FSP graphics hand-off block not found\n");
  55                return -ENXIO;
  56        }
  57
  58        vesa->x_resolution = ginfo->width;
  59        vesa->y_resolution = ginfo->height;
  60        vesa->bits_per_pixel = 32;
  61        vesa->bytes_per_scanline = ginfo->pixels_per_scanline * 4;
  62        vesa->phys_base_ptr = ginfo->fb_base;
  63
  64        if (ginfo->pixel_format >= pixel_bitmask) {
  65                debug("FSP set unknown framebuffer format: %d\n",
  66                      ginfo->pixel_format);
  67                return -EINVAL;
  68        }
  69        fbinfo = &fsp_framebuffer_format_map[ginfo->pixel_format];
  70        vesa->red_mask_size = fbinfo->red.size;
  71        vesa->red_mask_pos = fbinfo->red.pos;
  72        vesa->green_mask_size = fbinfo->green.size;
  73        vesa->green_mask_pos = fbinfo->green.pos;
  74        vesa->blue_mask_size = fbinfo->blue.size;
  75        vesa->blue_mask_pos = fbinfo->blue.pos;
  76        vesa->reserved_mask_size = fbinfo->rsvd.size;
  77        vesa->reserved_mask_pos = fbinfo->rsvd.pos;
  78
  79        return 0;
  80}
  81
  82static int fsp_video_probe(struct udevice *dev)
  83{
  84        struct video_uc_plat *plat = dev_get_uclass_plat(dev);
  85        struct video_priv *uc_priv = dev_get_uclass_priv(dev);
  86        struct vesa_mode_info *vesa = &mode_info.vesa;
  87        int ret;
  88
  89        if (!ll_boot_init())
  90                return -ENODEV;
  91
  92        printf("Video: ");
  93
  94        /* Initialize vesa_mode_info structure */
  95        ret = save_vesa_mode(vesa);
  96        if (ret)
  97                goto err;
  98
  99        /*
 100         * The framebuffer base address in the FSP graphics info HOB reflects
 101         * the value assigned by the FSP. After PCI enumeration the framebuffer
 102         * base address may be relocated. Let's get the updated one from device.
 103         *
 104         * For IGD, it seems to be always on BAR2.
 105         */
 106        vesa->phys_base_ptr = dm_pci_read_bar32(dev, 2);
 107        gd->fb_base = vesa->phys_base_ptr;
 108
 109        ret = vbe_setup_video_priv(vesa, uc_priv, plat);
 110        if (ret)
 111                goto err;
 112
 113        mtrr_add_request(MTRR_TYPE_WRCOMB, vesa->phys_base_ptr, 256 << 20);
 114        mtrr_commit(true);
 115
 116        printf("%dx%dx%d @ %x\n", uc_priv->xsize, uc_priv->ysize,
 117               vesa->bits_per_pixel, vesa->phys_base_ptr);
 118
 119        return 0;
 120
 121err:
 122        printf("No video mode configured in FSP!\n");
 123        return ret;
 124}
 125
 126static int fsp_video_bind(struct udevice *dev)
 127{
 128        struct video_uc_plat *plat = dev_get_uclass_plat(dev);
 129
 130        /* Set the maximum supported resolution */
 131        plat->size = 2560 * 1600 * 4;
 132
 133        return 0;
 134}
 135
 136#ifdef CONFIG_INTEL_GMA_ACPI
 137static int fsp_video_acpi_write_tables(const struct udevice *dev,
 138                                       struct acpi_ctx *ctx)
 139{
 140        struct igd_opregion *opregion;
 141        int ret;
 142
 143        log_debug("ACPI:    * IGD OpRegion\n");
 144        opregion = (struct igd_opregion *)ctx->current;
 145
 146        ret = intel_gma_init_igd_opregion((struct udevice *)dev, opregion);
 147        if (ret)
 148                return ret;
 149
 150        acpi_inc_align(ctx, sizeof(struct igd_opregion));
 151
 152        return 0;
 153}
 154#endif
 155
 156struct acpi_ops fsp_video_acpi_ops = {
 157#ifdef CONFIG_INTEL_GMA_ACPI
 158        .write_tables   = fsp_video_acpi_write_tables,
 159#endif
 160};
 161
 162static const struct udevice_id fsp_video_ids[] = {
 163        { .compatible = "fsp-fb" },
 164        { }
 165};
 166
 167U_BOOT_DRIVER(fsp_video) = {
 168        .name   = "fsp_video",
 169        .id     = UCLASS_VIDEO,
 170        .of_match = fsp_video_ids,
 171        .bind   = fsp_video_bind,
 172        .probe  = fsp_video_probe,
 173        .flags  = DM_FLAG_PRE_RELOC,
 174        ACPI_OPS_PTR(&fsp_video_acpi_ops)
 175};
 176
 177static struct pci_device_id fsp_video_supported[] = {
 178        { PCI_DEVICE_CLASS(PCI_CLASS_DISPLAY_VGA << 8, 0xffff00) },
 179        { },
 180};
 181
 182U_BOOT_PCI_DEVICE(fsp_video, fsp_video_supported);
 183