1 /*
2 * logo.c
3 *
4 * Copyright (c) 2007-2020 Allwinnertech Co., Ltd.
5 * Author: zhengxiaobin <zhengxiaobin@allwinnertech.com>
6 *
7 * This software is licensed under the terms of the GNU General Public
8 * License version 2, as published by the Free Software Foundation, and
9 * may be copied, distributed, and modified under those terms.
10 *
11 * This program is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 * GNU General Public License for more details.
15 *
16 */
17 #include "logo.h"
18 #include <linux/memblock.h>
19
20 static u32 disp_reserve_size;
21 static u32 disp_reserve_base;
22
23 #ifndef MODULE
disp_reserve_mem(bool reserve)24 int disp_reserve_mem(bool reserve)
25 {
26 if (!disp_reserve_size || !disp_reserve_base)
27 return -EINVAL;
28
29 if (reserve)
30 memblock_reserve(disp_reserve_base, disp_reserve_size);
31 else
32 memblock_free(disp_reserve_base, disp_reserve_size);
33
34 return 0;
35 }
36
early_disp_reserve(char * str)37 static int __init early_disp_reserve(char *str)
38 {
39 u32 temp[3] = {0};
40
41 if (!str)
42 return -EINVAL;
43
44 get_options(str, 3, temp);
45
46 disp_reserve_size = temp[1];
47 disp_reserve_base = temp[2];
48 if (temp[0] != 2 || disp_reserve_size <= 0)
49 return -EINVAL;
50
51 /*arch_mem_end = memblock_end_of_DRAM();*/
52 disp_reserve_mem(true);
53 pr_info("disp reserve base 0x%x ,size 0x%x\n",
54 disp_reserve_base, disp_reserve_size);
55 return 0;
56 }
57 early_param("disp_reserve", early_disp_reserve);
58 #endif
59
bmp_to_fb(const void * psrc,struct bmp_header * bmp_header,struct fb_info * info,void * pdst)60 static int bmp_to_fb(const void *psrc, struct bmp_header *bmp_header,
61 struct fb_info *info, void *pdst)
62 {
63 int srclinesize, dstlinesize, w, h;
64 const unsigned char *psrcline = NULL, *psrcdot = NULL;
65 unsigned char *pdstline = NULL, *pdstdot = NULL;
66 int i = 0, j = 0, zero_num = 0, bmp_real_height = 0;
67 int BppBmp = 3;
68
69 if (!psrc || !pdst || !bmp_header || !info) {
70 lcd_fb_wrn("Invalid parameter\n");
71 return -1;
72 }
73
74 if (bmp_header->bit_count == 24)
75 zero_num = (4 - ((3 * bmp_header->width) % 4)) & 3;
76
77 w = (info->var.xres < bmp_header->width) ? info->var.xres
78 : bmp_header->width;
79 bmp_real_height = (bmp_header->height & 0x80000000) ? (-bmp_header->
80 height) : (bmp_header->height);
81 h = (info->var.yres < bmp_real_height) ? info->var.yres : bmp_real_height;
82
83 BppBmp = bmp_header->bit_count >> 3;
84 srclinesize = bmp_header->width * BppBmp + zero_num;
85 dstlinesize = info->var.xres * (info->var.bits_per_pixel >> 3);
86 psrcline = (const unsigned char *)psrc;
87 pdstline = (unsigned char *)pdst;
88
89 if (bmp_header->height & 0x80000000) {
90 for (i = 0; i < h; ++i) {
91 psrcdot = psrcline;
92 pdstdot = pdstline;
93 if (info->var.bits_per_pixel == bmp_header->bit_count) {
94 memcpy(pdstline, psrcline, srclinesize);
95 } else {
96 for (j = 0; j < w; ++j) {
97 if (info->var.bits_per_pixel == 32 &&
98 bmp_header->bit_count == 24) {
99 *pdstdot++ = psrcdot[j * BppBmp];
100 *pdstdot++ = psrcdot[j * BppBmp + 1];
101 *pdstdot++ = psrcdot[j * BppBmp + 2];
102 *pdstdot++ = 0xff;
103 } else if (info->var.bits_per_pixel == 16 &&
104 bmp_header->bit_count >= 24) {
105 /* little endian */
106 *pdstdot++ =
107 ((psrcdot[j * BppBmp + 1] << 3) &
108 0xe0) +
109 ((psrcdot[j * BppBmp] >> 3) & 0x1f);
110 *pdstdot++ =
111 (psrcdot[j * BppBmp + 2] & 0xf8) +
112 ((psrcdot[j * BppBmp + 1] >> 5) &
113 0x07);
114 }
115 }
116 }
117 psrcline += srclinesize;
118 pdstline += dstlinesize;
119 }
120 } else {
121 psrcline = (const unsigned char *)psrc +
122 (bmp_real_height - 1) * srclinesize;
123
124 for (i = h - 1; i >= 0; --i) {
125 psrcdot = psrcline;
126 pdstdot = pdstline;
127 if (info->var.bits_per_pixel == bmp_header->bit_count) {
128 memcpy(pdstline, psrcline, srclinesize);
129 } else {
130 for (j = 0; j < w; ++j) {
131 if (info->var.bits_per_pixel == 32 &&
132 bmp_header->bit_count == 24) {
133 *pdstdot++ = psrcdot[j * BppBmp];
134 *pdstdot++ = psrcdot[j * BppBmp + 1];
135 *pdstdot++ = psrcdot[j * BppBmp + 2];
136 *pdstdot++ = 0xff;
137 } else if (info->var.bits_per_pixel == 16 &&
138 bmp_header->bit_count >= 24) {
139 /* little endian */
140 *pdstdot++ =
141 ((psrcdot[j * BppBmp + 1] << 3) &
142 0xe0) +
143 ((psrcdot[j * BppBmp] >> 3) & 0x1f);
144 *pdstdot++ =
145 (psrcdot[j * BppBmp + 2] & 0xf8) +
146 ((psrcdot[j * BppBmp + 1] >> 5) &
147 0x07);
148 }
149 }
150 }
151 psrcline -= srclinesize;
152 pdstline += dstlinesize;
153 }
154 }
155
156 return 0;
157 }
158
Fb_map_kernel(unsigned long phys_addr,unsigned long size)159 static void *Fb_map_kernel(unsigned long phys_addr, unsigned long size)
160 {
161 int npages = PAGE_ALIGN(size) / PAGE_SIZE;
162 struct page **pages = vmalloc(sizeof(struct page *) * npages);
163 struct page **tmp = pages;
164 struct page *cur_page = phys_to_page(phys_addr);
165 pgprot_t pgprot;
166 void *vaddr = NULL;
167 int i;
168
169 if (!pages)
170 return NULL;
171
172 for (i = 0; i < npages; i++)
173 *(tmp++) = cur_page++;
174
175 pgprot = pgprot_noncached(PAGE_KERNEL);
176 vaddr = vmap(pages, npages, VM_MAP, pgprot);
177
178 vfree(pages);
179 return vaddr;
180 }
181
Fb_unmap_kernel(void * vaddr)182 static void Fb_unmap_kernel(void *vaddr)
183 {
184 vunmap(vaddr);
185 }
186
Fb_map_kernel_logo(struct fb_info * info)187 static int Fb_map_kernel_logo(struct fb_info *info)
188 {
189 void *vaddr = NULL;
190 uintptr_t paddr = 0;
191 void *screen_offset = NULL, *image_offset = NULL;
192 char *bmp_data = NULL;
193 struct bmp_pad_header bmp_pad_header;
194 struct bmp_header *bmp_header;
195 unsigned int x, y, bmp_bpix;
196 unsigned int effective_width, effective_height;
197 uintptr_t offset;
198
199 paddr = disp_reserve_base;
200 if (!paddr || !disp_reserve_size || !info || !info->screen_base) {
201 lcd_fb_wrn("Fb_map_kernel_logo failed!");
202 return -1;
203 }
204
205 /* parser bmp header */
206 offset = paddr & ~PAGE_MASK;
207 vaddr = (void *)Fb_map_kernel(paddr, sizeof(struct bmp_header));
208 if (vaddr == NULL) {
209 lcd_fb_wrn("fb_map_kernel failed, paddr=0x%p,size=0x%x\n",
210 (void *)paddr, (unsigned int)sizeof(struct bmp_header));
211 return -1;
212 }
213
214 memcpy(&bmp_pad_header.signature[0], vaddr + offset,
215 sizeof(struct bmp_header));
216 bmp_header = (struct bmp_header *) &bmp_pad_header.signature[0];
217 if ((bmp_header->signature[0] != 'B')
218 || (bmp_header->signature[1] != 'M')) {
219 Fb_unmap_kernel(vaddr);
220 #if defined(CONFIG_DECOMPRESS_LZMA)
221 return lzma_decode(paddr, info);
222 #else
223 lcd_fb_wrn("this is not a bmp picture.\n");
224 return -1;
225
226 #endif
227 }
228
229 bmp_bpix = bmp_header->bit_count / 8;
230
231 if ((bmp_bpix != 3) && (bmp_bpix != 4)) {
232 lcd_fb_wrn("Only bmp24 and bmp32 is supported!\n");
233 return -1;
234 }
235
236 x = bmp_header->width;
237 y = (bmp_header->height & 0x80000000) ? (-bmp_header->
238 height) : (bmp_header->height);
239 if (x != info->var.xres || y != info->var.yres) {
240 Fb_unmap_kernel(vaddr);
241 lcd_fb_wrn("Bmp [%u x %u] is not equal to fb[%d x %d]\n", x, y,
242 info->var.xres, info->var.yres);
243 return -1;
244 }
245
246 if ((paddr <= 0) || x <= 1 || y <= 1) {
247 lcd_fb_wrn("kernel logo para error!\n");
248 return -EINVAL;
249 }
250
251 Fb_unmap_kernel(vaddr);
252
253 /* map the total bmp buffer */
254 vaddr =
255 (void *)Fb_map_kernel(paddr,
256 disp_reserve_size);
257 if (vaddr == NULL) {
258 lcd_fb_wrn("fb_map_kernel failed, paddr=0x%p,size=0x%x\n",
259 (void *)paddr,
260 (unsigned int)(x * y * bmp_bpix +
261 sizeof(struct bmp_header)));
262 return -1;
263 }
264
265 bmp_data = (char *)(vaddr + bmp_header->data_offset + offset);
266 image_offset = (void *)bmp_data;
267 effective_width = x;
268 effective_height = y;
269 screen_offset =
270 (void *__force)info->screen_base;
271
272 bmp_to_fb(image_offset, bmp_header, info,
273 screen_offset);
274
275 Fb_unmap_kernel(vaddr);
276 return 0;
277 }
278
logo_parse(struct fb_info * info)279 int logo_parse(struct fb_info *info)
280 {
281 int ret = -1;
282
283 ret = Fb_map_kernel_logo(info);
284
285 #ifndef MODULE
286 disp_reserve_mem(false);
287 #endif
288 return ret;;
289 }
290