MTK LCM显示驱动源码分析(一)

来源:互联网 发布:80端口入侵教程 编辑:程序博客网 时间:2024/06/05 03:49
 一. MTK的LCM驱动在以下目录中:
        kernel-3.18\drivers\misc\mediatek\video\common\Mtkfb.c
二. Mtkfb.c源码分析:
1.几个重要的结构体

(1)struct platform_driver 结构体:这个结构体是 platform总线的驱动结构体,其成员包含一系列函数指针,一个 struct device_driver结构体类型的成员driver等。

struct platform_driver {int (*probe)(struct platform_device *);int (*remove)(struct platform_device *);void (*shutdown)(struct platform_device *);struct device_driver driver;const struct platform_device_id *id_table;……};
(2)struct platform_device 结构体:这个结构体是 platform设备结构体,其成员主要描述platform设备属性。

struct platform_device {const char*name;intid;struct devicedev;u32num_resources;struct resource*resource;const struct platform_device_id*id_entry;char *driver_override; /* Driver name to force a match */……};
(3)struct device_driver 结构体:该结构体是驱动结构体,包含描述驱动一些属性的成员,以及对驱动操作的函数指针,注意其中的成员 of_match_table,该成员在驱动与dts中设备匹配的过程起重要作用。

struct device_driver {const char*name;struct bus_type*bus;struct module*owner;const struct of_device_id*of_match_table;const struct acpi_device_id*acpi_match_table;int (*probe) (struct device *dev);int (*remove) (struct device *dev);void (*shutdown) (struct device *dev);const struct dev_pm_ops *pm;struct driver_private *p;……};
(4)struct device 结构体:该结构体是设备结构体,包含描述设备一些属性的成员,注意其中的成员 driver,它是一个驱动结构体的指针。

struct device {struct device*parent;struct device_private*p;struct kobject kobj;struct bus_type*bus;struct device_driver *driver;/* which driver has allocated this device */void*driver_data;/* Driver data, set and get with dev_set/get_drvdata function */struct device_node*of_node; /* associated device tree node */struct acpi_dev_nodeacpi_node; /* associated ACPI device node */……};
(5)struct mtkfb_device 结构体:mtkfb设备结构体,注意其中的成员fb_info和 struct device结构体 dev。

struct mtkfb_device {int state;struct fb_info *fb_info;/* Linux fbdev framework data */struct device *dev;……};
(6)struct fb_info 结构体:注意其中的 struct device * 类型的成员 device。

struct fb_info {struct fb_ops *fbops;struct device *device;/* This is the parent */struct device *dev;/* This is this fb device */……};
(7)display_primary_path_context 结构体,显示驱动的最基本的一个结构体,几乎包含了与display相关的所有成员,在以后会经常遇到。

typedef struct {DISP_POWER_STATE state;unsigned int lcm_fps;DISP_PRIMARY_PATH_MODE mode;struct mutex lock;disp_lcm_handle *plcm;cmdqRecHandle cmdq_handle_config_esd;cmdqRecHandle cmdq_handle_trigger;cmdqRecHandle cmdq_handle_config;disp_path_handle dpmgr_handle;disp_path_handle ovl2mem_path_handle;char *mutex_locker;……} display_primary_path_context;
1.分析驱动的入口函数 mtkfb_init

int __init mtkfb_init(void){platform_driver_register(&mtkfb_driver);    //mtkfb驱动的注册mtkfb_ipo_init();    // 注册内核通知链(notifier chain)}
2.分析 mtkfb_driver,下面的代码填充了 mtkfb_driver 中的 driver 成员。

static struct platform_driver mtkfb_driver = {.driver = {.name = MTKFB_DRIVER,//该宏定义为"mtkfb".pm = &mtkfb_pm_ops,// 电源管理函数指针结构体.bus = &platform_bus_type,// 该驱动挂在 platform 总线上.probe = mtkfb_probe, // 模块加载函数.remove = mtkfb_remove,  // 模块卸载函数.suspend = mtkfb_suspend,//挂起函数.resume = mtkfb_resume, //唤醒函数.shutdown = mtkfb_shutdown, //关闭函数.of_match_table = mtkfb_of_ids,  //定义driver的id,用于与dts中对应的device匹配},};
3.分析 platform_driver_register,该函数用于platform总线类型的驱动的注册。

(1)platform_driver_register 的定义为:

#define platform_driver_register(drv) \__platform_driver_register(drv, THIS_MODULE)
(2)__platform_driver_register 的定义为:

int __platform_driver_register(struct platform_driver *drv, struct module *owner)  //drv的实参为 mtkfb_driver{drv->driver.owner = owner;if (drv->probe)drv->driver.probe = platform_drv_probe;/*如果填充了mtkfb_driver的probe成员,mtkfb_driver.driver.probe使用platform默认的驱动加载函数。  这里没有填充,使用我们自己定义的probe函数,即:mtkfb_probe*/return driver_register(&drv->driver);  // 如果mtkfb_driver.driver注册成功,则返回0}
4.分析 mtkfb_pm_ops,该结构体包含一系列电源管理的函数指针,从下面的代码可以看到,mtkfb_pm_suspend 函数,实际上调用的是 mtkfb_suspend 函数。

(1)mtkfb_pm_ops 的定义为:

const struct dev_pm_ops mtkfb_pm_ops = {    .suspend = mtkfb_pm_suspend,.resume = mtkfb_pm_resume,.freeze = mtkfb_pm_freeze,.restore_noirq = mtkfb_pm_restore_noirq,}; /* 结构体struct dev_pm_ops 包含一系列电源管理函数指针*/
(2)分析 mtkfb_pm_suspend

int mtkfb_pm_suspend(struct device *device){struct platform_device *pdev = to_platform_device(device);BUG_ON(pdev == NULL);/* 如果pdev == NULL,打印bug信息*/return mtkfb_suspend((struct device *)pdev, PMSG_SUSPEND);  /*后面会详细分析 mtkfb_suspend 函数的实现*//*指针的强制转换有什么意义:无论什么类型的指针变量,在内存中本质上都是一样的,都是指向一个变量首字节的地址;而这个不同的类型仅仅是向系统说明该指针所指向的变量在内存中占据字节的数目。*/}
(3)分析 mtkfb_pm_resume,实际上调用了 mtkfb_resume  函数。

int mtkfb_pm_resume(struct device *device){struct platform_device *pdev = to_platform_device(device);BUG_ON(pdev == NULL);return mtkfb_resume((struct device *)pdev);   /*后面会详细分析 mtkfb_resume 函数的实现*/}
(4)分析 mtkfb_pm_freeze,该函数的功能是禁止 esd  check 。

int mtkfb_pm_freeze(struct device *device){primary_display_esd_check_enable(0);  }void primary_display_esd_check_enable(int enable){if (enable) {pr_warn("[DISP][ESD]esd check thread wakeup\n");atomic_set(&esd_check_task_wakeup, 1);    /*获取 esd check 原子变量*/wake_up_interruptible(&esd_check_task_wq);  /*唤醒esd check 任务等待队列*/} else {DISPMSG("[ESD]esd check thread stop\n");atomic_set(&esd_check_task_wakeup, 0);  /*释放 esd check 原子变量*/}}
(5)分析 mtkfb_pm_restore_noirq,该函数将一个变量 is_ipoh_bootup 赋值为1,该变量与 primary_display_resume 函数相关。

int mtkfb_pm_restore_noirq(struct device *device){is_ipoh_bootup = true;return 0;}/*与 is_ipoh_bootup 相关的代码:*/int primary_display_resume(void){if (is_ipoh_bootup) {DISPMSG("[primary display path] leave primary_display_resume -- IPOH\n"); /* 离开 primary_display_resume 函数*/DISPMSG("ESD check start[begin]\n");  primary_display_esd_check_enable(1); /* 使能esd check */DISPMSG("ESD check start[end]\n");is_ipoh_bootup = false;DISPMSG("[POWER]start cmdq[begin]--IPOH\n");_cmdq_start_trigger_loop();  /* start trigger loop */DISPMSG("[POWER]start cmdq[end]--IPOH\n");pgc->state = DISP_ALIVE;  goto done;  }}
5.分析 platform_bus_type,注意其中的成员 platform_match 函数。

(1) platform_bus_type 的定义为:

struct bus_type platform_bus_type = {.name= "platform",.match= platform_match,.uevent= platform_uevent,};
(2)platform_match 函数的定义如下,该函数用于 driver 与 device 的匹配,现在一般直接在dts中添加一个 device 的属性即可。

static int platform_match(struct device *dev, struct device_driver *drv){struct platform_device *pdev = to_platform_device(dev);struct platform_driver *pdrv = to_platform_driver(drv);/* When driver_override is set, only bind to the matching driver */if (pdev->driver_override)return !strcmp(pdev->driver_override, drv->name);/* Attempt an OF style match first,从dts中寻找 device(前缀为OF的函数,表示与dts相关的代码) */if (of_driver_match_device(dev, drv))return 1;/* Then try ACPI style match */if (acpi_driver_match_device(dev, drv))return 1;/* Then try to match against the id table */if (pdrv->id_table)return platform_match_id(pdrv->id_table, pdev) != NULL;/* fall-back to driver name match */return (strcmp(pdev->name, drv->name) == 0);}
6.分析 mtkfb_remove,模块卸载函数。
(1)相关的结构体

enum mtkfb_state {MTKFB_DISABLED = 0,MTKFB_SUSPENDED = 99,MTKFB_ACTIVE = 100};
(2)mtkfb_remove 函数定义为:

static int mtkfb_remove(struct device *dev){struct mtkfb_device *fbdev = dev->driver_data;  /* 获取 fbdev 设备  */enum mtkfb_state saved_state = fbdev->state; /* 保存 fbdev 设备的当前状态 */fbdev->state = MTKFB_DISABLED;  /* 将 fbdev 设备的状态设为 0*/mtkfb_free_resources(fbdev, saved_state);  /* 释放 mtkfb 的资源*/return 0;}
(3)分析 mtkfb_free_resources,该函数实际上调用了 unregister_framebuffer 这个函数。

static void mtkfb_free_resources(struct mtkfb_device *fbdev, int state){int r = 0;switch (state) {case MTKFB_ACTIVE:r = unregister_framebuffer(fbdev->fb_info);}}
(4)分析 unregister_framebuffer,该函数实际上调用了 do_unregister_framebuffer 这个函数,释放 fb_info。

int unregister_framebuffer(struct fb_info *fb_info){ret = do_unregister_framebuffer(fb_info);  //注销 fb_info}
7.分析 mtkfb_suspend,该函数实际上调用了 ovl2mem_wait_done 这个函数。

(1)mtkfb_suspend 函数的定义为:

static int mtkfb_suspend(struct device *pdev, pm_message_t mesg){ovl2mem_wait_done();}
(2)分析 ovl2mem_wait_done 函数,该函数实际上调用了 dpmgr_wait_event_timeout 这个函数。

void ovl2mem_wait_done(void){dpmgr_wait_event_timeout(pgc->dpmgr_handle, DISP_PATH_EVENT_FRAME_COMPLETE, HZ / 30);/* dpmgr_wait_event_timeout 这个函数,设置了一个超时时间为 HZ/30,用来等待 frame event complete 。                   若超时未完成,直接返回,不会产生阻塞 */}
8.分析 mtkfb_resume,该函数什么也没有做。
(1)mtkfb_resume 函数的定义为:

static int mtkfb_resume(struct device *pdev){return 0;}
9.分析 mtkfb_shutdown,该函数实际上调用了 primary_display_suspend 函数,用来将display子系统设为sleep状态。

(1)mtkfb_shutdown 函数的定义为:

static void mtkfb_shutdown(struct device *pdev){primary_display_suspend();}
10.分析 mtkfb_of_ids,填充 compatible 成员。

(1) mtkfb_of_ids 的定义为:

struct of_device_id{charname[32];chartype[32];charcompatible[128];const void *data;};static const struct of_device_id mtkfb_of_ids[] = {{.compatible = "mediatek,mtkfb",},{}};
(2)  上面的代码填充了 mtkfb_driver.driver.mtkfb_of_ids.compatible 成员。然后,我们可以在对应项目的 dts 文件中,添加以下代码后,即可完成driver与device的匹配。

MTKFB@5e200000 {compatible = "mediatek,MTKFB";reg = <0x7F000000 0x1000000>;};
11.分析内核通知链函数 mtkfb_ipo_init ,(如果不熟悉 notifier chain,先学习内核通知链相关的知识。)
(1)先关注一下相关的结构体和函数指针:

typedefint (*notifier_fn_t)(struct notifier_block *nb,  unsigned long action, void *data); struct blocking_notifier_head {struct rw_semaphore rwsem;struct notifier_block __rcu *head;};/* 定义一个内核通知链头 */struct notifier_block {notifier_fn_t notifier_call;  /* 当相应事件发生时应该调用的函数,由被通知方提供  */struct notifier_block __rcu *next; /* 指向下一个通知链结构体,链表使用 rcu机制 */int priority;  /* 优先级 */};  /* block  表明该内核通知链是可阻塞的,该通知链运行在进程上下文中 */
(2)mtkfb_ipo_init 的定义为:

struct notifier_block pm_nb;int mtkfb_ipo_init(void){pm_nb.notifier_call = mtkfb_ipoh_restore;  /* 被通知方的回调函数*/pm_nb.priority = 0;  /* 优先级为0 */register_pm_notifier(&pm_nb);  /* 注册*/return 0;}
(3)操作函数 mtkfb_ipoh_restore 的实现如下:

int mtkfb_ipoh_restore(struct notifier_block *nb, unsigned long val, void *ign){switch (val) {case PM_RESTORE_PREPARE:  /* 恢复一个已经保存的映像… */primary_display_ipoh_restore();return NOTIFY_DONE;   /* 表示对相关的事件类型不关心 */case PM_POST_RESTORE:  /* 恢复失败… */primary_display_ipoh_recover();return NOTIFY_DONE;}return NOTIFY_OK;   /* 顺利执行 */}int primary_display_ipoh_restore(void){primary_display_esd_check_enable(0);  /* 停止 esd check 线程*/_cmdq_stop_trigger_loop();/*  停止命令触发循环… */}int primary_display_ipoh_recover(void){_cmdq_start_trigger_loop();  /*  开始命令触发循环…*/}
(4)注册内核通知链 register_pm_notifier 函数的实现如下:

static BLOCKING_NOTIFIER_HEAD(pm_chain_head);   /* 初始化内核通知链头…*/int register_pm_notifier(struct notifier_block *nb){return blocking_notifier_chain_register(&pm_chain_head, nb);  /*  注册一个可阻塞的通知链 */}int blocking_notifier_chain_register(struct blocking_notifier_head *nh, struct notifier_block *n){ret = notifier_chain_register(&nh->head, n); /*注册通知链 */}

注意:所有函数和结构体均删掉了无用的部分,只抽出了代码的框架。

在下一部分,将分析mktfb驱动的重点函数源码:mtkfb_probe函数



原创粉丝点击