Xeon-SP boards: Factor out OCP VPD `get_cxl_mode()` impl
[coreboot2.git] / src / lib / edid_fill_fb.c
blobe4fb08c3fdac3995723d452af1d7263bed0fec5f
1 /* SPDX-License-Identifier: MIT */
3 #include <console/console.h>
4 #include <edid.h>
5 #include <boot/coreboot_tables.h>
6 #include <framebuffer_info.h>
7 #include <string.h>
8 #include <stdlib.h>
9 #include <commonlib/list.h>
11 struct fb_info {
12 struct list_node node;
13 struct lb_framebuffer fb;
15 static struct list_node list;
18 * Allocate a new framebuffer info struct on heap.
19 * Returns NULL on error.
21 static struct fb_info *fb_new_framebuffer_info(void)
23 struct fb_info *ret;
24 ret = malloc(sizeof(struct fb_info));
25 if (ret)
26 memset(ret, 0, sizeof(struct fb_info));
28 return ret;
32 * Fills a provided framebuffer info struct and adds it to the internal list if it's
33 * valid. Returns NULL on error.
35 struct fb_info *
36 fb_add_framebuffer_info_ex(const struct lb_framebuffer *fb)
38 struct fb_info *info;
39 uint8_t bpp_mask;
41 /* Validate input */
42 if (!fb || !fb->x_resolution || !fb->y_resolution || !fb->bytes_per_line ||
43 !fb->bits_per_pixel) {
44 printk(BIOS_ERR, "%s: Invalid framebuffer data provided\n", __func__);
45 return NULL;
48 bpp_mask = fb->blue_mask_size + fb->green_mask_size + fb->red_mask_size +
49 fb->reserved_mask_size;
50 if (bpp_mask > fb->bits_per_pixel) {
51 printk(BIOS_ERR,
52 "%s: channel bit mask=%d is greater than BPP=%d ."
53 " This is a driver bug. Framebuffer is invalid.\n",
54 __func__, bpp_mask, fb->bits_per_pixel);
55 return NULL;
56 } else if (bpp_mask != fb->bits_per_pixel) {
57 printk(BIOS_WARNING,
58 "%s: channel bit mask=%d and BPP=%d don't match."
59 " This is a driver bug.\n",
60 __func__, bpp_mask, fb->bits_per_pixel);
63 info = fb_new_framebuffer_info();
64 if (!info)
65 return NULL;
67 printk(BIOS_INFO, "framebuffer_info: bytes_per_line: %d, bits_per_pixel: %d\n "
68 " x_res x y_res: %d x %d, size: %d at 0x%llx\n",
69 fb->bytes_per_line, fb->bits_per_pixel, fb->x_resolution,
70 fb->y_resolution, (fb->bytes_per_line * fb->y_resolution),
71 fb->physical_address);
73 /* Update */
74 info->fb = *fb;
76 list_insert_after(&info->node, &list);
78 return info;
82 * Allocates a new framebuffer info struct and fills it for 32/24/16bpp framebuffers.
83 * Intended for drivers that only support reporting the current information or have a single
84 * modeset invocation.
86 * Complex drivers should use fb_add_framebuffer_info_ex() instead.
88 struct fb_info *
89 fb_add_framebuffer_info(uintptr_t fb_addr, uint32_t x_resolution,
90 uint32_t y_resolution, uint32_t bytes_per_line,
91 uint8_t bits_per_pixel)
93 struct fb_info *info = NULL;
95 switch (bits_per_pixel) {
96 case 32:
97 case 24: {
98 /* FIXME: 24 BPP might be RGB8 or XRGB8 */
99 /* packed into 4-byte words */
101 const struct lb_framebuffer fb = {
102 .physical_address = fb_addr,
103 .x_resolution = x_resolution,
104 .y_resolution = y_resolution,
105 .bytes_per_line = bytes_per_line,
106 .bits_per_pixel = bits_per_pixel,
107 .red_mask_pos = 16,
108 .red_mask_size = 8,
109 .green_mask_pos = 8,
110 .green_mask_size = 8,
111 .blue_mask_pos = 0,
112 .blue_mask_size = 8,
113 .reserved_mask_pos = 24,
114 .reserved_mask_size = 8,
115 .orientation = LB_FB_ORIENTATION_NORMAL,
118 info = fb_add_framebuffer_info_ex(&fb);
119 break;
121 case 16: {
122 /* packed into 2-byte words */
123 const struct lb_framebuffer fb = {
124 .physical_address = fb_addr,
125 .x_resolution = x_resolution,
126 .y_resolution = y_resolution,
127 .bytes_per_line = bytes_per_line,
128 .bits_per_pixel = 16,
129 .red_mask_pos = 11,
130 .red_mask_size = 5,
131 .green_mask_pos = 5,
132 .green_mask_size = 6,
133 .blue_mask_pos = 0,
134 .blue_mask_size = 5,
135 .reserved_mask_pos = 0,
136 .reserved_mask_size = 0,
137 .orientation = LB_FB_ORIENTATION_NORMAL,
139 info = fb_add_framebuffer_info_ex(&fb);
140 break;
142 default:
143 printk(BIOS_ERR, "%s: unsupported BPP %d\n", __func__, bits_per_pixel);
145 if (!info)
146 printk(BIOS_ERR, "%s: failed to add framebuffer info\n", __func__);
148 return info;
151 void fb_set_orientation(struct fb_info *info, enum lb_fb_orientation orientation)
153 if (!info)
154 return;
156 info->fb.orientation = orientation;
160 * Take an edid, and create a framebuffer.
162 struct fb_info *fb_new_framebuffer_info_from_edid(const struct edid *edid,
163 uintptr_t fb_addr)
165 return fb_add_framebuffer_info(fb_addr, edid->x_resolution, edid->y_resolution,
166 edid->bytes_per_line, edid->framebuffer_bits_per_pixel);
169 int fill_lb_framebuffer(struct lb_framebuffer *framebuffer)
171 struct fb_info *i;
173 list_for_each(i, list, node) {
174 //TODO: Add support for advertising all framebuffers in this list
175 *framebuffer = i->fb;
176 return 0;
178 return -1;