kmain();
--thread_t *thread_bs2 = thread_create("bootstrap2", &bootstrap2, NULL,DEFAULT_PRIORITY, DEFAULT_STACK_SIZE);
-- bootstrap2(void *arg);
-- platform_init();
主要讲这3个部分:
1、初始化lk中的fb,获取大小、长宽等,同时给驱动结构体pgc分配空间,为进行驱动初始化做准备。
/* initialize the frame buffet information */
g_fb_size = mt_disp_get_vram_size();
g_fb_base = mblock_reserve_ext(&g_boot_arg->mblock_info, g_fb_size, 0x10000, 0x78000000, 0, "framebuffer");
2、mt_disp_init((void *)g_fb_base);
3、mt65xx_backlight_on();
void platform_init(void)
{
/* initialize the frame buffet information */
g_fb_size = mt_disp_get_vram_size();
g_fb_base = mblock_reserve_ext(&g_boot_arg->mblock_info, g_fb_size, 0x10000, 0x78000000, 0, "framebuffer");
...
mt_disp_init((void *)g_fb_base);
...
mt65xx_backlight_on();
...
}
1、mt_disp_get_vram_size();
--DISP_GetVRamSize();
--vramSize = DISP_GetFBRamSize();
-- DISP_GetScreenWidth(void)
--primary_display_get_width();
--if (pgc->plcm == NULL) {
pgc->plcm = disp_lcm_probe(NULL, LCM_INTERFACE_NOTDEFINED);//跑probe函数,lcm参数初始化。
...}
vramSize += DAL_GetLayerSize();
return vramSize;
//pgc结构体的定义start//
#define pgc _get_context
static display_primary_path_context* _get_context(void)
{
static int is_context_inited = 0;
static display_primary_path_context g_context;
> if (!is_context_inited) {
memset((void*)&g_context, 0, sizeof(display_primary_path_context));
is_context_inited = 1;
}
return &g_context;
}
//pgc结构体的定义end//
2、mt_disp_init((void *)g_fb_base);
---/// fb base pa and va
fb_addr_pa_k = arm_mmu_va2pa((unsigned int)lcdbase);
fb_addr_pa = (void *)(unsigned int)(fb_addr_pa_k & 0xffffffffull);
fb_addr = lcdbase;
primary_display_init(NULL)
--pgc->plcm = disp_lcm_probe( lcm_name, LCM_INTERFACE_NOTDEFINED)
--//当_lcm_count() > 0时会调用lcm_drv->compare_id() != 0时break,找到相应lcm
compare_id()
--ret = disp_lcm_init(pgc->plcm);
--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);
if (ret == 0) {
isLCMConnected = 0;
DISPMSG("lcm is not connected\n");
} else {
isLCMConnected = 1;
DISPMSG("lcm is connected\n");
}
3、void mt65xx_backlight_on(void){
--enum led_brightness backlight_level = get_cust_led_default_level();
mt65xx_leds_brightness_set(MT65XX_LED_TYPE_LCD, backlight_level);//默认backlight_level = LED_FULL
--mt65xx_led_set_cust(&cust_led_list[type], level)
-- switch (cust->mode) {
...
case MT65XX_LED_MODE_GPIO:
return ((cust_brightness_set)(cust->data))(level);
case MT65XX_LED_MODE_PMIC:
return brightness_set_pmic(cust->data, level);
case MT65XX_LED_MODE_CUST_LCM:
return ((cust_brightness_set)(cust->data))(level);
case MT65XX_LED_MODE_CUST_BLS_PWM:
return ((cust_brightness_set)(cust->data))(level); ////dts中对应的背光模式 MT65XX_LED_MODE_CUST_BLS_PWM
case MT65XX_LED_MODE_NONE:
default:
break;
}
}
//与背光相关的结构体
enum led_brightness {
LED_OFF = 0,
LED_HALF = 127,
LED_FULL = 255,
};
enum mt65xx_led_type
{
MT65XX_LED_TYPE_RED = 0,
MT65XX_LED_TYPE_GREEN,
MT65XX_LED_TYPE_BLUE,
MT65XX_LED_TYPE_JOGBALL,
MT65XX_LED_TYPE_KEYBOARD,
MT65XX_LED_TYPE_BUTTON,
MT65XX_LED_TYPE_LCD,
MT65XX_LED_TYPE_TOTAL,
};
enum mt65xx_led_mode
{
MT65XX_LED_MODE_NONE,
MT65XX_LED_MODE_PWM,
MT65XX_LED_MODE_GPIO,
MT65XX_LED_MODE_PMIC,
MT65XX_LED_MODE_CUST_LCM,
MT65XX_LED_MODE_CUST_BLS_PWM //5
};
//dts中对应的背光模式,在K39tv1_64_bsp.dts中
led6:led@6 {
compatible = "mediatek,lcd-backlight";
led_mode = <5>; //对应的背光模式MT65XX_LED_MODE_CUST_BLS_PWM
data = <1>;
pwm_config = <0 2 0 0 0>;
};
mtkfb.c:
module_init(mtkfb_init);
int __init mtkfb_init(void)
{
platform_driver_register(&mtkfb_driver)
--.of_match_table = mtkfb_of_ids,
--{.compatible = "mediatek,MTKFB",}//和设备树中的相匹配后跑prob函数
...
}
static int mtkfb_probe(struct platform_device *pdev)
{
...
|_parse_tag_videolfb();//用于获取LK传递过来的lcm型号参数
| --chosen_node = of_find_node_by_path("/chosen");
| ret = __parse_tag_videolfb(chosen_node);
| --videolfb_tag = (struct tag_videolfb *)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));
| mtkfb_lcm_name[strlen(videolfb_tag->lcmname)] = '\0';//解析出lcd的名字,lk在初始化时进行lcm匹配修改放入相应的到chosen节点,来传递给kernel。
|
|primary_display_init(mtkfb_find_lcm_driver(), lcd_fps, is_lcm_inited); //进行LCM主要的初始化
| --pgc->plcm = disp_lcm_probe(lcm_name, LCM_INTERFACE_NOTDEFINED, is_lcm_inited);
| --primary_display_check_recovery_init();//ESD检测
| --primary_display_check_task =kthread_create(primary_display_check_recovery_worker_kthread, NULL,"disp_check");//创建线程
| --wake_up_process(primary_display_check_task);//唤醒线程函数
| --static int primary_display_check_recovery_worker_kthread(void *data)
| --do {
| ret = primary_display_esd_check();
|
| if (ret == 1) {
| DISPERR("[ESD]esd check fail, will do esd recovery. try=%d\n", i);
| primary_display_esd_recovery();//ESD check failed 挂起LCM,重新进行初始化。
| -- { ...DISPDBG("[POWER]lcm suspend[begin]\n");
| disp_lcm_suspend(primary_get_lcm());
| DISPCHECK("[POWER]lcm suspend[end]\n");
|
| mmprofile_log_ex(ddp_mmp_get_events()->esd_recovery_t, MMPROFILE_FLAG_PULSE, 0, 7);
|
| DISPDBG("[ESD]lcm force init[begin]\n");
| disp_lcm_init(primary_get_lcm(), 1);
| DISPCHECK("[ESD]lcm force init[end]\n");...}
|
| recovery_done = 1;
| } else
| break;
|
| } while (++i < esd_try_cnt);//esd_try_cnt = 5
|
|
...
}
disp_lcm.c->disp_lcm_probe();在for循环中遍历lcm_driver_list[]这个数组。匹配到正确id后返回1,跳出for循环。
ESD读取寄存器一般是读0x0A,读出0X9C。有的IC厂家为了自己产品的稳定性,会多弄几组寄存器用于读取,就不是简单的读取0x9c的值了。