android LCM启动流程——LK(转载)

本文转载自:https://blog.csdn.net/u010787514/article/details/82632684

目录

一、整体流程概述

二、详细流程分析

1、LK中LCD的唯一入口

target_display_init()

gcdb_display_init()

2、屏幕识别&获取初始化参数信息

oem_panel_select()

dsi_panel_init

初始化panel结构体

3、屏幕进一步初始化及点亮

mdss_dsi_panel_power()

mdss_dsi_panel_clock

msm_fb_alloc()&fbcon_setup(&(panel->fb));

display_image_on_screen()

msm_display_config

msm_display_on()

mdss_dsi_bl_enable


一、整体流程概述

    首先从aboot_init开始,去走LCD的初始化流程,在aboot中判断是哪种存储方式和启动方式,然后进入LCD在LK的唯一初始化入口——target_display_init。然后会调用对应的gcdb_display_init方法。判断是哪个屏,并初始化对应的参数,以及对其进行上电,最终点亮屏幕。与此同时在点亮之后,会在aboot中将对应的屏幕信息写入到pbuf中,以便kernel能够获取到对应的屏幕信息,然后加载参数并点亮。如下是简单的流程图:

android LCM启动流程——LK(转载)_第1张图片

二、详细流程分析

1、LK中LCD的唯一入口

首先我们从aboot_init方法开始,看如何一步步启动LCD:


   
   
   
   
  1. void aboot_init(const struct app_descriptor *app)
  2. {
  3. ... ...
  4. target_display_init(device.display_panel);
  5. ... ...
  6. }

aboot中省略了系统系统的前期准备以及相关的启动模式,这部分后续文章在进行分析,当前继续分析LCD启动相关。

这里就可以看到我们的入口方法:target_display_init()。

  • target_display_init()

    根据不同的平台,此处调用的target_display_init()也是不同的,我们以MSM8909为例。此处调用的是msm8909目录下的Target_display.c文件。我们开始看下target_display_init()的调用流程:


   
   
   
   
  1. void target_display_init(const char *panel_name)
  2. {
  3. ... ...
  4. if (target_splash_disable()) //如果splash_disable的宏开启,则LK阶段不再初始化LCD,参数等的初始化均在kernel阶段进行
  5. return;
  6. do {
  7. target_force_cont_splash_disable( false);
  8. ret = gcdb_display_init(oem.panel, MDP_REV_305, MIPI_FB_ADDR);
  9. if (!ret || ret == ERR_NOT_SUPPORTED) {
  10. break;
  11. } else {
  12. target_force_cont_splash_disable( true);
  13. msm_display_off();
  14. }
  15. } while (++panel_loop <= oem_panel_max_auto_detect_panels());
  16. ... ...
  17. }
  • gcdb_display_init()

    target_display_init方法中最关键的部分即do...while结构。这里会对LCD继续做初始化,即gcdb_display_init方法。该方法在gcdb_display.c (bootable\bootloader\lk\dev\gcdb\display),我们先来看下该方法的实现:


   
   
   
   
  1. int gcdb_display_init(const char *panel_name, uint32_t rev, void *base)
  2. {
  3. int ret = NO_ERROR;
  4. int pan_type;
  5. dsi_video_mode_phy_db.pll_type = DSI_PLL_TYPE_28NM;
  6. //通过读取对应的ID或者mipi回读判断是哪块屏,并将屏幕信息保存在pinfo结构体中
  7. pan_type = oem_panel_select(panel_name, &panelstruct, &(panel.panel_info),
  8. &dsi_video_mode_phy_db);
  9. if (pan_type == PANEL_TYPE_DSI) {
  10. if (update_dsi_display_config())
  11. goto error_gcdb_display_init;
  12. target_dsi_phy_config(&dsi_video_mode_phy_db);
  13. mdss_dsi_check_swap_status();
  14. mdss_dsi_set_pll_src();
  15. if (dsi_panel_init(&(panel.panel_info), &panelstruct)) {
  16. dprintf(CRITICAL, "DSI panel init failed!\n");
  17. ret = ERROR;
  18. goto error_gcdb_display_init;
  19. }
  20. panel.panel_info.mipi.mdss_dsi_phy_db = &dsi_video_mode_phy_db;
  21. panel.pll_clk_func = mdss_dsi_panel_clock;
  22. panel.dfps_func = mdss_dsi_mipi_dfps_config;
  23. panel.power_func = mdss_dsi_panel_power;
  24. panel.pre_init_func = mdss_dsi_panel_pre_init;
  25. panel.bl_func = mdss_dsi_bl_enable;
  26. panel.dsi2HDMI_config = mdss_dsi2HDMI_config;
  27. /*
  28. * Reserve fb memory to store pll codes and pass
  29. * pll codes values to kernel.
  30. */
  31. panel.panel_info.dfps.dfps_fb_base = base;
  32. base += DFPS_PLL_CODES_SIZE;
  33. panel.fb.base = base;
  34. dprintf(SPEW, "dfps base=0x%p,d, fb_base=0x%p!\n",
  35. panel.panel_info.dfps.dfps_fb_base, base);
  36. panel.fb.width = panel.panel_info.xres;
  37. panel.fb.height = panel.panel_info.yres;
  38. panel.fb.stride = panel.panel_info.xres;
  39. panel.fb.bpp = panel.panel_info.bpp;
  40. panel.fb.format = panel.panel_info.mipi.dst_format;
  41. } else if (pan_type == PANEL_TYPE_EDP) {
  42. mdss_edp_panel_init(&(panel.panel_info));
  43. /* prepare func is set up at edp_panel_init */
  44. panel.clk_func = mdss_edp_panel_clock;
  45. panel.power_func = mdss_edp_panel_power;
  46. panel.bl_func = mdss_edp_bl_enable;
  47. panel.fb.format = FB_FORMAT_RGB888;
  48. } else {
  49. dprintf(CRITICAL, "Target panel init not found!\n");
  50. ret = ERR_NOT_SUPPORTED;
  51. goto error_gcdb_display_init;
  52. }
  53. panel.fb.base = base;
  54. panel.mdp_rev = rev;
  55. //通过获取到的屏幕信息继续进行初始化
  56. ret = msm_display_init(&panel);
  57. error_gcdb_display_init:
  58. display_enable = ret ? 0 : 1;
  59. return ret;
  60. }

    可以看到该方法主要有四个动作:

    ① 选取对应的屏幕:dsi_panel_init()

        pan_type = oem_panel_select(panel_name, &panelstruct, &(panel.panel_info),
                 &dsi_video_mode_phy_db);

    ② 将初始化信息保存在pinfo中:dsi_panel_init()

        dsi_panel_init(&(panel.panel_info), &panelstruct)

    ③ 根据panel type初始化panel结构体

    ④ 根据上述信息进一步初始化LCD:msm_display_init()

        ret = msm_display_init(&panel);

2、屏幕识别&获取初始化参数信息

  • oem_panel_select()

    该方法同样根据平台不同会各自选取对应的执行文件,我们同样使用MSM8909对应的Oem_panel.c。此方法会根据硬件ID或者回读MIPI的方法来识别不同的屏。然后将识别到的屏幕信息保存在panelstruct结构体中。


   
   
   
   
  1. int oem_panel_select(const char *panel_name, struct panel_struct *panelstruct,
  2. struct msm_panel_info *pinfo,
  3. struct mdss_dsi_phy_ctrl *phy_db)
  4. {
  5. uint32_t hw_id = board_hardware_id();
  6. uint32_t platform_subtype = board_hardware_subtype();
  7. int32_t panel_override_id;
  8. if (panel_name) {
  9. panel_override_id = panel_name_to_id(supp_panels,
  10. ARRAY_SIZE(supp_panels), panel_name);
  11. if (panel_override_id < 0) {
  12. dprintf(CRITICAL, "Not able to search the panel:%s\n",
  13. panel_name);
  14. } else if (panel_override_id < UNKNOWN_PANEL) {
  15. /* panel override using fastboot oem command */
  16. panel_id = panel_override_id;
  17. dprintf(INFO, "OEM panel override:%s\n",
  18. panel_name);
  19. goto panel_init;
  20. }
  21. }
  22. if((panel_id=switch_panel_id())==UNKNOWN_PANEL) //获取屏幕ID
  23. {
  24. return PANEL_TYPE_UNKNOWN;
  25. }
  26. special_panel = panel_id;
  27. panel_init:
  28. phy_db->regulator_mode = DSI_PHY_REGULATOR_LDO_MODE;
  29. return init_panel_data(panelstruct, pinfo, phy_db); //获取配置参数
  30. }

    ① 首先我们来看下如何识别不同的LCD:switch_panel_id()


   
   
   
   
  1. /*
  2. * switch panel id by id0 and id1
  3. */
  4. int switch_panel_id(void)
  5. {
  6. int lcd_id0;
  7. int lcd_id1;
  8. gpio_tlmm_config(panel_id0.pin_id, 0,
  9. panel_id0.pin_direction, panel_id0.pin_pull,
  10. panel_id0.pin_strength, panel_id0.pin_state);
  11. gpio_tlmm_config(panel_id1.pin_id, 0,
  12. panel_id1.pin_direction, panel_id1.pin_pull,
  13. panel_id1.pin_strength, panel_id1.pin_state);
  14. //mdelay(10);
  15. lcd_id1= 1;
  16. lcd_id0= 1;
  17. lcd_id1=gpio_status(panel_id1.pin_id); //获取gpio状态
  18. lcd_id0=gpio_status(panel_id0.pin_id);
  19. dprintf(INFO, "lancelot lcd_id0=%d.\n",lcd_id0);
  20. dprintf(INFO, "lancelot lcd_id1=%d.\n",lcd_id1);
  21. if((lcd_id1 == 1)&&(lcd_id0 == 0)){
  22. return JD9365_STARRY_VIDEO_PANEL;
  23. } else{
  24. return NT35521Z_INX101_VIDEO_PANEL;
  25. }
  26. }

    此处给出的是通过两个硬件ID脚的状态组合进行识别的。即ID0和ID1。分别有高、低两种状态。两个ID脚的组合可以实现四种状态(00,01,10,11),也就是说我们足够识别四种屏。当然硬件上首先要能够进行区分。

    ② 区分panel id后,我们就可以根据panel id获取不同的配置参数信息:init_panel_data()


   
   
   
   
  1. static int init_panel_data(struct panel_struct *panelstruct,
  2. struct msm_panel_info *pinfo,
  3. struct mdss_dsi_phy_ctrl *phy_db)
  4. {
  5. int pan_type = PANEL_TYPE_DSI; //panel type
  6. switch (panel_id) {
  7. ... ...
  8. case NT35521Z_INX101_VIDEO_PANEL:
  9. panelstruct->paneldata = &nt35521z_inx101_video_panel_data;
  10. panelstruct->panelres = &nt35521z_inx101_video_panel_res;
  11. panelstruct->color = &nt35521z_inx101_video_color ;
  12. panelstruct->videopanel = &nt35521z_inx101_video_video_panel ;
  13. panelstruct->commandpanel = &nt35521z_inx101_video_command_panel ;
  14. panelstruct->state = &nt35521z_inx101_video_state;
  15. panelstruct->laneconfig = &nt35521z_inx101_video_lane_config;
  16. panelstruct->paneltiminginfo
  17. = &nt35521z_inx101_video_timing_info;
  18. panelstruct->panelresetseq
  19. = &nt35521z_inx101_video_reset_seq;
  20. panelstruct->backlightinfo = &nt35521z_inx101_video_backlight;
  21. pinfo->mipi.panel_on_cmds
  22. = nt35521z_inx101_video_on_command;
  23. pinfo->mipi.num_of_panel_on_cmds
  24. = NT35521Z_INX101_VIDEO_ON_COMMAND;
  25. pinfo->mipi.panel_off_cmds
  26. = nt35521z_inx101_video_off_command;
  27. pinfo->mipi.num_of_panel_off_cmds
  28. = NT35521Z_INX101_VIDEO_OFF_COMMAND;
  29. memcpy(phy_db->timing,
  30. nt35521z_inx101_video_timings, TIMING_SIZE);
  31. break;
  32. ... ...
  33. }
  34. return pan_type;
  35. }

    init_panel_data()初始化panel数据,主要初始化panel_struct结构体数据,然后返回panel类型PANEL_TYPE_DSI(还有EDP和HDMI格式)。据对应的panel_id值将对应的屏幕参数赋值给panelstruct结构体。此结构体对应/dsi-panel-xxx-video.dtsi文件,此结构体主要成员如下:


   
   
   
   
  1. struct panel_struct {
  2. struct panel_config *paneldata; //基本参数信息
  3. struct panel_resolution *panelres; //Panel的分辨率、时序参数、极性等数据
  4. struct color_info *color;
  5. struct videopanel_info *videopanel;
  6. struct commandpanel_info *commandpanel;
  7. struct command_state *state;
  8. struct lane_configuration *laneconfig; //这里可看出只支持到4lane,支持的lane对应的state为1,否则为0
  9. struct panel_timing *paneltiminginfo;
  10. struct panel_reset_sequence *panelresetseq; //对应设备树文件的qcom,mdss-dsi-reset-sequence =<1 20>, <0 20>, <1 20>;这里可让pin状态及演示多久后再修改pin状态。
  11. struct backlight *backlightinfo;
  12. struct fb_compression fbcinfo;
  13. struct topology_config *config;
  14. };
  15. struct backlight {
  16. uint16_t bl_interface_type; //背光控制方式
  17. uint16_t bl_min_level; //背光最小值
  18. uint16_t bl_max_level; //背光最大值
  19. uint16_t bl_step; //间隔值
  20. uint16_t bl_pmic_controltype;
  21. char *bl_pmic_model;
  22. };
  • dsi_panel_init

    panel_display.c (bootable\bootloader\lk\dev\gcdb\display)

    根据panel_info和panelstruct将对应屏幕的参数初始化到pinfo中。


   
   
   
   
  1. int dsi_panel_init(struct msm_panel_info *pinfo,
  2. struct panel_struct *pstruct)
  3. {
  4. int ret = NO_ERROR;
  5. /* Resolution setting*/
  6. pinfo->xres = pstruct->panelres->panel_width;
  7. pinfo->yres = pstruct->panelres->panel_height;
  8. pinfo->lcdc.h_back_porch = pstruct->panelres->hback_porch;
  9. pinfo->lcdc.h_front_porch = pstruct->panelres->hfront_porch;
  10. pinfo->lcdc.h_pulse_width = pstruct->panelres->hpulse_width;
  11. pinfo->lcdc.v_back_porch = pstruct->panelres->vback_porch;
  12. pinfo->lcdc.v_front_porch = pstruct->panelres->vfront_porch;
  13. pinfo->lcdc.v_pulse_width = pstruct->panelres->vpulse_width;
  14. pinfo->lcdc.hsync_skew = pstruct->panelres->hsync_skew;
  15. pinfo->border_top = pstruct->panelres->vtop_border;
  16. pinfo->border_bottom = pstruct->panelres->vbottom_border;
  17. pinfo->border_left = pstruct->panelres->hleft_border;
  18. pinfo->border_right = pstruct->panelres->hright_border;
  19. ... ...
  20. }
  • 初始化panel结构体

    初始化panel全局变量的其他结构体成员


   
   
   
   
  1. panel.panel_info.mipi.mdss_dsi_phy_db = &dsi_video_mode_phy_db;
  2. panel.pll_clk_func = mdss_dsi_panel_clock;
  3. panel.dfps_func = mdss_dsi_mipi_dfps_config;
  4. panel.power_func = mdss_dsi_panel_power;
  5. panel.pre_init_func = mdss_dsi_panel_pre_init;
  6. panel.bl_func = mdss_dsi_bl_enable;
  7. panel.dsi2HDMI_config = mdss_dsi2HDMI_config;
  8. /*
  9. * Reserve fb memory to store pll codes and pass
  10. * pll codes values to kernel.
  11. */
  12. panel.panel_info.dfps.dfps_fb_base = base;
  13. base += DFPS_PLL_CODES_SIZE;
  14. panel.fb.base = base;
  15. dprintf(SPEW, "dfps base=0x%p,d, fb_base=0x%p!\n",
  16. panel.panel_info.dfps.dfps_fb_base, base);
  17. panel.fb.width = panel.panel_info.xres;
  18. panel.fb.height = panel.panel_info.yres;
  19. panel.fb.stride = panel.panel_info.xres;
  20. panel.fb.bpp = panel.panel_info.bpp;
  21. panel.fb.format = panel.panel_info.mipi.dst_format;

3、屏幕进一步初始化及点亮

    获取到对应的屏幕信息以及参数后,会调用msm_display_init方法,进一步的为屏幕的点亮做初始化的动作。实际在该方法中就开始对屏幕进行上电、第一帧显示动画、背光灯的进行控制。


   
   
   
   
  1. int msm_display_init(struct msm_fb_panel_data *pdata)
  2. {
  3. int ret = NO_ERROR;
  4. ... ...
  5. /* Turn on panel 给panel上电*/
  6. if (pdata->power_func)
  7. ret = pdata->power_func( 1, &(panel->panel_info));
  8. ... ...
  9. /* Enable clock 使能CLK*/
  10. if (pdata->clk_func)
  11. ret = pdata->clk_func( 1, &(panel->panel_info));
  12. ... ...
  13. //调用calculate_clock_config(pinfo)计算时钟配置和调用target_panel_clock(enable, pinfo)配置目标panel的时钟。
  14. if (pdata->pll_clk_func)
  15. ret = pdata->pll_clk_func( 1, &(panel->panel_info));
  16. ... ...
  17. //为帧缓冲器(frame buffer)分配内存。
  18. ret = msm_fb_alloc(&(panel->fb));
  19. if (ret)
  20. goto msm_display_init_out;
  21. fbcon_setup(&(panel->fb));
  22. display_image_on_screen(); //调用fetch_image_from_partition()从splash分区获取lk logo图片,如果splash分区没有满足要求的数据,就显示默认的logo。
  23. ... ...
  24. ret = msm_display_config(); //根据pinfo->type,比如我们这里是MIPI_VIDEO_PANEL来配置msm平台display,配置时还需要根据MDP(MobileDisplay processor)的版本来调用对应的config函数
  25. if (ret)
  26. goto msm_display_init_out;
  27. ret = msm_display_on();
  28. if (ret)
  29. goto msm_display_init_out;
  30. if (pdata->post_power_func)
  31. ret = pdata->post_power_func( 1);
  32. if (ret)
  33. goto msm_display_init_out;
  34. /* Turn on backlight */
  35. if (pdata->bl_func)
  36. ret = pdata->bl_func( 1);
  37. if (ret)
  38. goto msm_display_init_out;
  39. msm_display_init_out:
  40. return ret;
  41. }

通过上述方法可以看到,在这里就可以看到第一帧画面了。我们来拆分下msm_display_init方法,看他分别作了哪些动作。

  • mdss_dsi_panel_power()


   
   
   
   
  1. static int mdss_dsi_panel_power(uint8_t enable,
  2. struct msm_panel_info *pinfo)
  3. {
  4. int ret = NO_ERROR;
  5. if (enable) {
  6. ret = target_ldo_ctrl(enable, pinfo);
  7. if (ret) {
  8. dprintf(CRITICAL, "LDO control enable failed\n");
  9. return ret;
  10. }
  11. ... ...
  12. /* Panel Reset */
  13. if (!panelstruct.paneldata->panel_lp11_init) {
  14. ret = mdss_dsi_panel_reset(enable);
  15. if (ret) {
  16. dprintf(CRITICAL, "panel reset failed\n");
  17. return ret;
  18. }
  19. }
  20. dprintf(SPEW, "Panel power on done\n");
  21. } else {
  22. /* Disable panel and ldo */
  23. ret = mdss_dsi_panel_reset(enable);
  24. if (ret) {
  25. dprintf(CRITICAL, "panel reset disable failed\n");
  26. return ret;
  27. }
  28. ret = target_ldo_ctrl(enable, pinfo);
  29. if (ret) {
  30. dprintf(CRITICAL, "ldo control disable failed\n");
  31. return ret;
  32. }
  33. dprintf(SPEW, "Panel power off done\n");
  34. }
  35. return ret;
  36. }

    target_ldo_ctrl()--->regulator_enable()给L2、L6和L17供电。另外是否会进行reset,取决于我们在dtsi中给lp11附的值。

  • mdss_dsi_panel_clock

    调用calculate_clock_config(pinfo)计算时钟配置和调用target_panel_clock(enable, pinfo)配置目标panel的时钟。


   
   
   
   
  1. static uint32_t mdss_dsi_panel_clock(uint8_t enable,
  2. struct msm_panel_info *pinfo)
  3. {
  4. uint32_t ret = NO_ERROR;
  5. ret = calculate_clock_config(pinfo);
  6. if (ret)
  7. dprintf(CRITICAL, "Clock calculation failed\n");
  8. else
  9. ret = target_panel_clock(enable, pinfo);
  10. return ret;
  11. }
  • msm_fb_alloc()&fbcon_setup(&(panel->fb));

    为帧缓冲器(frame buffer)分配内存。

  • display_image_on_screen()

    调用fetch_image_from_partition()从splash分区获取lk logo图片,如果splash分区没有满足要求的数据,就显示默认的logo。


   
   
   
   
  1. void display_image_on_screen(void)
  2. {
  3. #if DISPLAY_TYPE_MIPI
  4. int fetch_image_from_partition();
  5. if (fetch_image_from_partition() < 0) {
  6. display_default_image_on_screen();
  7. } else {
  8. /* data has been put into the right place */
  9. fbcon_flush();
  10. }
  11. #else
  12. display_default_image_on_screen();
  13. #endif
  14. }
  • msm_display_config

    ① mdss_dsi_phy_init()

    如果有两个MIPI DSI接口MIPI_DSI0和MIPI_DSI1就调用两次mdss_dsi_phy_init(),msm8909只有MIPI_DSI0,MSM8994等有两个DSI接口。

    ② mdss_dsi_host_init()

    初始化DSI接口的host控制器。

    ③ mdss_dsi_panel_pre_init()

    根据lp11的值判定是否走reset


   
   
   
   
  1. case MIPI_VIDEO_PANEL:
  2. dprintf(INFO, "Config MIPI_VIDEO_PANEL.\n");
  3. mdp_rev = mdp_get_revision();
  4. if (mdp_rev == MDP_REV_50 || mdp_rev == MDP_REV_304 ||
  5. mdp_rev == MDP_REV_305)
  6. ret = mdss_dsi_config(panel);
  7. else
  8. ret = mipi_config(panel);
  9. if (ret)
  10. goto msm_display_config_out;
  11. if (pinfo->early_config)
  12. ret = pinfo->early_config(( void *)pinfo);
  13. ret = mdp_dsi_video_config(pinfo, &(panel->fb));
  14. if (ret)
  15. goto msm_display_config_out;
  16. break;
  • msm_display_on()


   
   
   
   
  1. int msm_display_on()
  2. {
  3. ... ...
  4. case MIPI_VIDEO_PANEL:
  5. dprintf(INFO, "Turn on MIPI_VIDEO_PANEL.\n");
  6. ret = mdp_dsi_video_on(pinfo);
  7. if (ret)
  8. goto msm_display_on_out;
  9. ret = mdss_dsi_post_on(panel);
  10. if (ret)
  11. goto msm_display_on_out;
  12. ret = mipi_dsi_on(pinfo);
  13. if (ret)
  14. goto msm_display_on_out;
  15. break;
  16. ... ...
  17. }

    ① 调用mdp_dsi_video_on()使能DSI VIDEO

    ② mdss_dsi_post_on()使用初始化命令来初始化panel,对应qcom,mdss-dsi-on-command部分。


   
   
   
   
  1. int mdss_dsi_post_on(struct msm_fb_panel_data *panel)
  2. {
  3. int ret = 0;
  4. struct msm_panel_info *pinfo = &(panel->panel_info);
  5. if (pinfo->mipi.cmds_post_tg) {
  6. ret = mdss_dsi_panel_initialize(&pinfo->mipi, pinfo->mipi.broadcast);
  7. if (ret) {
  8. dprintf(CRITICAL, "dsi panel init error\n");
  9. }
  10. }
  11. return ret;
  12. }

    ③ mipi_dsi_on()


   
   
   
   
  1. int mipi_dsi_on(struct msm_panel_info *pinfo)
  2. {
  3. int ret = NO_ERROR;
  4. unsigned long ReadValue;
  5. unsigned long count = 0;
  6. ReadValue = readl(pinfo->mipi.ctl_base + INT_CTRL) & 0x00010000;
  7. mdelay( 10);
  8. while (ReadValue != 0x00010000) {
  9. ReadValue = readl(pinfo->mipi.ctl_base + INT_CTRL) & 0x00010000;
  10. count++;
  11. if (count > 0xffff) {
  12. dprintf(CRITICAL, "Video lane test failed\n");
  13. return ERROR;
  14. }
  15. }
  16. dprintf(INFO, "Video lane tested successfully\n");
  17. return ret;
  18. }
  • mdss_dsi_bl_enable

    对应调用mdss_dsi_bl_enable()--->panel_backlight_ctrl(enable)--->target_backlight_ctrl(panelstruct.backlightinfo,enable)

可知根据panelstruct.backlightinfo来进行背光控制,而panelstruct.backlightinfo在oem_panel_select()--->init_panel_data()被赋值

panelstruct->backlightinfo =&xxx_video_backlight;


   
   
   
   
  1. static int mdss_dsi_bl_enable(uint8_t enable)
  2. {
  3. int ret = NO_ERROR;
  4. ret = panel_backlight_ctrl(enable);
  5. if (ret)
  6. dprintf(CRITICAL, "Backlight %s failed\n", enable ? "enable" :
  7. "disable");
  8. return ret;
  9. }

    至此,屏幕已经显示第一帧画面,且背光也是正常亮起。lk的显示已经完成。

    其实LK还有一步很重要的工作,就是把我们识别到的屏幕信息传递给kernel,它是如何传递的呢?下一篇小文档将会单独讲解该信息的传递。

你可能感兴趣的:(lcd学习)