blob: 1df37e80726b4177602977200a70c482791bad81 [file] [log] [blame]
Patrick Georgi593124d2020-05-10 19:44:08 +02001/* SPDX-License-Identifier: MIT */
Nico Huber3db76532017-05-18 18:07:34 +02002
3#include <console/console.h>
4#include <edid.h>
5#include <boot/coreboot_tables.h>
Patrick Rudolph73192882020-02-19 12:10:51 +01006#include <framebuffer_info.h>
7#include <string.h>
8#include <stdlib.h>
Patrick Rudolph73192882020-02-19 12:10:51 +01009#include <list.h>
Nico Huber3db76532017-05-18 18:07:34 +020010
Patrick Rudolph73192882020-02-19 12:10:51 +010011struct fb_info {
12 struct list_node node;
13 struct lb_framebuffer fb;
14};
15static struct list_node list;
Nico Huber3db76532017-05-18 18:07:34 +020016
17/*
Patrick Rudolph73192882020-02-19 12:10:51 +010018 * Allocate a new framebuffer info struct on heap.
19 * Returns NULL on error.
Nico Huber3db76532017-05-18 18:07:34 +020020 */
Patrick Rudolph73192882020-02-19 12:10:51 +010021static struct fb_info *fb_new_framebuffer_info(void)
Nico Huber3db76532017-05-18 18:07:34 +020022{
Patrick Rudolph73192882020-02-19 12:10:51 +010023 struct fb_info *ret;
24 ret = malloc(sizeof(struct fb_info));
25 if (ret)
26 memset(ret, 0, sizeof(struct fb_info));
Nico Huber3db76532017-05-18 18:07:34 +020027
Patrick Rudolph73192882020-02-19 12:10:51 +010028 return ret;
Nico Huber3db76532017-05-18 18:07:34 +020029}
30
Patrick Rudolph73192882020-02-19 12:10:51 +010031/*
32 * Fills a provided framebuffer info struct and adds it to the internal list if it's
33 * valid. Returns NULL on error.
34 */
35struct fb_info *
36fb_add_framebuffer_info_ex(const struct lb_framebuffer *fb)
Nicolas Boichat87f265b2019-08-06 08:29:52 +080037{
Patrick Rudolph73192882020-02-19 12:10:51 +010038 struct fb_info *info;
39 uint8_t bpp_mask;
40
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;
46 }
47
48 bpp_mask = fb->blue_mask_size + fb->green_mask_size + fb->red_mask_size +
49 fb->reserved_mask_size;
Raul E Rangel8b043c02021-01-13 10:50:37 -070050 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);
Patrick Rudolph73192882020-02-19 12:10:51 +010055 return NULL;
Raul E Rangel8b043c02021-01-13 10:50:37 -070056 } 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);
Patrick Rudolph73192882020-02-19 12:10:51 +010061 }
62
63 info = fb_new_framebuffer_info();
64 if (!info)
65 return NULL;
66
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);
72
73 /* Update */
74 info->fb = *fb;
75
76 list_insert_after(&info->node, &list);
77
78 return info;
79}
80
81/*
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.
85 *
86 * Complex drivers should use fb_add_framebuffer_info_ex() instead.
87 */
88struct fb_info *
89fb_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)
92{
93 struct fb_info *info = NULL;
94
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 */
100
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,
116 };
117
118 info = fb_add_framebuffer_info_ex(&fb);
119 break;
120 }
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,
138 };
139 info = fb_add_framebuffer_info_ex(&fb);
140 break;
141 }
142 default:
143 printk(BIOS_ERR, "%s: unsupported BPP %d\n", __func__, bits_per_pixel);
144 }
145 if (!info)
146 printk(BIOS_ERR, "%s: failed to add framebuffer info\n", __func__);
147
148 return info;
149}
150
151void fb_set_orientation(struct fb_info *info, enum lb_fb_orientation orientation)
152{
153 if (!info)
154 return;
155
156 info->fb.orientation = orientation;
157}
158
159/*
160 * Take an edid, and create a framebuffer.
161 */
Patrick Rudolph8b56c8c2020-02-19 12:57:00 +0100162struct fb_info *fb_new_framebuffer_info_from_edid(const struct edid *edid,
163 uintptr_t fb_addr)
Patrick Rudolph73192882020-02-19 12:10:51 +0100164{
165 return fb_add_framebuffer_info(fb_addr, edid->x_resolution, edid->y_resolution,
166 edid->bytes_per_line, edid->framebuffer_bits_per_pixel);
Nicolas Boichat87f265b2019-08-06 08:29:52 +0800167}
168
Nico Huber3db76532017-05-18 18:07:34 +0200169int fill_lb_framebuffer(struct lb_framebuffer *framebuffer)
170{
Patrick Rudolph73192882020-02-19 12:10:51 +0100171 struct fb_info *i;
Nico Huber3db76532017-05-18 18:07:34 +0200172
Patrick Rudolph73192882020-02-19 12:10:51 +0100173 list_for_each(i, list, node) {
174 //TODO: Add support for advertising all framebuffers in this list
175 *framebuffer = i->fb;
176 return 0;
177 }
178 return -1;
Nico Huber3db76532017-05-18 18:07:34 +0200179}