新路程------英飞凌imx6的lvds驱动

2024-09-04 00:58

本文主要是介绍新路程------英飞凌imx6的lvds驱动,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

  最近拿到一块开发版,打算在lvds上做些小修改,之前也接触过一点驱动,但是现在的驱动框架看起来和之前的有点差异。

关于lcd的参数信息请参考这篇文章 http://blog.csdn.net/longxiaowu/article/details/24319933

 lvds的驱动在framebuffer驱动之下,也就是上层应用只知道有个framebuffer设备也就是dev/fb,而至于下面的显示输出用vga也好hdmi也好还是lvds也好是不关心的。

lvds驱动干的事也挺简单,就是把fb_info这个机构体填充好而已,但是现在并没有在驱动中直接搞一个fb_info的结构体而是在framebuffer驱动中已经申请好了,ldb.c中拿过来

填充一下而已。

代码如下

static int ldb_disp_init(struct mxc_dispdrv_handle *disp,struct mxc_dispdrv_setting *setting)  //这个setting中有个fb_info结构体
{int ret = 0, i;struct ldb_data *ldb = mxc_dispdrv_getdata(disp);   //lvds自身的结构体struct fsl_mxc_ldb_platform_data *plat_data = ldb->pdev->dev.platform_data;struct resource *res;uint32_t base_addr;uint32_t reg, setting_idx;uint32_t ch_mask = 0, ch_val = 0;uint32_t ipu_id, disp_id;/* if input format not valid, make RGB666 as default*/if (!valid_mode(setting->if_fmt)) {dev_warn(&ldb->pdev->dev, "Input pixel format not valid"" use default RGB666\n");setting->if_fmt = IPU_PIX_FMT_RGB666;}if (!ldb->inited) {char di_clk[] = "ipu1_di0_clk";char ldb_clk[] = "ldb_di0_clk";int lvds_channel = 0;setting_idx = 0;res = platform_get_resource(ldb->pdev, IORESOURCE_MEM, 0);  //用来获取设备的各种参数比如基地址if (IS_ERR(res))return -ENOMEM;base_addr = res->start;ldb->reg = ioremap(base_addr, res->end - res->start + 1);ldb->control_reg = ldb->reg + 2;ldb->gpr3_reg = ldb->reg + 3;ldb->lvds_bg_reg = regulator_get(&ldb->pdev->dev, plat_data->lvds_bg_reg);if (!IS_ERR(ldb->lvds_bg_reg)) {regulator_set_voltage(ldb->lvds_bg_reg, 2500000, 2500000);regulator_enable(ldb->lvds_bg_reg);}/* ipu selected by platform data setting */setting->dev_id = plat_data->ipu_id;reg = readl(ldb->control_reg);/* refrence resistor select */reg &= ~LDB_BGREF_RMODE_MASK;if (plat_data->ext_ref)reg |= LDB_BGREF_RMODE_EXT;elsereg |= LDB_BGREF_RMODE_INT;/* TODO: now only use SPWG data mapping for both channel */reg &= ~(LDB_BIT_MAP_CH0_MASK | LDB_BIT_MAP_CH1_MASK);reg |= LDB_BIT_MAP_CH0_SPWG | LDB_BIT_MAP_CH1_SPWG;/* channel mode setting */reg &= ~(LDB_CH0_MODE_MASK | LDB_CH1_MODE_MASK);reg &= ~(LDB_DATA_WIDTH_CH0_MASK | LDB_DATA_WIDTH_CH1_MASK);if (bits_per_pixel(setting->if_fmt) == 24)reg |= LDB_DATA_WIDTH_CH0_24 | LDB_DATA_WIDTH_CH1_24;elsereg |= LDB_DATA_WIDTH_CH0_18 | LDB_DATA_WIDTH_CH1_18;if (g_ldb_mode)ldb->mode = g_ldb_mode;elseldb->mode = plat_data->mode;if ((ldb->mode == LDB_SIN0) || (ldb->mode == LDB_SIN1)) {ret = ldb->mode - LDB_SIN0;if (plat_data->disp_id != ret) {dev_warn(&ldb->pdev->dev,"change IPU DI%d to IPU DI%d for LDB ""channel%d.\n",plat_data->disp_id, ret, ret);plat_data->disp_id = ret;}} else if (((ldb->mode == LDB_SEP0) || (ldb->mode == LDB_SEP1))&& (cpu_is_mx6q() || cpu_is_mx6dl())) {if (plat_data->disp_id == plat_data->sec_disp_id) {dev_err(&ldb->pdev->dev,"For LVDS separate mode,""two DIs should be different!\n");return -EINVAL;}if (((!plat_data->disp_id) && (ldb->mode == LDB_SEP1))|| ((plat_data->disp_id) &&(ldb->mode == LDB_SEP0))) {dev_dbg(&ldb->pdev->dev,"LVDS separate mode:""swap DI configuration!\n");ipu_id = plat_data->ipu_id;disp_id = plat_data->disp_id;plat_data->ipu_id = plat_data->sec_ipu_id;plat_data->disp_id = plat_data->sec_disp_id;plat_data->sec_ipu_id = ipu_id;plat_data->sec_disp_id = disp_id;}}if (ldb->mode == LDB_SPL_DI0) {reg |= LDB_SPLIT_MODE_EN | LDB_CH0_MODE_EN_TO_DI0| LDB_CH1_MODE_EN_TO_DI0;setting->disp_id = 0;} else if (ldb->mode == LDB_SPL_DI1) {reg |= LDB_SPLIT_MODE_EN | LDB_CH0_MODE_EN_TO_DI1| LDB_CH1_MODE_EN_TO_DI1;setting->disp_id = 1;} else if (ldb->mode == LDB_DUL_DI0) {reg &= ~LDB_SPLIT_MODE_EN;reg |= LDB_CH0_MODE_EN_TO_DI0 | LDB_CH1_MODE_EN_TO_DI0;setting->disp_id = 0;} else if (ldb->mode == LDB_DUL_DI1) {reg &= ~LDB_SPLIT_MODE_EN;reg |= LDB_CH0_MODE_EN_TO_DI1 | LDB_CH1_MODE_EN_TO_DI1;setting->disp_id = 1;} else if (ldb->mode == LDB_SIN0) {reg &= ~LDB_SPLIT_MODE_EN;setting->disp_id = plat_data->disp_id;if (setting->disp_id == 0)reg |= LDB_CH0_MODE_EN_TO_DI0;elsereg |= LDB_CH0_MODE_EN_TO_DI1;ch_mask = LDB_CH0_MODE_MASK;ch_val = reg & LDB_CH0_MODE_MASK;} else if (ldb->mode == LDB_SIN1) {reg &= ~LDB_SPLIT_MODE_EN;setting->disp_id = plat_data->disp_id;if (setting->disp_id == 0)reg |= LDB_CH1_MODE_EN_TO_DI0;elsereg |= LDB_CH1_MODE_EN_TO_DI1;ch_mask = LDB_CH1_MODE_MASK;ch_val = reg & LDB_CH1_MODE_MASK;} else { /* separate mode*/setting->disp_id = plat_data->disp_id;/* first output is LVDS0 or LVDS1 */if (ldb->mode == LDB_SEP0)lvds_channel = 0;elselvds_channel = 1;reg &= ~LDB_SPLIT_MODE_EN;if ((lvds_channel == 0) && (setting->disp_id == 0))reg |= LDB_CH0_MODE_EN_TO_DI0;else if ((lvds_channel == 0) && (setting->disp_id == 1))reg |= LDB_CH0_MODE_EN_TO_DI1;else if ((lvds_channel == 1) && (setting->disp_id == 0))reg |= LDB_CH1_MODE_EN_TO_DI0;elsereg |= LDB_CH1_MODE_EN_TO_DI1;ch_mask = lvds_channel ? LDB_CH1_MODE_MASK :LDB_CH0_MODE_MASK;ch_val = reg & ch_mask;if (bits_per_pixel(setting->if_fmt) == 24) {if (lvds_channel == 0)reg &= ~LDB_DATA_WIDTH_CH1_24;elsereg &= ~LDB_DATA_WIDTH_CH0_24;} else {if (lvds_channel == 0)reg &= ~LDB_DATA_WIDTH_CH1_18;elsereg &= ~LDB_DATA_WIDTH_CH0_18;}}writel(reg, ldb->control_reg);if (ldb->mode <  LDB_SIN0) {ch_mask = LDB_CH0_MODE_MASK | LDB_CH1_MODE_MASK;ch_val = reg & (LDB_CH0_MODE_MASK | LDB_CH1_MODE_MASK);}/* clock setting */if ((cpu_is_mx6q() || cpu_is_mx6dl()) &&((ldb->mode == LDB_SEP0) || (ldb->mode == LDB_SEP1)))ldb_clk[6] += lvds_channel;elseldb_clk[6] += setting->disp_id;ldb->setting[setting_idx].ldb_di_clk = clk_get(&ldb->pdev->dev,ldb_clk);if (IS_ERR(ldb->setting[setting_idx].ldb_di_clk)) {dev_err(&ldb->pdev->dev, "get ldb clk0 failed\n");iounmap(ldb->reg);return PTR_ERR(ldb->setting[setting_idx].ldb_di_clk);}di_clk[3] += setting->dev_id;di_clk[7] += setting->disp_id;ldb->setting[setting_idx].di_clk = clk_get(&ldb->pdev->dev,di_clk);if (IS_ERR(ldb->setting[setting_idx].di_clk)) {dev_err(&ldb->pdev->dev, "get di clk0 failed\n");iounmap(ldb->reg);return PTR_ERR(ldb->setting[setting_idx].di_clk);}dev_dbg(&ldb->pdev->dev, "ldb_clk to di clk: %s -> %s\n", ldb_clk, di_clk);/* fb notifier for clk setting */ldb->nb.notifier_call = ldb_fb_event,ret = fb_register_client(&ldb->nb);if (ret < 0) {iounmap(ldb->reg);return ret;}ldb->inited = true;} //在此之前都是设置一些register的参数而已ldb->setting[setting_idx].ch_mask = ch_mask;ldb->setting[setting_idx].ch_val = ch_val;if (cpu_is_mx6q() || cpu_is_mx6dl())ldb_ipu_ldb_route(setting->dev_id, setting->disp_id, ldb);/** ldb_di0_clk -> ipux_di0_clk* ldb_di1_clk -> ipux_di1_clk*/clk_set_parent(ldb->setting[setting_idx].di_clk,ldb->setting[setting_idx].ldb_di_clk);/* must use spec video mode defined by driver */ret = fb_find_mode(&setting->fbi->var, setting->fbi, setting->dft_mode_str,ldb_modedb, ldb_modedb_sz, NULL, setting->default_bpp);  //填充fb_videomode,填充fb_var_screeninfoif (ret != 1)fb_videomode_to_var(&setting->fbi->var, &ldb_modedb[0]);INIT_LIST_HEAD(&setting->fbi->modelist);for (i = 0; i < ldb_modedb_sz; i++) {struct fb_videomode m;fb_var_to_videomode(&m, &setting->fbi->var);if (fb_mode_is_equal(&m, &ldb_modedb[i])) {fb_add_videomode(&ldb_modedb[i],&setting->fbi->modelist);  //把选中的mode加入到list中去break;}}/* save current ldb setting for fb notifier */ldb->setting[setting_idx].active = true;ldb->setting[setting_idx].ipu = setting->dev_id;ldb->setting[setting_idx].di = setting->disp_id;return ret;
}

到此结束,一个fb_fix_screeninfo没有看到在哪里被赋值,还有就是没有看到framebuffer_register

其实framebuffer_register是在mxc_ipuv3_fb.c中

fbi = mxcfb_init_fbinfo(&pdev->dev, &mxcfb_ops);   //初始化fb_info结构体, 其中fb->var.active为FB_ACTIVATE_NOW


ret = mxcfb_option_setup(pdev, fbi);    //从cmdline获取fb设置,如果没有,就默认使用board中tek_fb_data里的值。


fb_get_options    //拿之前video=mxcfb0获取的值和mxcfbx做比较,如果相匹配,然后在解析对应后面的参数。x是当前对应的fb number号,所以这样就会一一对应。如果后面带:off字样,表示不使用此路通道。

ret = mxcfb_dispdrv_init(pdev, fbi);就是这里调用了ldb.c里的init

mxc_dispdrv_gethandle ->    //根据传进来的disp_dev name在dispdrv_list中匹配获取对应的driver handle,这里是获取的是ldb的handle,它的注册是在ldb_probe()的mxc_dispdrv_register实现的,它将自己添加到了dispdrv_list。

entry->drv->init    ->    //mxc_dispdrv.c 调用对应driver的init函数,这里就是ldb driver对应的init了。
 ldb_disp_init ->    ldb.c
fb_find_mode    //寻找最合适的LCD参数
mxcfb_register    ->

register_framebuffer    //注册fb

所有现在的架构就是和以前不一样了

这篇关于新路程------英飞凌imx6的lvds驱动的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/1134547

相关文章

Linux_kernel驱动开发11

一、改回nfs方式挂载根文件系统         在产品将要上线之前,需要制作不同类型格式的根文件系统         在产品研发阶段,我们还是需要使用nfs的方式挂载根文件系统         优点:可以直接在上位机中修改文件系统内容,延长EMMC的寿命         【1】重启上位机nfs服务         sudo service nfs-kernel-server resta

安卓玩机工具------小米工具箱扩展工具 小米机型功能拓展

小米工具箱扩展版                     小米工具箱扩展版 iO_Box_Mi_Ext是由@晨钟酱开发的一款适用于小米(MIUI)、多亲(2、2Pro)、多看(多看电纸书)的多功能工具箱。该工具所有功能均可以免root实现,使用前,请打开开发者选项中的“USB调试”  功能特点 【小米工具箱】 1:冻结MIUI全家桶,隐藏状态栏图标,修改下拉通知栏图块数量;冻结

驱动(RK3588S)第七课时:单节点设备树

目录 需求一、设备树的概念1、设备树的后缀名:2、设备树的语法格式3、设备树的属性(重要)4、设备树格式举例 二、设备树所用函数1、如何在内核层种获取设备树节点:2、从设备树上获取 gpio 口的属性3、获取节点上的属性只针对于字符串属性的4、函数读取 np 结点中的 propname 属性的值,并将读取到的 u32 类型的值保存在 out_value 指向的内存中,函数的返回值表示读取到的

驱动安装注册表指令

HKCR: HKEY_CLASSES_ROOT HKCU: HKEY_CURRENT_USER HKLM: HKEY_LOCAL_MACHINE HKU: HEKY_USER HER: 相对根键

UMDF驱动安装

VS2013 + WDF8.1,UMDF驱动选择User Mode Driver,不要选User Mode Driver 2.0,否则Win7安装有问题,如图 另外,在驱动安装时不要忘记WUDFUpdate_<主版本号><次版本号>.dll文件,具体文件名在INF中查找。此文件可在WDF的安装目录中找到。注意:在WDF的安装目录中会有3个WUDFUpdate_xxx.dll文件,x86,x6

电脑驱动分类

电脑驱动程序(驱动程序)是操作系统与硬件设备之间的桥梁,用于使操作系统能够识别并与硬件设备进行通信。以下是常见的驱动分类: 1. 设备驱动程序 显示驱动程序:控制显卡和显示器的显示功能,负责图形渲染和屏幕显示。 示例:NVIDIA、AMD 显示驱动程序。打印机驱动程序:允许操作系统与打印机通信,控制打印任务。 示例:HP、Canon 打印机驱动程序。声卡驱动程序:管理音频输入和输出,与声卡硬件

麒麟系统安装GPU驱动

1.nvidia 1.1显卡驱动 本机显卡型号:nvidia rtx 3090 1.1.1下载驱动 打开 https://www.nvidia.cn/geforce/drivers/ 也可以直接使用下面这个地址下载 https://www.nvidia.com/download/driverResults.aspx/205464/en-us/ 1.1.3安装驱动 右击,

windows10 卸载网络驱动以及重新安装

右键桌面此电脑的图标,点击管理,设备管理器—网络适配器,找到下图中的驱动(不同的系统或者显卡会导致网卡驱动名称与下图不一样,多为Realtek开头),右键选择卸载设备,然后重启电脑,系统会自动重新安装驱动 新电脑首次安装驱动: 根据主板厂家,比如华硕,进入华硕官网,点击服务支持,点击下载中心,选择型号,点击右侧驱动程序和工具软件,选择windows版本,下载相应的驱动,下载完之后在对应文件中找

笔记整理—内核!启动!—kernel部分(1)驱动与内核的关系

首先,恭喜完成了uboot部分的内容整理,其次补充一点,uboot第一部分和第二部分的工作不是一定的,在不同的版本中,可能这个初始化早一点,那个的又放在了第二部分,版本不同,造成的工作顺序不同,但终归是要完成基本内容初始化并传参给kernel的。         那么至于驱动与内核的关系,用一张图来说明最适合不过:         驱动位于OS层的中下层与硬件相接。驱动是内

RK3288 点亮LVDS屏

本文记录调试 LVDS接口屏的一些关键步骤,主要是dts文件中关于 频率、分辨率 、时序参数的设置  环境: RK3288 9tripod CV5  linux 4.4.189 LCD:JYT121XQ01 (追曦 DS1212)12.1电容触控屏   查看屏幕规格书    只要在rockchip dts 中 设置 T(HB)=Thb+Thf+Thsyn=320clock  T