android屏幕启动流程
点亮一个新屏幕,下面以8909-x26的屏幕为例。
启动引导部分:
一、添加对应的.h文件
首先添加一个.h头文件,命名为panel_ili9806e_fwvga_hsd_helitai_x26_video.h,该文件放在路径/bootable/bootloader/lk/dev/gcdb/include/下面。因为这里包含了各种型号的屏幕的头文件,也就是初始化代码,并且放在了启动引导目录。根据命名,知道该屏幕的IC(芯片)是ili9806e,屏幕分辨率是fwvga,玻璃是HSD,模组厂是helitai(合力泰)。
屏幕工作的关键是芯片、玻璃、模组厂!
在头文件里面会对屏幕进行初始化,如backlight(背光),lane(通道),color(颜 {MOD}),timing_information(定时)等。
/*---------------------------------------------------------------------------*/
/* Backlight setting */
/*---------------------------------------------------------------------------*/
static struct backlight ili9806e_fwvga_hsd_helitai_x26_video_backlight = {
1, 1, 4095, 100, 1, "PMIC_8941"
};
/*---------------------------------------------------------------------------*/
/* Lane configuration */
/*---------------------------------------------------------------------------*/
static struct lane_configuration ili9806e_fwvga_hsd_helitai_x26_video_lane_config = {
2, 1, 1, 1, 0, 0, 0
};
/*---------------------------------------------------------------------------*/
/* Panel color information */
/*---------------------------------------------------------------------------*/
static struct color_info ili9806e_fwvga_hsd_helitai_x26_video_color = {
24, 0, 0xff, 0, 0, 0
};
static char ili9806e_fwvga_hsd_helitai_x26_video_on_cmd0[] = {
0x06, 0x00, 0x39, 0xC0,
0xFF, 0xFF, 0x98, 0x06,
0x04, 0x01, 0xFF, 0xFF,
};
......
二、oem_penel.c文件添加自己的新屏幕(路径:bootable/bootloader/lk/target/msm8909_x26_q1/)
(1).首先添加屏幕初始化的头文件”panel_ili9806e_fwvga_hsd_helitai_x26_video.h“,即:
#include “include/panel_ili9806e_fwvga_hsd_helitai_x26_video.h”.
(2).在枚举类型中添加自己的新屏幕:
其中该枚举类型在文件mipi_panel_reg_id.h中(路径:./bootable/bootloader/lk/platform/msm_shared/include/)
enum {
......
ILI9806E_FWVGA_HSD_HELITAI_x26_VIDEO_PANEL,//add your panel.
UNKNOWN_PANEL
};
(3).在函数init_panel_data()中,添加自己的板子的case语句,即新屏幕的数据初始化。
case ILI9806E_FWVGA_HSD_HELITAI_x26_VIDEO_PANEL:
panelstruct->paneldata = &ili9806e_fwvga_hsd_helitai_x26_video_panel_data;
panelstruct->panelres = &ili9806e_fwvga_hsd_helitai_x26_video_panel_res;
panelstruct->color = &ili9806e_fwvga_hsd_helitai_x26_video_color;
panelstruct->videopanel = &ili9806e_fwvga_hsd_helitai_x26_video_video_panel;
panelstruct->commandpanel = &ili9806e_fwvga_hsd_helitai_x26_video_command_panel;
panelstruct->state = &ili9806e_fwvga_hsd_helitai_x26_video_state;
panelstruct->laneconfig = &ili9806e_fwvga_hsd_helitai_x26_video_lane_config;
panelstruct->paneltiminginfo = &ili9806e_fwvga_hsd_helitai_x26_video_timing_info;
panelstruct->panelresetseq = &ili9806e_fwvga_hsd_helitai_x26_video_reset_seq;
panelstruct->backlightinfo = &ili9806e_fwvga_hsd_helitai_x26_video_backlight;
pinfo->mipi.panel_cmds = ili9806e_fwvga_hsd_helitai_x26_video_on_command;
pinfo->mipi.num_of_panel_cmds = ARRAY_SIZE(ili9806e_fwvga_hsd_helitai_x26_video_on_command);
memcpy(phy_db->timing,ili9806e_fwvga_hsd_helitai_x26_video_timings, TIMING_SIZE);
pinfo->mipi.signature = ILI9806E_FWVGA_HSD_HELITAI_x26_VIDEO_SIGNATURE;
break;
(4).在函数oem_panel_select()中,必须让控制板的id选择自己新添加的,否则,开机屏幕不亮。
case HW_PLATFORM_QRD:
if (lcm_gpio_id == 1) {
panel_id = ILI9806E_FWVGA_HSD_HUASHI_VIDEO_PANEL;
} else {
panel_id = ILI9806E_FWVGA_HSD_HELITAI_x26_VIDEO_PANEL;//add
your panel
}
break;
到此,lk(little kernel)部分,屏幕相关的工作就完成了!
程序执行流程:
(1)当按下开机键,程序自然就是从main函数开始执行,不过main是C 语言的叫法。(具体可以参见BIOS过程)。
(2)程序运行到APP_START(aboot)
.init = aboot_init,
APP_END
就会调用aboot_init()函数。aboot意为“引导”。
(2)引导的时候自然有屏幕的启动和初始化,aboot_init()函数调用target_display_init()函数,条件是DISPLAY_SPLASH_SCREEN为1。
(3)在函数target_display_init()最后,ret = gcdb_display_init();程序自然跳转到函数gcdb_display_init()
(4)在gcdb_display_init中首先调用oem_panel_select()函数,然后又跳转到oem_panel_select函数。
hw_id的值由board_hardware_id()返回,返回了11,然后进入qrd路线。107行知lcm_gpio_id=0,所以在else分支(lcm_gpio_id =0)下添加自己的屏幕,即将panel_id设置为ILI9806E_FWVGA_HSD_HELITAI_x26
_VIDEO_PANEL.(panel_id = ILI9806E_FWVGA_HSD_HELITAI_x26_VIDEO_PANEL)。
(5)oem_panel_select()函数最后return init_panel_data(),程序进入init_panel_data(),
(6)在init_panel_data()中已经添加了自己的case语句,根据第109行,Func:oem_panel_select panel_id = 17 ,说明,已经选择了添加的新屏幕来初始化,因为枚举变量中自己新添加的屏幕(ILI9806E_FWVGA_HSD_HELITAI_x26_VIDEO_PANEL)刚好是第17个。这样panel_ili9806e_fwvga_hsd_helitai_x26_video.h文件参数全部用到。最后返回pan_type.
(7)程序继续在oem_panel_select()中,也返回pan_type,然后退出oem_panel_select()函数。回到gcdb_display_init()中,接收了pan_type,所以日志117行打印出pan_type是PANEL_TYPE_DSI。
(8)在gcdb_display_init中自然初始化DSI下的项目,如:
panel.fb.width,
panel.fb.height,
panel.fb.stride,
panel.fb.bpp
...
(9)第117行,display_enable = 1,ret = 0;gcdb_display_init()返回,说明屏幕bootloader部分完成,新屏幕可用,成功返回0.然后回到函数target_display_init()。
(10)第118行, in function:target_display_init,line:350,ret = 0.说明 target_display_init函数也成功结束。
(11)到此开机中屏幕的点亮结束了。
编译bootloader:make aboot -j6
烧写bootloader:fastboot flash aboot emmc_appsboot.mbn
附log:
......
106 [1450][1450]#mipi_get_lcm_pin_id().pin[8]_status = 0
107 ------
Func:oem_panel_select
lcm_gpio_id = 0
----------
108 hw_id = 11
109 -Func:oem_panel_select panel_id = 17 -------
110 in function:gcdb_display_init,line:379,panel_type is PANEL_TYPE_DSI
111 in function:gcdb_display_init,line:386,panel init successfully!
112 [1540][1540] Config MIPI_VIDEO_PANEL.
113 [1690][1690] Panic Lut0 la90000 Lut1 ff Robest 0
114 [1700][1700] Turn on MIPI_VIDEO_PANEL.
115 [1720][1720] Video lane tested successfully
116 in function:gcdb_display_init,line:419,panel_type is PANEL_TYPE_DSI
117 display_enable = 1,ret = 0
118 in function:target_display_init,line:350,ret = 0
......
内核部分:
三、(1)在路径kernel/arch/arm/boot/dts/msm8909_x26_q1下添加内核配置文件: dsi-panel-ili9806e-fwvga-hsd-helitai-x26-video.dtsi.
该文件是屏幕的配置文件,屏幕休眠唤醒时会走此文件。配置项目包括:
mdss-dsi-h-back-porch、mdss-dsi-h-front-porch、mdss-dsi-h-pulse-width、mdss-dsi-h-sync-skew等。
具体可参考文件:kernel/Documentation/devicetree/bindings/fb
其中在文件开头有一变量dsi_ili9806e_fwvga_hsd_hlt_x26_vid,其值必须和启动引导部分的结构体ili9806e_fwvga_hsd_helitai_x26_video_panel_data的第一个成员相同。
引导部分和内核相关联就是这个panel_node_id,这样屏幕待机之后唤醒就会找到引导时候的初始化屏幕路线。引导部分和内核部分的桥梁就是panel_node_id(变量dsi_ili9806e_fwvga_hsd_hlt_x26_vid),他写进cmd-line,最后传给内核。
(2)在文件msm8909-mdss-panels.dtsi添加头文件:
即添加一行代码:#include "dsi-panel-ili9806e-fwvga-hsd-helitai-x26-video.dtsi"
其中该文件是屏幕的配置文件
(3)添加自己的屏幕(注意语法,不要漏掉分号):
&dsi_ili9806e_fwvga_hsd_hlt_x26_vid {
qcom,cont-splash-enabled;
};
(4)将id设置为自己的id,这一步很重要,否则,开机屏幕正常,但是一旦休眠,再次唤醒手机,手机就是白屏,因为,唤醒虽然走的是开机的初始化路线,但是在这里却进入了另一种型号的屏幕了!
&mdss_dsi0 {
/*qcom,dsi-pref-prim-pan = <&dsi_ili9806e_fwvga_video>;*/
qcom,dsi-pref-prim-pan = <&dsi_ili9806e_fwvga_hsd_hlt_x26_vid>;//在这一行改为自己的屏幕
pinctrl-names = "mdss_default", "mdss_sleep";
......
};
到此,内核部分修改完成!
编译:make bootimage -j6
烧写:sudo fastboot flash boot boot.img