En el desarrollo de Android/Linux, el logotipo de arranque es el símbolo de la marca del dispositivo y, a menudo, debe personalizarse según los diferentes clientes o escenarios de aplicación. Para la plataforma RK3568, el logotipo de arranque generalmente está empaquetado en el archivo img del firmware, lo que significa que cada vez que se cambia el logotipo, es necesario volver a compilar y grabar todo el firmware, lo que sin duda aumenta la complejidad del desarrollo y hace perder tiempo. Este artículo presentará un método para reemplazar dinámicamente U-Boot y Kernel Logo en el sistema RK3568 Android/Linux.
referencia:
RK3399 permite el proceso del logotipo de inicio,
el nombramiento de particiones y la configuración U-Boot de la partición de almacenamiento de Android y la plataforma Rockchip.
Antecedentes de la demanda
El método tradicional requiere que recompilemos y grabemos el firmware cada vez que cambiamos el logo. Esto no solo lleva mucho tiempo, sino que también consume tiempo ^^, así que resolvamos este problema.
solución
El objetivo es cambiar dinámicamente el logotipo de inicio cuando el dispositivo ya se está ejecutando. Para ello propuse el siguiente plan:
-
Cree una nueva partición (o use una partición existente) : almacene el archivo del logotipo en esta partición. Cuando se inicia el dispositivo, el sistema primero intentará cargar el logotipo desde esta partición. Si no hay ningún archivo de logotipo en la partición, el sistema volverá al logotipo predeterminado.
-
Modificar el código fuente de U-Boot : durante el proceso de inicio de U-Boot, modificamos la lógica de carga de Logo. Primero intente cargar el logotipo desde la partición recién creada. Si falla, cárguelo desde el archivo de recursos predeterminado.
Detalles de implementacion
Utilice la partición existente para almacenar el logotipo
Primero necesitamos determinar dónde se almacena el archivo Logo. Dado que las particiones del sistema y del proveedor son de solo lectura, y la partición de datos se borrará después de restaurar la configuración de fábrica, decidí crear una nueva partición para almacenar el archivo Logo (de hecho, ya la he creado antes. Si quieres Para hacerlo, puede utilizar la partición existente del sistema, como /cache, correspondiente a mmc 0:a).
rk3568_r:/ $ df
Filesystem 1K-blocks Used Available Use% Mounted on
tmpfs 1001716 824 1000892 1% /dev
tmpfs 1001716 12 1001704 1% /mnt
/dev/block/mmcblk0p11 11760 144 11132 2% /metadata
/dev/block/dm-0 956964 954064 0 100% /
/dev/block/dm-5 692224 96 692128 1% /mnt/scratch
overlay 692224 96 692128 1% /system
overlay 692224 96 692128 1% /vendor
overlay 692224 96 692128 1% /odm
overlay 692224 96 692128 1% /product
overlay 692224 96 692128 1% /system_ext
tmpfs 1001716 0 1001716 0% /apex
tmpfs 1001716 264 1001452 1% /linkerconfig
/dev/block/mmcblk0p10 364504 916 351792 1% /cache
/dev/block/mmcblk0p12 3952 364 3468 10% /mnt/private
/dev/block/dm-6 25528320 43916 25353332 1% /data
tmpfs 1001716 0 1001716 0% /data_mirror
/dev/fuse 25528320 43916 25353332 1% /storage/emulated
En la plataforma Rockchip, el nombre y la configuración de las particiones generalmente están definidos por el árbol de dispositivos (DTB/DTBO). Por ejemplo, el 0 en mmc 0:c representa el 0.º dispositivo de almacenamiento y c es un número hexadecimal que representa 12, por lo que corresponde a la 12.ª partición.
OK Después de seleccionar la partición, creamos una nueva carpeta debajo de la partición, por ejemplo custom_logo
, colocamos logo.bmp
y logo_kernel.bmp
.
rk3568_r:/mnt/private/custom_logo $ ls
logo.bmp logo_kernel.bmp
rk3568_r:/mnt/private/custom_logo $
Si insiste en utilizar un método de partición personalizado, puede buscarlo en CSDN y no entrará en detalles aquí.
Modificar el código fuente de U-Boot
El código para cargar el Logo en U-Boot se encuentra /u-boot/drivers/video/drm/rockchip_display.c
en load_bmp_logo
el método. Nuestra estrategia es intentar primero cargar el logotipo desde la partición recién creada y, si falla, cargarlo desde el archivo de recursos predeterminado. Por cierto, he comprobado que es compatible con Linux y Android!! Solo cambia la partición y estará bien.
Aquí está el fragmento de código modificado:
static int load_bmp_logo(struct logo_info *logo, const char *bmp_name)
{
#define BUFFER_SIZE 128
#ifdef CONFIG_ROCKCHIP_RESOURCE_IMAGE
struct rockchip_logo_cache *logo_cache;
struct bmp_header *header;
void *dst = NULL, *pdst;
char cmd[BUFFER_SIZE] = {
"0"};
int size, len;
int ret = 0;
int reserved = 0;
if (!logo || !bmp_name)
return -EINVAL;
logo_cache = find_or_alloc_logo_cache(bmp_name);
if (!logo_cache)
return -ENOMEM;
if (logo_cache->logo.mem) {
memcpy(logo, &logo_cache->logo, sizeof(*logo));
return 0;
}
header = malloc(RK_BLK_SIZE);
if (!header)
return -ENOMEM;
/*len = rockchip_read_resource_file(header, bmp_name, 0, RK_BLK_SIZE);
if (len != RK_BLK_SIZE) {
ret = -EINVAL;
goto free_header;
}*/
//---add start
sprintf(cmd, "ext4load mmc 0:c 0x%p custom_logo/%s %x", header,bmp_name, RK_BLK_SIZE);
printf("load_bmp_logo 尝试从MMC加载 %s...\n", bmp_name);
if(run_command(cmd, 0)){
len = rockchip_read_resource_file(header, bmp_name, 0, RK_BLK_SIZE);
if (len != RK_BLK_SIZE) {
printf("load_bmp_logo 从资源文件加载 %s 失败\n", bmp_name);
ret = -EINVAL;
goto free_header;
}
}
//---add end
logo->bpp = get_unaligned_le16(&header->bit_count);
logo->width = get_unaligned_le32(&header->width);
logo->height = get_unaligned_le32(&header->height);
reserved = get_unaligned_le32(&header->reserved);
if (logo->height < 0)
logo->height = -logo->height;
size = get_unaligned_le32(&header->file_size);
if (!can_direct_logo(logo->bpp)) {
if (size > MEMORY_POOL_SIZE) {
printf("failed to use boot buf as temp bmp buffer\n");
ret = -ENOMEM;
goto free_header;
}
pdst = get_display_buffer(size);
} else {
pdst = get_display_buffer(size);
dst = pdst;
}
/*len = rockchip_read_resource_file(pdst, bmp_name, 0, size);
if (len != size) {
printf("failed to load bmp %s\n", bmp_name);
ret = -ENOENT;
goto free_header;
}*/
//---add start
memset(cmd, 0, BUFFER_SIZE);
sprintf(cmd, "ext4load mmc 0:c 0x%p custom_logo/%s %x", pdst, bmp_name, size);
if(run_command(cmd, 0)){
len = rockchip_read_resource_file(pdst, bmp_name, 0, size);
if (len != size) {
printf("load_bmp_logo 加载bmp %s 失败\n", bmp_name);
printf("failed to load bmp %s\n", bmp_name);
ret = -ENOENT;
goto free_header;
}
}
//---add end
if (!can_direct_logo(logo->bpp)) {
int dst_size;
/*
* 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));
free_header:
free(header);
return ret;
#else
return -EINVAL;
#endif
}
depuración
Conéctese al puerto serie y presione Ctrl + C para ingresar al modo de línea de comando uboot. Después de escribir, puede ext4ls mmc 0:c /custom_logo
ver las dos imágenes del logotipo personalizado que ingresamos. OK, y estará listo para cepillar uboot.img.
=> ext4ls mmc 0:c /custom_logo
<DIR> 4096 .
<DIR> 4096 ..
170326 logo.bmp
170326 logo_kernel.bmp
----------下面3行只是调试显示而已 并没什么关系
=> rockchip_show_bmp logo_kernel.bmp
load_bmp_logo 尝试从MMC加载 logo_kernel.bmp...
512 bytes read in 44 ms (10.7 KiB/s)
170326 bytes read in 48 ms (3.4 MiB/s)
VOP VP0 enable Smart0[654x258->654x258@633x411] fmt[2] addr[0x7dfa7000]
=> rockchip_show_bmp logo.bmp
VOP VP0 enable Smart0[654x258->654x258@633x411] fmt[2] addr[0x7df2a000]
=> rockchip_show_logo
VOP VP0 enable Smart0[654x258->654x258@633x411] fmt[2] addr[0x7df2a000]
=>
Otros hallazgos: cuando leí el registro, descubrí que la función load_kernel_bmp_logo no se ejecutó en absoluto. Luego leí los comentarios y descubrí, está bien, no importa.
/* Note: used only for rkfb kernel driver */
static int load_kernel_bmp_logo(struct logo_info *logo, const char *bmp_name)
verificar
Conéctese al puerto serie y observe el registro de impresión de depuración. Puede ver que primero se lee logo.bmp y luego logo_kernel.bmp, que corresponde al logotipo de uboot y al logotipo del kernel. ¡Listo! Si no existen estos dos archivos de logotipos personalizados, se utilizará el valor predeterminado del sistema.
## Baudrate 1500000 bps not supported
himport_r: can't insert "baudrate=1500000" into hash table
dwmmc@fe2b0000: 1, dwmmc@fe2c0000: 2, sdhci@fe310000: 0
Bootdev(atags): mmc 0
MMC0: HS200, 200Mhz
PartType: EFI
boot mode: recovery (misc)
FIT: No fdt blob
boot mode: None
Android 11.0, Build 2021.7, v2
Found DTB in boot part
DTB: rk-kernel.dtb
HASH(c): OK
ANDROID: fdt overlay OK
I2c0 speed: 100000Hz
vsel-gpios- not found! Error: -2
vdd_cpu init 900000 uV
PMIC: RK8090 (on=0x40, off=0x00)
vdd_logic init 900000 uV
vdd_gpu init 900000 uV
vdd_npu init 900000 uV
io-domain: OK
Model: Rockchip RK3568 EVB3568 Board
load_bmp_logo 尝试从MMC加载 logo.bmp...
..............
Fdt Ramdisk skip relocation
## Booting Android Image at 0x0027f800 ...
Kernel load addr 0x00280000 size 32057 KiB
RAM disk load addr 0x0a200000 size 804 KiB
## Flattened Device Tree blob at 0x0a100000
Booting using the fdt blob at 0x0a100000
XIP Kernel Image from 0x00280000 to 0x00280000 ... OK
'reserved-memory' linux,cma: addr=10000000 size=800000
'reserved-memory' ramoops@110000: addr=110000 size=f0000
Using Device Tree in place at 000000000a100000, end 000000000a1223a7
load_bmp_logo 尝试从MMC加载 logo_kernel.bmp...
duda
Una pregunta es que después de este cambio, si el logo del kernel tiene 24 bits de profundidad, el logo se invertirá a 8 bits, pero ¿no?
Luego, según mi investigación, descubrí que la estructura de almacenamiento de las imágenes BMP de 8 bits es diferente de la de las imágenes BMP de 24 bits, especialmente en el procesamiento de tablas de colores y datos de píxeles. Estas diferencias pueden afectar la forma en que se representa la imagen y si es necesario voltearla verticalmente.
Por lo tanto, sin un procesamiento especial, las imágenes BMP se mostrarán al revés.
En el código, hay esta sección:
if (reserved == BMP_PROCESSED_FLAG)
logo->ymirror = 0;
else
logo->ymirror = 1;
Aquí ymirror
parece que se utiliza para abordar este problema. Cuando ymirror
se establece en 1, la imagen se voltea verticalmente y se muestra normalmente. Y BMP_PROCESSED_FLAG
parece ser una bandera utilizada para indicar si la imagen BMP ha sido procesada (por ejemplo, ha sido volteada).
Si descubre que el logotipo BMP de 24 bits de profundidad se muestra al revés, es posible que deba verificar los siguientes puntos:
-
Cómo se almacenan los archivos BMP : asegúrese de que sus archivos BMP se almacenen de abajo hacia arriba. Si ya está almacenado de arriba hacia abajo, no es necesario darle la vuelta.
-
BMP_PROCESSED_FLAG
Configuración : asegúrese de que esta bandera indique correctamente si la imagen BMP se ha procesado. -
ymirror
Uso : asegúrese de utilizar la bandera correctamente al renderizar imágenesymirror
.
Para resolver este problema, considere configurarlo siempre ymirror
en 1 (o configurarlo según corresponda), o al crear el archivo BMP, asegúrese de que esté almacenado de arriba hacia abajo (ambos con 8 bits).
Resumir
A través de mi método anterior, logramos con éxito la función de cambiar dinámicamente el U-Boot y el logotipo del kernel en el sistema RK3568 Android/Linux. Esto no sólo simplifica el proceso de desarrollo sino que también proporciona una mayor flexibilidad en el firmware del dispositivo.