• 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 ", __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内核启动过程中不要出现黑屏。

     

    Early suspend & Early resume

    Early suspend是有wakelock还占有,系统还不能整体suspend,但是可以关闭屏幕、背光、输入等;在Early suspended状态时,重新打开屏幕、背光和输入,是为对应的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去设置背光。

    用户态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工作执行到msm_fb_panel_data::set_backlight,然后-> "bkl_trigger".led_trigger -> "wled".brightness_set

    可以认为"lcd_backlight"是背光抽象设备,通过led_triggerled组映射到不同的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 ");

    298                         return;

    299         }

    300

    301         pr_debug("Taylor: %s : Set BL:%d ",__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向系统注册每个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);

     

    每个ledbrightness_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 ",

    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 ", 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 ");

    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功能时,统计直方图使用;

    更新屏幕前complete(&msmfb_update_notify)从而在准确时间点启动直方图统计;2*HZ后,msmfb_no_update_notify_timer超时,在timer超时回调中complete(&mfd->msmfb_no_update_notify)结束直方图统计。

     

    sw_refresher

    使用定时器去触发mdp_refresh_screen,添加work进行dma_fnc调用。

    针对某些接口的VIDEO模式屏且控制器没有hw_refresh支持时,可以使用sw_refresher

     

    FB_ACTIVATE_VBL标志涵义

    fb_var_screeninfo结构体的成员变量activate的值设置FB_ACTIVATE_VBL,表示要等到下一个垂直同步事件出现时,再将当前要渲染的图形缓冲区的内容绘制出来。这样做的目的是避免出现屏幕闪烁,即避免前后两个图形缓冲区的内容各有一部分同时出现屏幕中。

  • 相关阅读:
    c#扩展函数
    c# 正则匹配对称括号
    sqllocaldb 2016安装
    scrapy图片数据爬取
    Scrapy爬取全站数据并存储到数据库和文件中
    Scrapy基于终端指令的持久化存储
    nginx指定配置文件
    腾讯云安装python36
    Django部署腾讯云服务时候报错:SQLite 3.8.3 or later is required (found 3.7.17)
    flask打包下载zip文件
  • 原文地址:https://www.cnblogs.com/LoongEmbedded/p/5298208.html
Copyright © 2020-2023  润新知