【精选】全志D1/D1s芯片:芒果派麻雀点RGB屏填坑 您所在的位置:网站首页 瓜瓜在线填坑 【精选】全志D1/D1s芯片:芒果派麻雀点RGB屏填坑

【精选】全志D1/D1s芯片:芒果派麻雀点RGB屏填坑

2023-10-19 03:42| 来源: 网络整理| 查看: 265

前言

最近全志推出了D1处理器,搭载平头哥玄铁906 RISC-V的应用处理器。于是准备入手玩一下,买了芒果派做了基于D1s的麻雀板,D1s是D1内封64M DDR的版本,去掉了hdmi输出,号称点屏强芯,点个屏来玩玩。 先晒下小巧精致的麻雀: 在这里插入图片描述

点屏

手上正好有块480*272的rgb屏,可以用这个小板子来点一下。想来rgb屏幕应该很好适配,dts里改几个参数就完事了,不过多次调整怎么也没法让画面正常输出,这个问题应该有不少人遇到。先直入主题说一下如何修复问题吧,后面在详细记录填坑过程。

快速上手体验

我修复的代码patch在这里 https://download.csdn.net/download/qq_34440409/66654101,下载下来后分别到kernel uboot 里打上patch即可。 然后屏幕参数DTS里根据自己的屏参配置下,可以参考我的配置,主要是以下几个参数:

/* part 3 */ lcd_width = ; /* 随便写 */ lcd_height = ;/* 随便写 */ lcd_x = ; lcd_y = ; lcd_dclk_freq = ; lcd_hbp = ; lcd_ht = ; lcd_hspw = ; lcd_vbp = ; lcd_vt = ; lcd_vspw = ;

另外屏幕起来后加载到kernel启动会明显感觉到颜色发生了变化,在kernel 的DTS里找到dmic,并关闭

&dmic { pinctrl-names = "default","sleep"; pinctrl-0 = ; pinctrl-1 = ; status = "disable"; };

这个据网友反馈是屏引脚占用导致。

详细填坑过程记录 1.关闭uboot logo显示

为了方便调试我们先针对内核修改,把uboot点屏给他关了。 打开文件 D1\lichee\brandy-2.0\u-boot-2018\configs\sun20iw1p1_defconfig 搜索 CONFIG_DISP2_SUNXI 并注释。重新编译烧录就不会在显示uboot logo了

2.确定屏参

点RGB屏一般就是配一下几个参数的事,这些参数屏手册一般都会给出来,例如我的屏参手册 在这里插入图片描述 从这里可以直接对应到DTS里的几个配置项

lcd_x = ; lcd_y = ; lcd_dclk_freq = ; lcd_hbp = ; lcd_ht = ; lcd_vbp = ; lcd_vt = ;

还剩下lcd_hspw,lcd_vspw hspw (HSYNC plus width)行同步脉宽 单位:像素时钟周期 vspw (VSYNC width)垂直同步脉宽 单位:显示一行的时间th 以水平方向为例说一下几个参数的关系: ht = h显示区域像素 + hbp + hfb + hspw 525 = 480 + 40 + 5 + 0 由此可以确定hspw与vspw 两项的值为0,按经验来说 spw这项一般不需要额外关注。

3.查看LCD显示调试信息

但我照着手册填好后点屏画面总是糊的,调整一番参数多次尝试无果,确定参数应该是没有问题的,那只能翻手册查看调试信息排坑了。 关于D1/D1s芯片资料可以在这里获取https://whycan.com/t_6440.html 查看lcd调试指南,我们可以通过

cat /sys/class/disp/disp/attr/sys

查看显示信息 在这里插入图片描述 DTS里配置的值算出来是60帧没有问题,分辨率也正常,但是实际跑的帧率为322,这差太多了,根据帧率计算公式: lcd_dclk_freq * 1000000 * num_of_pixel_clk = lcd_ht * lcd_vt * fps 式子里 lcd_dclk_freq单位为Mhz num_of_pixel_clk = 1 ,因为我们是并行RGB接口,一个时钟发送一个像素 将我们的DTS配置带入以上公式 fps确实应该是60,但实际fps为322,那么我们假设时钟可能不对,反推一下将322fps带入公式算dclk得到 525 * 288 * 322.5 = 48.762M 这个时候我们更改下DTS 按800 * 480的屏参配置

lcd_dclk_freq = ; lcd_hbp = ; lcd_ht = ; lcd_hspw = ; lcd_vbp = ; lcd_vt = ; lcd_vspw = ;

查看显示信息 在这里插入图片描述 根据实际帧率计算dclk 1055 * 525 * 87.7 = 48.574M 由此可以大概能猜到,dclk确实是48M,而dts的对dclk的设置应该是不生效的。

查看下lcd相关的时钟

cat /sys/kernel/debug/clk/clk_summary cat /sys/kernel/debug/clk/clk_summary | grep tcon

在这里插入图片描述 这里的时钟具体含义与dclk的关系暂时不得而知,可以先留意一下,后面再来对应。

4.通过修改寄存器尝试解决问题

既然猜到了dclk有问题,那么可以去查下寄存器手册找到该值的地址,确定下问题。 最终查到的dclk寄存器描述如下: 在这里插入图片描述 dclk寄存器基地址: 在这里插入图片描述 dclk地址为:0x05461044 用devmem工具读一下寄存器的值 devmem 0x05461044 在这里插入图片描述 根据寄存器的描述:Tdclk = Tsclk/DCLKDIV。 Tsclk是个啥我们也不清楚,但我们可以用已知量先反推计算下: Tsclk = Tdclk * DCLKDIV = 48 * 6 = 288 Mhz 看到这个数字你想到了什么,前面查看时钟时 tcon-lcd0 的值不就是这个吗。 现在知道了Tsclk = 288M ,要想让我们的dclk为9M,那就得改DCLKDIV为32。

把我们的设备烧录回480 * 272的DTS配置,写寄存器 devmem 0x05461044 32 0xF0000020 写完后立马看到屏幕显示正常了,确定是这个问题无疑。 DTS设置不生效就要去驱动源码里查问题了。

5.梳理屏幕显示驱动

DTS里可知 lcd_driver_name = “default_lcd” 我们可以通过搜索"default_lcd"来找屏驱动文件,找到了drivers/video/fbdev/sunxi/disp2/disp/lcd/default_panel.c,查看文件发现只有上下电时序,初始化序列相关,没有我们需要的,那直接按解析参数来搜索好了。 进入到内核目录,执行 grep -rn "lcd_dclk_freq" 在这里插入图片描述 找到文件drivers/video/fbdev/sunxi/disp2/disp/de/disp_lcd.c lcd 显示初始化使能主要有这个函数来完成:disp_lcd_fake_enable,梳理出其中主要关注的调用

disp_lcd_fake_enable(...) { ...//省略若干代码 lcd_clk_enable(lcd); //该函数通过调用 lcd_clk_config 来配置lcd相关时钟 ret = cal_real_frame_period(lcd); //通过调用do_div(temp, lcd->timings.dclk_rate_set); 设置了 dclk_rate_set ... }

先来看下 lcd_clk_config 函数,时钟配置的代码在这里:

lcd_clk_config(...) { ...//省略若干代码 disp_al_lcd_get_clk_info(lcd->hwdev_index, &clk_info, &lcdp->panel_info); dclk_rate = lcdp->panel_info.lcd_dclk_freq * 1000000; /* Mhz -> hz */ if (lcdp->panel_info.lcd_if == LCD_IF_DSI) { lcd_rate = dclk_rate * clk_info.dsi_div; pll_rate = lcd_rate * clk_info.lcd_div; } else { lcd_rate = dclk_rate * clk_info.tcon_div; pll_rate = lcd_rate * clk_info.lcd_div; } ... dclk_rate_set = lcd_rate_set / clk_info.tcon_div; if ((pll_rate_set != pll_rate) || (lcd_rate_set != lcd_rate) || (dclk_rate_set != dclk_rate)) { DE_WRN ("disp %d, clk: pll(%ld),clk(%ld),dclk(%ld) dsi_rate(%ld)\n clk real:pll(%ld),clk(%ld),dclk(%ld) dsi_rate(%ld)\n", lcd->disp, pll_rate, lcd_rate, dclk_rate, dsi_rate, pll_rate_set, lcd_rate_set, dclk_rate_set, dsi_rate_set); } return 0; }

dclk_rate 就是我们DTS传入的9Mhz参数,通过该值计算得到两个时钟 lcd_rate 与 pll_rate ,根据代码可以得知 pll_rate = lcd_rate = dclk_rate * tcon_div;

pll_rate、 lcd_rate、 dclk_rate 这些都是我们根据DTS得到的值,实际设置值为 pll_rate_set、 lcd_rate_set、dclk_rate_set。这个函数末尾已经加了打印,当计算值与实际设置值不一致时就会打印,查看下启动打印有没有: 在这里插入图片描述 可以看到上面设置没有生效,pll_rate实际是288M,加下打印

DE_WRN("lyrdebug start\n"); if (lcdp->clk_parent) { DE_WRN("lyrdebug set pll_rate_set(%ld)\n",pll_rate); clk_set_rate(lcdp->clk_parent, pll_rate); pll_rate_set = clk_get_rate(lcdp->clk_parent); DE_WRN("lyrdebug get pll_rate_set(%ld)\n",pll_rate_set); } if (clk_info.lcd_div) lcd_rate_set = pll_rate_set / clk_info.lcd_div; else lcd_rate_set = pll_rate_set; DE_WRN("lyrdebug get lcd_rate_set-1-(%ld)\n",lcd_rate_set); clk_set_rate(lcdp->clk_tcon_lcd, lcd_rate_set); lcd_rate_set = clk_get_rate(lcdp->clk_tcon_lcd); DE_WRN("lyrdebug get lcd_rate_set-2-(%ld)\n",lcd_rate_set); DE_WRN("lyrdebug end\n");

查看打印: 在这里插入图片描述 可以得知设置pll_rate这步不生效,那么解决问题就有两个路线了,

继续追查clk_set_rate(lcdp->clk_parent, pll_rate)为何不生效,至于具体原因那就要去查手册pll_rate相关的属性注意项了保持pll_rate为288M,更改DCLK_DIV的值来使得最终给到dclk的值为实际值。

这里我们就懒得再去追查pll_rate设置不生效原因了,我们先假设pll_rate最小值为288M或者他只能设置为288M。 然后找到DCLK_DIV设置的地方,去修改。 通过上面代码分析可以知道pll_rate 与 dclk_rate 的关系: pll_rate = lcd_rate = dclk_rate * tcon_div 那么这个tcon_div应当就是DCLK_DIV了 tcon_div的值来自函数disp_al_lcd_get_clk_info 搜索这个函数,找到源码: 在这里插入图片描述 可以看到很多结果,哪个才是我们真正使用的源文件呢,这里有个小技巧,通过.o文件来反推,找到了该函数位于文件: drivers/video/fbdev/sunxi/disp2/disp/de/lowlevel_v2x/disp_al.c中 打开文件找到函数disp_al_lcd_get_clk_info

... static struct lcd_clk_info clk_tbl[] = { {LCD_IF_HV, 6, 1, 1, 0}, {LCD_IF_CPU, 12, 1, 1, 0}, {LCD_IF_LVDS, 7, 1, 1, 0}, #if defined(DSI_VERSION_40) {LCD_IF_DSI, 4, 1, 4, 150000000}, #else {LCD_IF_DSI, 4, 1, 4, 0}, #endif /*endif DSI_VERSION_40*/ {LCD_IF_VDPO, 4, 1, 1, 0}, }; ... disp_al_lcd_get_clk_info(...) { ... for (i = 0; i tcon_div = clk_tbl[i].tcon_div; lcd_div = clk_tbl[i].lcd_div; dsi_div = clk_tbl[i].dsi_div; dsi_rate = clk_tbl[i].dsi_rate; find = 1; break; } } ... }

从这里就知道了tcon_div值来自clk_tbl[]中,默认为6,这与我们之前寄存器查看得到值是对得上的。

6.动手修改

上面已经找到了tcon_div值设置的位置,就在这下面添加代码好了

if(panel->lcd_dclk_freq lcd_dclk_freq >= 3){ tcon_div = 288/panel->lcd_dclk_freq; }

意思是当DTS中设置的dclk在3到48M之间时自动计算tcon_div的值,要满足tcon_div小于128。

kernel修改完毕后编译测试显示正常,来看下显示调试信息 在这里插入图片描述 可以看到实际帧率与设置帧率完全一致了。

Uboot的修改也是同样的道理,UBoot显示驱动代码路径在D1\lichee\brandy-2.0\u-boot-2018\drivers\video\sunxi\disp2\disp\de\

完成

最后晒一下屏幕显示结果 在这里插入图片描述



【本文地址】

公司简介

联系我们

今日新闻

    推荐新闻

    专题文章
      CopyRight 2018-2019 实验室设备网 版权所有