MTK LK阶段 display框架

LK阶段display流程
./lk/kernel/main.c:186:
kmain
    // do any super early platform initialization
    platform_early_init();
    thread_t *thread_bs2 = thread_create("bootstrap2", &bootstrap2, NULL, DEFAULT_PRIORITY, DEFAULT_STACK_SIZE);
    bootstrap2
        arch_init();
        fs_init();
        platform_init(); //./lk/platform/mt6735/platform.c:974
            /* framebuffer的大小
            透过读id找到现在插入的LCM,根据LCM的分辨率申请相应大小的frame buffer并确定frame buffer起始地址*/
            g_fb_size = mt_disp_get_vram_size();
            //framebuffer的起始地址
            g_fb_base = mblock_reserve_ext(&g_boot_arg->mblock_info, g_fb_size, 0x10000, 0x80000000, 0, "framebuffer");
            //mtk display系统初始化 ddp中各个模块和lcm配置初始化
            mt_disp_init((void *)g_fb_base);
                primary_display_init(NULL);
                    /* 根据 lcm_name 名字从 lcm_driver_list 数组表当中寻找lcm驱动进行匹配。并将找到的lcm驱动赋值到plcm->drv中,
                        那么返回的plcm变量则包含lcm_drv的访问地址,这样就能访问lcm驱动的接口了 */
                    disp_lcm_handle *disp_lcm_probe(char *plcm_name, LCM_INTERFACE_ID lcm_id)
                        /* 判断LCM_DRIVER链表中lcm驱动的数量,如果为1个就直接拿来用给设备,不需要调用compare_id函数,如果多个就需要匹配硬件id号了。 */
                        lcm_drv->compare_id() 
                        for (i=0; i<_lcm_count(); i++) {
                            /*vendor / mediatek/proprietary/bootable/bootloader/lk/dev/lcm/mt65xx_lcm_list.c
                              我们一般需要把厂家提供的lcm_driver添加到lcm_driver_list数组,*/
                            lcm_drv= lcm_driver_list[i]; 
                            DISPDBG("we will check lcm: %s\n", lcm_drv->name);
                    /* 同kernel流程一样 */
                    lcm_param = disp_lcm_get_params(pgc->plcm);
                    if (primary_display_mode == DIRECT_LINK_MODE) {
                        _build_path_direct_link();
                            pgc->dpmgr_handle = dpmgr_create_path(DDP_SCENARIO_PRIMARY_DISP, pgc->cmdq_handle_config);
                            
                            //根据lcm接口类型获得目标模块,这里为DISP_MODULE_DSI0
                            dst_module = _get_dst_module_by_lcm(pgc->plcm);
                            
                            //设置ddp的最后一个模块为DISP_MODULE_DSI0
                            dpmgr_path_set_dst_module(pgc->dpmgr_handle, dst_module);
                            dpmgr_set_lcm_utils(pgc->dpmgr_handle, pgc->plcm->drv);
                                mod_drv->set_lcm_utils(module_name, lcm_drv);
                                    //设置各个模块中lcm相关的操作函数,调用ddp_dsi_set_lcm_utils,最终调用lcm_drv->set_util_funcs(utils)将操作函数赋给lcm_util
                                    ddp_dsi_set_lcm_utils 
                                        
                        DISPCHECK("primary display is DIRECT LINK MODE\n");
                    } else if (primary_display_mode == DECOUPLE_MODE) {
                        _build_path_decouple(); 
                        DISPCHECK("primary display is DECOUPLE MODE\n");
                    } else if (primary_display_mode == SINGLE_LAYER_MODE) {
                        _build_path_single_layer();
                        DISPCHECK("primary display is SINGLE LAYER MODE\n");
                    } else if (primary_display_mode == DEBUG_RDMA1_DSI0_MODE) {
                        _build_path_debug_rdma1_dsi0();
                    _build_cmdq_trigger_loop();
                    _start_cmdq_trigger_loop();
                    
                    //ddp设置显示模式,video mode or command mode
                    dpmgr_path_set_video_mode(pgc->dpmgr_handle, primary_display_is_video_mode());
                    
                    //ddp上各个模块的初始化,ovl0、ovl1、rdma0、rdma1、color、aal、gamma、dither、dsi0
                    dpmgr_path_init(pgc->dpmgr_handle, CMDQ_DISABLE);
                        ddp_modules_driver[module_name]->init(module_name, cmdqHandle); //ddp_info.c中对ddp_modules_driver赋值
                    
                    //data_config结构体描述lcm分辨率、接口类型、数据排列等信息
                    disp_ddp_path_config data_config;
                    memset((void*)&data_config, 0, sizeof(disp_ddp_path_config));
                    memcpy(&(data_config.dsi_config), &(lcm_param->dsi), sizeof(LCM_DSI_PARAMS)); //这里只考虑DSI接口
                    
                    /* 长宽高,BPP初始化 */
                    data_config.dst_w = disp_lcm_width(pgc->plcm);
                    data_config.dst_h = disp_lcm_height(pgc->plcm);
                    
                    //调用各个模块的config函数
                    ret = dpmgr_path_config(pgc->dpmgr_handle, &data_config, CMDQ_DISABLE);
                        ddp_modules_driver[module_name]->config(module_name, config, cmdqHandle);
                    
                    //lcm初始化,通过回读0x0A寄存器判断lcm是否连接
                    //依次调用lcm的init_power和init函数,实现上电复位初始化的动作,并通过回读0x0A寄存器判断跟lcm之前是否连接OK
                    ret = disp_lcm_init(pgc->plcm);
                        DISPFUNC();
                        lcm_drv->init_power(); //调用LCM lcm init_power接口上电
                        lcm_drv->init(); //调用LCM驱动lcm_init接口
                        DISPCHECK("lcm init \n");
                        ret = DSI_dcs_read_lcm_reg_v2(_get_dst_module_by_lcm(plcm), NULL, 0x0A, (UINT8 *)&buffer,1);
                        DISPMSG("read from lcm 0x0A: %d\n", buffer);
                        isLCMConnected = 1;
                        DISPMSG("lcm is connected\n"); //LCM 驱动已经connect
 
                    //关联event与irq,并且使能event,例如一帧刷完这个event,便产生一个中断
                    //映射event和中断,并且使能中断事件
                    dpmgr_map_event_to_irq(pgc->dpmgr_handle, DISP_PATH_EVENT_IF_VSYNC, DDP_IRQ_DSI0_FRAME_DONE);
                    dpmgr_enable_event(pgc->dpmgr_handle, DISP_PATH_EVENT_IF_VSYNC);
                    dpmgr_enable_event(pgc->dpmgr_handle, DISP_PATH_EVENT_FRAME_DONE);
                memset((void*)lcdbase, 0x0, DISP_GetVRamSize());
                
                //lk阶段定义了2层layer(最多支持4层layer),FB_LAYER和BOOT_MENU_LAYER, 
                primary_display_config_input(&input);
                    //将各层layer信息传递给overlay
                    ret = _convert_disp_input_to_ovl(&(data_config.ovl_config[input->layer]), input);
                    
                    //打开overlay模块配置,执行config函数(config函数会对ovl_dirty进行check,为0则直接返回,相当于bypass)
                    data_config.ovl_dirty = 1;
                    ret = dpmgr_path_config(pgc->dpmgr_handle, &data_config, primary_display_use_cmdq);
                    
                    // 设置显示需要触发overlay
                    pgc->need_trigger_overlay = 1;
            drv_video_init();
            
            boot_mode_select(); //模式选择,例如fastboot,recoverary
            /* 将logo加载到分配的RAM中 */
            logo_size = mboot_common_load_logo((unsigned long)mt_get_logo_db_addr_pa(), "logo");
                mt_get_logo_db_addr_pa //返回logo的地址
                    dprintf(0,"mt_get_logo_db_addr_pa: 0x%08x\n",(unsigned int)logo_db_addr_pa);
            PROFILING_START("show logo");
            
            //根据启动方式选择加载的logo,填充到fb中
            mt_disp_show_boot_logo(); 
                dprintf(INFO, "[lk logo: %s %d]\n",__FUNCTION__,__LINE__);
                mt_logo_get_custom_if();
                    init_fb_screen();
                    fill_animation_logo(BOOT_LOGO_INDEX, mt_get_fb_buf(), (void *)mt_get_tempfb_addr(), logo_addr, phical_screen);
                    mt_disp_update(0, 0, CFG_DISPLAY_WIDTH, CFG_DISPLAY_HEIGHT);
            PROFILING_START("backlight");
            
            刷新fb有关的cache,并且调用各个模块start和trigger函数将fb内容更新到lcm上
            mt_disp_update(0, 0, CFG_DISPLAY_WIDTH, CFG_DISPLAY_HEIGHT);
        apps_init();
 
 
APP_START(mt_boot)
.init = mt_boot_init,
 APP_END
 
 
mt_boot_init
    set_serial_num();
    boot_linux_from_storage(); //vendor/mediatek/proprietary/bootable/bootloader/lkapp/mt_boot/mt_boot.c
        bootargs_init((void *)tags_target_addr);
        custom_port_in_kernel(g_boot_mode, cmdline_get());
        send_root_of_trust_info();
        set_boot_phase(BOOT_PHASE_KERNEL);
        boot_linux((void *)kernel_target_addr, (unsigned *)tags_target_addr, board_machtype(), (void *)ramdisk_target_addr, ramdisk_real_sz);
            boot_linux_fdt((void *)kernel, (unsigned *)tags, machtype, (void *)ramdisk, ramdisk_sz);
                load_images(g_boot_mode);
                mt_disp_config_frame_buffer(fdt);
                target_fdt_firmware(fdt, sn_buf);
                    res = mt_disp_get_lcd_product_codes(lcd_product_codes);
                        res = primary_display_get_lcd_product_codes(out);
                            res = disp_lcm_get_product_codes(pgc->plcm, out);
                                lcm_drv->get_lcd_product_codes(out);
        
 
    fastboot:
        target_fastboot_init();
        mt_part_dump();
        sz = target_get_max_flash_size();
        fastboot_init(target_get_scratch_address(), sz);
        udc_start();
 
 
        
/* LK将lcm相关的信息,写到cmdline中,传递给kernel */
void cmd_boot(const char *arg, void *data, unsigned sz)    
    n = snprintf(cmdline_tmpbuf, CMDLINE_TMP_CONCAT_SIZE, "lcm=%1d-%s", DISP_IsLcmFound(), mt_disp_get_lcm_id());
    cmdline_append(cmdline_tmpbuf);
    n = snprintf(cmdline_tmpbuf, CMDLINE_TMP_CONCAT_SIZE, "fps=%1d", mt_disp_get_lcd_time());
    cmdline_append(cmdline_tmpbuf);
    n = snprintf(cmdline_tmpbuf, CMDLINE_TMP_CONCAT_SIZE, "vram=%1d", DISP_GetVRamSize());
    cmdline_append(cmdline_tmpbuf);    
 
 
/* kernel中从 "/chosen" 获取 LCM 信息 */
mtkfb_find_lcm_driver
    _parse_tag_videolfb();
        chosen_node = of_find_node_by_path("/chosen");
        __parse_tag_videolfb(chosen_node);
            videolfb_tag = (struct tag_video_lfb *)of_get_property(node, "atag,videolfb", (int *)&size);
            memset((void *)mtkfb_lcm_name, 0, sizeof(mtkfb_lcm_name));
            strncpy((char *)mtkfb_lcm_name, videolfb_tag->lcmname, sizeof(mtkfb_lcm_name));
            lcd_fps = videolfb_tag->fps;
            vramsize = videolfb_tag->vram;
            fb_base = videolfb_tag->fb_base;
    return mtkfb_lcm_name;

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值