]>
git.ipfire.org Git - people/ms/u-boot.git/blob - drivers/video/video_bmp.c
2 * Copyright (c) 2015 Google, Inc
4 * SPDX-License-Identifier: GPL-2.0+
8 #include <bmp_layout.h>
13 #include <asm/unaligned.h>
15 #ifdef CONFIG_VIDEO_BMP_RLE8
16 #define BMP_RLE8_ESCAPE 0
17 #define BMP_RLE8_EOL 0
18 #define BMP_RLE8_EOBMP 1
19 #define BMP_RLE8_DELTA 2
21 static void draw_unencoded_bitmap(ushort
**fbp
, uchar
*bmap
, ushort
*cmap
,
25 *(*fbp
)++ = cmap
[*bmap
++];
30 static void draw_encoded_bitmap(ushort
**fbp
, ushort col
, int cnt
)
41 static void video_display_rle8_bitmap(struct udevice
*dev
,
42 struct bmp_image
*bmp
, ushort
*cmap
,
43 uchar
*fb
, int x_off
, int y_off
)
45 struct video_priv
*priv
= dev_get_uclass_priv(dev
);
52 debug("%s\n", __func__
);
53 width
= get_unaligned_le32(&bmp
->header
.width
);
54 height
= get_unaligned_le32(&bmp
->header
.height
);
55 bmap
= (uchar
*)bmp
+ get_unaligned_le32(&bmp
->header
.data_offset
);
61 if (bmap
[0] == BMP_RLE8_ESCAPE
) {
68 /* 16bpix, 2-byte per pixel, width should *2 */
69 fb
-= (width
* 2 + priv
->line_length
);
79 /* 16bpix, 2-byte per pixel, x should *2 */
80 fb
= (uchar
*)(priv
->fb
+ (y
+ y_off
- 1)
81 * priv
->line_length
+ (x
+ x_off
) * 2);
90 if (x
+ runlen
> width
)
94 draw_unencoded_bitmap(
109 /* aggregate the same code */
110 while (bmap
[0] == 0xff &&
111 bmap
[2] != BMP_RLE8_ESCAPE
&&
112 bmap
[1] == bmap
[3]) {
116 if (x
+ runlen
> width
)
120 draw_encoded_bitmap((ushort
**)&fb
,
131 __weak
void fb_put_byte(uchar
**fb
, uchar
**from
)
133 *(*fb
)++ = *(*from
)++;
136 #if defined(CONFIG_BMP_16BPP)
137 __weak
void fb_put_word(uchar
**fb
, uchar
**from
)
139 *(*fb
)++ = *(*from
)++;
140 *(*fb
)++ = *(*from
)++;
142 #endif /* CONFIG_BMP_16BPP */
144 #define BMP_ALIGN_CENTER 0x7fff
147 * video_splash_align_axis() - Align a single coordinate
149 *- if a coordinate is 0x7fff then the image will be centred in
151 *- if a coordinate is -ve then it will be offset to the
152 * left/top of the centre by that many pixels
153 *- if a coordinate is positive it will be used unchnaged.
155 * @axis: Input and output coordinate
156 * @panel_size: Size of panel in pixels for that axis
157 * @picture_size: Size of bitmap in pixels for that axis
159 static void video_splash_align_axis(int *axis
, unsigned long panel_size
,
160 unsigned long picture_size
)
162 unsigned long panel_picture_delta
= panel_size
- picture_size
;
163 unsigned long axis_alignment
;
165 if (*axis
== BMP_ALIGN_CENTER
)
166 axis_alignment
= panel_picture_delta
/ 2;
168 axis_alignment
= panel_picture_delta
+ *axis
+ 1;
172 *axis
= max(0, (int)axis_alignment
);
175 static void video_set_cmap(struct udevice
*dev
,
176 struct bmp_color_table_entry
*cte
, unsigned colours
)
178 struct video_priv
*priv
= dev_get_uclass_priv(dev
);
180 ushort
*cmap
= priv
->cmap
;
182 debug("%s: colours=%d\n", __func__
, colours
);
183 for (i
= 0; i
< colours
; ++i
) {
184 *cmap
= ((cte
->red
<< 8) & 0xf800) |
185 ((cte
->green
<< 3) & 0x07e0) |
186 ((cte
->blue
>> 3) & 0x001f);
192 int video_bmp_display(struct udevice
*dev
, ulong bmp_image
, int x
, int y
,
195 struct video_priv
*priv
= dev_get_uclass_priv(dev
);
196 ushort
*cmap_base
= NULL
;
199 struct bmp_image
*bmp
= map_sysmem(bmp_image
, 0);
202 unsigned long width
, height
, byte_width
;
203 unsigned long pwidth
= priv
->xsize
;
204 unsigned colours
, bpix
, bmp_bpix
;
205 struct bmp_color_table_entry
*palette
;
208 if (!bmp
|| !(bmp
->header
.signature
[0] == 'B' &&
209 bmp
->header
.signature
[1] == 'M')) {
210 printf("Error: no valid bmp image at %lx\n", bmp_image
);
215 width
= get_unaligned_le32(&bmp
->header
.width
);
216 height
= get_unaligned_le32(&bmp
->header
.height
);
217 bmp_bpix
= get_unaligned_le16(&bmp
->header
.bit_count
);
218 hdr_size
= get_unaligned_le16(&bmp
->header
.size
);
219 debug("hdr_size=%d, bmp_bpix=%d\n", hdr_size
, bmp_bpix
);
220 palette
= (void *)bmp
+ 14 + hdr_size
;
222 colours
= 1 << bmp_bpix
;
224 bpix
= VNBITS(priv
->bpix
);
226 if (bpix
!= 1 && bpix
!= 8 && bpix
!= 16 && bpix
!= 32) {
227 printf("Error: %d bit/pixel mode, but BMP has %d bit/pixel\n",
234 * We support displaying 8bpp BMPs on 16bpp LCDs
235 * and displaying 24bpp BMPs on 32bpp LCDs
237 if (bpix
!= bmp_bpix
&&
238 !(bmp_bpix
== 8 && bpix
== 16) &&
239 !(bmp_bpix
== 24 && bpix
== 32)) {
240 printf("Error: %d bit/pixel mode, but BMP has %d bit/pixel\n",
241 bpix
, get_unaligned_le16(&bmp
->header
.bit_count
));
245 debug("Display-bmp: %d x %d with %d colours, display %d\n",
246 (int)width
, (int)height
, (int)colours
, 1 << bpix
);
249 video_set_cmap(dev
, palette
, colours
);
251 padded_width
= (width
& 0x3 ? (width
& ~0x3) + 4 : width
);
254 video_splash_align_axis(&x
, priv
->xsize
, width
);
255 video_splash_align_axis(&y
, priv
->ysize
, height
);
258 if ((x
+ width
) > pwidth
)
260 if ((y
+ height
) > priv
->ysize
)
261 height
= priv
->ysize
- y
;
263 bmap
= (uchar
*)bmp
+ get_unaligned_le32(&bmp
->header
.data_offset
);
264 fb
= (uchar
*)(priv
->fb
+
265 (y
+ height
- 1) * priv
->line_length
+ x
* bpix
/ 8);
270 cmap_base
= priv
->cmap
;
271 #ifdef CONFIG_VIDEO_BMP_RLE8
272 u32 compression
= get_unaligned_le32(&bmp
->header
.compression
);
273 debug("compressed %d %d\n", compression
, BMP_BI_RLE8
);
274 if (compression
== BMP_BI_RLE8
) {
276 /* TODO implement render code for bpix != 16 */
277 printf("Error: only support 16 bpix");
278 return -EPROTONOSUPPORT
;
280 video_display_rle8_bitmap(dev
, bmp
, cmap_base
, fb
, x
,
289 byte_width
= width
* 2;
291 for (i
= 0; i
< height
; ++i
) {
293 for (j
= 0; j
< width
; j
++) {
295 fb_put_byte(&fb
, &bmap
);
297 *(uint16_t *)fb
= cmap_base
[*bmap
];
299 fb
+= sizeof(uint16_t) / sizeof(*fb
);
302 bmap
+= (padded_width
- width
);
303 fb
-= byte_width
+ priv
->line_length
;
307 #if defined(CONFIG_BMP_16BPP)
309 for (i
= 0; i
< height
; ++i
) {
311 for (j
= 0; j
< width
; j
++)
312 fb_put_word(&fb
, &bmap
);
314 bmap
+= (padded_width
- width
) * 2;
315 fb
-= width
* 2 + priv
->line_length
;
318 #endif /* CONFIG_BMP_16BPP */
319 #if defined(CONFIG_BMP_24BPP)
321 for (i
= 0; i
< height
; ++i
) {
322 for (j
= 0; j
< width
; j
++) {
328 fb
-= priv
->line_length
+ width
* (bpix
/ 8);
331 #endif /* CONFIG_BMP_24BPP */
332 #if defined(CONFIG_BMP_32BPP)
334 for (i
= 0; i
< height
; ++i
) {
335 for (j
= 0; j
< width
; j
++) {
341 fb
-= priv
->line_length
+ width
* (bpix
/ 8);
344 #endif /* CONFIG_BMP_32BPP */