当前位置: 首页 > news >正文

全志linux开发屏幕适配(二)`HDMI`驱动适配说明

HDMI驱动适配
2.2.1、标准分辨率

查看当前已经支持的标准分辨率,文件路径:./sdk-linux-github/brandy/brandy-2.0/u-boot-2018/include/sunxi_display2.h

enum disp_tv_mode { DISP_TV_MOD_480I = 0, DISP_TV_MOD_576I = 1, DISP_TV_MOD_480P = 2, DISP_TV_MOD_576P = 3, DISP_TV_MOD_720P_50HZ = 4, DISP_TV_MOD_720P_60HZ = 5, DISP_TV_MOD_1080I_50HZ = 6, DISP_TV_MOD_1080I_60HZ = 7, DISP_TV_MOD_1080P_24HZ = 8, DISP_TV_MOD_1080P_50HZ = 9, DISP_TV_MOD_1080P_60HZ = 0xa, DISP_TV_MOD_1080P_24HZ_3D_FP = 0x17, DISP_TV_MOD_720P_50HZ_3D_FP = 0x18, DISP_TV_MOD_720P_60HZ_3D_FP = 0x19, DISP_TV_MOD_1080P_25HZ = 0x1a, DISP_TV_MOD_1080P_30HZ = 0x1b, DISP_TV_MOD_PAL = 0xb, DISP_TV_MOD_PAL_SVIDEO = 0xc, DISP_TV_MOD_NTSC = 0xe, DISP_TV_MOD_NTSC_SVIDEO = 0xf, DISP_TV_MOD_PAL_M = 0x11, DISP_TV_MOD_PAL_M_SVIDEO = 0x12, DISP_TV_MOD_PAL_NC = 0x14, DISP_TV_MOD_PAL_NC_SVIDEO = 0x15, DISP_TV_MOD_3840_2160P_30HZ = 0x1c, DISP_TV_MOD_3840_2160P_25HZ = 0x1d, DISP_TV_MOD_3840_2160P_24HZ = 0x1e, DISP_TV_MOD_4096_2160P_24HZ = 0x1f, DISP_TV_MOD_4096_2160P_25HZ = 0x20, DISP_TV_MOD_4096_2160P_30HZ = 0x21, DISP_TV_MOD_3840_2160P_60HZ = 0x22, DISP_TV_MOD_4096_2160P_60HZ = 0x23, DISP_TV_MOD_3840_2160P_50HZ = 0x24, DISP_TV_MOD_4096_2160P_50HZ = 0x25, DISP_TV_MOD_1280_1024P_60HZ = 0x41, DISP_TV_MOD_1024_768P_60HZ = 0x42, DISP_TV_MOD_900_540P_60HZ = 0x43, DISP_TV_MOD_1920_720P_60HZ = 0x44, /* * vga * NOTE:macro'value of new solution must between * DISP_VGA_MOD_640_480P_60 and DISP_VGA_MOD_MAX_NUM * or you have to modify is_vag_mode function in drv_tv.h */ DISP_VGA_MOD_640_480P_60 = 0x50, DISP_VGA_MOD_800_600P_60 = 0x51, DISP_VGA_MOD_1024_768P_60 = 0x52, DISP_VGA_MOD_1280_768P_60 = 0x53, DISP_VGA_MOD_1280_800P_60 = 0x54, DISP_VGA_MOD_1366_768P_60 = 0x55, DISP_VGA_MOD_1440_900P_60 = 0x56, DISP_VGA_MOD_1920_1080P_60 = 0x57, DISP_VGA_MOD_1280_720P_60 = 0x58, DISP_VGA_MOD_1920_1200P_60 = 0x5a, DISP_VGA_MOD_MAX_NUM = 0x5b, DISP_TV_MODE_NUM = 0x5c, };

可以看到当前已经支持多种常规标准的分辨率,选择需要的分辨率修改设备树配置就好,修改参数如下:

//以修改为720p60fps为例 screen0_output_type = <3>; screen0_output_mode = <5>; dev0_output_type = <3>; dev0_output_mode = <5>; dev0_screen_id = <0>; dev0_do_hpd = <1>; fb0_format = <0>; fb0_width = <1280>; fb0_height = <720>;
2.2.2、自定义分辨率

​ 总会有特殊的屏幕分辨率,,,

graph TD A[自定义分辨率参数步骤] --> B[新增 自定义分辨率 枚举] B --> C[U-Boot 层定义更新<br/>brandy-2.0/u-boot-2018] B --> D[Kernel 层定义更新<br/>kernel/linux-4.9] C --> C0[hdmi_core.c/h 添加<br/> 自定义 VIC 值] C --> C1[sunxi_display2.h 添加<br/> 自定义 display subsystem 枚举] C --> C2[hdmi_core.c中的hdmi_mode_tbl 添加<br/> 新模式映射] C --> C3[core_edid.c的 supported_dtd 表中添加<br/>自定义 DTD] C --> E[edid.c 添加对应<br/> timing 参数] D --> H[同步修改 kernel<br/> 的 hdmi_core.c/h] D --> I[同步添加<br/> kernel edid.c / core_edid.c] I --> J[编译 kernel,支持新 mode] E --> K[调试打印 timing 参数,验证时序] J --> L[修改 DTS / sys_config.fex] L --> M[dev0_output_mode = 自定义 display subsystem 枚举<br/>fb0_width/fb0_height对应分辨率] M --> N[sys_config_my.fex: <br/>output_mode = 自定义 display subsystem 枚举] N --> O[U-Boot 加载时读取 fex → 传递给 Kernel] O --> P[Kernel 读取 /disp2/hdmi_core 解析 自定义 VIC 值] P --> Q[显示控制器 DE 初始化完成<br/>LCD/HDMI 输出自定义分辨率信号]

​ 那么,先分析新增的屏幕参数,屏幕参数如下:

pixelclock = 40000000, hactive = 720, hfront_porch = 106, hback_porch = 120, hsync_len = 60, vactive = 720, vfront_porch = 20, vback_porch = 20, vsync_len = 4,

先计算出需要在驱动中设置的参数:

  1. 水平总周期(htotal) = hactive + hfront + hback + hsync

    • 720 + 106 = 826
    • 826 + 120 = 946
    • 946 + 60 = 1006

    所以htotal = 1006

  2. 垂直总周期(vtotal) = vactive + vfront + vback + vsync

    • 720 + 20 = 740
    • 740 + 20 = 760
    • 760 + 4 = 764

    所以vtotal = 764

  3. 水平blanking(hblank) = hfront + hback + hsync

    • 106 + 120 = 226
    • 226 + 60 = 286

    所以hblank = 286

  4. 垂直blanking(vblank) = vfront + vback + vsync

    • 20 + 20 = 40
    • 40 + 4 = 44

    所以vblank = 44

  5. 按照pixelclock40000000Hz)计算实际刷新率

    • 先算分母htotal * vtotal
      • 1006 * 764
      • 1006 * 700 = 704,200
      • 1006 * 60 = 60,360
      • 1006 * 4 = 4,024
      • 合计 = 704,200 + 60,360 + 4,024 = 768,584
    • 则刷新率 =pixelclock / (htotal * vtotal)=40,000,000 / 768,584
      • 768,584 * 52 = 39,966,368
      • 40,000,000 - 39,966,368 = 33,632 (余数)
      • 33,632 / 768,584 ≈ 0.043758…
      • 所以刷新率 ≈ 52.04375839205604 Hz
    • 四舍五入(mHz)=>52.043758... * 1000 ≈ 52043.758...-> 52044

结论:用 40 MHz 和提供的porch/hsync/vsync,输出大约52.044 Hz,并非60 Hz。如果你真正想要60.000 Hz,需要更高的pixelclock(下面给出计算)。

要得到 60 Hz 的pixelclock(反算)

  • 需要pixelclock_required = htotal * vtotal * 60
  • 我们已经有htotal * vtotal = 768,584
  • 768,584 * 60 = 46,115,040 Hz = 46.11504MHz
  • 所以:要真60Hzpixelclock≈ 46.11504MHz(不是 40MHz)。

总结修改步骤:

  1. hdmi_core.h中定义新的HDMI_VIC(自定义VIC值)

    • HDMI标准的VIC通常是0x00~0xFF范围内的代码(标准VIC有约定的编号)。设备树里已经用了0x2010x2020x203做“自定义/扩展”编号(看起来这是项目约定:把自定义模式放在0x200+区间)。新模式需有一个唯一的代码供内部识别并与EDID/DTD对应。

    注意与坑

    • 不要与已有值冲突:确保0x204未被其它地方占用。检查所有相关头文件以避免重复定义(不同文件复制的头文件需同步)。
    • 十六进制/十进制混用容易出错:在头文件用0x204(十六进制)更直观,但在其他地方(比如device tree)可能需要十进制(详见步骤 7)。
    • 如果项目以后会合并标准VIC,考虑在注释里标注这是“私有/扩展VIC区间”。
  2. 在各种sunxi_display2.h中增加DISP_TV_MOD

    • DISP_TV_MOD_*display subsystem的统一枚举。驱动/设备树/工具链在配置输出模式时使用该枚举值。你在设备树里用的数字(如dev0_output_mode = <69>;)就是这个枚举的十进制表示(0x45= 69)。 所以需要在所有相关头文件里添加,确保在不同子系统(board,sdk_demo,platform libs)里都能被识别。

    注意与坑

    • 多处同步:这些头文件在仓库里被拷贝多处——必须全部修改,遗漏一个会出现链接或编译断裂,或在某个子模块编译时缺少定义。把定义统一放到一个共享头文件里是较好的长期做法。
    • 数值冲突:0x45已被选择,但要检查是否与其它DISP类型(VGATVVGA mode)冲突。
    • device treedts)与fex使用:注意device tree<69>跟这里0x45是同一含义(十进制vs十六进制),一定要换算正确。
  3. hdmi_mode_tbl中加入新模式映射

    • hdmi_mode_tbl[]是框架把平台的DISP_TV_MOD_*(平台/驱动层内部的分辨率枚举)映射为HDMIVICVideo Identification Code)或自定义代码。若不在此表中注册,驱动不会把自定义的DISP模式映射到HDMI层,从而无法输出该分辨率。

    注意与坑

    • u-bootkernel两处都改:这是必须的。原因:u-boothdmi层用于早期引导显示(logo/boot messages);kerneldriver用于系统启动后的显示。若只改其中一处,会出现开机能看到但系统启动后不对的情况(或反之)。
    • 枚举一致性:确保DISP_TV_MOD_720_720P_60HZHDMI_VIC_720x720P61在步骤 1、2 中定义的值与这里完全一致(同样的宏/值、同样的十六进制/十进制)。不一致会导致编译或运行时找不到对应项。
  4. EDIDsupported_dtd表中添加自定义DTD

    • 设备的EDID解析常用一个“支持时序表”(supported detailed timing table/supported_dtd)来匹配sink(显示器)返回的EDID信息。把自定义分辨率加入这个表,HDMI驱动在遇到相应EDID时才能识别并接受该模式。
    • 结构中通常包括:一个“刷新率x1000”(我的是52044)、一个结构体数组(包含VIC code,pixelclock,hactive,hblank,hfront,hsync,hback,vactive,vblank,vfront,vsync等字段)。

    重要参数的来源与计算(逐步)

    • hblank = hfront_porch + hback_porch + hsync_len = 106 + 120 + 60 = 286(见上)。
    • vblank = vfront_porch + vback_porch + vsync_len = 20 + 20 + 4 = 44(见上)。
    • 我在结构里写的40000:依据项目里其它DTD条目的格式,这里是pixelclock单位为kHz(即40000 => 40,000 kHz = 40 MHz)。一定要跟项目里现有条目的单位一致(有的实现用10kHz单位,有的用kHz单位)。仔细查看supported_dtd_t的定义或邻近已有条目(例如233500)可推断单位。
    • 第一项52044:就是刷新率* 100052.043758... Hz -> 52044),EDID匹配逻辑会读取并比较这个刷新率标识。

    如何找清楚每个字段的含义(建议)

    • edid.c中搜索supported_dtd_t或结构定义,确认每个数组索引代表哪个时序字段,然后按顺序填入。这比盲目复制数字稳妥。
    • 如果不能立即找到struct定义,用现有已正确模式的一行做对照,把已知模式(例如1080p)中每个数字跟你的时序逐项比对(这正是你已经做的)。

    常见坑

    • 单位错认(10kHz/kHz/Hz):会导致刷新率clock全错,显示器拒绝信号。始终按项目里已有条目单位写入。
    • 字段顺序错:很多实现自行封装DTD,字段顺序不是标准EDID的字节序。
    • EDID vs VIC:某些sink会通过CEA里的VIC匹配而忽略DTD;需要同时在hdmi_mode_tblVIC定义和EDID DTD中一致化。
  5. core_edid.c中把新的HDMI_VIC加入“被特殊处理”的判断

    • 部分代码路径会先尝试用CEA/VIC(标准编号)匹配显示器能力;对自定义的扩展VIC(如0x201..0x204)希望直接使用DTD的精确时序信息,而不要用CEA代码强行匹配(避免被错误映射到标准VIC),因此将这些code置 0 强制使用DTD数据。

    注意与坑

    • 顺序敏感:这个分支需要放在合适位置,否则可能在edid_done=false或其他情况下被覆盖。
    • 兼容性:如果某些sink只支持CEA标准模式,而不支持自定义的DTD,那么当驱动把code置 0 后,显示器可能不显示(因为没有标准VIC匹配)。这不是代码错误,而是显示器能力限制。
    # 文件路径 hdmi2/hdmi_core/core_edid.c # 添加内容 # @@ -266,12 +266,13 @@ static void edid_set_video_prefered(sink_edid_t *sink_cap, } if ((pVideo->mDtd.mCode == 0x201) - || (pVideo->mDtd.mCode == 0x202) - || (pVideo->mDtd.mCode == 0x203)) { - pVideo->mCea_code = 0; - pVideo->mHdmi_code = 0; - return; - } + || (pVideo->mDtd.mCode == 0x202) + || (pVideo->mDtd.mCode == 0x203) + || (pVideo->mDtd.mCode == 0x204)) { + pVideo->mCea_code = 0; + pVideo->mHdmi_code = 0; + return; + } #if defined(__LINUX_PLAT__) if (!core->mode.edid_done) { pVideo->mCea_code = pVideo->mDtd.mCode;
  6. hdmi_get_video_timming_info()加入printk()日志(调试)

    • 实机调试时这是最直接、最快速确认驱动真正使用的时序参数的办法:很多问题不是写错字段,而是某处被覆盖(比如device tree/board配置优先级),或者EDID解析/匹配之后变形。打印可以告诉你最终驱动拿到的时序是什么。

    注意

    • 打印很多内容会影响kernel/u-boot console输出,建议仅在调试时添加,验证后移除或用#ifdef DEBUG包裹。
    • u-boot打印和kernel printk级别序列号不同,注意查看对应日志(串口 /dmesg)。
    # 文件路径 brandy/brandy-2.0/u-boot-2018/drivers/video/sunxi/disp2/hdmi2/hdmi_core/hdmi_core.c # 添加内容 # @@ -1060,9 +1060,18 @@ s32 hdmi_get_video_timming_info(struct disp_video_timings **video_info) info.vactive_space = 0; info.trd_mode = 0; } + printk("%s %d \n",__func__, __LINE__); + printk("info.pixel_clk:%d \n", info.pixel_clk ); + printk("x_res:%d \n", info.x_res ); + printk("y_res:%d \n", info.y_res ); + printk("hor_total_time:%d \n", info.hor_total_time ); + printk("hor_sync_time:%d \n", info.hor_sync_time ); + printk("hor_back_porch:%d \n", info.hor_back_porch ); + printk("hor_front_porch:%d \n", info.hor_front_porch ); + printk("ver_total_time:%d \n", info.ver_total_time ); + printk("ver_sync_time:%d \n", info.ver_sync_time ); + printk("ver_back_porch:%d \n", info.ver_back_porch ); + printk("ver_front_porch:%d \n", info.ver_front_porch ); *video_info = &info; return 0;
  7. Device Treeboard.dts)中设置output_modeframebuffer大小

    • dev0_output_mode指定启动时(Bootloader/fex/sys_configdriver)应选用的显示模式值。定义的DISP_TV_MOD_720_720P_60HZ的值0x45 = 69,设备树使用十进制<69>
    • fb0_width/fb0_heightframebuffer的默认尺寸,驱动会根据fb的 长宽 和 输出模式 进行缩放/裁剪/显示配置。它们要和你想要的输出一致,否则可能出现图像被拉伸或黑边。

    注意与坑

    • 十六进制/十进制换算:头文件使用0x45(16 进制),dts常以十进制在<...>中表示。确保换算正确:0x45 = 4*16 + 5 = 64 + 5 = 69。错一个地方会导致选择错误模式。
    • fb0_width/height的作用:在某些平台framebufferbuffer大小若与输出不一致,驱动会进行缩放。如果想使framebuffer同分辨率完全匹配,设置一致是合理的。但注意若使用多屏2D GPU,某些限制(alignmentstride)可能要求width16/32的倍数。
    • 设备树生效:修改完.dts必须编译生成.dtb并烧录/加载,否则系统仍使用旧配置。
  8. sys_config_my.fex修改output_mode

    • 许多Allwinner平台使用fex(或其后继格式)作为早期启动的配置文件。output_mode通常被启动脚本bootloader读取来决定默认输出模式(便于在没有完整kernel驱动前就能输出)。
    • fexdevice tree/dts同步,避免开机阶段和kernel阶段不一致。

    注意

    • 在同一平台上可能同时存在fexdtsu-boot env三处配置:所有位置都要同步(或决定只使用其中一种方式),否则表现会不一致。
    • 修改fex后要用平台工具重新生成镜像或把fex放到boot分区,按平台规范操作。
2.2.3、supported_dtd表参数说明

当前全志对于supported_dtd定义如下:

//brandy/brandy-2.0/u-boot-2018/drivers/video/sunxi/disp2/hdmi2/hdmi_core/api/edid.h//brandy/brandy-2.0/u-boot-2018/drivers/video/sunxi/disp2/hdmi2/hdmi_core/api/core_api.htypedefstruct{/** VIC code */u32 mCode;/** Identifies modes that ONLY can be displayed in YCC 4:2:0 */u8 mLimitedToYcc420;/** Identifies modes that can also be displayed in YCC 4:2:0 */u8 mYcc420;u16 mPixelRepetitionInput;/** In units of 1KHz */u32 mPixelClock;/** 1 for interlaced, 0 progressive */u8 mInterlaced;u16 mHActive;u16 mHBlanking;u16 mHBorder;u16 mHImageSize;/*For picture aspect ratio*/u16 mHSyncOffset;u16 mHSyncPulseWidth;/** 0 for Active low, 1 active high */u8 mHSyncPolarity;u16 mVActive;u16 mVBlanking;u16 mVBorder;u16 mVImageSize;/*For picture aspect ratio*/u16 mVSyncOffset;u16 mVSyncPulseWidth;/** 0 for Active low, 1 active high */u8 mVSyncPolarity;}dtd_t;typedefstructsupported_dtd{u32 refresh_rate;/* 1HZ * 1000 */dtd_tdtd;}supported_dtd_t;

结构体字段逐项详解(dtd_t

  1. mCodeu32VIC代码

    • 含义:Video Identification Code,标识该模式的“编号”。
    • 单位/格式:整数,通常用十六进制写(如0x204),也可以十进制。
    • 约定:把自定义扩展放在0x200+区间,所以用0x204合理。
    • 验证:此值要与hdmi_core.h中的HDMI_VIC_...hdmi_mode_tbl中的映射一致。
  2. mLimitedToYcc420/mYcc420u8

    • 含义:
      • mLimitedToYcc420:如果为 1,表示该 mode 只能以YCbCr 4:2:0格式显示(通常用于某些HDMI 2.0/HEVC场景),否则为 0。
      • mYcc420:表示该模式“也可以”以YCbCr 4:2:0显示(向后兼容标记)。
    • 常用取值:大多数普通RGB模式都写0
    • 何时用 1:针对编码 / 带宽 / 色度子采样限制时才设为 1。
  3. mPixelRepetitionInputu16

    • 含义:像素重复系数(pixel repetition / pixel duplication),常出现在某些低分辨率被上采样到更高传输时序的场合。
    • 常用值:0表示无重复(大多数模式)。若是 2 表示每像素水平重复 2 次等。
    • 建议:不需要时填0
  4. mPixelClocku32(单位:1 KHz

    • 明确单位:注释写着 “In units of 1KHz” —— 也就是说要把pixel clock写成千赫(kHz)
      • 例如40,000,000 Hz40 MHz)写作40000kHz)。
    • 计算已有target pixelclock时直接除 1000;也可以target refresh时可反算,见下面示例)。
    • 常见坑:误把单位当成Hz10 kHz,会导致数值相差100010倍,显示器会拒绝。
  5. mInterlacedu8

    • 含义:1= 交错(interlaced),0= 逐行(progressive)。
    • 对应你场景:720×720很可能是progressive,即0
  6. 水平/垂直像素时序(关键字段)

    EDID/Detailed Timing常用字段表示法与驱动里字段的对应(常见解释):

    • mHActive:有效像素宽(像素数)
    • mHBlanking:水平blanking总像素数 =hfront+hsync+hback(注意:驱动里有单独的HSyncOffsetHSyncPulseWidth,但HBlanking仍为总空白像素)
    • mHBorder:水平边框(像素)。几乎总为0
    • mHImageSize:图像水平物理长度(通常以mm为单位,用于画面纵横比)。
      • 如果不知道物理尺寸,填0(驱动大多数时候只用 aspect ratio 或直接忽略)。
    • mHSyncOffset:水平同步偏移 = 前肩(front porch)的像素数(即H front porch
    • mHSyncPulseWidthhsync脉宽(像素数)
    • mHSyncPolarity0 = active low1 = active high(必须与显示器EDID或你想要的时序一致)

    对应垂直:

    • mVActive:有效行数(行)
    • mVBlanking:垂直 blanking 总行数 =vfront+ vsync + vback
    • mVBorder:垂直边框(行),通常0
    • mVImageSize:图像垂直物理高度(mm),不确定可设0
    • mVSyncOffset:垂直前肩(front porch)行数
    • mVSyncPulseWidth:vsync 脉宽(行)
    • mVSyncPolarity:0/1 与水平类似

    注意:

    • mHBlanking不是hfront_porch + hback_porch(它还应包含hsync_len)。字段mHSyncOffsetmHSyncPulseWidth再细分了 blanking 的组成部分;总的关系:

      mHBlanking = mHSyncOffset + mHSyncPulseWidth + hback_porch

      一般直接算mHBlanking = hfront + hsync + hbackmHSyncOffset = hfrontmHSyncPulseWidth = hsync,这与驱动实现一致。

    • 同理垂直方向mVBlanking = vfront + vsync + vback

  7. supported_dtd_trefresh_rate字段

    u32 refresh_rate; /* 1HZ * 1000 */
    • 含义:把刷新率(Hz)乘以 1000 后的整数存储(例如 52.0437… Hz -> 存52044)。
    • 计算建议:int(round(refresh_hz * 1000))或者按整数方式四舍五入。
2.2.4、supported_dtd参数计算演示

示例参数:

# 厂家提供屏幕参数示例 pixelclock = 40,000,000 Hz hactive = 720 hfront_porch = 106 hback_porch = 120 hsync_len = 60 vactive = 720 vfront_porch = 20 vback_porch = 20 vsync_len = 4
  1. 水平总周期htotal

    逐位计算:

    • hactive + hfront = 720 + 106 = 826
    • hback = 826 + 120 = 946
    • hsync = 946 + 60 = 1006
      所以htotal = 1006
  2. 垂直总周期vtotal

    逐位计算:

    • vactive + vfront = 720 + 20 = 740
    • vback = 740 + 20 = 760
    • vsync = 760 + 4 = 764
      所以vtotal = 764
  3. 总像素数每帧 =htotal*vtotal

    逐步乘法(为确保不出错,逐步写出中间):

    • 1006 * 764
      • 1006 * 700 = 704,200
      • 1006 * 60 = 60,360
      • 1006 * 4 = 4,024
      • 合计 = 704,200 + 60,360 + 4,024 = 768,584

    所以pixels_per_frame = 768,584

  4. 40 MHz计算刷新率

    • pixelclock = 40,000,000 Hz
    • refresh = pixelclock / pixels_per_frame
      • 40,000,000 / 768,584 ≈ ?
        逐步除法(找整近似):
    • 768,584 * 52 = 39,966,368
    • 40,000,000 − 39,966,368 = 33,632(余数)
    • 33,632 / 768,584 ≈ 0.043758...
    • 所以refresh ≈ 52.04375839205604 Hz

    把它 *1000 并四舍五入:

    • 52.043758... * 1000 = 52043.758...
    • 四舍五入 =>52044

    因此refresh_rate字段写52044

  5. mPixelClock(单位kHz

    • pixelclock_khz = 40,000,000 / 1000 = 40000 kHz
    • 所以写mPixelClock = 40000
  6. hblank / vblank

    • hblank = hfront + hsync + hback = 106 + 60 + 120 = 286
    • vblank = vfront + vsync + vback = 20 + 4 + 20 = 44
  7. 其它直接字段映射

    • mHActive = 720
    • mHBlanking = 286
    • mHBorder = 0(通常)
    • mHImageSize = 0(除非你知道屏幕物理宽mm,通常不必填)
    • mHSyncOffset = hfront_porch = 106
    • mHSyncPulseWidth = hsync_len = 60
    • mHSyncPolarity =根据硬件,常用1active high)或0active low)。
    • mVActive = 720
    • mVBlanking = 44
    • mVBorder = 0
    • mVImageSize = 0
    • mVSyncOffset = vfront_porch = 20
    • mVSyncPulseWidth = vsync_len = 4
    • mVSyncPolarity =H同理,示例里用1
  8. 其余flag

    • mInterlaced = 0 (progressive)
    • mLimitedToYcc420 = 0
    • mYcc420 = 0
    • mPixelRepetitionInput = 0

那么最终数据为

/* 720x720 @ ~52.044Hz, pixelclock 40 MHz */{52044,{0x204,/* mCode: HDMI_VIC_720x720P61 */0,/* mLimitedToYcc420 */0,/* mYcc420 */0,/* mPixelRepetitionInput */40000,/* mPixelClock (kHz) -> 40,000 kHz = 40 MHz */0,/* mInterlaced */720,/* mHActive */286,/* mHBlanking (hfront + hsync + hback = 106+60+120) */0,/* mHBorder */0,/* mHImageSize (mm) - 0 if unknown */106,/* mHSyncOffset (front porch) */60,/* mHSyncPulseWidth */1,/* mHSyncPolarity (1 = active high) */720,/* mVActive */44,/* mVBlanking (vfront + vsync + vback = 20+4+20) */0,/* mVBorder */0,/* mVImageSize (mm) - 0 if unknown */20,/* mVSyncOffset (vertical front porch) */4,/* mVSyncPulseWidth */1}},/* mVSyncPolarity (1 = active high) */

重点注意

​ 如果需要“真正60Hz” 的替代(反算pixelclock并写入),希望最终刷新≈60.000 Hz(不是52Hz),也就是修改刷新率,那么需要修改pixelclock

  • pixelclock_required_hz = htotal * vtotal * 60
    已知htotal * vtotal = 768,584,逐步乘:
  • 768,584 * 60 = 768,584 * (6 * 10) = (768,584 * 6) * 10
    • 768,584 * 6 = 4,611,504
    • *10 => 46,115,040
      所以需要46,115,040 Hz46.11504 MHz.

写入mPixelClock时以 kHz 单位:46,115,040 / 1000 = 46115.04→ 四舍五入写46115(kHz)。

mPixelClock = 46115时的实际 refresh:

  • pixelclock_hz = 46,115,000
  • refresh = 46,115,000 / 768,584 ≈ 59.999948... Hz
  • refresh * 1000 ≈ 59999.948-> 四舍五入为60000(即显示接近60.000Hz

对应的supported_dtd_t行(60Hz近似):

/* 720x720 @ ~60Hz (pixelclock rounded to 46115 kHz -> ~59.99995Hz) */{60000,{0x204,0,0,0,46115,/* mPixelClock (kHz) ~ 46115 => 46.115 MHz */0,720,286,0,0,106,60,1,720,44,0,0,20,4,1}},

虽然这能把refresh_rate写成60000(表示60.000Hz),实际能否成功取决于:

  • 目标显示器是否接受该时序(很多显示器对pixel clock/porch/sync polarity有要求)。
  • HDMI传输链(PHY)能否以该pixelclock工作(有些PHY对非标准clocks有限制)。
2.2.5、supported_dtd参数常见问题
  1. 单位误会:
    • mPixelClock单位是kHz(注意不是Hz,也不是10kHz)。
    • refresh_rate1000Hz*1000)。
  2. 字段顺序 / 含义:
    • 一定按dtd_t定义的顺序填数值(驱动直接memcpy解析数组);若顺序错位,会导致非常奇怪的时序。
  3. mHImageSize/mVImageSize
    • 这些通常是以mm为单位的物理尺寸,用于计算像素纵横比(PAR)。如果不知道设备的物理尺寸,填0比填错误值更安全。
  4. mPixelRepetitionInput
    • 多数情形填0。如果设备需要像素重复(比如720p输出但显示器期望1440时序),才会用到。
  5. HSYNC/VSYNC极性:
    • 如果显示器EDID指定了极性,尽量跟随;如果不确定,实验1active high)或0active low)。多数LCD采用positive(1),但并非绝对。
  6. EDID DTD vs CEA VIC匹配:
    • 即使把DTD加入supported_dtd_t,显示器可能更倾向于使用CEA的标准VIC。如果新增了自定义VIC,必须同步在core_edid.chdmi_mode_tbl等处做判断以优先使用DTD
  7. 四舍五入规则:
    • mPixelClockkHz四舍五入(或向下取整),并根据结果计算refresh_rateHz*1000),然后四舍五入到整数。
http://www.cnnetsun.cn/news/2941894.html

相关文章:

  • Apache服务器本质:一个可定制的TCP连接处理网关
  • MetaboAnalystR 4.3:一站式代谢组学分析的终极开源解决方案
  • 前沿AI公司终将凋零
  • MPC866硬件接口深度解析:从引脚配置到内存控制器实战
  • 深入理解GLuCoSE-base-ja-openmind架构:基于LUKE的日语文本嵌入技术原理
  • 上三角数字三角形:循环嵌套与格式化输出的核心实现与调试指南
  • BERTicelli:下一代社交媒体安全防护的智能语义引擎
  • GPT-4o单图空间反演:从2D照片生成精准鸟瞰图的原理与应用
  • Ollama+Open WebUI本地AI中枢:从部署到RAG生产实践
  • 数字取证实战:从美亚杯竞赛解析电子数据调查核心技能
  • Docker 镜像漏洞扫描实践:从 CI 集成到修复策略的完整安全链路
  • 从遮蔽到重建:Masked Autoencoder (MAE) 如何革新视觉自监督预训练
  • 深入解析NXP MSC8251 QUICC Engine:以太网与TDM接口的硬件加速原理与实战
  • 5分钟快速上手:C开发的轻量级PS1模拟器ScePSX终极指南
  • SQL RANK()函数原理与并列跳号机制详解
  • 大模型能力分层:GPT-4o、GPT-4 Turbo与GPT-3.5的工程化协同策略
  • PCIe5.0 SSD如何成为本地大模型推理的性能中枢
  • 重新定义网页资源获取:猫抓浏览器扩展如何简化多媒体内容管理
  • B站硬核会员自动答题神器:3分钟搞定100题挑战
  • HuggingGPT 模式过时了?论垂直领域 Agent 的必然性
  • LVGL图片显示全链路配置:从存储格式、解码器到缓存优化的嵌入式UI实战
  • 终极指南:SY_AICC/GPT2-xl文本生成模型如何快速上手?10分钟完成你的第一个AI创作
  • 构建便携版VC++ 2019开发环境:原理、实践与避坑指南
  • Langchain-Chatchat本地知识库部署实战指南
  • AI在重型机械标准冲突判断中的能力边界实测
  • S32K324 FLS模块配置实战:从AUTOSAR存储驱动到汽车电子核心
  • RAG 检索策略优化:从向量搜索到混合检索的精度提升
  • 金融社群运营全攻略:从合规定位到高转化链路设计
  • 网络迷因deideiapuapu的传播机制与内容创作实战指南
  • Python map() 迭代器原理与生产级数据流处理实战