全志linux开发屏幕适配(二)`HDMI`驱动适配说明
HDMI驱动适配2.2.1、标准分辨率查看当前已经支持的标准分辨率文件路径./sdk-linux-github/brandy/brandy-2.0/u-boot-2018/include/sunxi_display2.henum 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:macrovalue 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[同步修改 kernelbr/ 的 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,先计算出需要在驱动中设置的参数水平总周期htotal hactive hfront hback hsync720 106 826826 120 946946 60 1006所以htotal 1006垂直总周期vtotal vactive vfront vback vsync720 20 740740 20 760760 4 764所以vtotal 764水平blankinghblank hfront hback hsync106 120 226226 60 286所以hblank 286垂直blankingvblank vfront vback vsync20 20 4040 4 44所以vblank 44按照pixelclock40000000Hz计算实际刷新率先算分母htotal * vtotal1006 * 7641006 * 700 704,2001006 * 60 60,3601006 * 4 4,024合计 704,200 60,360 4,024 768,584则刷新率 pixelclock / (htotal * vtotal)40,000,000 / 768,584768,584 * 52 39,966,36840,000,000 - 39,966,368 33,632 余数33,632 / 768,584 ≈ 0.043758…所以刷新率 ≈ 52.04375839205604 Hz四舍五入mHz52.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,584768,584 * 60 46,115,040 Hz 46.11504MHz所以要真60Hzpixelclock≈ 46.11504MHz不是 40MHz。总结修改步骤在hdmi_core.h中定义新的HDMI_VIC自定义VIC值HDMI标准的VIC通常是0x000xFF范围内的代码标准VIC有约定的编号。设备树里已经用了0x201、0x202、0x203做“自定义/扩展”编号看起来这是项目约定把自定义模式放在0x200区间。新模式需有一个唯一的代码供内部识别并与EDID/DTD对应。注意与坑不要与已有值冲突确保0x204未被其它地方占用。检查所有相关头文件以避免重复定义不同文件复制的头文件需同步。十六进制/十进制混用容易出错在头文件用0x204十六进制更直观但在其他地方比如device tree可能需要十进制详见步骤 7。如果项目以后会合并标准VIC考虑在注释里标注这是“私有/扩展VIC区间”。在各种sunxi_display2.h中增加DISP_TV_MODDISP_TV_MOD_*是display subsystem的统一枚举。驱动/设备树/工具链在配置输出模式时使用该枚举值。你在设备树里用的数字如dev0_output_mode 69;就是这个枚举的十进制表示0x45 69。 所以需要在所有相关头文件里添加确保在不同子系统board,sdk_demo,platform libs里都能被识别。注意与坑多处同步这些头文件在仓库里被拷贝多处——必须全部修改遗漏一个会出现链接或编译断裂或在某个子模块编译时缺少定义。把定义统一放到一个共享头文件里是较好的长期做法。数值冲突0x45已被选择但要检查是否与其它DISP类型VGA、TV、VGA mode冲突。device treedts与fex使用注意device tree的69跟这里0x45是同一含义十进制vs十六进制一定要换算正确。在hdmi_mode_tbl中加入新模式映射hdmi_mode_tbl[]是框架把平台的DISP_TV_MOD_*平台/驱动层内部的分辨率枚举映射为HDMI的VICVideo Identification Code或自定义代码。若不在此表中注册驱动不会把自定义的DISP模式映射到HDMI层从而无法输出该分辨率。注意与坑在u-boot与kernel两处都改这是必须的。原因u-boot的hdmi层用于早期引导显示logo/boot messageskernel的driver用于系统启动后的显示。若只改其中一处会出现开机能看到但系统启动后不对的情况或反之。枚举一致性确保DISP_TV_MOD_720_720P_60HZ和HDMI_VIC_720x720P61在步骤 1、2 中定义的值与这里完全一致同样的宏/值、同样的十六进制/十进制。不一致会导致编译或运行时找不到对应项。在EDID的supported_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 - 52044EDID匹配逻辑会读取并比较这个刷新率标识。如何找清楚每个字段的含义建议在edid.c中搜索supported_dtd_t或结构定义确认每个数组索引代表哪个时序字段然后按顺序填入。这比盲目复制数字稳妥。如果不能立即找到struct定义用现有已正确模式的一行做对照把已知模式例如1080p中每个数字跟你的时序逐项比对这正是你已经做的。常见坑单位错认10kHz/kHz/Hz会导致刷新率clock全错显示器拒绝信号。始终按项目里已有条目单位写入。字段顺序错很多实现自行封装DTD字段顺序不是标准EDID的字节序。EDID vs VIC某些sink会通过CEA里的VIC匹配而忽略DTD需要同时在hdmi_mode_tbl、VIC定义和EDID DTD中一致化。在core_edid.c中把新的HDMI_VIC加入“被特殊处理”的判断部分代码路径会先尝试用CEA/VIC标准编号匹配显示器能力对自定义的扩展VIC如0x201..0x204希望直接使用DTD的精确时序信息而不要用CEA代码强行匹配避免被错误映射到标准VIC因此将这些code置 0 强制使用DTD数据。注意与坑顺序敏感这个分支需要放在合适位置否则可能在edid_donefalse或其他情况下被覆盖。兼容性如果某些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;在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;在Device Treeboard.dts中设置output_mode和framebuffer大小dev0_output_mode指定启动时Bootloader/fex/sys_config及driver应选用的显示模式值。定义的DISP_TV_MOD_720_720P_60HZ的值0x45 69设备树使用十进制69。fb0_width/fb0_height是framebuffer的默认尺寸驱动会根据fb的 长宽 和 输出模式 进行缩放/裁剪/显示配置。它们要和你想要的输出一致否则可能出现图像被拉伸或黑边。注意与坑十六进制/十进制换算头文件使用0x4516 进制dts常以十进制在...中表示。确保换算正确0x45 4*16 5 64 5 69。错一个地方会导致选择错误模式。fb0_width/height的作用在某些平台framebuffer的buffer大小若与输出不一致驱动会进行缩放。如果想使framebuffer同分辨率完全匹配设置一致是合理的。但注意若使用多屏2D GPU某些限制alignment、stride可能要求width是16/32的倍数。设备树生效修改完.dts必须编译生成.dtb并烧录/加载否则系统仍使用旧配置。在sys_config_my.fex修改output_mode许多Allwinner平台使用fex或其后继格式作为早期启动的配置文件。output_mode通常被启动脚本bootloader读取来决定默认输出模式便于在没有完整kernel驱动前就能输出。把fex与device tree/dts同步避免开机阶段和kernel阶段不一致。注意在同一平台上可能同时存在fex、dts、u-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_tmCode—u32—VIC代码含义Video Identification Code标识该模式的“编号”。单位/格式整数通常用十六进制写如0x204也可以十进制。约定把自定义扩展放在0x200区间所以用0x204合理。验证此值要与hdmi_core.h中的HDMI_VIC_...、hdmi_mode_tbl中的映射一致。mLimitedToYcc420/mYcc420—u8含义mLimitedToYcc420如果为 1表示该 mode 只能以YCbCr 4:2:0格式显示通常用于某些HDMI 2.0/HEVC场景否则为 0。mYcc420表示该模式“也可以”以YCbCr 4:2:0显示向后兼容标记。常用取值大多数普通RGB模式都写0。何时用 1针对编码 / 带宽 / 色度子采样限制时才设为 1。mPixelRepetitionInput—u16含义像素重复系数pixel repetition / pixel duplication常出现在某些低分辨率被上采样到更高传输时序的场合。常用值0表示无重复大多数模式。若是 2 表示每像素水平重复 2 次等。建议不需要时填0。mPixelClock—u32单位1 KHz明确单位注释写着 “In units of 1KHz” —— 也就是说要把pixel clock写成千赫(kHz)。例如40,000,000 Hz40 MHz写作40000kHz。计算已有target pixelclock时直接除 1000也可以target refresh时可反算见下面示例。常见坑误把单位当成Hz或10 kHz会导致数值相差1000或10倍显示器会拒绝。mInterlaced—u8含义1 交错interlaced0 逐行progressive。对应你场景720×720很可能是progressive即0。水平/垂直像素时序关键字段EDID/Detailed Timing常用字段表示法与驱动里字段的对应常见解释mHActive有效像素宽像素数mHBlanking水平blanking总像素数 hfronthsynchback注意驱动里有单独的HSyncOffset与HSyncPulseWidth但HBlanking仍为总空白像素mHBorder水平边框像素。几乎总为0。mHImageSize图像水平物理长度通常以mm为单位用于画面纵横比。如果不知道物理尺寸填0驱动大多数时候只用 aspect ratio 或直接忽略。mHSyncOffset水平同步偏移 前肩front porch的像素数即H front porchmHSyncPulseWidthhsync脉宽像素数mHSyncPolarity0 active low1 active high必须与显示器EDID或你想要的时序一致对应垂直mVActive有效行数行mVBlanking垂直 blanking 总行数 vfront vsync vbackmVBorder垂直边框行通常0mVImageSize图像垂直物理高度mm不确定可设0mVSyncOffset垂直前肩front porch行数mVSyncPulseWidthvsync 脉宽行mVSyncPolarity0/1 与水平类似注意mHBlanking不是hfront_porch hback_porch它还应包含hsync_len。字段mHSyncOffset与mHSyncPulseWidth再细分了 blanking 的组成部分总的关系mHBlanking mHSyncOffset mHSyncPulseWidth hback_porch一般直接算mHBlanking hfront hsync hbackmHSyncOffset hfrontmHSyncPulseWidth hsync这与驱动实现一致。同理垂直方向mVBlanking vfront vsync vback。supported_dtd_t的refresh_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水平总周期htotal逐位计算hactive hfront 720 106 826hback 826 120 946hsync 946 60 1006所以htotal 1006。垂直总周期vtotal逐位计算vactive vfront 720 20 740vback 740 20 760vsync 760 4 764所以vtotal 764。总像素数每帧 htotal*vtotal逐步乘法为确保不出错逐步写出中间1006 * 7641006 * 700 704,2001006 * 60 60,3601006 * 4 4,024合计 704,200 60,360 4,024 768,584所以pixels_per_frame 768,584。按40 MHz计算刷新率pixelclock 40,000,000 Hzrefresh pixelclock / pixels_per_frame40,000,000 / 768,584 ≈ ?逐步除法找整近似768,584 * 52 39,966,36840,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。mPixelClock单位kHzpixelclock_khz 40,000,000 / 1000 40000 kHz所以写mPixelClock 40000。hblank / vblankhblank hfront hsync hback 106 60 120 286vblank vfront vsync vback 20 4 20 44其它直接字段映射mHActive 720mHBlanking 286mHBorder 0通常mHImageSize 0除非你知道屏幕物理宽mm通常不必填mHSyncOffset hfront_porch 106mHSyncPulseWidth hsync_len 60mHSyncPolarity 根据硬件常用1active high或0active low。mVActive 720mVBlanking 44mVBorder 0mVImageSize 0mVSyncOffset vfront_porch 20mVSyncPulseWidth vsync_len 4mVSyncPolarity 同H同理示例里用1。其余flagmInterlaced 0 progressivemLimitedToYcc420 0mYcc420 0mPixelRepetitionInput 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 10660120) */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 20420) */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也就是修改刷新率那么需要修改pixelclockpixelclock_required_hz htotal * vtotal * 60已知htotal * vtotal 768,584逐步乘768,584 * 60 768,584 * (6 * 10) (768,584 * 6) * 10768,584 * 6 4,611,504*10 46,115,040所以需要46,115,040 Hz≈46.11504 MHz.写入mPixelClock时以 kHz 单位46,115,040 / 1000 46115.04→ 四舍五入写46115kHz。用mPixelClock 46115时的实际 refreshpixelclock_hz 46,115,000refresh 46,115,000 / 768,584 ≈ 59.999948... Hzrefresh * 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参数常见问题单位误会mPixelClock单位是kHz注意不是Hz也不是10kHz。refresh_rate要1000Hz*1000。字段顺序 / 含义一定按dtd_t定义的顺序填数值驱动直接memcpy解析数组若顺序错位会导致非常奇怪的时序。mHImageSize/mVImageSize这些通常是以mm为单位的物理尺寸用于计算像素纵横比PAR。如果不知道设备的物理尺寸填0比填错误值更安全。mPixelRepetitionInput多数情形填0。如果设备需要像素重复比如720p输出但显示器期望1440时序才会用到。HSYNC/VSYNC极性如果显示器EDID指定了极性尽量跟随如果不确定实验1active high或0active low。多数LCD采用positive(1)但并非绝对。EDID DTD vs CEA VIC匹配即使把DTD加入supported_dtd_t显示器可能更倾向于使用CEA的标准VIC。如果新增了自定义VIC必须同步在core_edid.c、hdmi_mode_tbl等处做判断以优先使用DTD。四舍五入规则对mPixelClock用kHz四舍五入或向下取整并根据结果计算refresh_rateHz*1000然后四舍五入到整数。