显示屏驱动
Posted 四季帆
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了显示屏驱动相关的知识,希望对你有一定的参考价值。
1. frambuffer简介
Linux kernel为显示屏设备提供了一个驱动框架叫FrameBuffer(中文也称“帧缓冲区”),所以编写显示屏驱动的任务也就变成了调用FrameBuffer框架提供的接口,注册包含具体显示屏控制器信息的结构体到FrameBuffer框架。
所以正常情况下,显示屏驱动应该就两层,第一层是FrameBuffer 驱动框架层,第二层就是具体的显示屏控制器对应的驱动代码。
通过阅读Imx6dl SOC数据手册可知
显示接口桥接:提供从IPU支持的数字显示接口到其他接口的可选转换:
LVDS bridge (LDB): providing up to one LVDS interface
HDMI transmitter
MIPI/DSI transmitter
Imx6dl 这款SOC 集成了三种显示屏接口的控制器,所以Imx6dl 的显示屏驱动在第二层的基础上,将各种接口不同的部分分离出去形成第三层,三种接口的共性部分留在第二层。
2. 驱动分析
以hdmi接口的显示屏为例,驱动第三层:mxc_hdmi.c文件
//hdmi_i2c和hdmi_video驱动都在mxc_hdmi.c文件中
module_init(mxc_hdmi_i2c_init);
static int __init mxc_hdmi_i2c_init(void)
{
return i2c_add_driver(&mxc_hdmi_i2c_driver);
}
static struct i2c_driver mxc_hdmi_i2c_driver = {
.driver = {
.name = "mxc_hdmi_i2c",
.of_match_table = imx_hdmi_i2c_match,
},
.probe = mxc_hdmi_i2c_probe,
.remove = mxc_hdmi_i2c_remove,
.id_table = mxc_hdmi_i2c_id,
};
static int mxc_hdmi_i2c_probe(struct i2c_client *client, const struct i2c_device_id *id)
{
if (!i2c_check_functionality(client->adapter,
I2C_FUNC_SMBUS_BYTE | I2C_FUNC_I2C)) //检查i2c_adapter的特性
return -ENODEV;
hdmi_i2c = client; //将该设备赋值到全局变量中hdmi_i2c
return 0;
}
----------------------------------------------------------------------------------------
static int __init mxc_hdmi_init(void)
{
return platform_driver_register(&mxc_hdmi_driver);
}
module_init(mxc_hdmi_init);
static struct platform_driver mxc_hdmi_driver = {
.probe = mxc_hdmi_probe,
.remove = mxc_hdmi_remove,
.driver = {
.name = "mxc_hdmi",
.of_match_table = imx_hdmi_dt_ids,
.owner = THIS_MODULE,
},
};
static int mxc_hdmi_probe(struct platform_device *pdev)
{
struct mxc_hdmi *hdmi;
struct device *temp_class;
struct resource *res;
int ret = 0;
/* Check I2C driver is loaded and available check hdcp function is enable by dts */
hdmi_hdcp_get_property(pdev);
if (!hdmi_i2c && !hdcp_init)
return -ENODEV;
res = platform_get_resource(pdev, IORESOURCE_MEM, 0); //获取platform资源res
hdmi = devm_kzalloc(&pdev->dev, sizeof(struct mxc_hdmi), GFP_KERNEL);
g_hdmi = hdmi; //将申请到的mxc_hdmi结构体类型的内存赋值给全局指针g_hdmi
hdmi_major = register_chrdev(hdmi_major, "mxc_hdmi", &mxc_hdmi_fops); //注册字符设备mxc_hdmi
hdmi_class = class_create(THIS_MODULE, "mxc_hdmi"); //在sys/class/路径下创建mxc_hdmi/目录
//在sys/class/mxc_hdmi/路径下创建设备节点mxc_hdmi
temp_class = device_create(hdmi_class, NULL, MKDEV(hdmi_major, 0), NULL, "mxc_hdmi");
hdmi->pdev = pdev;
hdmi->core_pdev = platform_device_alloc("mxc_hdmi_core", -1);
hdmi->gpr_base = ioremap(res->start, resource_size(res)); //通过ioremap将hdmi_video的物理地址映射为虚拟地址
hdmi->gpr_hdmi_base = hdmi->gpr_base + 3;
hdmi->gpr_sdma_base = hdmi->gpr_base;
hdmi->disp_mxc_hdmi = mxc_dispdrv_register(&mxc_hdmi_drv); //注册mxc_hdmi_drv
······
return 0;
}
static struct mxc_dispdrv_driver mxc_hdmi_drv = {
.name = DISPDRV_HDMI,
.init = mxc_hdmi_disp_init,
.deinit = mxc_hdmi_disp_deinit,
.enable = mxc_hdmi_power_on,
.disable = mxc_hdmi_power_off,
};
struct mxc_dispdrv_handle *mxc_dispdrv_register(struct mxc_dispdrv_driver *drv)
{
struct mxc_dispdrv_entry *new;
new = kzalloc(sizeof(struct mxc_dispdrv_entry), GFP_KERNEL);
new->drv = drv;
list_add_tail(&new->list, &dispdrv_list); //添加到dispdrv_list 链表
return (struct mxc_dispdrv_handle *)new;
}
以上是关于显示屏驱动的主要内容,如果未能解决你的问题,请参考以下文章