Platform: RK3566
OS: Android 11
U-boot: v2017.09
Kernel: v4.19.219
SDK Version:rk356x_box_11.0_release_v1.0.9_20220309
Module: uboot logo
问题
替换开机logo后出现报错死机的情况,主要报错信息如下:
"Synchronous Abort" handler, esr 0x96000145
Reason: Exception from a Data abort, from current exception level
PC = 0000000000a01afc
LR = 0000000000a51c08
SP = 00000000eb9f8560
ESR_EL2 = 0000000096000145
Reloc Off = 00000000ed34b000
解法
uboot目录下修改
diff --git a/drivers/video/drm/rockchip_display.c b/drivers/video/drm/rockchip_display.c
index 939beb9387..775597841e 100644
--- a/drivers/video/drm/rockchip_display.c
+++ b/drivers/video/drm/rockchip_display.c
@@ -1331,6 +1331,7 @@ static int load_bmp_logo(struct logo_info *logo, const char *bmp_name)
ret = -EINVAL;
goto free_header;
}
+ flush_dcache_range((ulong)dst, ALIGN((ulong)dst + dst_size, CONFIG_SYS_CACHELINE_SIZE));
logo->offset = 0;
logo->ymirror = 0;
@@ -1345,7 +1346,7 @@ static int load_bmp_logo(struct logo_info *logo, const char *bmp_name)
memcpy(&logo_cache->logo, logo, sizeof(*logo));
- flush_dcache_range((ulong)dst, ALIGN((ulong)dst + dst_size, CONFIG_SYS_CACHELINE_SIZE));
+ //flush_dcache_range((ulong)dst, ALIGN((ulong)dst + dst_size, CONFIG_SYS_CACHELINE_SIZE));
free_header:
简要分析
上述解法据客户说来源于RK姚工,没有做具体的解释,我自己尝试简单分析理解下:
- 我测试到该问题与logo图片的位深有关,24位的会出问题,8位的不会。据客户反馈2G ddr的机器上不会,我手上的是4G和8G的,都测到了问题。
- 看定义注释可知flush_dcache_range()函数应该是用于清除指定范围的dcache
/*
* Flush range(clean & invalidate) from all levels of D-cache/unified cache
*/
void flush_dcache_range(unsigned long start, unsigned long stop)
{
__asm_flush_dcache_range(start, stop);
}
/*
* void __asm_flush_dcache_range(start, end)
*
* clean & invalidate data cache in the range
*
* x0: start address
* x1: end address
*/
.pushsection .text.__asm_flush_dcache_range, "ax"
ENTRY(__asm_flush_dcache_range)
mrs x3, ctr_el0
lsr x3, x3, #16
and x3, x3, #0xf
mov x2, #4
lsl x2, x2, x3 /* cache line size */
/* x2 <- minimal cache line size in cache system */
sub x3, x2, #1
bic x0, x0, x3
1: dc civac, x0 /* clean & invalidate data or unified cache */
add x0, x0, x2
cmp x0, x1
b.lo 1b
dsb sy
ret
ENDPROC(__asm_flush_dcache_range)
.popsection
其中的ALIGN()宏是一个内存对齐操作1,防止frame buffer可能不是cache line size的整数倍时出错。
#define ALIGN(x,a) __ALIGN_MASK((x),(typeof(x))(a)-1)
#define __ALIGN_MASK(x,mask) (((x)+(mask))&~(mask))
- 根据参考资料2,cache有3种操作:clean,invalid,flush,其中flush是对每条cache line 先clean,再invalid.
- 上述出问题的代码位于
load_bmp_logo()
函数,看其命名应该就是加载logo的bmp图片,其中通过can_direct_logo()
来判断位深,如果是24位或32位就直接设置下offset和ymirror然后送到cache去,如果位深小等于16位则要先强制设为16位再进行操作。根据目前的测试情况,是只能对小等于16位的图片进行flush cache,否则就会出错。
虽然看了一些参考资料34,但是出错的具体原因还不甚明了,希望有了解的同学可以指导一下。
if (!can_direct_logo(logo->bpp)) {
/*
* TODO: force use 16bpp if bpp less than 16;
*/
logo->bpp = (logo->bpp <= 16) ? 16 : logo->bpp;
dst_size = logo->width * logo->height * logo->bpp >> 3;
dst = get_display_buffer(dst_size);
if (!dst) {
ret = -ENOMEM;
goto free_header;
}
if (bmpdecoder(pdst, dst, logo->bpp)) {
printf("failed to decode bmp %s\n", bmp_name);
ret = -EINVAL;
goto free_header;
}
flush_dcache_range((ulong)dst, ALIGN((ulong)dst + dst_size, CONFIG_SYS_CACHELINE_SIZE));
logo->offset = 0;
logo->ymirror = 0;
} else {
logo->offset = get_unaligned_le32(&header->data_offset);
if (reserved == BMP_PROCESSED_FLAG)
logo->ymirror = 0;
else
logo->ymirror = 1;
}
logo->mem = dst;
memcpy(&logo_cache->logo, logo, sizeof(*logo));
如有谬误欢迎指正,感谢阅读~