RK3588 U-Boot 启动 Logo 显示流程详解
目录
概述
RK3588 的 U-Boot 启动 Logo 显示功能基于 DRM (Direct Rendering Manager) 子系统实现,支持多种显示接口(HDMI、eDP、MIPI、LVDS等)和多种格式的 BMP Logo 图片。
主要特性
| 特性 | 描述 |
|---|---|
| 显示接口 | HDMI0/1, eDP0/1, MIPI0/1, LVDS0/1, RGB, BT1120/656 |
| VOP | VOP2 (Video Output Processor 2) - 支持4个Video Port |
| BMP格式 | 8bpp(RLE8压缩), 24bpp, 32bpp |
| 显示模式 | 全屏(Fullscreen), 居中(Center) |
| Logo来源 | Resource分区, Distro分区, 内置编译 |
显示子系统架构
┌─────────────────────────────────────────────────────────────────────┐
│ RK3588 显示子系统架构 │
└─────────────────────────────────────────────────────────────────────┘
┌─────────────────────────────────────────────────────────────────┐
│ 应用层 (U-Boot 命令) │
│ rockchip_show_logo | rockchip_show_bmp | bmp info │
└─────────────────────────────────────────────────────────────────┘
│
▼
┌─────────────────────────────────────────────────────────────────┐
│ DRM Display Framework │
│ rockchip_display.c (显示子系统管理) │
│ ├─ display_init() 初始化显示设备 │
│ ├─ display_logo() 显示Logo │
│ ├─ load_bmp_logo() 加载BMP图片 │
│ └─ display_set_plane() 设置显示平面 │
└─────────────────────────────────────────────────────────────────┘
│
┌──────────────────────────┼──────────────────────────┐
│ │ │
▼ ▼ ▼
┌─────────┐ ┌─────────┐ ┌─────────┐
│ VOP2 │ │ Panel │ │ Bridge │
│ (CRTC) │◄────────────►│ (Connector)◄─────────┤ (HDMI/ │
│ │ │ │ │ MIPI/ │
│ Overlay │ │ ┌─────┐│ │ eDP) │
│ Cluster │ │ │ LCD ││ └─────────┘
│ Smart │ │ └─────┘│
│ Layer │ │ ┌─────┐│
│ │ │ │ HDMI││
│ │ │ └─────┘│
└─────────┘ └─────────┘
│ │
└──────────┬───────────────┘
│
▼
┌─────────────────────────────────────────────────────────────────┐
│ 显示输出 │
│ ┌──────┐ ┌──────┐ ┌──────┐ ┌──────┐ ┌──────┐ │
│ │ HDMI│ │ eDP │ │ MIPI│ │ LVDS│ │ RGB │ │
│ └──────┘ └──────┘ └──────┘ └──────┘ └──────┘ │
└─────────────────────────────────────────────────────────────────┘
Logo显示流程
1. 整体流程
┌────────────────────────────────────────────────────────────────────┐
│ Logo 显示完整流程 │
└────────────────────────────────────────────────────────────────────┘
U-Boot 启动
│
▼
┌──────────────────────────────────────────────────────────────────┐
│ 1. rockchip_display_probe() │
│ drivers/video/drm/rockchip_display.c:1871 │
│ ├─ 解析设备树 display-subsystem │
│ ├─ 解析 route 节点获取显示路径 │
│ ├─ 为每个显示路径创建 display_state │
│ ├─ 关联 CRTC (VOP2) 和 Connector (Panel/Bridge) │
│ ├─ 读取 Logo 配置 (logo,uboot / logo,kernel) │
│ └─ 初始化显示缓冲区 │
└──────────────────────────────────────────────────────────────────┘
│
▼
┌──────────────────────────────────────────────────────────────────┐
│ 2. rockchip_show_logo() │
│ drivers/video/drm/rockchip_display.c:1412 │
│ 遍历所有 display_state,为每个显示设备加载并显示 Logo │
└──────────────────────────────────────────────────────────────────┘
│
▼
┌──────────────────────────────────────────────────────────────────┐
│ 3. load_bmp_logo() │
│ drivers/video/drm/rockchip_display.c:1251 │
│ ├─ 检查 logo cache,已加载则直接返回 │
│ ├─ 读取 BMP 头部 (512 bytes) │
│ ├─ 确定图片来源: │
│ │ ├─ FROM_RESOURCE: resource 分区 │
│ │ ├─ FROM_DISTRO: distro 分区 │
│ │ └─ FROM_INTERNEL: 编译内置 │
│ ├─ 读取完整 BMP 数据到显示缓冲区 │
│ ├─ 解码 BMP (如果不是 16/32 bpp) │
│ └─ 填充 logo_info 结构体 │
└──────────────────────────────────────────────────────────────────┘
│
▼
┌──────────────────────────────────────────────────────────────────┐
│ 4. display_logo() │
│ drivers/video/drm/ockchip_display.c:997 │
│ ├─ display_init() │
│ │ ├─ 初始化 Connector (Panel/Bridge) │
│ │ ├─ 获取显示时序 (display_get_timing) │
│ │ ├─ 验证时序 (display_mode_valid) │
│ │ ├─ 初始化 CRTC (VOP2) │
│ │ └─ 设置显示模式 │
│ ├─ 根据 logo bpp 设置 crtc format │
│ ├─ 计算 src_rect (Logo尺寸) 和 crtc_rect (显示位置) │
│ ├─ display_check() 检查配置 │
│ ├─ display_set_plane() 设置显示平面 │
│ └─ display_enable() 启用显示输出 │
└──────────────────────────────────────────────────────────────────┘
│
▼
Logo 显示完成
2. 显示子系统初始化
文件位置: drivers/video/drm/rockchip_display.c:1871
static int rockchip_display_probe(struct udevice *dev)
{
struct video_priv *uc_priv = dev_get_uclass_priv(dev);
struct video_uc_platdata *plat = dev_get_uclass_platdata(dev);
// 1. 初始化显示缓冲区
init_display_buffer(plat->base);
// 2. 解析 display-subsystem/route 节点
route_node = dev_read_subnode(dev, "route");
ofnode_for_each_subnode(node, route_node) {
if (!ofnode_is_available(node))
continue;
// 3. 获取连接器 endpoint
phandle = ofnode_read_u32_default(node, "connect", -1);
ep_node = of_find_node_by_phandle(phandle);
// 4. 通过 endpoint 找到对应的 CRTC (VOP)
vop_node = of_get_parent(port_parent_node);
uclass_get_device_by_ofnode(UCLASS_VIDEO_CRTC,
np_to_ofnode(vop_node), &crtc_dev);
crtc = (struct rockchip_crtc *)dev_get_driver_data(crtc_dev);
// 5. 获取 Connector (Panel/Bridge)
conn = rockchip_of_get_connector(np_to_ofnode(ep_node));
// 6. 读取 Logo 配置
if (!ret && !ofnode_read_string_index(node, "logo,uboot", 0, &name))
memcpy(s->ulogo_name, name, strlen(name));
if (!ret && !ofnode_read_string_index(node, "logo,kernel", 0, &name))
memcpy(s->klogo_name, name, strlen(name));
// 7. 读取显示模式
ofnode_read_string_index(node, "logo,mode", 0, &name);
if (!strcmp(name, "fullscreen"))
s->logo_mode = ROCKCHIP_DISPLAY_FULLSCREEN;
else
s->logo_mode = ROCKCHIP_DISPLAY_CENTER;
// 8. 创建 display_state 并加入链表
s = malloc(sizeof(*s));
s->conn_state.connector = conn;
s->crtc_state.crtc = crtc;
list_add_tail(&s->head, &rockchip_display_list);
}
// 9. 预初始化显示设备
display_pre_init();
return 0;
}
3. Logo加载流程
文件位置: drivers/video/drm/rockchip_display.c:1251
static int load_bmp_logo(struct logo_info *logo, const char *bmp_name)
{
struct rockchip_logo_cache *logo_cache;
struct bmp_header *header;
void *dst = NULL, *pdst;
int size;
// 1. 查找或创建 logo cache
logo_cache = find_or_alloc_logo_cache(bmp_name);
if (logo_cache->logo.mem) {
memcpy(logo, &logo_cache->logo, sizeof(*logo));
return 0; // 已缓存,直接返回
}
// 2. 读取 BMP 头部
header = malloc(RK_BLK_SIZE); // 512 bytes
#ifdef CONFIG_ROCKCHIP_RESOURCE_IMAGE
len = rockchip_read_resource_file(header, bmp_name, 0, RK_BLK_SIZE);
if (len == RK_BLK_SIZE)
logo_source = FROM_RESOURCE;
#endif
if (rockchip_read_distro_logo(header, bmp_name, RK_BLK_SIZE) == 0)
logo_source = FROM_DISTRO;
else {
header = (struct bmp_header *)logo_bmp;
logo_source = FROM_INTERNEL;
}
// 3. 获取 BMP 信息
logo->bpp = get_unaligned_le16(&header->bit_count);
logo->width = get_unaligned_le32(&header->width);
logo->height = get_unaligned_le32(&header->height);
size = get_unaligned_le32(&header->file_size);
// 4. 分配显示缓冲区
pdst = get_display_buffer(size);
// 5. 读取完整 BMP 数据
if (logo_source == FROM_RESOURCE)
rockchip_read_resource_file(pdst, bmp_name, 0, size);
else if (logo_source == FROM_DISTRO)
rockchip_read_distro_logo(pdst, bmp_name, size);
else
pdst = (void*)logo_bmp; // 内置
// 6. 解码 BMP (如果不是 16/32 bpp)
if (!can_direct_logo(logo->bpp)) {
// 需要解码,使用 bmpdecoder
logo->bpp = (logo->bpp <= 16) ? 16 : logo->bpp;
dst_size = logo->width * logo->height * logo->bpp >> 3;
dst = get_display_buffer(dst_size);
bmpdecoder(pdst, dst, logo->bpp); // 解码为 RGB565/RGB888
logo->offset = 0;
logo->ymirror = 0;
} else {
// 16/32 bpp 可以直接使用
logo->offset = get_unaligned_le32(&header->data_offset);
if (reserved == BMP_PROCESSED_FLAG)
logo->ymirror = 0;
else
logo->ymirror = 1;
}
logo->mem = dst;
// 7. 缓存 logo 信息
memcpy(&logo_cache->logo, logo, sizeof(*logo));
// 8. 刷新缓存
flush_dcache_range((ulong)dst, ALIGN((ulong)dst + dst_size, CONFIG_SYS_CACHELINE_SIZE));
return ret;
}
4. Logo显示流程
文件位置: drivers/video/drm/rockchip_display.c:997
static int display_logo(struct display_state *state)
{
struct crtc_state *crtc_state = &state->crtc_state;
struct connector_state *conn_state = &state->conn_state;
struct logo_info *logo = &state->logo;
int hdisplay, vdisplay, ret;
// 1. 初始化显示设备
ret = display_init(state);
if (!state->is_init || ret)
return -ENODEV;
// 2. 根据 logo bpp 设置格式
switch (logo->bpp) {
case 16:
crtc_state->format = ROCKCHIP_FMT_RGB565;
break;
case 24:
crtc_state->format = ROCKCHIP_FMT_RGB888;
break;
case 32:
crtc_state->format = ROCKCHIP_FMT_ARGB8888;
break;
default:
printf("can't support bmp bits[%d]\n", logo->bpp);
return -EINVAL;
}
// 3. 设置源矩形 (Logo尺寸)
hdisplay = conn_state->mode.crtc_hdisplay;
vdisplay = conn_state->mode.vdisplay;
crtc_state->src_rect.w = logo->width;
crtc_state->src_rect.h = logo->height;
crtc_state->src_rect.x = 0;
crtc_state->src_rect.y = 0;
crtc_state->ymirror = logo->ymirror;
crtc_state->rb_swap = 0


429

被折叠的 条评论
为什么被折叠?



