• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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