QCom MSM MDP显示驱动一些点的简记
簡要記錄了Qualcom MSM8xxx MDP Framebuffer驅動中的一些點。
Framebuffer設備的sysfs
330static int msm_fb_create_sysfs(struct platform_device *pdev)
331{
332???????? int rc;
333???????? struct msm_fb_data_type *mfd = platform_get_drvdata(pdev);
334
335???????? rc = sysfs_create_group(&mfd->fbi->dev->kobj, &msm_fb_attr_group);
336???????? if (rc)
337???????????????????????? MSM_FB_ERR("%s: sysfs group creation failed, rc=%d\n", __func__,
338???????????????????????????????????????? rc);
339???????? return rc;
340}
?
root@android:/sys/class/graphics/fb0 # ls -al
-rw-r--r-- root???? root???????? 4096 1970-06-27 09:37 bits_per_pixel
-rw-r--r-- root???? root???????? 4096 1970-06-27 09:37 blank
-rw-r--r-- root???? root???????? 4096 1970-06-27 09:37 console
-rw-r--r-- root???? root???????? 4096 1970-06-27 09:37 cursor
-r--r--r-- root???? root???????? 4096 1970-06-27 09:37 dev
-rw-r--r-- root???? root???????? 4096 1970-06-27 09:37 mode
-rw-r--r-- root? ???root???????? 4096 1970-06-27 09:37 modes
-r--r--r-- root???? root???????? 4096 1970-06-27 09:37 msm_fb_type
-r--r--r-- root???? root???????? 4096 1970-06-27 09:37 name
-rw-r--r-- root???? root???????? 4096 1970-06-27 09:37 pan
drwxr-xr-x root???? root? ????????????1970-06-27 08:28 power
-rw-r--r-- root???? root???????? 4096 1970-06-27 09:37 rotate
-rw-r--r-- root???? root???????? 4096 1970-06-27 09:37 state
-r--r--r-- root???? root???????? 4096 1970-06-27 09:37 stride
lrwxrwxrwx root???? root??????????? ??1970-06-27 09:37 subsystem -> ../../../../class/graphics
-rw-r--r-- root???? root???????? 4096 1970-06-27 08:28 uevent
-rw-r--r-- root???? root???????? 4096 1970-06-27 09:37 virtual_size
-r--r--r-- root???? root???????? 4096 1970-06-27 08:28 vsync_event
root@android:/sys/class/graphics/fb0 # cat msm_fb_type????????????????????????
mipi dsi cmd panel
root@android:/sys/class/graphics/fb0 # cat bits_per_pixel?????????????????????
32
130|root@android:/sys/class/graphics/fb0 # cat dev
29:0
root@android:/sys/class/graphics/fb0 # cat modes
U:480x854p-0
root@android:/sys/class/graphics/fb0 # cat name
msmfb42_90501
root@android:/sys/class/graphics/fb0 # cat stride
1920
root@android:/sys/class/graphics/fb0 # cat virtual_size?????????????????????
480,2566
?
cont_splash_done?field
Add support for "Continuous Splash Screen" feature.
The image displayed on the screen by the android bootloaderdriver should continue till the android animation shows up.
Delay the display initialization for MDP, display dependent clocksand panel power on functions.
bootloader顯示的image在linux內核啟動過程中保持顯示在屏幕上,知道開機動畫顯示,即linux內核啟動過程中不要出現(xiàn)黑屏。
?
Early suspend & Early resume
Early suspend是有wakelock還占有,系統(tǒng)還不能整體suspend,但是可以關閉屏幕、背光、輸入等;在Early suspended狀態(tài)時,重新打開屏幕、背光和輸入,是為對應的early resume。
fb_register中相關設置如下:
1551?????????????????????? mfd->early_suspend.suspend = msmfb_early_suspend;
1552?????????????????????? mfd->early_suspend.resume = msmfb_early_resume;
1553?????????????????????? mfd->early_suspend.level = EARLY_SUSPEND_LEVEL_DISABLE_FB - 2;
1554?????????????????????? register_early_suspend(&mfd->early_suspend);
數據結構定義如下:
23/* The early_suspend structure defines suspend and resume hooks to be called
24 * when the user visible sleep state of the system changes, and a level to
25 * control the order. They can be used to turn off the screen and input
26 * devices that are not used for wakeup.
27 * Suspend handlers are called in low to high level order, resume handlers are
28 * called in the opposite order. If, when calling register_early_suspend,
29 * the suspend handlers have already been called without a matching call to the
30 * resume handlers, the suspend handler will be called directly from
31 * register_early_suspend. This direct call can violate the normal level order.
32 */
33enum {
34?????????? EARLY_SUSPEND_LEVEL_BLANK_SCREEN = 50,
35?????????? EARLY_SUSPEND_LEVEL_STOP_DRAWING = 100,
36?????????? EARLY_SUSPEND_LEVEL_DISABLE_FB = 150,
37};
38struct early_suspend {
39#ifdef CONFIG_HAS_EARLYSUSPEND
40?????????? struct list_head link;
41?????????? int level;
42?????????? void (*suspend)(struct early_suspend *h);
43?????????? void (*resume)(struct early_suspend *h);
44#endif
45};
?
backlight
msm_fb_set_backlight以后是使用led_trigger調用真正led_classdev "wled"的brightnes_set去設置背光。
用戶態(tài)ioctl通過msm_fb_set_backlight調用到msm_fb_panel_data::set_backlight,
"lcd_backlight".brightness_set -> msm_fb_panel_data::set_backlight -> "bkl_trigger".led_trigger -> "wled".brightness_set。然后找真正操作硬件IC部分。
驅動中設置背光則是繞過"lcd_backlight"設備直接通過backlight_worker工作執(zhí)行到msm_fb_panel_data::set_backlight,然后-> "bkl_trigger".led_trigger -> "wled".brightness_set。
可以認為"lcd_backlight"是背光抽象設備,通過led_trigger的led組映射到不同的led_classdev設備
以三星DSI CMD屏為例:
In mipi_samsung.c
294static void mipi_samsung_set_backlight(struct msm_fb_data_type *mfd)
295{
296???????? if (!cci_fb_UpdateDone){
297???????????????????????? printk("Taylor: No BL before LCM on\n");
298???????????????????????? return;
299???????? }
300
301???????? pr_debug("Taylor: %s : Set BL:%d\n",__func__, mfd->bl_level);
302???????? if ((mipi_samsung_pdata->enable_wled_bl_ctrl)
303???????? ??? && (wled_trigger_initialized)) {
304???????????????????????? led_trigger_event(bkl_led_trigger, mfd->bl_level);
305???????????????????????? return;
306???????? }
307}
?
kernel/drivers/leds/leds-pm8xxx.c
#define PM8XXX_LEDS_DEV_NAME?????? "pm8xxx-led"
2283static struct platform_driver pm8xxx_led_driver = {
2284?????? .probe????????????????? = pm8xxx_led_probe,
2285?????? .remove?????????????????????????????? = __devexit_p(pm8xxx_led_remove),
2286?????? .driver?????????????????? = {
2287?????????????????????? .name?? = PM8XXX_LEDS_DEV_NAME,
2288?????????????????????? .owner = THIS_MODULE,
2289?????? },
2290};
?
pm8xxx_led_probe會對pm8038_led_info數組中的每個led使用設置led_classdev字段,并且初始化work item,然后使用led_classdev_register向系統(tǒng)注冊每個led設備。
2197?????????????????????? INIT_WORK(&led_dat->work, pm8xxx_led_work);
2198?????????????????????? INIT_WORK(&led_dat->modework, pm8xxx_mode_work);
2199?????????????????????? INIT_WORK(&led_dat->testwork, pm8xxx_test_work);
?
每個led的brightness_set字段設置為pm8xxx_led_set。
1790static void pm8xxx_led_set(struct led_classdev *led_cdev,
1791?????? enum led_brightness value)
1792{
1793?????? struct??? pm8xxx_led_data *led;
1794
1795?????? led = container_of(led_cdev, struct pm8xxx_led_data, cdev);
1796
1797?????? if (value < LED_OFF || value > led->cdev.max_brightness) {
1798?????????????????????? dev_err(led->cdev.dev, "Invalid brightness value exceeds");
1799?????????????????????? return;
1800?????? }
1801
1802?????? led->cdev.brightness = value;
1803?????? schedule_work(&led->work);
1804}
?
1730static void pm8xxx_led_work(struct work_struct *work)
1731{
1732?????? int rc;
1733
1734?????? struct pm8xxx_led_data *led = container_of(work,
1735?????????????????????????????????????????????????????????????????????? struct pm8xxx_led_data, work);
1736
1737?????? if (led->pwm_dev == NULL) {
1738?????????????????????? __pm8xxx_led_work(led, led->cdev.brightness);
1739?????? } else {
1740?????????????????????? rc = pm8xxx_led_pwm_work(led);
1741?????????????????????? if (rc)
1742?????????????????????????????????????? pr_err("could not configure PWM mode for LED:%d\n",
1743?????????????????????????????????????????????????????????????????????????????????????????????????????????????????????? led->id);
1744?????? }
1745}
對PM8XXX_ID_WLED,是使用__pm8xxx_led_work
1692static void __pm8xxx_led_work(struct pm8xxx_led_data *led,
1693?????????????????????????????????????????????????????????????????????? enum led_brightness level)
1694{
1695?????? int rc;
1696
1697?????? mutex_lock(&led->lock);
1698
1699?????? switch (led->id) {
1700?????? case PM8XXX_ID_LED_KB_LIGHT:
1701?????????????????????? led_kp_set(led, level);
1702?????????????????????? break;
1703?????? case PM8XXX_ID_LED_0:
1704?????? case PM8XXX_ID_LED_1:
1705?????? case PM8XXX_ID_LED_2:
1706?????????????????????? led_lc_set(led, level);
1707?????????????????????? break;
1708?????? case PM8XXX_ID_FLASH_LED_0:
1709?????? case PM8XXX_ID_FLASH_LED_1:
1710?????????????????????? led_flash_set(led, level);
1711?????????????????????? break;
1712??????case PM8XXX_ID_WLED:
1713??????????????????????rc = led_wled_set(led, level);
1714?????????????????????? if (rc < 0)
1715?????????????????????????????????????? pr_err("wled brightness set failed %d\n", rc);
1716?????????????????????? break;
1717?????? case PM8XXX_ID_RGB_LED_RED:
1718?????? case PM8XXX_ID_RGB_LED_GREEN:
1719?????? case PM8XXX_ID_RGB_LED_BLUE:
1720?????????????????????? led_rgb_set(led, level);
1721?????????????????????? break;
1722?????? default:
1723?????????????????????? dev_err(led->cdev.dev, "unknown led id %d", led->id);
1724?????????????????????? break;
1725?????? }
1726
1727?????? mutex_unlock(&led->lock);
1728}
led_wled_set寫電源管理芯片pm8xxx的控制寄存器,控制wled。
?
Framebuffer fb_info::node
registered_fb它是一個數組,它的類型就是struct fb_info,它用于保存我們調用register_framebuffer傳進來的struct fb_info。
num_registered_fb代表注冊幀緩沖設備的個數。
? ?1522 ? ? ? ? for (i = 0; i < FB_MAX; i++)
? ?1523 ? ? ? ? ? ? ? ? if (!registered_fb[i])
? ?1524 ? ? ? ? ? ? ? ? ? ? ? ? break;
? ?1525 ? ? ? ? fb_info->node = i;
相當于找到一個空的次設備號。
?
Framebuffer像素格式
主屏Framebuffer格式?RGBA8888, config時指定;屏格式為RGB565或RGB888,由overlay pipe做轉換。
In mipi_dsi_probe()
481???????? /*
482???????? * get/set panel specific fb info
483???????? */
484???????? mfd->panel_info = pdata->panel_info;
485???????? pinfo = &mfd->panel_info;
486
487???????? if (mfd->panel_info.type == MIPI_VIDEO_PANEL)
488???????????????????????? mfd->dest = DISPLAY_LCDC;
489???????? else
490?????????????????????????mfd->dest = DISPLAY_LCD;
491
492???????? if (mdp_rev == MDP_REV_303 &&
493???????????????????????? mipi_dsi_pdata->get_lane_config) {
494???????????????????????? if (mipi_dsi_pdata->get_lane_config() != 2) {
495???????????????????????????????????????? pr_info("Changing to DSI Single Mode Configuration\n");
496#ifdef CONFIG_FB_MSM_MDP303
497???????????????????????????????????????? update_lane_config(pinfo);
498#endif
499???????????????????????? }
500???????? }
501
502???????? if (mfd->index == 0)
503?????????????????????????mfd->fb_imgType = MSMFB_DEFAULT_TYPE;?? // configed as RGBA8888 for fb0
504???????? else
505???????????????????????? mfd->fb_imgType = MDP_RGB_565;
?
msmfb_update_notify/ msmfb_no_update_notify
用于CABL功能時,統(tǒng)計直方圖使用;
更新屏幕前complete(&msmfb_update_notify)從而在準確時間點啟動直方圖統(tǒng)計;2*HZ后,msmfb_no_update_notify_timer超時,在timer超時回調中complete(&mfd->msmfb_no_update_notify)結束直方圖統(tǒng)計。
?
sw_refresher
使用定時器去觸發(fā)mdp_refresh_screen,添加work進行dma_fnc調用。
針對某些接口的VIDEO模式屏且控制器沒有hw_refresh支持時,可以使用sw_refresher。
?
FB_ACTIVATE_VBL標志涵義
fb_var_screeninfo結構體的成員變量activate的值設置FB_ACTIVATE_VBL,表示要等到下一個垂直同步事件出現(xiàn)時,再將當前要渲染的圖形緩沖區(qū)的內容繪制出來。這樣做的目的是避免出現(xiàn)屏幕閃爍,即避免前后兩個圖形緩沖區(qū)的內容各有一部分同時出現(xiàn)屏幕中。
總結
以上是生活随笔為你收集整理的QCom MSM MDP显示驱动一些点的简记的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 如何提高android串口kernel
- 下一篇: android 串口调试