diff --git a/IMX6ULL/doc_pic/03_LCD/17_单Buffer的缺点与改进方法.md b/IMX6ULL/doc_pic/03_LCD/17_单Buffer的缺点与改进方法.md index 49d672d..55d2ba4 100644 --- a/IMX6ULL/doc_pic/03_LCD/17_单Buffer的缺点与改进方法.md +++ b/IMX6ULL/doc_pic/03_LCD/17_单Buffer的缺点与改进方法.md @@ -19,16 +19,118 @@ ### 1. 单Buffer的缺点 +* 如果APP速度很慢,可以看到它在LCD上缓慢绘制图案 +* 即使APP速度很高,LCD控制器不断从Framebuffer中读取数据来显示,而APP不断把数据写入Framebuffer + + * 假设APP想把LCD显示为整屏幕的蓝色、红色 + + * 很大几率出现这种情况: + + * LCD控制器读取Framebuffer数据,读到一半时,在LCD上显示了半屏幕的蓝色 + * 这是APP非常高效地把整个Framebuffer的数据都改为了红色 + * LCD控制器继续读取数据,于是LCD上就会显示半屏幕蓝色、半屏幕红色 + * 人眼就会感觉到屏幕闪烁、撕裂 + + ![image-20210203172823180](pic/02_LCD驱动/048_singble_buffer.png) ### 2. 使用多Buffer来改进 +上述两个缺点的根源是一致的:Framebuffer中的数据还没准备好整帧数据,就被LCD控制器使用了。 +使用双buffer甚至多buffer可以解决这个问题: - -### 3. 内核驱动程序分析 - - -### 4. APP编写方法 +* 假设有2个Framebuffer:FB0、FB1 +* LCD控制器正在读取FB0 +* APP写FB1 +* 写好FB1后,让LCD控制器切换到FB1 +* APP写FB0 +* 写好FB0后,让LCD控制器切换到FB0 +### 3. 内核驱动程序、APP互相配合使用多buffer + +流程如下: + +![image-20210203180534206](pic/02_LCD驱动/049_drv_app_use_double_buff.png) + +* 驱动:分配多个buffer + + ```c + fb_info->fix.smem_len = SZ_32M; + fbi->screen_base = dma_alloc_writecombine(fbi->device, + fbi->fix.smem_len, + (dma_addr_t *)&fbi->fix.smem_start, + GFP_DMA | GFP_KERNEL); + ``` + + + +* 驱动:保存buffer信息 + + ```c + fb_info->fix.smem_len // 含有总buffer大小 + fb_info->var // 含有单个buffer信息 + ``` + +* APP:读取buffer信息 + + ```c + ioctl(fd_fb, FBIOGET_FSCREENINFO, &fix); + ioctl(fd_fb, FBIOGET_VSCREENINFO, &var); + + // 计算是否支持多buffer,有多少个buffer + screen_size = var.xres * var.yres * var.bits_per_pixel / 8; + nBuffers = fix.smem_len / screen_size; + ``` + +* APP:使能多buffer + + ```c + var.yres_virtual = nBuffers * var.yres; + ioctl(fd_fb, FBIOPUT_VSCREENINFO, &var); + ``` + +* APP:写buffer + + ```c + fb_base = (unsigned char *)mmap(NULL , fix.smem_len, PROT_READ | PROT_WRITE, MAP_SHARED, fd_fb, 0); + + /* get buffer */ + pNextBuffer = fb_base + nNextBuffer * screen_size; + + /* set buffer */ + lcd_draw_screen(pNextBuffer, colors[i]); + ``` + +* APP:开始切换buffer + + ```c + /* switch buffer */ + var.yoffset = nNextBuffer * var.yres; + ioctl(fd_fb, FBIOPAN_DISPLAY, &var); + ``` + +* 驱动:切换buffer + + ```c + // fbmem.c + fb_ioctl + do_fb_ioctl + fb_pan_display(info, &var); + err = info->fbops->fb_pan_display(var, info) // 调用硬件相关的函数 + ``` + + 示例: + ![image-20210203180357860](pic/02_LCD驱动/050_mxsfb_pan_display.png) + + + +* APP:等待切换完成(在驱动程序中已经等待切换完成了,所以这个调用并无必要) + + ```c + ret = 0; + ioctl(fd_fb, FBIO_WAITFORVSYNC, &ret); + ``` + + \ No newline at end of file diff --git a/IMX6ULL/doc_pic/03_LCD/pic/02_LCD驱动/048_singble_buffer.png b/IMX6ULL/doc_pic/03_LCD/pic/02_LCD驱动/048_singble_buffer.png new file mode 100644 index 0000000..83007a5 Binary files /dev/null and b/IMX6ULL/doc_pic/03_LCD/pic/02_LCD驱动/048_singble_buffer.png differ diff --git a/IMX6ULL/doc_pic/03_LCD/pic/02_LCD驱动/049_drv_app_use_double_buff.png b/IMX6ULL/doc_pic/03_LCD/pic/02_LCD驱动/049_drv_app_use_double_buff.png new file mode 100644 index 0000000..95dd901 Binary files /dev/null and b/IMX6ULL/doc_pic/03_LCD/pic/02_LCD驱动/049_drv_app_use_double_buff.png differ diff --git a/IMX6ULL/doc_pic/03_LCD/pic/02_LCD驱动/050_mxsfb_pan_display.png b/IMX6ULL/doc_pic/03_LCD/pic/02_LCD驱动/050_mxsfb_pan_display.png new file mode 100644 index 0000000..17c308e Binary files /dev/null and b/IMX6ULL/doc_pic/03_LCD/pic/02_LCD驱动/050_mxsfb_pan_display.png differ diff --git a/README.md b/README.md index 33b6710..e7414e3 100644 --- a/README.md +++ b/README.md @@ -71,6 +71,10 @@ git clone https://e.coding.net/weidongshan/doc_and_source_for_drivers.git * 2021.01.28 发布"LCD驱动":16\_上机实验\_基于IMX6ULL * 2021.01.29 发布"LCD驱动":17\_单Buffer的缺点与改进方法 * 2021.02.01 发布"LCD驱动":18\_编写使用多buffer的应用程序 +* 2021.02.03 发布"LCD驱动": + * 15\_编程_配置LCD控制器之寄存器操作\_基于STM32MP157 + * 16\_上机实验\_基于STM32MP157 + * 18\_STM32MP157内核自带的LCD驱动不支持多buffer diff --git a/STM32MP157/doc_pic/03_LCD/09_硬件_STM32MP157的LCD控制器.md b/STM32MP157/doc_pic/03_LCD/09_硬件_STM32MP157的LCD控制器.md index 0ba7f4e..f58aad3 100644 --- a/STM32MP157/doc_pic/03_LCD/09_硬件_STM32MP157的LCD控制器.md +++ b/STM32MP157/doc_pic/03_LCD/09_硬件_STM32MP157的LCD控制器.md @@ -222,8 +222,8 @@ CFBADD:设置LAYER1(图层1)的显存地址。 ![](pic/02_LCD驱动/030_LTDC_L1CFBLR.png) -CFBP:Framebuffer中以行像素所占据的字节数 -CFBLL:Framebuffer中以行像素所占据的字节数+7 +CFBP:Framebuffer中一行像素所占据的字节数 +CFBLL:Framebuffer中一行像素所占据的字节数+7 diff --git a/STM32MP157/doc_pic/03_LCD/14_编程_配置LCD控制器_基于STM32MP157.md b/STM32MP157/doc_pic/03_LCD/14_编程_配置LCD控制器之获得LCD参数_基于STM32MP157.md similarity index 92% rename from STM32MP157/doc_pic/03_LCD/14_编程_配置LCD控制器_基于STM32MP157.md rename to STM32MP157/doc_pic/03_LCD/14_编程_配置LCD控制器之获得LCD参数_基于STM32MP157.md index 2beea93..5d09a35 100644 --- a/STM32MP157/doc_pic/03_LCD/14_编程_配置LCD控制器_基于STM32MP157.md +++ b/STM32MP157/doc_pic/03_LCD/14_编程_配置LCD控制器之获得LCD参数_基于STM32MP157.md @@ -108,7 +108,8 @@ LCD驱动程序的核心就是: 参考内核文件: * `drivers\video\of_videomode.c` -* `drivers\video\fbdev\mxsfb.c` +* GIT仓库里IMX6ULL的驱动程序 + * `STM32MP157\source\A7\03_LCD\12_lcd_drv_imx6ull_from_kernel_4.9.88\mxsfb.c` #### 3.2 使用参数配置LCD控制器 diff --git a/STM32MP157/doc_pic/03_LCD/14_编程_配置LCD控制器_基于STM32MP157.tif b/STM32MP157/doc_pic/03_LCD/14_编程_配置LCD控制器之获得LCD参数_基于STM32MP157.tif similarity index 100% rename from STM32MP157/doc_pic/03_LCD/14_编程_配置LCD控制器_基于STM32MP157.tif rename to STM32MP157/doc_pic/03_LCD/14_编程_配置LCD控制器之获得LCD参数_基于STM32MP157.tif diff --git a/STM32MP157/doc_pic/03_LCD/15_编程_配置LCD控制器之寄存器操作_基于STM32MP157.md b/STM32MP157/doc_pic/03_LCD/15_编程_配置LCD控制器之寄存器操作_基于STM32MP157.md new file mode 100644 index 0000000..83539af --- /dev/null +++ b/STM32MP157/doc_pic/03_LCD/15_编程_配置LCD控制器之寄存器操作_基于STM32MP157.md @@ -0,0 +1,125 @@ +## 编程\_配置LCD控制器之寄存器操作\_基于STM32MP157 + +参考资料,GIT仓库里: + +* 芯片资料 + + * `STM32MP157\开发板配套资料\datasheeet\02_Core_board(核心板)\CPU\CPU开发参考手册\DM00327659.pdf` + * `《35 LCD-TFT display controller (LTDC)》` + +* STM32MP157的LCD裸机程序 + + * `STM32MP157\source\A7\03_LCD\05_参考的裸机源码\03_font_test` + +* 内核自带的STM32MP157 LCD驱动程序 + * 驱动源码: + + * LCD相关:`Linux-5.4\drivers\gpu\drm\panel\panel-myir070tft.c` + * LCD控制器相关:`Linux-5.4\drivers\gpu\drm\stm\ltdc.c` + * GPU相关:`Linux-5.4\drivers\gpu\drm\stm\drv.c` + * 设备树: + * `Linux-5.4/arch/arm/boot/dts/stm32mp157c-100ask-512d-lcd-v1.dts` + * `Linux-5.4/arch/arm/boot/dts/stm32mp151.dtsi` + * `Linux-5.4/arch/arm/boot/dts/stm32mp15-pinctrl.dtsi` + +* 本节视频编写好的代码 + + * `STM32MP157\source\A7\03_LCD\10_lcd_drv_lcdcontroller_reg_config_use_devicetre` + +* 引脚配置工具/设备树生成工具 + + * 打开:http://download.100ask.net/ + * 找到开发板:"100ASK_STM32MP157_PRO开发板" + * 下载开发板配套资料 + * 下载完后,工具在如下目录里: + + ![image-20210122094724188](pic/02_LCD驱动/041_pins_tools.png) + +### 1. 硬件相关的操作 + +LCD驱动程序的核心就是: + +* 分配fb_info +* 设置fb_info +* 注册fb_info +* 硬件相关的设置 + + + +硬件相关的设置又可以分为3部分: + * 引脚设置 + * 时钟设置 + * LCD控制器设置 + + + +### 2. 在设备树里指定LCD参数 + +```shell + framebuffer-mylcd { + compatible = "100ask,lcd_drv"; + pinctrl-names = "default"; + pinctrl-0 = <&mylcd_pinctrl>; + backlight-gpios = <&gpio1 8 GPIO_ACTIVE_HIGH>; + + clocks = <&clks IMX6UL_CLK_LCDIF_PIX>, + <&clks IMX6UL_CLK_LCDIF_APB>; + clock-names = "pix", "axi"; + + display = <&display0>; + + display0: display { + bits-per-pixel = <24>; + bus-width = <24>; + + display-timings { + native-mode = <&timing0>; + + timing0: timing0_1024x768 { + clock-frequency = <50000000>; + hactive = <1024>; + vactive = <600>; + hfront-porch = <160>; + hback-porch = <140>; + hsync-len = <20>; + vback-porch = <20>; + vfront-porch = <12>; + vsync-len = <3>; + + hsync-active = <0>; + vsync-active = <0>; + de-active = <1>; + pixelclk-active = <0>; + }; + + }; + }; + }; +``` + + + +### 3. 编程 + +#### 3.1 从设备树获得参数 + +时序参数、引脚极性等信息,都被保存在一个display_timing结构体里: + +![image-20210125185436508](pic/02_LCD驱动/042_display_timing.png) + +参考内核文件: + +* `drivers\video\of_display_timing.c` + +* `drivers\video\fbdev\mxsfb.c` + + + +#### 3.2 使用参数配置LCD控制器 + +根据芯片手册,一个一个设置寄存器: + +* Framebuffer地址设置 +* Framebuffer中数据格式设置 +* LCD时序参数设置 +* LCD引脚极性设置 \ No newline at end of file diff --git a/STM32MP157/doc_pic/03_LCD/16_上机实验_基于STM32MP157.md b/STM32MP157/doc_pic/03_LCD/16_上机实验_基于STM32MP157.md new file mode 100644 index 0000000..da5a7e2 --- /dev/null +++ b/STM32MP157/doc_pic/03_LCD/16_上机实验_基于STM32MP157.md @@ -0,0 +1,229 @@ +## 上机实验\_基于STM32MP157 + +参考资料,GIT仓库里: + +* 芯片资料 + + * `STM32MP157\开发板配套资料\datasheeet\02_Core_board(核心板)\CPU\CPU开发参考手册\DM00327659.pdf` + * `《35 LCD-TFT display controller (LTDC)》` + +* STM32MP157的LCD裸机程序 + + * `STM32MP157\source\A7\03_LCD\05_参考的裸机源码\03_font_test` + +* 内核自带的STM32MP157 LCD驱动程序 + * 驱动源码: + + * LCD相关:`Linux-5.4\drivers\gpu\drm\panel\panel-myir070tft.c` + * LCD控制器相关:`Linux-5.4\drivers\gpu\drm\stm\ltdc.c` + * GPU相关:`Linux-5.4\drivers\gpu\drm\stm\drv.c` + * 设备树: + * `Linux-5.4/arch/arm/boot/dts/stm32mp157c-100ask-512d-lcd-v1.dts` + * `Linux-5.4/arch/arm/boot/dts/stm32mp151.dtsi` + * `Linux-5.4/arch/arm/boot/dts/stm32mp15-pinctrl.dtsi` + +* 本节视频测试通过的代码 + + * `STM32MP157\source\A7\03_LCD\11_lcd_drv_stm32mp157_ok` + +* 搭建开发环境 +* 视频:https://www.100ask.net/ + * 《Linux系列教程之快速入门》之《【第2篇】环境搭建、Linux基本操作、工具使用》 + * 文档:` git clone https://e.coding.net/weidongshan/01_all_series_quickstart.git` + * 《嵌入式Linux应用开发完全手册\_韦东山全系列视频文档全集V2.8.pdf》 + +### 1. 要做的事情 + +* 去除内核自带的驱动程序 + +* 加入我们编写的驱动程序、设备树文件 + +* 重新编译内核、设备树 + +* 上机测试:使用编译出来的内核、设备树启动板子 + + + +### 2. 去除内核自带的驱动程序 +* 设置工具链 + + ```shell + source /home/book/100ask_stm32mp157_pro-sdk/ToolChain/openstlinux_eglfs-linux-gnueabi/environment-setup-cortexa7t2hf-neon-vfpv4-ostl-linux-gnueabi + export ARCH=arm + export CROSS_COMPILE=arm-ostl-linux-gnueabi- + ``` + +* 配置内核使用STM32MP157默认配置 + + ```shell + ~/100ask_stm32mp157_pro-sdk/$ cd Linux-5.4 + ~/100ask_stm32mp157_pro-sdk/Linux-5.4$ make 100ask_stm32mp157_pro_defconfig + ``` +* 去掉自带的驱动程序:执行`make menuconfig`,如下配置内核 + ```shell + Device Drivers ---> + Graphics support ---> + < > DRM Support for STMicroelectronics SoC Series // 输入N + ``` + + + +* 解决可能出现的问题 + + * 如果执行`make menuconfnig`出现如下问题: + + ![image-20210203095417662](pic/02_LCD驱动/043_make_menuconfig_ncurse.png) + + * 就先执行以下命令: + + ```shell + sudo apt install lib32ncursesw5 lib32ncursesw5-dev + ``` + + + +### 3. 加入新驱动程序、设备树 +* 复制驱动程序: + * 把`11_lcd_drv_stm32mp157_ok\lcd_drv.c`放到内核源码目录`drivers/video/fbdev` + * 备份内核自带设备树文件:`arch/arm/boot/dts/stm32mp157c-100ask-512d-lcd-v1.dts` + * 把`11_lcd_drv_stm32mp157_ok\stm32mp157c-100ask-512d-lcd-v1.dts`放到内核源码目录`arch/arm/boot/dts/` + +* 修改内核文件: + * 修改:`drivers/video/fbdev/Makefile`,使用我们提供的lcd_drv.c,如下: + + ```shell +obj-y += lcd_drv.o + ``` + + + +### 4. 重新编译内核、设备树 + +**以下命令在Ubuntu中执行。** + +* 设置工具链 + + ```shell + source /home/book/100ask_stm32mp157_pro-sdk/ToolChain/openstlinux_eglfs-linux-gnueabi/environment-setup-cortexa7t2hf-neon-vfpv4-ostl-linux-gnueabi + export ARCH=arm + export CROSS_COMPILE=arm-ostl-linux-gnueabi- + ``` + +* 配置、编译 + + ```shell + ~/100ask_stm32mp157_pro-sdk/$ cd Linux-5.4 + ~/100ask_stm32mp157_pro-sdk/Linux-5.4$ + ~/100ask_stm32mp157_pro-sdk/Linux-5.4$ make uImage LOADADDR=0xC2000040 + ~/100ask_stm32mp157_pro-sdk/Linux-5.4$ make dtbs + ``` + +* 得到 + * 内核:`arch/arm/boot/uImage` + * 设备树文件:`arch/arm/boot/dts/stm32mp157c-100ask-512d-lcd-v1.dtb` + +* 复制到NFS目录: + + ```shell + $ cp arch/arm/boot/uImage ~/nfs_rootfs/ + $ cp arch/arm/boot/dts/stm32mp157c-100ask-512d-lcd-v1.dtb ~/nfs_rootfs/ + ``` + + + +### 5. 上机测试 + +**以下命令在开发板中执行。** + +#### 5.1 更换内核、设备树 + +* 挂载NFS + + * vmware使用NAT(假设windowsIP为192.168.1.100) + + ```shell + [root@100ask:~]# mount -t nfs -o nolock,vers=3,port=2049,mountport=9999 + 192.168.1.100:/home/book/nfs_rootfs /mnt + ``` + + * vmware使用桥接,或者不使用vmware而是直接使用服务器:假设Ubuntu IP为192.168.1.137 + + ```shell + [root@100ask:~]# mount -t nfs -o nolock,vers=3 192.168.1.137:/home/book/nfs_rootfs /mnt + ``` + +* 确定单板上内核、设备树保存在哪里 + + 由于版本变化,STM32MP157单板上烧录的系统可能有细微差别,在开发板上执行`cat /proc/mounts`后, + 可以得到两种结果(见下图): + + * 保存内核、设备树的分区,挂载在/boot目录下:无需特殊操作 + * 保存内核、设备树的分区,挂载在/mnt目录下 + * 在视频里、后面文档里,都是更新/boot目录下的文件,所以要先执行以下命令重新挂载: + * `mount /dev/mmcblk2p2 /boot` + + + ![image-20210203132435507](pic/02_LCD驱动/047_boot_mount.png) + +* 更新单板文件 + + ```shell + [root@100ask:~]# cp /mnt/uImage /boot + [root@100ask:~]# cp /mnt/stm32mp157c-100ask-512d-lcd-v1.dtb /boot + [root@100ask:~]# sync + ``` + +* 重启开发板观察现象 + + * 如果可以看到企鹅LOGO,就表示正常 + + * 如果在终端中可以查看到存在`/dev/fb0`节点,也表示正常 + + + + +#### 5.2 板子无法启动,使用uboot下载内核、设备树 + +使用新内核、设备树启动单板时,打印`Starting kernel`后就再无输出,串口信息如下: +![image-20210203094102367](pic/02_LCD驱动/044_cannot_boot.png) + +这表示内核或设备树有问题,只能使用uboot来下载其他内核、设备树来调试。 + +重启开发板,按住空格进入uboot,在uboot使用nfs命令下载uImage、设备树来启动开发板。 + +* 以下命令适用于:vmware使用桥接 + +```shell +=> setenv ipaddr 192.168.1.112 //设置开发板的IP地址。 +=> nfs c4000000 192.168.1.137:/home/book/nfs_rootfs/stm32mp157c-100ask-512d-lcd-v1.dtb +=> nfs c4100000 192.168.1.137:/home/book/nfs_rootfs/uImage +=> setenv bootargs root=/dev/mmcblk2p3 rw +=> bootm c4100000 - 0xc4000000 +``` + + + +* 以下命令使用于:vmware使用NAT,并且先启动tftpd64,在tftpd64所设置目录下放入uImage和设备树文件 + +```shell +=> setenv serverip 192.168.1.100 //设置服务器的IP地址,这里指的是Ubuntu主机IP +=> setenv ipaddr 192.168.1.112 //设置开发板的IP地址。 +=> tftpboot 0xc4000000 stm32mp157c-100ask-512d-lcd-v1.dtb +=> tftpboot c4100000 uImage +=> setenv bootargs root=/dev/mmcblk2p3 rw +=> bootm c4100000 - 0xc4000000 +``` + + + +#### 5. 问题所在 + +* 设备树中引脚冲突,如下修改 + +![image-20210203094835973](pic/02_LCD驱动/045_pins_conflict.png) + + + +* 驱动程序函数使用方法有变化 + +![image-20210203095040925](pic/02_LCD驱动/046_dma_alloc_wc.png) \ No newline at end of file diff --git a/STM32MP157/doc_pic/03_LCD/17_单Buffer的缺点与改进方法.md b/STM32MP157/doc_pic/03_LCD/17_单Buffer的缺点与改进方法.md index 49d672d..55d2ba4 100644 --- a/STM32MP157/doc_pic/03_LCD/17_单Buffer的缺点与改进方法.md +++ b/STM32MP157/doc_pic/03_LCD/17_单Buffer的缺点与改进方法.md @@ -19,16 +19,118 @@ ### 1. 单Buffer的缺点 +* 如果APP速度很慢,可以看到它在LCD上缓慢绘制图案 +* 即使APP速度很高,LCD控制器不断从Framebuffer中读取数据来显示,而APP不断把数据写入Framebuffer + + * 假设APP想把LCD显示为整屏幕的蓝色、红色 + + * 很大几率出现这种情况: + + * LCD控制器读取Framebuffer数据,读到一半时,在LCD上显示了半屏幕的蓝色 + * 这是APP非常高效地把整个Framebuffer的数据都改为了红色 + * LCD控制器继续读取数据,于是LCD上就会显示半屏幕蓝色、半屏幕红色 + * 人眼就会感觉到屏幕闪烁、撕裂 + + ![image-20210203172823180](pic/02_LCD驱动/048_singble_buffer.png) ### 2. 使用多Buffer来改进 +上述两个缺点的根源是一致的:Framebuffer中的数据还没准备好整帧数据,就被LCD控制器使用了。 +使用双buffer甚至多buffer可以解决这个问题: - -### 3. 内核驱动程序分析 - - -### 4. APP编写方法 +* 假设有2个Framebuffer:FB0、FB1 +* LCD控制器正在读取FB0 +* APP写FB1 +* 写好FB1后,让LCD控制器切换到FB1 +* APP写FB0 +* 写好FB0后,让LCD控制器切换到FB0 +### 3. 内核驱动程序、APP互相配合使用多buffer + +流程如下: + +![image-20210203180534206](pic/02_LCD驱动/049_drv_app_use_double_buff.png) + +* 驱动:分配多个buffer + + ```c + fb_info->fix.smem_len = SZ_32M; + fbi->screen_base = dma_alloc_writecombine(fbi->device, + fbi->fix.smem_len, + (dma_addr_t *)&fbi->fix.smem_start, + GFP_DMA | GFP_KERNEL); + ``` + + + +* 驱动:保存buffer信息 + + ```c + fb_info->fix.smem_len // 含有总buffer大小 + fb_info->var // 含有单个buffer信息 + ``` + +* APP:读取buffer信息 + + ```c + ioctl(fd_fb, FBIOGET_FSCREENINFO, &fix); + ioctl(fd_fb, FBIOGET_VSCREENINFO, &var); + + // 计算是否支持多buffer,有多少个buffer + screen_size = var.xres * var.yres * var.bits_per_pixel / 8; + nBuffers = fix.smem_len / screen_size; + ``` + +* APP:使能多buffer + + ```c + var.yres_virtual = nBuffers * var.yres; + ioctl(fd_fb, FBIOPUT_VSCREENINFO, &var); + ``` + +* APP:写buffer + + ```c + fb_base = (unsigned char *)mmap(NULL , fix.smem_len, PROT_READ | PROT_WRITE, MAP_SHARED, fd_fb, 0); + + /* get buffer */ + pNextBuffer = fb_base + nNextBuffer * screen_size; + + /* set buffer */ + lcd_draw_screen(pNextBuffer, colors[i]); + ``` + +* APP:开始切换buffer + + ```c + /* switch buffer */ + var.yoffset = nNextBuffer * var.yres; + ioctl(fd_fb, FBIOPAN_DISPLAY, &var); + ``` + +* 驱动:切换buffer + + ```c + // fbmem.c + fb_ioctl + do_fb_ioctl + fb_pan_display(info, &var); + err = info->fbops->fb_pan_display(var, info) // 调用硬件相关的函数 + ``` + + 示例: + ![image-20210203180357860](pic/02_LCD驱动/050_mxsfb_pan_display.png) + + + +* APP:等待切换完成(在驱动程序中已经等待切换完成了,所以这个调用并无必要) + + ```c + ret = 0; + ioctl(fd_fb, FBIO_WAITFORVSYNC, &ret); + ``` + + \ No newline at end of file diff --git a/STM32MP157/doc_pic/03_LCD/18_STM32MP157内核自带的LCD驱动不支持多buffer.md b/STM32MP157/doc_pic/03_LCD/18_STM32MP157内核自带的LCD驱动不支持多buffer.md new file mode 100644 index 0000000..62f57f5 --- /dev/null +++ b/STM32MP157/doc_pic/03_LCD/18_STM32MP157内核自带的LCD驱动不支持多buffer.md @@ -0,0 +1,179 @@ +## STM32MP157内核自带的LCD驱动不支持多buffer + +* 本节视频编写好的程序,在GIT仓库里 + * `IMX6ULL\source\03_LCD\14_use_multi_framebuffer` + * `STM32MP157\source\A7\03_LCD\14_use_multi_framebuffer` + +* 参考程序:应用基础课程里使用Framebuffer的精简程序 + * `IMX6ULL\source\03_LCD\14_use_multi_framebuffer\reference\07_framebuffer` + * `STM32MP157\source\A7\03_LCD\14_use_multi_framebuffer\reference\07_framebuffer` + +* 参考程序:使用多buffer的APP,在GIT仓库里 + * `IMX6ULL\source\03_LCD\13_multi_framebuffer_example\testcamera` + * `STM32MP157\source\A7\03_LCD\13_multi_framebuffer_example\testcamera` + + + +### 1. STM32MP157内核自带的LCD驱动不支持都buffer + +所以无法在STM32MP157观察到多buffer的效果。 +如果想学习多buffer的APP如何编写,请学习IMX6ULL的视频:`18_编写使用多buffer的应用程序` + + + +### 2. 恢复自带的驱动(不想那么复杂的话,直接重烧系统) + +**注意**: + +* 一旦使用重新编译的内核,板子自带的GUI无法运行 + +* 原因在于内核重新编译后,也需要重新编译、安装各类模块,还有第3方模块。 + +* 编译第3方模块涉及buildroot的使用 + +* 这些不是LCD的内容,所以建议还是直接通过USB恢复系统 + + + +#### 2.1 在Ubuntu上编译内核、设备树 + +* 设置工具链,执行如下命令: + +```shell +source /home/book/100ask_stm32mp157_pro-sdk/ToolChain/openstlinux_eglfs-linux-gnueabi/environment-setup-cortexa7t2hf-neon-vfpv4-ostl-linux-gnueabi +export ARCH=arm +export CROSS_COMPILE=arm-ostl-linux-gnueabi- +``` + + + +* 去掉自己编写的驱动程序 + * 修改内核文件:`drivers/video/fbdev/Makefile`,如下注释掉lcd_drv.o那行: + +```shell + #obj-y += lcd_drv.o +``` + +* 重新配置内核选择自带驱动程序,执行`make menuconfig`,如下配置2项: + + ```shell + Device Drivers ---> + Graphics support ---> + <*> DRM Support for STMicroelectronics SoC Series // 输入Y选择 + <*> STMicroelectronics specific extensions for Synopsys MIPI DSI // 输入Y选择 + ``` + +* 恢复设备树 + + * 把GIT仓库中`STM32MP157\source\A7\03_LCD\11_lcd_drv_stm32mp157_ok\origin\stm32mp157c-100ask-512d-lcd-v1.dts` + * 复制到内核目录:`arch/arm/boot/dts`目录下 + +* 编译内核、设备树 + + ```shell + ~/100ask_stm32mp157_pro-sdk/$ cd Linux-5.4 + ~/100ask_stm32mp157_pro-sdk/Linux-5.4$ make uImage LOADADDR=0xC2000040 + ~/100ask_stm32mp157_pro-sdk/Linux-5.4$ make dtbs + ``` + +* 得到 + * 内核:`arch/arm/boot/uImage` + * 设备树文件:`arch/arm/boot/dts/stm32mp157c-100ask-512d-lcd-v1.dtb` + +* 复制到NFS目录: + + ```shell + $ cp arch/arm/boot/uImage ~/nfs_rootfs/ + $ cp arch/arm/boot/dts/stm32mp157c-100ask-512d-lcd-v1.dtb ~/nfs_rootfs/ + ``` + + + +#### 2.2 在开发板上通过NFS更新内核、设备树 + +* 挂载NFS + + * vmware使用NAT(假设windowsIP为192.168.1.100) + + ```shell + [root@100ask:~]# mount -t nfs -o nolock,vers=3,port=2049,mountport=9999 + 192.168.1.100:/home/book/nfs_rootfs /mnt + ``` + + * vmware使用桥接,或者不使用vmware而是直接使用服务器:假设Ubuntu IP为192.168.1.137 + + ```shell + [root@100ask:~]# mount -t nfs -o nolock,vers=3 192.168.1.137:/home/book/nfs_rootfs /mnt + ``` + +* 确定单板上内核、设备树保存在哪里 + + 由于版本变化,STM32MP157单板上烧录的系统可能有细微差别,在开发板上执行`cat /proc/mounts`后, + 可以得到两种结果(见下图): + + * 保存内核、设备树的分区,挂载在/boot目录下:无需特殊操作 + * 保存内核、设备树的分区,挂载在/mnt目录下 + * 在视频里、后面文档里,都是更新/boot目录下的文件,所以要先执行以下命令重新挂载: + * `mount /dev/mmcblk2p2 /boot` + + + ![image-20210203132435507](pic/02_LCD驱动/047_boot_mount.png) + +* 更新单板文件 + + ```shell + [root@100ask:~]# cp /mnt/uImage /boot + [root@100ask:~]# cp /mnt/stm32mp157c-100ask-512d-lcd-v1.dtb /boot + ``` + + + + + +### 3. 编译、运行APP + +* 设置工具链,执行如下命令: + +```shell +export ARCH=arm +export CROSS_COMPILE=arm-buildroot-linux-gnueabihf- +export PATH=$PATH:/home/book/100ask_stm32mp157_pro-sdk/ToolChain/arm-buildroot-linux-gnueabihf_sdk-buildroot/bin +``` + +* 上传代码、编译 + * 代码位置:GIT仓库`STM32MP157\source\A7\03_LCD\14_use_multi_framebuffer` + * 上传到Ubuntu + * 在`14_use_multi_framebuffer`目录下执行make,可以得到`multi_framebuffer_test` + +* 通过NFS放到开发板/bin目录 + + ```shell + mount -t nfs -o nolock,vers=3 192.168.1.137:/home/book/nfs_rootfs /mnt + cp /mnt/multi_framebuffer_test /bin + ``` + + + +* 在开发板执行 + + ```shell + systemctl stop myir //关闭自带的GUI程序 + multi_framebuffer_test double 或 multi_framebuffer_test single + ``` + +* 由于STM32MP157自带的LCD驱动不支持多buffer,上述命令效果一样 + + + +### 4. LCD自动黑屏 + +为了省电,LCD在10分钟左右会自动黑屏。 + +我们可以禁止LCD自动黑屏,执行以下命令即可: + +```shell +#close lcd sleep +echo -e "\033[9;0]" > /dev/tty1 +echo -e "\033[?25l" > /dev/tty1 +``` + diff --git a/STM32MP157/doc_pic/03_LCD/pic/02_LCD驱动/043_make_menuconfig_ncurse.png b/STM32MP157/doc_pic/03_LCD/pic/02_LCD驱动/043_make_menuconfig_ncurse.png new file mode 100644 index 0000000..e41b96e Binary files /dev/null and b/STM32MP157/doc_pic/03_LCD/pic/02_LCD驱动/043_make_menuconfig_ncurse.png differ diff --git a/STM32MP157/doc_pic/03_LCD/pic/02_LCD驱动/044_cannot_boot.png b/STM32MP157/doc_pic/03_LCD/pic/02_LCD驱动/044_cannot_boot.png new file mode 100644 index 0000000..5d91940 Binary files /dev/null and b/STM32MP157/doc_pic/03_LCD/pic/02_LCD驱动/044_cannot_boot.png differ diff --git a/STM32MP157/doc_pic/03_LCD/pic/02_LCD驱动/045_pins_conflict.png b/STM32MP157/doc_pic/03_LCD/pic/02_LCD驱动/045_pins_conflict.png new file mode 100644 index 0000000..1e70c63 Binary files /dev/null and b/STM32MP157/doc_pic/03_LCD/pic/02_LCD驱动/045_pins_conflict.png differ diff --git a/STM32MP157/doc_pic/03_LCD/pic/02_LCD驱动/046_dma_alloc_wc.png b/STM32MP157/doc_pic/03_LCD/pic/02_LCD驱动/046_dma_alloc_wc.png new file mode 100644 index 0000000..f924e1f Binary files /dev/null and b/STM32MP157/doc_pic/03_LCD/pic/02_LCD驱动/046_dma_alloc_wc.png differ diff --git a/STM32MP157/doc_pic/03_LCD/pic/02_LCD驱动/047_boot_mount.png b/STM32MP157/doc_pic/03_LCD/pic/02_LCD驱动/047_boot_mount.png new file mode 100644 index 0000000..a3967b7 Binary files /dev/null and b/STM32MP157/doc_pic/03_LCD/pic/02_LCD驱动/047_boot_mount.png differ diff --git a/STM32MP157/doc_pic/03_LCD/pic/02_LCD驱动/048_singble_buffer.png b/STM32MP157/doc_pic/03_LCD/pic/02_LCD驱动/048_singble_buffer.png new file mode 100644 index 0000000..83007a5 Binary files /dev/null and b/STM32MP157/doc_pic/03_LCD/pic/02_LCD驱动/048_singble_buffer.png differ diff --git a/STM32MP157/doc_pic/03_LCD/pic/02_LCD驱动/049_drv_app_use_double_buff.png b/STM32MP157/doc_pic/03_LCD/pic/02_LCD驱动/049_drv_app_use_double_buff.png new file mode 100644 index 0000000..95dd901 Binary files /dev/null and b/STM32MP157/doc_pic/03_LCD/pic/02_LCD驱动/049_drv_app_use_double_buff.png differ diff --git a/STM32MP157/doc_pic/03_LCD/pic/02_LCD驱动/050_mxsfb_pan_display.png b/STM32MP157/doc_pic/03_LCD/pic/02_LCD驱动/050_mxsfb_pan_display.png new file mode 100644 index 0000000..17c308e Binary files /dev/null and b/STM32MP157/doc_pic/03_LCD/pic/02_LCD驱动/050_mxsfb_pan_display.png differ diff --git a/STM32MP157/source/A7/03_LCD/10_lcd_drv_lcdcontroller_reg_config_use_devicetre/lcd_drv.c b/STM32MP157/source/A7/03_LCD/10_lcd_drv_lcdcontroller_reg_config_use_devicetre/lcd_drv.c new file mode 100644 index 0000000..1fc4328 --- /dev/null +++ b/STM32MP157/source/A7/03_LCD/10_lcd_drv_lcdcontroller_reg_config_use_devicetre/lcd_drv.c @@ -0,0 +1,420 @@ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include + +#include + +struct stm32mp157_lcdif { + volatile unsigned int LTDC_IDR; + volatile unsigned int LTDC_LCR; + volatile unsigned int LTDC_SSCR; + volatile unsigned int LTDC_BPCR; + volatile unsigned int LTDC_AWCR; + volatile unsigned int LTDC_TWCR; + volatile unsigned int LTDC_GCR; + volatile unsigned int LTDC_GC1R; + volatile unsigned int LTDC_GC2R; + volatile unsigned int LTDC_SRCR; + unsigned char RESERVED_0[4]; + volatile unsigned int LTDC_BCCR; + unsigned char RESERVED_1[4]; + volatile unsigned int LTDC_IER; + volatile unsigned int LTDC_ISR; + volatile unsigned int LTDC_ICR; + volatile unsigned int LTDC_LIPCR; + volatile unsigned int LTDC_CPSR; + volatile unsigned int LTDC_CDSR; + unsigned char RESERVED_2[56]; + volatile unsigned int LTDC_L1CR; + volatile unsigned int LTDC_L1WHPCR; + volatile unsigned int LTDC_L1WVPCR; + volatile unsigned int LTDC_L1CKCR; + volatile unsigned int LTDC_L1PFCR; + volatile unsigned int LTDC_L1CACR; + volatile unsigned int LTDC_L1DCCR; + volatile unsigned int LTDC_L1BFCR; + unsigned char RESERVED_3[8]; + volatile unsigned int LTDC_L1CFBAR; + volatile unsigned int LTDC_L1CFBLR; + volatile unsigned int LTDC_L1CFBLNR; + unsigned char RESERVED_4[12]; + volatile unsigned int LTDC_L1CLUTWR; + unsigned char RESERVED_5[60]; + volatile unsigned int LTDC_L2CR; + volatile unsigned int LTDC_L2WHPCR; + volatile unsigned int LTDC_L2WVPCR; + volatile unsigned int LTDC_L2CKCR; + volatile unsigned int LTDC_L2PFCR; + volatile unsigned int LTDC_L2CACR; + volatile unsigned int LTDC_L2DCCR; + volatile unsigned int LTDC_L2BFCR; + unsigned char RESERVED_6[8]; + volatile unsigned int LTDC_L2CFBAR; + volatile unsigned int LTDC_L2CFBLR; + volatile unsigned int LTDC_L2CFBLNR; + unsigned char RESERVED_7[12]; + volatile unsigned int LTDC_L2CLUTWR; +}; + + +struct lcd_regs { + volatile unsigned int fb_base_phys; + volatile unsigned int fb_xres; + volatile unsigned int fb_yres; + volatile unsigned int fb_bpp; +}; + +static struct lcd_regs *mylcd_regs; + +static struct fb_info *myfb_info; + +static unsigned int pseudo_palette[16]; + +static struct gpio_desc *bl_gpio; + +static struct clk *pixel_clk; + +struct stm32mp157_lcdif *lcdif; + +static void Stm32mp157_lcd_controller_enable(struct stm32mp157_lcdif *lcdif) +{ + lcdif->LTDC_SRCR |= 1; /*加载LAYER的参数*/ + lcdif->LTDC_GCR |= 1<<0; /* 使能STM32MP157的LCD控制器 */ +} + +static int lcd_controller_init(struct stm32mp157_lcdif *lcdif, struct display_timing *dt, int lcd_bpp, int fb_bpp, unsigned int fb_phy) +{ + int bpp_mode; + int pol_vclk = 0; + int pol_vsync = 0; + int pol_hsync = 0; + int pol_de = 0; + + lcd_bpp = lcd_bpp; + + /*[11:0]垂直同步信号宽度tvp,[27:16]水平同步信号宽度thp*/ + lcdif->LTDC_SSCR = (dt->vsync_len.typ << 0) | (dt->hsync_len.typ << 16); + + /*清空LTDC_BPCR寄存器*/ + lcdif->LTDC_BPCR = 0 ; + /*[11:0] VSYNC宽度tvp + 上黑框tvb - 1*/ + lcdif->LTDC_BPCR |= (dt->vsync_len.typ + dt->vback_porch.typ - 1) << 0 ; + /*[27:16]HSYNC宽度thp + 左黑框thb - 1*/ + lcdif->LTDC_BPCR |= (dt->hsync_len.typ + dt->hback_porch.typ - 1) << 16; + + /*清空LTDC_AWCR寄存器*/ + lcdif->LTDC_AWCR = 0 ; + /*[11:0] VSYNC宽度tvp + 上黑框tvb + 垂直有效高度yres - 1*/ + lcdif->LTDC_AWCR |= (dt->vsync_len.typ + dt->vback_porch.typ + dt->vactive.typ - 1) << 0; + /*[27:16] HSYNC宽度thp + 左黑框thb + 水平有效高度xres - 1*/ + lcdif->LTDC_AWCR |= (dt->hsync_len.typ + dt->hback_porch.typ + dt->hactive.typ - 1) << 16; + + /*清空LTDC_TWCR寄存器*/ + lcdif->LTDC_TWCR = 0; + /*[11:0] VSYNC宽度tvp + 上黑框tvb + 垂直有效高度yres + 下黑框tvf - 1 , 即垂直方向上的总周期*/ + lcdif->LTDC_TWCR |= (dt->vsync_len.typ + dt->vback_porch.typ + dt->vactive.typ + dt->vfront_porch.typ - 1) << 0; + /*[27:16] HSYNC宽度thp + 左黑框thb + 垂直有效高度xres + 右黑框thf - 1 , 即水平方向上的总周期*/ + lcdif->LTDC_TWCR |= (dt->hsync_len.typ + dt->hback_porch.typ + dt->hactive.typ + dt->hfront_porch.typ - 1) << 16; + + if (dt->flags & DISPLAY_FLAGS_PIXDATA_POSEDGE) + pol_vclk = 1; + if (dt->flags & DISPLAY_FLAGS_DE_HIGH) + pol_de = 1; + if (dt->flags & DISPLAY_FLAGS_VSYNC_HIGH) + pol_vsync = 1; + if (dt->flags & DISPLAY_FLAGS_HSYNC_HIGH) + pol_hsync = 1; + + /*清空LTDC_GCR寄存器*/ + lcdif->LTDC_GCR &= ~(0xF << 28); + /* 1 : DOTCLK下降沿有效 ,根据屏幕配置文件将其设置为1 */ + lcdif->LTDC_GCR |= pol_vclk << 28; + /* 1 : ENABLE信号高电平有效,根据屏幕配置文件将其设置为1 */ + lcdif->LTDC_GCR |= pol_de << 29; + /* 0 : VSYNC低电平有效 ,根据屏幕配置文件将其设置为0 */ + lcdif->LTDC_GCR |= pol_vsync << 30 ; + /* 0 : HSYNC低电平有效 , 根据屏幕配置文件将其设置为0 */ + lcdif->LTDC_GCR |= pol_hsync << 31 ; + + /*layer 1的相关设置如下*/ + lcdif->LTDC_L1WHPCR |= (dt->hsync_len.typ + dt->hback_porch.typ + dt->hactive.typ - 1) << 16 | (dt->hsync_len.typ + dt->hback_porch.typ ) ; + + lcdif->LTDC_L1WVPCR |= (dt->vsync_len.typ + dt->vback_porch.typ + dt->vactive.typ - 1) << 16 | (dt->vsync_len.typ + dt->vback_porch.typ ) ; + + lcdif->LTDC_L1CFBLR = (dt->hactive.typ * (fb_bpp>>3) + 7) | (dt->hactive.typ * (fb_bpp>>3))<< 16; + + lcdif->LTDC_L1CFBLNR = dt->vactive.typ;/*显存总共的行数*/ + + /*透明度填充值,当选的bpp格式是ARGB8888,ARGB1555等会使用到,如选的是RGB565,RBG888等者不设置也可以*/ + lcdif->LTDC_L1CACR = 0xff; + + /* + *BC = BF1 x C + BF2 x Cs + *BF1为LTDC_L1BFCR设置的[10:8]值,设置为100:constant alpha即LTDC_L1CACR设置的值0xff,表示完全不透明 + *BF2为LTDC_L1BFCR设置的[2:0]值,设置为101:constant alpha即LTDC_L1CACR设置的值0xff,表示完全不透明 + *C为当前层的颜色, + *Cs为背景色,不设置,默认值为0,即黑色 + *LTDC_L1BFCR寄存器也是针对有透明度的像素格式而设置,如用RGB565等也可不设置 + */ + lcdif->LTDC_L1BFCR = (4<<8) | (5<<0); + + /*当bpp为16时,数据格式为RGB565 , 当bpp为32时,数据格式为ARGB8888*/ + switch(fb_bpp) + { + case 16:{ + bpp_mode = 0x2;break;} + case 32:{ + bpp_mode = 0x0;break;} + default:{ + bpp_mode = 0x0;break;} + } + + lcdif->LTDC_L1PFCR = 0 ; + lcdif->LTDC_L1PFCR |= bpp_mode; /*设置像素格式*/ + + lcdif->LTDC_L1CFBAR = fb_phy; /*设置显存地址*/ + + lcdif->LTDC_L1CR |= 0x1;/*1 layer 使能*/ +} + + + +/* from pxafb.c */ +static inline unsigned int chan_to_field(unsigned int chan, + struct fb_bitfield *bf) +{ + chan &= 0xffff; + chan >>= 16 - bf->length; + return chan << bf->offset; +} + +static int mylcd_setcolreg(unsigned regno, + unsigned red, unsigned green, unsigned blue, + unsigned transp, struct fb_info *info) +{ + unsigned int val; + + /* dprintk("setcol: regno=%d, rgb=%d,%d,%d\n", + regno, red, green, blue); */ + + switch (info->fix.visual) { + case FB_VISUAL_TRUECOLOR: + /* true-colour, use pseudo-palette */ + + if (regno < 16) { + u32 *pal = info->pseudo_palette; + + val = chan_to_field(red, &info->var.red); + val |= chan_to_field(green, &info->var.green); + val |= chan_to_field(blue, &info->var.blue); + + pal[regno] = val; + } + break; + + default: + return 1; /* unknown type */ + } + + return 0; +} + + +static struct fb_ops myfb_ops = { + .owner = THIS_MODULE, + .fb_setcolreg = mylcd_setcolreg, + .fb_fillrect = cfb_fillrect, + .fb_copyarea = cfb_copyarea, + .fb_imageblit = cfb_imageblit, +}; + +static int mylcd_probe(struct platform_device *pdev) +{ + struct device_node *display_np; + dma_addr_t phy_addr; + int ret; + int width; + int bits_per_pixel; + struct display_timings *timings = NULL; + struct display_timing *timing; + struct resource *res; + + display_np = of_parse_phandle(pdev->dev.of_node, "display", 0); + + /* get common info */ + ret = of_property_read_u32(display_np, "bus-width", &width); + ret = of_property_read_u32(display_np, "bits-per-pixel", + &bits_per_pixel); + + /* get timming */ + timings = of_get_display_timings(display_np); + timing = timings->timings[timings->native_mode]; + + /* get gpio from device tree */ + bl_gpio = gpiod_get(&pdev->dev, "backlight", 0); + + /* config bl_gpio as output */ + gpiod_direction_output(bl_gpio, 1); + + /* set val: gpiod_set_value(bl_gpio, status); */ + + /* get clk from device tree */ + pixel_clk = devm_clk_get(&pdev->dev, "lcd"); + + /* set rate */ + clk_set_rate(pixel_clk, timing->pixelclock.typ); + + /* enable clk */ + clk_prepare_enable(pixel_clk); + + /* 1.1 分配fb_info */ + myfb_info = framebuffer_alloc(0, NULL); + + /* 1.2 设置fb_info */ + /* a. var : LCD分辨率、颜色格式 */ + myfb_info->var.xres_virtual = myfb_info->var.xres = timing->hactive.typ; + myfb_info->var.yres_virtual = myfb_info->var.yres = timing->vactive.typ; + + myfb_info->var.bits_per_pixel = bits_per_pixel; /* rgb565 */ + if (bits_per_pixel == 16) + { + myfb_info->var.red.offset = 11; + myfb_info->var.red.length = 5; + + myfb_info->var.green.offset = 5; + myfb_info->var.green.length = 6; + + myfb_info->var.blue.offset = 0; + myfb_info->var.blue.length = 5; + } + else if (bits_per_pixel == 24 || bits_per_pixel == 32) + { + myfb_info->var.red.offset = 16; + myfb_info->var.red.length = 8; + + myfb_info->var.green.offset = 8; + myfb_info->var.green.length = 8; + + myfb_info->var.blue.offset = 0; + myfb_info->var.blue.length = 8; + } + else + { + return -EINVAL; + } + + /* b. fix */ + strcpy(myfb_info->fix.id, "100ask_lcd"); + myfb_info->fix.smem_len = myfb_info->var.xres * myfb_info->var.yres * myfb_info->var.bits_per_pixel / 8; + if (myfb_info->var.bits_per_pixel == 24) + myfb_info->fix.smem_len = myfb_info->var.xres * myfb_info->var.yres * 4; + + + /* fb的虚拟地址 */ + myfb_info->screen_base = dma_alloc_wc(NULL, myfb_info->fix.smem_len, &phy_addr, + GFP_KERNEL); + myfb_info->fix.smem_start = phy_addr; /* fb的物理地址 */ + + myfb_info->fix.type = FB_TYPE_PACKED_PIXELS; + myfb_info->fix.visual = FB_VISUAL_TRUECOLOR; + + myfb_info->fix.line_length = myfb_info->var.xres * myfb_info->var.bits_per_pixel / 8; + if (myfb_info->var.bits_per_pixel == 24) + myfb_info->fix.line_length = myfb_info->var.xres * 4; + + + /* c. fbops */ + myfb_info->fbops = &myfb_ops; + myfb_info->pseudo_palette = pseudo_palette; + + + /* 1.3 注册fb_info */ + register_framebuffer(myfb_info); + + /* 1.4 硬件操作 */ + res = platform_get_resource(pdev, IORESOURCE_MEM, 0); + lcdif = devm_ioremap_resource(&pdev->dev, res); + //lcdif = ioremap(0x5a001000, sizeof(struct stm32mp157_lcdif)); + lcd_controller_init(lcdif, timing, width, bits_per_pixel, phy_addr); + + /* enable lcd controller */ + Stm32mp157_lcd_controller_enable(lcdif); + + /* enable backlight */ + gpiod_set_value(bl_gpio, 1); + + return 0; +} + + +static int mylcd_remove(struct platform_device *pdev) +{ + /* 反过来操作 */ + /* 2.1 反注册fb_info */ + unregister_framebuffer(myfb_info); + + /* 2.2 释放fb_info */ + framebuffer_release(myfb_info); + + //iounmap(lcdif); + + return 0; +} + + +static const struct of_device_id mylcd_of_match[] = { + { .compatible = "100ask,lcd_drv", }, + { }, +}; +MODULE_DEVICE_TABLE(of, simplefb_of_match); + +static struct platform_driver mylcd_driver = { + .driver = { + .name = "mylcd", + .of_match_table = mylcd_of_match, + }, + .probe = mylcd_probe, + .remove = mylcd_remove, +}; + +static int __init lcd_drv_init(void) +{ + int ret; + struct device_node *np; + + ret = platform_driver_register(&mylcd_driver); + if (ret) + return ret; + + return 0; +} + +/* 2. 出口 */ +static void __exit lcd_drv_exit(void) +{ + platform_driver_unregister(&mylcd_driver); +} + + +module_init(lcd_drv_init); +module_exit(lcd_drv_exit); + +MODULE_AUTHOR("www.100ask.net"); +MODULE_DESCRIPTION("Framebuffer driver for the linux"); +MODULE_LICENSE("GPL"); + diff --git a/STM32MP157/source/A7/03_LCD/10_lcd_drv_lcdcontroller_reg_config_use_devicetre/stm32mp157c-100ask-512d-lcd-v1.dts b/STM32MP157/source/A7/03_LCD/10_lcd_drv_lcdcontroller_reg_config_use_devicetre/stm32mp157c-100ask-512d-lcd-v1.dts new file mode 100644 index 0000000..ea60642 --- /dev/null +++ b/STM32MP157/source/A7/03_LCD/10_lcd_drv_lcdcontroller_reg_config_use_devicetre/stm32mp157c-100ask-512d-lcd-v1.dts @@ -0,0 +1,174 @@ +// SPDX-License-Identifier: (GPL-2.0+ OR BSD-3-Clause) +/* +* Copyright (C) 100ASK 2020 - All Rights Reserved +* Author: 100ask +* support: weidongshan@qq.com +*/ + +/dts-v1/; + +#include "stm32mp157c-100ask-512d-v1.dts" + +/ { + model = "100ASK YA157C v2 www.100ask.com"; + compatible = "st,stm32mp157c-100ask-512d-v1", "st,stm32mp157"; + + + framebuffer-mylcd { + compatible = "100ask,lcd_drv"; + reg = <0x5a001000 0x400>; + pinctrl-names = "default"; + pinctrl-0 = <<dc_pins_a>; + backlight-gpios = <&gpioe 11 GPIO_ACTIVE_HIGH>; + clocks = <&rcc LTDC_PX>; + clock-names = "lcd"; + + display = <&display0>; + + display0: display { + bits-per-pixel = <24>; + bus-width = <24>; + + display-timings { + native-mode = <&timing0>; + + timing0: timing0_1024x600 { + clock-frequency = <50000000>; + hactive = <1024>; + vactive = <600>; + hfront-porch = <160>; + hback-porch = <140>; + hsync-len = <20>; + vback-porch = <20>; + vfront-porch = <12>; + vsync-len = <3>; + + hsync-active = <0>; + vsync-active = <0>; + de-active = <1>; + pixelclk-active = <0>; + }; + + }; + }; + }; + + + /*LCD Panel*/ + panel { + compatible = "myir,070tft"; + interrupts = <11 IRQ_TYPE_EDGE_FALLING>; + interrupt-parent = <&gpioe>; + pinctrl-names = "default", "sleep"; + pinctrl-0 = <<dc_pins_a>; + pinctrl-1 = <<dc_pins_sleep_a>; + //reset-gpios = <&gpioe 12 GPIO_ACTIVE_LOW>; + + backlight = <&panel_backlight>; + status = "okay"; + + port { + panel_in: endpoint { + remote-endpoint = <<dc_ep0_out>; + }; + + }; + }; +}; + +&spi5 { + pinctrl-names = "default", "sleep"; + pinctrl-0 = <&spi5_pins_a>; + pinctrl-1 = <&spi5_sleep_pins_a>; + status = "okay"; + cs-gpios = <&gpioh 5 GPIO_ACTIVE_LOW>; + spidev: icm20608@0{ + compatible = "invensense,icm20608"; + interrupts = <0 IRQ_TYPE_EDGE_FALLING>; + interrupt-parent = <&gpioz>; + spi-max-frequency = <8000000>; + reg = <0>; + }; +}; + +/* test HDMI*/ +<dc { + status = "okay"; + port { + #address-cells = <1>; + #size-cells = <0>; + + ltdc_ep1_out: endpoint@1 { + reg = <1>; + remote-endpoint = <&sii9022_in>; + }; + }; +}; + + +/*HDMI*/ +&i2c4 { + clock-frequency = <100000>; + hdmi-transmitter@40 { // use a dummy device + compatible = "sil,sii9022"; + reg = <0x40>; + reset-gpios = <&gpiob 10 GPIO_ACTIVE_LOW>; + interrupts = <13 IRQ_TYPE_EDGE_FALLING>; + interrupt-parent = <&gpiob>; + //pinctrl-names = "default", "sleep"; + //pinctrl-0 = <<dc_pins_a>; + //pinctrl-1 = <<dc_pins_sleep_a>; + status = "disabled"; + + ports { + #address-cells = <1>; + #size-cells = <0>; + + port@0 { + reg = <0>; + sii9022_in: endpoint { + remote-endpoint = <<dc_ep1_out>; + }; + }; + + }; + }; + +#if 1 + sii902x: sii902x@39 { + compatible = "SiI,sii902x"; + reset-gpios = <&gpiob 10 GPIO_ACTIVE_LOW>; + //pinctrl-names = "default"; + //pinctrl-0 = <&pinctrl_sii902x>; + interrupts = <13 IRQ_TYPE_EDGE_FALLING>; + interrupt-parent = <&gpiob>; + mode_str ="1280x720M@60"; + bits-per-pixel = <16>; + reg = <0x39>; + status = "okay"; + + }; +#endif +}; + +&i2s2 { + status = "disable"; + +}; + +/*test LCD*/ +<dc { + status = "okay"; + + port { + #address-cells = <1>; + #size-cells = <0>; + + ltdc_ep0_out: endpoint@0 { + reg = <0>; + remote-endpoint = <&panel_in>; + }; + }; +}; + + diff --git a/STM32MP157/source/A7/03_LCD/11_lcd_drv_stm32mp157_ok/Makefile b/STM32MP157/source/A7/03_LCD/11_lcd_drv_stm32mp157_ok/Makefile new file mode 100644 index 0000000..19bf436 --- /dev/null +++ b/STM32MP157/source/A7/03_LCD/11_lcd_drv_stm32mp157_ok/Makefile @@ -0,0 +1,19 @@ + +# 1. 使用不同的开发板内核时, 一定要修改KERN_DIR +# 2. KERN_DIR中的内核要事先配置、编译, 为了能编译内核, 要先设置下列环境变量: +# 2.1 ARCH, 比如: export ARCH=arm64 +# 2.2 CROSS_COMPILE, 比如: export CROSS_COMPILE=aarch64-linux-gnu- +# 2.3 PATH, 比如: export PATH=$PATH:/home/book/100ask_roc-rk3399-pc/ToolChain-6.3.1/gcc-linaro-6.3.1-2017.05-x86_64_aarch64-linux-gnu/bin +# 注意: 不同的开发板不同的编译器上述3个环境变量不一定相同, +# 请参考各开发板的高级用户使用手册 + +KERN_DIR = /home/book/100ask_stm32mp157_pro-sdk/Linux-5.4 + +all: + make -C $(KERN_DIR) M=`pwd` modules + +clean: + make -C $(KERN_DIR) M=`pwd` modules clean + rm -rf modules.order + +obj-m += lcd_drv.o diff --git a/STM32MP157/source/A7/03_LCD/11_lcd_drv_stm32mp157_ok/lcd_drv.c b/STM32MP157/source/A7/03_LCD/11_lcd_drv_stm32mp157_ok/lcd_drv.c new file mode 100644 index 0000000..2ebebb8 --- /dev/null +++ b/STM32MP157/source/A7/03_LCD/11_lcd_drv_stm32mp157_ok/lcd_drv.c @@ -0,0 +1,421 @@ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include