重点:
- 开启 ACTLR.SMP
- TLB entry dcache 模式设置为 WRITE-BACK.
一次调试 rk3128 u-boot, 偶然发现 memcpy 很慢, 不到 24MB/s. 分析了 u-boot 代码, 没看出问题. 查看 cortex-a7 mpcore 手册, 发现协处理器 ACTLR.SMP 位没开启, SCTLR.C 位不起效:
开启后测试 memcpy , 没效果. 后面发现 u-boot 设置 TLB entry 的 cache 模式为 WRITE-THROUGH . 改为 WRITE-BACK 后速度暴增:
cache 开关的代码:
void
cache_on(
bool
on )
{
u32 * tlb = (u32 *)gd->arch.tlb_addr;
u32 i;
#define set_entry_cache_type(entry,val) tlb[entry] = ((entry)<<20) + (3<<10) + (val)
if
(on) {
u32 fb = (u32)gd->fb_base;
u32 malloc_start = gd->relocaddr - TOTAL_MALLOC_LEN;
u32 malloc_end = gd->relocaddr ;
for
(i = ((u32)CONFIG_RAM_PHY_START >> 20);
i < (((u32)CONFIG_RAM_PHY_START + SZ_512M) >> 20); ++i) {
set_entry_cache_type(i, DCACHE_WRITEBACK);
}
for
(i = (fb >> 20); i < ((fb + SZ_4M) >> 20); i++) {
set_entry_cache_type(i, DCACHE_OFF);
}
for
(i = (malloc_start >> 20); i < (malloc_end >> 20); i++) {
set_entry_cache_type(i, DCACHE_WRITETHROUGH);
}
asm
volatile
(
"mrc p15, 0, r0, c1, c0, 1 @ACTLR Enabling SMP bit in ACTLR\n"
"orr r0, r0, #(1 << 6) \n"
"mcr p15, 0, r0, c1, c0, 1 \n"
// flush tlb
"mov r0,#0 \n"
"mcr p15, 0, r0, c8, c7, 0\n"
);
}
else
{
unsigned
int
actlr;
asm
volatile
(
"mrc p15, 0, %0, c1, c0, 1"
:
"=r"
(actlr));
if
(actlr & (1<<6)) {
set_cr(get_cr() & ~(CR_M | CR_D));
}
}
}
注:
不能直接修改 cache-cp15.c 中的 mmu_setup(), 因为 rk 的 u-boot 开机初始化对 cache 支持不完善, 真正开启 cache 会导致死机, 笔者是在 board_late_init() 中开启.
rk 的 dma, sd 驱动对 cache 支持不完善, 所以上面的代码将 malloc 内存区域设置为 DCACHE_WRITETHROUGH; 也可以关闭 sd dma , 屏蔽 CONFIG_RK_MMC_DMA 配置, 但 mmc 读取速度会降低.
framebuffer 区域开启 cache 后, 屏幕画面会有一点不正常, 因此设置为 DCACHE_OFF
进 USB 烧写模式时, 需要关闭 cache, 即在 do_rockusb() 调用前关闭 cache, 否则烧写的数据有可能会出错