RK3399开启开机logo

环境:rk3399 linux SDK linux kernel版本为4.4.179 uboot版本为201709
显示接口:HDMI

一、u-boot开启logo显示

uboot显示框架代码

u-boot/drivers/video/display-uclass.c
u-boot/drivers/video/drm/bmp_helper.c
u-boot/drivers/video/drm/rockchip_display.c

显示驱动代码

u-boot/drivers/video/drm/dw_hdmi.c
u-boot/drivers/video/drm/rockchip_dw_hdmi.c
u-boot/drivers/video/drm/rockchip_analogix_dp.c
u-boot/drivers/video/drm/rockchip_analogix_dp_reg.c
u-boot/drivers/video/drm/rockchip_mipi_dsi.c
u-boot/drivers/video/drm/rockchip-dw-mipi-dsi.c
u-boot/drivers/video/drm/rockchip-inno-mipi-dphy.c
u-boot/drivers/video/drm/rockchip_lvds.c
u-boot/drivers/video/drm/rockchip_panel.c
u-boot/drivers/video/drm/rockchip_rgb.c
u-boot/drivers/video/drm/rockchip_vop.c
u-boot/drivers/video/drm/rockchip_vop_reg.c

因为是HDMI显示,所以uboot的defconfig中需要开启以下宏:

CONFIG_DRM_ROCKCHIP_DW_HDMI=y
CONFIG_ROCKCHIP_INNO_HDMI_PHY=y
CONFIG_ROCKCHIP_VENDOR_PARTITION=y

dts配置如下:

&route_hdmi {
        status = "okay";
        logo,mode = "center";
        connect = <&vopb_out_hdmi>;
};

&hdmi {
        #address-cells = <1>;
        #size-cells = <0>;
        #sound-dai-cells = <0>;
        status = "okay";
};

&display_subsystem {
        status = "okay";
};

&vopb_out_hdmi {
        status = "okay";
};

&vopl_out_hdmi {
        status = "disabled";
};

注意:这里的dts是u-boot中的dts。还有就是route_hdmi节点中的connect属性需要和内核中的配置一样,否则可能导致kernel阶段的logo不显示。
在uboot的命令行下可以利用下面命令进行logo显示的测试,前提是已经烧写过包含logo_kernel.bmp和logo.bmp的内核镜像。

=> rockchip_show_bmp logo_kernel.bmp      #显示logo_kernel.bmp图片
=> rockchip_show_bmp logo.bmp            #显示logo.bmp图片
=> rockchip_show_logo                    #显示logo

二、kernel开启logo显示

建议烧写一个带桌面的文件系统方便观察。在确定hdmi显示正常的情况下在调试显示logo,显示logo的代码主要在下面两个文件中:

kernel/drivers/gpu/drm/drm_fb_helper.c
kernel/drivers/gpu/drm/rockchip/rockchip_drm_drv.c

rockchip_drm_drv.c中的show_loader_logo函数负责显示kernel阶段的logo。
内核的dts配置如下:

&hdmi {
        #address-cells = <1>;
        #size-cells = <0>;
        #sound-dai-cells = <0>;
        status = "okay";
};

&display_subsystem {
        status = "okay";
};

&route_hdmi {
        status = "okay";
        logo,mode = "center";
        connect = <&vopb_out_hdmi>;
};

&vopb_out_hdmi {
        status = "okay";
};

&vopl_out_hdmi {
        status = "disabled";
};

logo为bmp格式,存放在kernel目录下,logo_kernel.bmp是内核logo,logo.bmp为uboot的logo。logo在内核编译后会被打包到resource.img中。

三、遇到的问题

  1. uboot阶段logo可以正常显示,kernel阶段的logo没有显示。
    出现这种情况的原因是route_hdmi节点中配置connect属性uboot和kernel的不一样导致。
  2. kernel logo显示时间很短,立刻就黑屏,持续到进入桌面。
    这个问题,网上有人有相同的经历,不过我按照网上给出的方法试了一下没起作用(http://www.manongjc.com/detail/14-bbfbwuxqyrcbgdj.html)。通过下面的调用关系发现调用register_framebuffer(info)时黑屏,
#函数调用关系
rockchip_drm_bind
     show_loader_logo(drm_dev)
     rockchip_drm_fbdev_init(drm_dev)    <rockchip_drm_fbdev.c:160>
        drm_fb_helper_initial_config(helper, PREFERRED_BPP); <drm_fb_helper.c +2112>
            drm_fb_helper_single_fb_probe(fb_helper, bpp_sel);
                register_framebuffer(info)    

这里简单说一下追这个代码的方法。方法比较笨,各位看官莫要见笑。

  • 第一种方式就是添加"while(1);"让程序停下来,然后观察logo是否消失,如果消失就向后退,否则接着向下追。
  • 第二种方式就是先用printk添加一句打印,接着加个长一点的延迟,这样就可以通过log信息和屏幕的显示情况来定位黑屏时在调用那个函数时出现的。
    接前面,register_framebuffer(info)用于注册/dev/fb0设备在其前后加log会过滤出下面两个log信息:
[ 12.838342] Freeing drm_logo memory: 696K
[ 12.925085] Console: switching to colour frame buffer device 240x67

以上两个log位于"kernel/drivers/tty/vt/vt.c"中的do_bind_con_driver函数,因为是分多次打印一行信息的,所以用grep不好搜索出来。

static int do_bind_con_driver(const struct consw *csw, int first, int last,
                           int deflt)
{
...省略部分代码...
        pr_info("Console: switching ");
        if (!deflt)
                printk("consoles %d-%d ", first+1, last+1);
        if (j >= 0) {
                struct vc_data *vc = vc_cons[j].d;

                printk("to %s %s %dx%d\n",
                       vc->vc_can_do_color ? "colour" : "mono",
                       desc, vc->vc_cols, vc->vc_rows);

                if (k >= 0) {
                        vc = vc_cons[k].d;
                        update_screen(vc);
                }
        } else
                printk("to %s\n", desc);

        retval = 0;
err:
        module_put(owner);
        return retval;
};

在do_bind_con_driver中添加“dump_stack()”将堆栈打印出来,这样就可以看到调用关系。

[    2.843140] [<ffffff800808826c>] dump_backtrace+0x0/0x220
[    2.843147] [<ffffff80080884b0>] show_stack+0x24/0x30
[    2.843156] [<ffffff80084026ec>] dump_stack+0x94/0xbc
[    2.843163] [<ffffff80084cb8d0>] do_bind_con_driver+0x3c/0x318
[    2.843168] [<ffffff80084cbf34>] do_take_over_console+0x184/0x1c8
[    2.843176] [<ffffff8008472fbc>] do_fbcon_takeover+0x78/0xe0
[    2.843180] [<ffffff8008476940>] fbcon_event_notify+0x3f8/0x7d8
[    2.843186] [<ffffff80080b90c4>] notifier_call_chain+0x70/0x90
[    2.843191] [<ffffff80080b9548>] __blocking_notifier_call_chain+0x58/0x84
[    2.843197] [<ffffff80080b95b0>] blocking_notifier_call_chain+0x3c/0x4c
[    2.843202] [<ffffff8008492380>] fb_notifier_call_chain+0x30/0x3c
[    2.843207] [<ffffff8008493ad8>] register_framebuffer+0xa8/0x278
[    2.843215] [<ffffff80084f94b0>] drm_fb_helper_initial_config+0x17c/0x320
[    2.843221] [<ffffff80085444cc>] rockchip_drm_fbdev_init+0xe4/0x118
[    2.843228] [<ffffff8008529460>] rockchip_drm_bind+0x904/0x1930
[    2.843237] [<ffffff80085a617c>] try_to_bring_up_master.part.2+0xa0/0x114
[    2.843242] [<ffffff80085a62c4>] component_master_add_with_match+0xd4/0x12c
[    2.843248] [<ffffff8008528648>] rockchip_drm_platform_probe+0x244/0x260
[    2.843254] [<ffffff80085adee4>] platform_drv_probe+0x5c/0xb0
[    2.843259] [<ffffff80085abe20>] driver_probe_device+0x260/0x3d0
[    2.843263] [<ffffff80085abfe4>] __driver_attach+0x54/0xa0
[    2.843267] [<ffffff80085a9e58>] bus_for_each_dev+0x8c/0x9c
[    2.843272] [<ffffff80085ab724>] driver_attach+0x30/0x3c
[    2.843276] [<ffffff80085ab2f4>] bus_add_driver+0x1fc/0x240
[    2.843281] [<ffffff80085acbac>] driver_register+0xa0/0xd8
[    2.843286] [<ffffff80085ade28>] __platform_driver_register+0x58/0x64
[    2.843294] [<ffffff80090a1a1c>] rockchip_drm_platform_driver_init+0x1c/0x24
[    2.843299] [<ffffff80080830b8>] do_one_initcall+0x78/0x194
[    2.843306] [<ffffff8009070e04>] kernel_init_freeable+0x21c/0x220
[    2.843314] [<ffffff8008bf2920>] kernel_init+0x18/0x100
[    2.843318] [<ffffff8008082ef0>] ret_from_fork+0x10/0x20

这里可以利用在线的代码阅读网站对上面的过程进行追踪,其中“fbcon_event_notify”这个函数在一个“Framebuffer Console”的驱动中被发现,代码位于“drivers/video/console/fbcon.c”中。这个驱动会将屏幕设置成一个控制台输出,这也就是为啥logo显示一半就黑屏了,而且仔细观察会发现在黑屏的这段时间屏幕的左上角会有光标显示。找到这个驱动对用的控制宏CONFIG_FRAMEBUFFER_CONSOLE,在defconfig中将其注释掉,接下来logo的显示就正常了。

  1. 用自己的图片后显示的logo图片颜色不正常。
    第一种情况是kernel显示颜色异常,可以尝试修改kernel/drivers/gpu/drm/rockchip/rockchip_drm_drv.c,用下面两种情况的代码都试试。
        switch (bpp) {
        case 16:
                mode_cmd.pixel_format = DRM_FORMAT_BGR565;
                break;
        case 24:
                mode_cmd.pixel_format = DRM_FORMAT_BGR888;
                break;
        case 32:
                mode_cmd.pixel_format = DRM_FORMAT_XRGB8888;
                break;
        default:
                pr_err("%s: unsupport to logo bpp %d\n", __func__, bpp);
                return NULL;
        }
                switch (bpp) {
        case 16:
                mode_cmd.pixel_format = DRM_FORMAT_RGB565;
                break;
        case 24:
                mode_cmd.pixel_format = DRM_FORMAT_RGB888;
                break;
        case 32:
                mode_cmd.pixel_format = DRM_FORMAT_XRGB8888;
                break;
        default:
                pr_err("%s: unsupport to logo bpp %d\n", __func__, bpp);
                return NULL;
        }

第二种情况:在内核编译的时候如果判断到bmp图片头的6、7字节不是0xcf和0x20如果不是编译的时候会对图片做处理。详见脚本kernel/scripts/bmpconvert。可以尝试修改self.rb_swap=0,让不要转换图片,看看能否修改错误。编译过一次的图片6、7字节会被修改,所以不会跑到这个地方。

        self.rb_swap = 0
        if self.bfReserved1 != 8399 and self.biHeight > 0:
            self.reverse_bmp_data()
            print("reverse data at first time")
        if self.bfReserved1 != 8399:
            self.rb_swap = 0				#修改的地方
            print("swap bgr to rgb at first time")
        if self.force_revers:
            self.reverse_bmp_data()
            print("reverse data by force")
        if self.force_swap:
            self.rb_swap = 1
            print("swap rb by force'")

        if self.bfReserved1 == 8399:
            self.file.close()

  • 3
    点赞
  • 14
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 6
    评论
评论 6
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

飘忽不定的bug

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值