]>
Commit | Line | Data |
---|---|---|
4a08c746 BM |
1 | // SPDX-License-Identifier: GPL-2.0+ |
2 | /* | |
3 | * Copyright (C) 2018, Bin Meng <[email protected]> | |
4 | * | |
5 | * EFI framebuffer driver based on GOP | |
6 | */ | |
7 | ||
8 | #include <common.h> | |
9 | #include <dm.h> | |
10 | #include <efi_api.h> | |
f7ae49fc | 11 | #include <log.h> |
4a08c746 BM |
12 | #include <vbe.h> |
13 | #include <video.h> | |
14 | ||
15 | struct pixel { | |
16 | u8 pos; | |
17 | u8 size; | |
18 | }; | |
19 | ||
20 | static const struct efi_framebuffer { | |
21 | struct pixel red; | |
22 | struct pixel green; | |
23 | struct pixel blue; | |
24 | struct pixel rsvd; | |
25 | } efi_framebuffer_format_map[] = { | |
26 | [EFI_GOT_RGBA8] = { {0, 8}, {8, 8}, {16, 8}, {24, 8} }, | |
27 | [EFI_GOT_BGRA8] = { {16, 8}, {8, 8}, {0, 8}, {24, 8} }, | |
28 | }; | |
29 | ||
30 | static void efi_find_pixel_bits(u32 mask, u8 *pos, u8 *size) | |
31 | { | |
32 | u8 first, len; | |
33 | ||
34 | first = 0; | |
35 | len = 0; | |
36 | ||
37 | if (mask) { | |
38 | while (!(mask & 0x1)) { | |
39 | mask = mask >> 1; | |
40 | first++; | |
41 | } | |
42 | ||
43 | while (mask & 0x1) { | |
44 | mask = mask >> 1; | |
45 | len++; | |
46 | } | |
47 | } | |
48 | ||
49 | *pos = first; | |
50 | *size = len; | |
51 | } | |
52 | ||
53 | static int save_vesa_mode(struct vesa_mode_info *vesa) | |
54 | { | |
55 | struct efi_entry_gopmode *mode; | |
56 | const struct efi_framebuffer *fbinfo; | |
57 | int size; | |
58 | int ret; | |
59 | ||
60 | ret = efi_info_get(EFIET_GOP_MODE, (void **)&mode, &size); | |
61 | if (ret == -ENOENT) { | |
62 | debug("efi graphics output protocol mode not found\n"); | |
63 | return -ENXIO; | |
64 | } | |
65 | ||
66 | vesa->phys_base_ptr = mode->fb_base; | |
67 | vesa->x_resolution = mode->info->width; | |
68 | vesa->y_resolution = mode->info->height; | |
69 | ||
70 | if (mode->info->pixel_format < EFI_GOT_BITMASK) { | |
71 | fbinfo = &efi_framebuffer_format_map[mode->info->pixel_format]; | |
72 | vesa->red_mask_size = fbinfo->red.size; | |
73 | vesa->red_mask_pos = fbinfo->red.pos; | |
74 | vesa->green_mask_size = fbinfo->green.size; | |
75 | vesa->green_mask_pos = fbinfo->green.pos; | |
76 | vesa->blue_mask_size = fbinfo->blue.size; | |
77 | vesa->blue_mask_pos = fbinfo->blue.pos; | |
78 | vesa->reserved_mask_size = fbinfo->rsvd.size; | |
79 | vesa->reserved_mask_pos = fbinfo->rsvd.pos; | |
80 | ||
81 | vesa->bits_per_pixel = 32; | |
82 | vesa->bytes_per_scanline = mode->info->pixels_per_scanline * 4; | |
83 | } else if (mode->info->pixel_format == EFI_GOT_BITMASK) { | |
84 | efi_find_pixel_bits(mode->info->pixel_bitmask[0], | |
85 | &vesa->red_mask_pos, | |
86 | &vesa->red_mask_size); | |
87 | efi_find_pixel_bits(mode->info->pixel_bitmask[1], | |
88 | &vesa->green_mask_pos, | |
89 | &vesa->green_mask_size); | |
90 | efi_find_pixel_bits(mode->info->pixel_bitmask[2], | |
91 | &vesa->blue_mask_pos, | |
92 | &vesa->blue_mask_size); | |
93 | efi_find_pixel_bits(mode->info->pixel_bitmask[3], | |
94 | &vesa->reserved_mask_pos, | |
95 | &vesa->reserved_mask_size); | |
96 | vesa->bits_per_pixel = vesa->red_mask_size + | |
97 | vesa->green_mask_size + | |
98 | vesa->blue_mask_size + | |
99 | vesa->reserved_mask_size; | |
100 | vesa->bytes_per_scanline = (mode->info->pixels_per_scanline * | |
101 | vesa->bits_per_pixel) / 8; | |
102 | } else { | |
103 | debug("efi set unknown framebuffer format: %d\n", | |
104 | mode->info->pixel_format); | |
105 | return -EINVAL; | |
106 | } | |
107 | ||
108 | return 0; | |
109 | } | |
110 | ||
111 | static int efi_video_probe(struct udevice *dev) | |
112 | { | |
113 | struct video_uc_platdata *plat = dev_get_uclass_platdata(dev); | |
114 | struct video_priv *uc_priv = dev_get_uclass_priv(dev); | |
115 | struct vesa_mode_info *vesa = &mode_info.vesa; | |
116 | int ret; | |
117 | ||
118 | /* Initialize vesa_mode_info structure */ | |
119 | ret = save_vesa_mode(vesa); | |
120 | if (ret) | |
121 | goto err; | |
122 | ||
123 | ret = vbe_setup_video_priv(vesa, uc_priv, plat); | |
124 | if (ret) | |
125 | goto err; | |
126 | ||
127 | printf("Video: %dx%dx%d\n", uc_priv->xsize, uc_priv->ysize, | |
128 | vesa->bits_per_pixel); | |
129 | ||
130 | return 0; | |
131 | ||
132 | err: | |
133 | printf("No video mode configured in EFI!\n"); | |
134 | return ret; | |
135 | } | |
136 | ||
137 | static const struct udevice_id efi_video_ids[] = { | |
138 | { .compatible = "efi-fb" }, | |
139 | { } | |
140 | }; | |
141 | ||
142 | U_BOOT_DRIVER(efi_video) = { | |
143 | .name = "efi_video", | |
144 | .id = UCLASS_VIDEO, | |
145 | .of_match = efi_video_ids, | |
146 | .probe = efi_video_probe, | |
147 | }; |