linux系统内核驱动显示开机logo
引入
目前本文讲述的的实现开机logo显示方式有两种:
1.uboot加载读取logo分区图片数据到物理内存中,然后内核部分进行显示。
2.在驱动中将图片转化为c数组元素进行显示
第一种:数组元素显示
-
将bmp图片转化成数组元素,可以借助工具进行转化,转化配置如下图:
注意上述几个标注位置,分辨率、不要包含图形头部数据、图片的像素位,这些要根据自己屏幕的配置进行选择,我这边目前使用的是spi接口16bit 565的屏幕,所以配置如上。
转化的数组如下:
-
关键lcd驱动logo代码显示部分
#if BOOTLOGO memcpy(fbi->screen_base, bootlogo_240x320,240*320* 2); #endif 该部分代码主要是将logo图片的像素数据直接传入frambuffer的显示虚拟地址内,可以等同于将图形数据写入屏幕内,上面的各项参数根据自己屏幕去对应配置,对应于我的屏幕如下:第一个参数是frambuffer的虚拟地址,也就是现存地址,2 代表logo数组名,3,代码要复制的字节数。
上述代码中有已经写好的代码;
第二种:从logo分区加载开机logo,方便后期应用层更换开机logo
1.自定义logo分区,并预置logo图片文件到分区内
由于我现在使用的全志的tina系统:
新增logo分区如下:
tina\device\config\chips\c200s\configs\F1C200s\linux\sys_partition.fex :

2.uboot部分读取logo分区到物理内存:
3.内核部分进行显示
内核部分能获取到uboot存储的logo图片数据关键在这个函数内,上述三个标注解释如下:
1.指定logo的大小2M
2.函数作用:将具有mem后缀的字符串解析成数字
可参考链接:https://blog.csdn.net/sheng__jun/article/details/78125126
3.__setup()的作用:将bootargs参数的fb_base的值传给 bootlogo_parse 函数 str参数,也就是将图片的存储地址传过来,这样这两者就联系起来了,图片数据获取到了,接下来的就是图片的显示了,因为当前是使用的是bmp图片,所以显示图片的代码如下:
static int Fb_map_kernel_logo(__u32 sel, struct fb_info *info)
{
void *vaddr = NULL;
unsigned int paddr = 0;
void *screen_offset = NULL, *image_offset = NULL;
char *tmp_buffer = NULL;
char *bmp_data = NULL;
struct sunxi_bmp_store_t s_bmp_info;
struct sunxi_bmp_store_t *bmp_info = &s_bmp_info;
struct bmp_image *bmp = NULL;
int zero_num = 0;
unsigned long x, y, bmp_bpix, fb_width, fb_height;
unsigned int effective_width, effective_height;
unsigned int offset;
int i = 0;
paddr = bootlogo_addr;
if (0 == paddr) {
__wrn("Fb_map_kernel_logo failed!");
return -1;
}
/* parser bmp header */
offset = paddr & ~PAGE_MASK;
vaddr = (void *)Fb_map_kernel(paddr, sizeof(struct bmp_header));
if (0 == vaddr) {
__wrn("fb_map_kernel failed, paddr=0x%x,size=0x%x\n", paddr,
sizeof(struct bmp_header));
return -1;
}
/* parser bmp header */
offset = paddr & ~PAGE_MASK;
vaddr = (void *)Fb_map_kernel(paddr, sizeof(struct bmp_header));
if (0 == vaddr) {
__wrn("fb_map_kernel failed, paddr=0x%x,size=0x%x\n", paddr,
sizeof(struct bmp_header));
return -1;
}
bmp = (struct bmp_image *)vaddr + offset;
if ((bmp->header.signature[0] != 'B') ||
(bmp->header.signature[1] != 'M')) {
__wrn("this is not a bmp picture\n");
return -1;
}
bmp_bpix = bmp->header.bit_count / 8;
if ((bmp_bpix != 2) && (bmp_bpix != 3) && (bmp_bpix != 4))
return -1;
if (bmp_bpix == 3)
zero_num = (4 - ((3*bmp->header.width) % 4))&3;
x = bmp->header.width;
y = (bmp->header.height & 0x80000000) ? (-bmp->header.height)
: (bmp->header.height);
fb_width = info->var.xres;
fb_height = info->var.yres;
if ((paddr <= 0) || x <= 1 || y <= 1) {
__wrn("kernel logo para error!\n");
return -EINVAL;
}
bmp_info->x = x;
bmp_info->y = y;
bmp_info->bit = bmp->header.bit_count;
bmp_info->buffer = (void *)(info->screen_base);
if (bmp_bpix == 3)
info->var.bits_per_pixel = 24;
else if (bmp_bpix == 4)
info->var.bits_per_pixel = 32;
else if (bmp_bpix == 2)
info->var.bits_per_pixel = 16;
else
info->var.bits_per_pixel = 32;
Fb_unmap_kernel(vaddr);
/* map the total bmp buffer */
vaddr = (void *)Fb_map_kernel(paddr,
x * y * bmp_bpix + sizeof(struct bmp_header));
if (0 == vaddr) {
__wrn("fb_map_kernel failed, paddr=0x%x,size=0x%x\n", paddr,
(unsigned int)(x * y
* bmp_bpix + sizeof(struct bmp_header)));
return -1;
}
bmp = (struct bmp_image *)vaddr + offset;
tmp_buffer = (char *)bmp_info->buffer;
screen_offset = (void *)bmp_info->buffer;
bmp_data = (char *)(vaddr + bmp->header.data_offset);
image_offset = (void *)bmp_data;
effective_width = (fb_width < x) ? fb_width : x;
effective_height = (fb_height < y) ? fb_height : y;
if (bmp->header.height & 0x80000000) {
if (fb_width > x) {
screen_offset = (void *)((u32)info->screen_base
+ (fb_width * (abs(fb_height - y) / 2)
+ abs(fb_width - x) / 2)
* (info->var.bits_per_pixel >> 3));
} else if (fb_width < x) {
image_offset = (void *)((u32)bmp_data
+ (x * ((y - fb_height) / 2)
+ (x - fb_width) / 2)
* (info->var.bits_per_pixel >> 3));
}
for (i = 0; i < effective_height; i++) {
memcpy((void *)screen_offset, image_offset,
effective_width
*(info->var.bits_per_pixel >> 3));
screen_offset = (void *)((u32)screen_offset
+ fb_width*(info->var.bits_per_pixel >> 3));
image_offset = (void *)image_offset
+ x * (info->var.bits_per_pixel >> 3);
}
} else {
screen_offset = (void *)((u32)info->screen_base
+(fb_width * (abs(fb_height - y) / 2)
+ abs(fb_width - x) / 2)
* (info->var.bits_per_pixel >> 3));
image_offset = (void *)((u32)image_offset
+ (x * (abs(y - fb_height) / 2)
+ abs(x - fb_width) / 2)
* (info->var.bits_per_pixel >> 3));
#if 0
if (3 == bmp_bpix) {
unsigned char *ptemp = NULL;
unsigned char temp = 0;
int h = 0;
ptemp = (char *)image_offset;
for (h = 0; h < effective_height; h++) {
for (i = 0;
i <= effective_width
* (info->var.bits_per_pixel >> 3) - 3;
i += 3) {
temp = ptemp[i];
ptemp[i] = ptemp[i+1];
ptemp[i+1] = temp;
}
ptemp = (char *)((void *)bmp_data
+ h * x
* (info->var.bits_per_pixel >> 3));
}
}
#endif
image_offset = (void *)bmp_data
+ (effective_height-1)
* x * (info->var.bits_per_pixel >> 3);
for (i = effective_height-1; i >= 0; i--) {
memcpy((void *)screen_offset, image_offset,
effective_width
*(info->var.bits_per_pixel >> 3));
screen_offset = (void *)((u32)screen_offset
+ fb_width*(info->var.bits_per_pixel >> 3));
image_offset = (void *)bmp_data
+ i * x * (info->var.bits_per_pixel >> 3);
}
}
Fb_unmap_kernel(vaddr);
return 0;
}
#endif
整个显示流程就是上述,具体实现见完整代码: