在lk下调试屏幕,可先了解下lk的代码流程,方便接下来的调试。这里以msm8996平台为例,描述lk的代码结构。
bootable/bootloader/lk/kernel/maic.c
/* called from crt0.S */
void kmain(void) __NO_RETURN __EXTERNALLY_VISIBLE;
void kmain(void)
{
// get us into some sort of thread context
thread_init_early();
// early arch stuff
arch_early_init();
// do any super early platform initialization
platform_early_init();
// do any super early target initialization
target_early_init();
dprintf(INFO, "welcome to lk\n\n");
bs_set_timestamp(BS_BL_START);
// deal with any static constructors
dprintf(SPEW, "calling constructors\n");
call_constructors();
// bring up the kernel heap
dprintf(SPEW, "initializing heap\n");
heap_init();
__stack_chk_guard_setup();
// initialize the threading system
dprintf(SPEW, "initializing threads\n");
thread_init();
// initialize the dpc system
dprintf(SPEW, "initializing dpc\n");
dpc_init();
// initialize kernel timers
dprintf(SPEW, "initializing timers\n");
timer_init();
#if (!ENABLE_NANDWRITE)
// create a thread to complete system initialization
dprintf(SPEW, "creating bootstrap completion thread\n");
thread_resume(thread_create("bootstrap2", &bootstrap2, NULL, DEFAULT_PRIORITY, DEFAULT_STACK_SIZE));
// enable interrupts
exit_critical_section();
// become the idle thread
thread_become_idle();
#else
bootstrap_nandwrite();
#endif
}
bootstrap2
static int bootstrap2(void *arg)
{
dprintf(SPEW, "top of bootstrap2()\n");
arch_init();
// XXX put this somewhere else
#if WITH_LIB_BIO
bio_init();
#endif
#if WITH_LIB_FS
fs_init();
#endif
// initialize the rest of the platform
dprintf(SPEW, "initializing platform\n");
platform_init();
// initialize the target
dprintf(SPEW, "initializing target\n");
target_init();
dprintf(SPEW, "calling apps_init()\n");
apps_init();
return 0;
}
void aboot_init(const struct app_descriptor *app)
{
unsigned reboot_mode = 0;
/* Setup page size information for nv storage */
if (target_is_emmc_boot())
{
page_size = mmc_page_size();
page_mask = page_size - 1;
}
else
{
page_size = flash_page_size();
page_mask = page_size - 1;
}
ASSERT((MEMBASE + MEMSIZE) > MEMBASE);
read_device_info(&device);
read_allow_oem_unlock(&device);
/* Display splash screen if enabled */
#if DISPLAY_SPLASH_SCREEN
#if NO_ALARM_DISPLAY
if (!check_alarm_boot()) {
#endif
dprintf(SPEW, "Display Init: Start\n");
#if DISPLAY_HDMI_PRIMARY
if (!strlen(device.display_panel))
strlcpy(device.display_panel, DISPLAY_PANEL_HDMI,
sizeof(device.display_panel));
#endif
#if ENABLE_WBC
/* Wait if the display shutdown is in progress */
while(pm_app_display_shutdown_in_prgs());
if (!pm_appsbl_display_init_done())
target_display_init(device.display_panel);
else
display_image_on_screen();
#else
target_display_init(device.display_panel);
#endif
dprintf(SPEW, "Display Init: Done\n");
#if NO_ALARM_DISPLAY
}
#endif
#endif
target_serialno((unsigned char *) sn_buf);
dprintf(SPEW,"serial number: %s\n",sn_buf);
memset(display_panel_buf, '\0', MAX_PANEL_BUF_SIZE);
/*
* Check power off reason if user force reset,
* if yes phone will do normal boot.
*/
if (is_user_force_reset())
goto normal_boot;
/* Check if we should do something other than booting up */
if (keys_get_state(KEY_VOLUMEUP) && keys_get_state(KEY_VOLUMEDOWN))
{
dprintf(ALWAYS,"dload mode key sequence detected\n");
if (set_download_mode(EMERGENCY_DLOAD))
{
dprintf(CRITICAL,"dload mode not supported by target\n");
}
else
{
reboot_device(DLOAD);
dprintf(CRITICAL,"Failed to reboot into dload mode\n");
}
boot_into_fastboot = true;
}
if (!boot_into_fastboot)
{
if (keys_get_state(KEY_HOME) || keys_get_state(KEY_VOLUMEUP))
boot_into_recovery = 1;
if (!boot_into_recovery &&
(keys_get_state(KEY_BACK) || keys_get_state(KEY_VOLUMEDOWN)))
boot_into_fastboot = true;
}
#if NO_KEYPAD_DRIVER
if (fastboot_trigger())
boot_into_fastboot = true;
#endif
#if USE_PON_REBOOT_REG
reboot_mode = check_hard_reboot_mode();
#else
reboot_mode = check_reboot_mode();
#endif
if (reboot_mode == RECOVERY_MODE)
{
boot_into_recovery = 1;
}
else if(reboot_mode == FASTBOOT_MODE)
{
boot_into_fastboot = true;
}
else if(reboot_mode == ALARM_BOOT)
{
boot_reason_alarm = true;
}
#if VERIFIED_BOOT
#if !VBOOT_MOTA
else if (reboot_mode == DM_VERITY_ENFORCING)
{
device.verity_mode = 1;
write_device_info(&device);
}
else if (reboot_mode == DM_VERITY_LOGGING)
{
device.verity_mode = 0;
write_device_info(&device);
}
else if (reboot_mode == DM_VERITY_KEYSCLEAR)
{
if(send_delete_keys_to_tz())
ASSERT(0);
}
#endif
#endif
normal_boot:
if (!boot_into_fastboot)
{
if (target_is_emmc_boot())
{
if(emmc_recovery_init())
dprintf(ALWAYS,"error in emmc_recovery_init\n");
if(target_use_signed_kernel())
{
if((device.is_unlocked) || (device.is_tampered))
{
#ifdef TZ_TAMPER_FUSE
set_tamper_fuse_cmd();
#endif
#if USE_PCOM_SECBOOT
set_tamper_flag(device.is_tampered);
#endif
}
}
boot_linux_from_mmc();
}
else
{
recovery_init();
#if USE_PCOM_SECBOOT
if((device.is_unlocked) || (device.is_tampered))
set_tamper_flag(device.is_tampered);
#endif
boot_linux_from_flash();
}
dprintf(CRITICAL, "ERROR: Could not do normal boot. Reverting "
"to fastboot mode.\n");
}
/* We are here means regular boot did not happen. Start fastboot. */
/* register aboot specific fastboot commands */
aboot_fastboot_register_commands();
/* dump partition table for debug info */
partition_dump();
/* initialize and start fastboot */
fastboot_init(target_get_scratch_address(), target_get_max_flash_size());
#if FBCON_DISPLAY_MSG
display_fastboot_menu_thread();
#endif
}
重点关注下target_display_init(device.display_panel),这里进行屏幕的初始化。
bootable/bootloader/lk/target/msm8996/target_display.c
void target_display_init(const char *panel_name)
{
struct oem_panel_data oem;
set_panel_cmd_string(panel_name);
oem = mdss_dsi_get_oem_data();
if (!strcmp(oem.panel, NO_PANEL_CONFIG)
|| !strcmp(oem.panel, SIM_VIDEO_PANEL)
|| !strcmp(oem.panel, SIM_DUALDSI_VIDEO_PANEL)
|| !strcmp(oem.panel, SIM_CMD_PANEL)
|| !strcmp(oem.panel, SIM_DUALDSI_CMD_PANEL)
|| oem.skip) {
dprintf(INFO, "Selected panel: %s\nSkip panel configuration\n",
oem.panel);
return;
} else if ((!strcmp(oem.panel, HDMI_PANEL_NAME)) || \
((!strlen(oem.panel)) && ((board_hardware_id() == HW_PLATFORM_SBC) ||
(platform_is_apq8096_mediabox())))) {
dprintf(INFO, "%s: HDMI is primary\n", __func__);
mdss_hdmi_display_init(MDP_REV_50, (void *) HDMI_FB_ADDR);
return;
}
if (gcdb_display_init(oem.panel, MDP_REV_50, (void *)MIPI_FB_ADDR)) {
target_force_cont_splash_disable(true);
msm_display_off();
}
if (!oem.cont_splash) {
dprintf(INFO, "Forcing continuous splash disable\n");
target_force_cont_splash_disable(true);
}
}
gcdb_display_init调用pan_type = oem_panel_select(panel_name, &panelstruct, &(panel.panel_info), &dsi_video_mode_phy_db),选择具体的屏幕
int gcdb_display_init(const char *panel_name, uint32_t rev, void *base)
{
int ret = NO_ERROR;
int pan_type;
dsi_video_mode_phy_db.pll_type = DSI_PLL_TYPE_28NM;
pan_type = oem_panel_select(panel_name, &panelstruct, &(panel.panel_info),
&dsi_video_mode_phy_db);
if (pan_type == PANEL_TYPE_DSI) {
if (update_dsi_display_config())
goto error_gcdb_display_init;
target_dsi_phy_config(&dsi_video_mode_phy_db);
mdss_dsi_check_swap_status();
mdss_dsi_set_pll_src();
if (dsi_panel_init(&(panel.panel_info), &panelstruct)) {
dprintf(CRITICAL, "DSI panel init failed!\n");
ret = ERROR;
goto error_gcdb_display_init;
}
panel.panel_info.mipi.mdss_dsi_phy_db = &dsi_video_mode_phy_db;
panel.pll_clk_func = mdss_dsi_panel_clock;
panel.dfps_func = mdss_dsi_mipi_dfps_config;
panel.power_func = mdss_dsi_panel_power;
panel.pre_init_func = mdss_dsi_panel_pre_init;
panel.bl_func = mdss_dsi_bl_enable;
panel.dsi2HDMI_config = mdss_dsi2HDMI_config;
/*
* If dfps enabled, reserve fb memory to store pll
* codes and pass pll codes values to kernel.
*/
if (panel.panel_info.dfps.panel_dfps.enabled) {
panel.panel_info.dfps.dfps_fb_base = base;
base += DFPS_PLL_CODES_SIZE;
dprintf(SPEW, "dfps base=0x%p,d, fb_base=0x%p!\n",
panel.panel_info.dfps.dfps_fb_base, base);
}
panel.fb.base = base;
panel.fb.width = panel.panel_info.xres;
panel.fb.height = panel.panel_info.yres;
panel.fb.stride = panel.panel_info.xres;
panel.fb.bpp = panel.panel_info.bpp;
panel.fb.format = panel.panel_info.mipi.dst_format;
} else if (pan_type == PANEL_TYPE_EDP) {
mdss_edp_panel_init(&(panel.panel_info));
/* prepare func is set up at edp_panel_init */
panel.clk_func = mdss_edp_panel_clock;
panel.power_func = mdss_edp_panel_power;
panel.bl_func = mdss_edp_bl_enable;
panel.fb.format = FB_FORMAT_RGB888;
} else {
dprintf(CRITICAL, "Target panel init not found!\n");
ret = ERR_NOT_SUPPORTED;
goto error_gcdb_display_init;
}
panel.fb.base = base;
panel.mdp_rev = rev;
ret = msm_display_init(&panel);
error_gcdb_display_init:
display_enable = ret ? 0 : 1;
return ret;
}
bootable/bootloader/lk/target/msm8996/oem_panel.c,找不到面板会根据平台有一个默认的屏幕配置。
int oem_panel_select(const char *panel_name, struct panel_struct *panelstruct,
struct msm_panel_info *pinfo,
struct mdss_dsi_phy_ctrl *phy_db)
{
uint32_t hw_id = board_hardware_id();
int32_t panel_override_id;
uint32_t ret = 0;
phy_db->pll_type = DSI_PLL_TYPE_THULIUM;
pinfo->has_bridge_chip = false;
if (panel_name) {
panel_override_id = panel_name_to_id(supp_panels,
ARRAY_SIZE(supp_panels), panel_name);
if (panel_override_id < 0) {
dprintf(CRITICAL, "Not able to search the panel:%s\n",
panel_name);
} else if (panel_override_id < UNKNOWN_PANEL) {
/* panel override using fastboot oem command */
panel_id = panel_override_id;
dprintf(INFO, "OEM panel override:%s\n",
panel_name);
goto panel_init;
}
}
switch (hw_id) {
case HW_PLATFORM_MTP:
panel_id = NT35596_1080P_VIDEO_PANEL;
break;
case HW_PLATFORM_FLUID:
case HW_PLATFORM_SURF:
panel_id = SHARP_WQXGA_DUALDSI_VIDEO_PANEL;
break;
case HW_PLATFORM_QRD:
panel_id = R69007_WQXGA_CMD_PANEL;
break;
case HW_PLATFORM_LIQUID:
panel_id = JDI_4K_DUALDSI_VIDEO_NOFBC_PANEL;
break;
case HW_PLATFORM_DRAGON:
panel_id = TRULY_FWVGA_VIDEO_PANEL;
break;
case HW_PLATFORM_ADP:
panel_id = ADV7533_720P_VIDEO_PANEL;
pinfo->has_bridge_chip = true;
break;
default:
dprintf(CRITICAL, "Display not enabled for %d HW type\n"
, hw_id);
return PANEL_TYPE_UNKNOWN;
}
panel_init:
if (pinfo->has_bridge_chip) { //i2c通信部分,如果该屏幕需要进行i2c初始化
ret = oem_panel_bridge_chip_init(pinfo);
if (ret) {
dprintf(CRITICAL, "Error in initializing bridge chip\n");
return ret;
}
}
return init_panel_data(panelstruct, pinfo, phy_db);
}
这里可以修改高通原有的屏幕参数,也可以自己新建一款屏幕。在bootable/bootloader/lk/dev/gcdb/display/include
有具体的屏幕参数。
我们只需适配自己的屏幕,基本上就可以在lk下正常显示了(屏幕的参数最好仔细确认,因为平台的差异会导致屏幕的参数有细微的变化)。