Merge git://www.denx.de/git/u-boot-imx
[oweals/u-boot.git] / arch / x86 / lib / fsp / fsp_graphics.c
1 /*
2  * Copyright (C) 2017, Bin Meng <bmeng.cn@gmail.com>
3  *
4  * SPDX-License-Identifier:     GPL-2.0+
5  */
6
7 #include <common.h>
8 #include <dm.h>
9 #include <vbe.h>
10 #include <video.h>
11 #include <asm/fsp/fsp_support.h>
12
13 DECLARE_GLOBAL_DATA_PTR;
14
15 struct pixel {
16         u8 pos;
17         u8 size;
18 };
19
20 static const struct fsp_framebuffer {
21         struct pixel red;
22         struct pixel green;
23         struct pixel blue;
24         struct pixel rsvd;
25 } fsp_framebuffer_format_map[] = {
26         [pixel_rgbx_8bpc] = { {0, 8}, {8, 8}, {16, 8}, {24, 8} },
27         [pixel_bgrx_8bpc] = { {16, 8}, {8, 8}, {0, 8}, {24, 8} },
28 };
29
30 static int save_vesa_mode(struct vesa_mode_info *vesa)
31 {
32         const struct hob_graphics_info *ginfo;
33         const struct fsp_framebuffer *fbinfo;
34
35         ginfo = fsp_get_graphics_info(gd->arch.hob_list, NULL);
36
37         /*
38          * If there is no graphics info structure, bail out and keep
39          * running on the serial console.
40          */
41         if (!ginfo) {
42                 debug("FSP graphics hand-off block not found\n");
43                 return -ENXIO;
44         }
45
46         vesa->x_resolution = ginfo->width;
47         vesa->y_resolution = ginfo->height;
48         vesa->bits_per_pixel = 32;
49         vesa->bytes_per_scanline = ginfo->pixels_per_scanline * 4;
50         vesa->phys_base_ptr = ginfo->fb_base;
51
52         if (ginfo->pixel_format >= pixel_bitmask) {
53                 debug("FSP set unknown framebuffer format: %d\n",
54                       ginfo->pixel_format);
55                 return -EINVAL;
56         }
57         fbinfo = &fsp_framebuffer_format_map[ginfo->pixel_format];
58         vesa->red_mask_size = fbinfo->red.size;
59         vesa->red_mask_pos = fbinfo->red.pos;
60         vesa->green_mask_size = fbinfo->green.size;
61         vesa->green_mask_pos = fbinfo->green.pos;
62         vesa->blue_mask_size = fbinfo->blue.size;
63         vesa->blue_mask_pos = fbinfo->blue.pos;
64         vesa->reserved_mask_size = fbinfo->rsvd.size;
65         vesa->reserved_mask_pos = fbinfo->rsvd.pos;
66
67         return 0;
68 }
69
70 static int fsp_video_probe(struct udevice *dev)
71 {
72         struct video_uc_platdata *plat = dev_get_uclass_platdata(dev);
73         struct video_priv *uc_priv = dev_get_uclass_priv(dev);
74         struct vesa_mode_info *vesa = &mode_info.vesa;
75         int ret;
76
77         printf("Video: ");
78
79         /* Initialize vesa_mode_info structure */
80         ret = save_vesa_mode(vesa);
81         if (ret)
82                 goto err;
83
84         /*
85          * The framebuffer base address in the FSP graphics info HOB reflects
86          * the value assigned by the FSP. After PCI enumeration the framebuffer
87          * base address may be relocated. Let's get the updated one from device.
88          *
89          * For IGD, it seems to be always on BAR2.
90          */
91         vesa->phys_base_ptr = dm_pci_read_bar32(dev, 2);
92
93         ret = vbe_setup_video_priv(vesa, uc_priv, plat);
94         if (ret)
95                 goto err;
96
97         printf("%dx%dx%d\n", uc_priv->xsize, uc_priv->ysize,
98                vesa->bits_per_pixel);
99
100         return 0;
101
102 err:
103         printf("No video mode configured in FSP!\n");
104         return ret;
105 }
106
107 static const struct udevice_id fsp_video_ids[] = {
108         { .compatible = "fsp-fb" },
109         { }
110 };
111
112 U_BOOT_DRIVER(fsp_video) = {
113         .name   = "fsp_video",
114         .id     = UCLASS_VIDEO,
115         .of_match = fsp_video_ids,
116         .probe  = fsp_video_probe,
117 };
118
119 static struct pci_device_id fsp_video_supported[] = {
120         { PCI_DEVICE_CLASS(PCI_CLASS_DISPLAY_VGA << 8, 0xffff00) },
121         { },
122 };
123
124 U_BOOT_PCI_DEVICE(fsp_video, fsp_video_supported);