edp极化问题解决之uefi篇

目录

[uefi 显示接口类型配置](#uefi 显示接口类型配置)

GOP目录代码结构

显示接口类型定义

显示流程

DTS配置

时序参数配置

关键数据结构disp_channel

[DTS 解析](#DTS 解析)

PDM参数解析流程

[channel open HDMI时序](#channel open HDMI时序)

[HDMI 静态时序](#HDMI 静态时序)

[hdmi_vo_prepare FRL时序获取](#hdmi_vo_prepare FRL时序获取)

总结


前述系统篇,edid从转换芯片中读取,转换芯片中的EDID 像素时钟频率与屏幕支持的不符合,导致极化。

而uefi中,即使EDID里面设置了屏幕支持的时钟频率,依然会极化。那时钟频率必然有其他来源。本文梳理uefi中的流程。海思在这uefi和系统中的两套设计的确很垃圾,合二为一有何不可。

uefi 显示接口类型配置

硬件设计变更,比如从mipi变更为hdmi,即需要修改配置,否则无法显示。本章示例接口变更带来的流程和配置。

GOP目录代码结构

disp 对应XDP 或者VDP

显示接口类型定义

code\uefi\VendorPkg\Include\Library\drv_disp_ext.h

复制代码
typedef enum {
    EXT_DRV_DISP_INTF_TYPE_HDMI = 0,
    EXT_DRV_DISP_INTF_TYPE_LCD,
    EXT_DRV_DISP_INTF_TYPE_BT1120,
    EXT_DRV_DISP_INTF_TYPE_BT656,
    EXT_DRV_DISP_INTF_TYPE_YPBPR = 0x8,
    EXT_DRV_DISP_INTF_TYPE_RGB,
    EXT_DRV_DISP_INTF_TYPE_CVBS,
    EXT_DRV_DISP_INTF_TYPE_SVIDEO,
    EXT_DRV_DISP_INTF_TYPE_VGA,
    EXT_DRV_DISP_INTF_TYPE_MIPI,
    EXT_DRV_DISP_INTF_TYPE_PANEL = 0x16,
    EXT_DRV_DISP_INTF_TYPE_ALL,

    EXT_DRV_DISP_INTF_TYPE_MAX
} disp_intf_type;

显示流程

code\uefi\VendorPkg\Drivers\Gop\Disp\disp\drv_display.c

复制代码
td_s32 drv_disp_open(ext_drv_display disp)
{
    td_s32 ret;
    disp_channel *disp_chan = TD_NULL;

    get_channel_by_id(disp, disp_chan);
     
	soc_err_disp("config drv_disp_open\n",disp,disp_chan->intf_info.display_intf.intf_type); //显示接口类型的

    //disp 0 disp intf_type: 24
    // disp 1 disp intf_type: 24


    ret = disp_get_pdm_param(disp);
    ....
    ....
    ....
    ....
    disp_chan->open = TD_TRUE;
	soc_err_disp("after config drv_disp_open\n",disp,disp_chan->intf_info.display_intf.intf_type);  //函数最后查看显示接口类型,明确接口类型的赋值在此函数中
  //disp 0 disp intf_type: 0     HDMI
    // disp 1 disp intf_type: 22  PANEL //这个与实际不符合。
    return TD_SUCCESS; /* must sucess to let open the other chanel, kernel will check open state for boot open error*/

上述流程中,初始时,显示接口的类型为最大值,即无效的显示接口;在上述接口后,获取到具体的显示接口类型。但硬件设计的两个接口类型都是HDMI,此时获取的一个接口类型为PANEL,与实际不符合。

DTS配置

复制代码
&pdm_disp1 {
	intf_0 = <SOCT_DISP_INTF_TYPE_PANEL 0 0 0 0 0 0 0>;
};

修改为:

复制代码
&pdm_disp1 {
	intf_0 = <SOCT_DISP_INTF_TYPE_HDMI 1  0 0 0 0 0 0>;
};

即将disp1 也配置为HDMI,并且是HDMI 1 ,而后上述open接口即可以获取到与硬件设计一致的显示接口类型。即可以正常显示。

时序参数配置

关键数据结构disp_channel

复制代码
typedef struct {
    ext_drv_display disp;
    td_bool open;

    disp_setting setting;
    td_bool disp_setting_change;

    /* disp intf info */
    disp_intf_ctrl intf_info;
    /* panel */
    disp_output_connect_type out_connect_type;
    disp_src_info disp_src_info;
    ext_disp_display_info disp_info;
    disp_proc_debug disp_debug;
} disp_channel;

DTS 解析

\code\uefi\VendorPkg\Library\Pdm\PdmLib.c

复制代码
Ret = FdtGetDtsConfigU32ArrayByName (DispNodeName, "disp_timing", (UINT32 *)&DispParam->disp_timing,
    sizeof(DispParam->disp_timing) / sizeof(UINT32));
  if (Ret < (EFI_STATUS)(sizeof(DispParam->disp_timing) / sizeof(INT32))) {
    DEBUG ((EFI_D_ERROR, "get disp_timing fail\n"));
    return EFI_PDM_ERROR;
  }

	disp_timing=<0 0 0 0 0 0 0 0 0 0 0 0 0 0>;
		//<vfb vbb vact hfb hbb hact vpw hpw idv ihs ivs clkreversal pix_freq refresh_rate>

PDM参数解析流程

PDM即显示管理,将display表示的显示实体与具体显示接口(例如HDMI)建立关联。并解析用户设置的PDM参数,例如显示的硬件路由,显示格式等参数。进而为后续具体的初始化,时序参数配置等建立基础。

\uefi\VendorPkg\Drivers\Gop\Hdmitx\drv_hdmitx.c

\uefi\VendorPkg\Drivers\Gop\Hdmitx\drv_hdmitx.c

\uefi\VendorPkg\Drivers\Gop\Disp\disp\drv_disp_interface.c

uefi\VendorPkg\Drivers\Gop\Disp\disp\drv_display.c

channel open HDMI时序

\uefi\VendorPkg\Drivers\Gop\Disp\disp\drv_display.c

disp_set_channel_open-->disp_set_output_timing--》drv_disp_update_intf_info

复制代码
 if (format == EXT_DRV_DISP_FMT_CUSTOM) {
        intf_info->disp_timing.static_timing.timing = *custom_timing;
        intf_info->disp_timing.static_timing.vic_num = 0;
        intf_info->disp_timing.static_timing.interlace = TD_FALSE;
        intf_info->disp_timing.static_timing.pix_repeat = 1;
        intf_info->disp_timing.static_timing.disp_fmt = EXT_DRV_DISP_FMT_CUSTOM;
        intf_info->disp_timing.static_timing.disp_3d_mode = EXT_DRV_DISP_STEREO_NONE;

        intf_info->disp_timing.static_timing.aspect_ratio.aspect_ratio_w = DISP_ASPECT_RATION_W;
        intf_info->disp_timing.static_timing.aspect_ratio.aspect_ratio_h = DISP_ASPECT_RATION_H;
    } else {
        ret = drv_disp_timing_get_timing_info(format, &(intf_info->disp_timing.static_timing), &timing_info);
        if (ret != TD_SUCCESS) {
            soc_err_disp("get timing cfg is error, fmt is %d\n", format);
            return ret;
        }
    }
    drv_disp_update_interface_info(disp, format, intf_info);

如果DTS中的format字段配置为 : EXT_DRV_DISP_FMT_CUSTOM = 0xC0,则时序采用dts中的。否则 通过format 获取具体时序参数的索引字段。

HDMI 静态时序

\uefi\VendorPkg\Drivers\Gop\Disp\disp\drv_display.c

disp_set_channel_open-》disp_set_output_timing

\uefi\VendorPkg\Drivers\Gop\Disp\disp\drv_disp_timing.c

drv_disp_update_intf_info--》drv_disp_timing_get_timing_info

根据上面的流程可知,时序参数由format决定。例如DTS中默认配置的1080 60fps,其时序参数如下,可以看到此处148MHZ时钟。VIC为329。

static disp_timing_infog_disp_format_param[]

uefi\VendorPkg\Include\Library\drv_disp_ext.h

EXT_DRV_DISP_FMT_VESA_1920X1080_60 (a9)与dts中的默认配置format

#define SOCT_DISP_FMT_VESA_1920X1080_60 169 (a9)

复制代码
/* |--INTFACE---||-----TOP-----||---HORIZON----||---BOTTOM----||-PULSE-||-INVERSE-| */
    /* Synm Iop  Itf  Vact Vbb Vfb Hact Hbb Hfb Bvact Bvbb Bvfb Hpw Vpw Hmid bIdv bIhs bIvs */
    // 11 UAPI_ENC_FMT_480P_60,
    // 73
    {
        EXT_DRV_DISP_FMT_VESA_1920X1080_60,
        EXT_DRV_DISP_STEREO_NONE,
        {   EXT_DRV_COLOR_PRIMARY_BT709, EXT_DRV_COLOR_CS_RGB, EXT_DRV_COLOR_FULL_RANGE,
            EXT_DRV_COLOR_TRANSFER_TYPE_GAMMA_SDR, EXT_DRV_COLOR_MATRIX_COEFFS_BT709
        },
        TD_FALSE,
        60000,
        148500,
        329,
        { 16, 9 },
        { 1, 1080, 41, 4, 1920, 192, 88, 1, 1, 1, 44, 5, 1, 0, 0, 0 },
    },

修改此处的时序为141MHZ,规避UEFI中极化问题。同时VIC修改为对应的401.

hdmi_vo_prepare FRL时序获取

\uefi\VendorPkg\Drivers\Gop\Disp\disp\drv_display.c

disp_set_channel_open-》disp_set_output_timing-》drv_disp_intf_output_prepare

\uefi\VendorPkg\Drivers\Gop\Disp\disp\drv_disp_interface.c

drv_disp_intf_output_prepare

\uefi\VendorPkg\Drivers\Gop\Hdmitx**\drv_hdmitx.c**

VIC 修改为401后,FRL时序流程跑不通,具体流程如下:

hdmi_vo_timing_prepare--》hdmi_cur_hw_config_decision--》hdmi_get_hdmi_mode_config-->drv_hdmitx_modes_get_frl_req_by_band

复制代码
struct frl_requirements *drv_hdmitx_modes_get_frl_req_by_band(const struct band_mode *in)
{
    td_u32 i;
    struct band_mode band;

    if (in == TD_NULL) {
        soc_log_alert("ptr is null.\n");
        return TD_NULL;
    }

    band.vic = in->vic;
    band.color_depth = in->color_depth;
    band.color_format = (in->color_format == RGB444) ? YCBCR444 : in->color_format;

    if (get_table_index_by_vic(band.vic) == 0) {
        soc_log_dbg("index is zero.\n");
        return TD_NULL;
    }
    // 此处frl table也不支持401 的vic,也会返回空。
    for (i = 0; i < ARRAY_SIZE(g_frl_req_table); i++) {
        if (band.vic == g_frl_req_table[i].band_mode.vic &&
            band.color_format == g_frl_req_table[i].band_mode.color_format &&
            band.color_depth == g_frl_req_table[i].band_mode.color_depth) {
            return &g_frl_req_table[i];
        }
    }

    return TD_NULL;
}
//如下接口不支持401的VIC,导致函数返回失败。而我们的屏幕采用了401的VIC
static td_u32 get_table_index_by_vic(td_u32 vic)
{
    if (vic > 0 && vic <= VIC_5120X2160P100_64_27) {
        return vic;
    } else if (vic >= VIC_5120X2160P120_64_27 && vic <= VIC_4096X2160P120_256_135) {
        return vic - 65; /* 65 = (192-128+1) */
    } else if (vic >= VIC_VESA_800X600P60 && vic <= VIC_VESA_1680X1050P60RB) {
        return vic - 102; /* 102 = (256-220+1)-(192-128 + 1) */
    } else {
        return 0;
    }
}

由于不采用FRL 模式,这里临时将FRL 相关流程注释掉。

总结

1)DTS中有些参数只给UEFI的,例如PDM中的inte_type字段,虽然之前配置和硬件不一致,但系统中可以显示,但uefi不显示。说明此字段只有uefi中会解析使用。

2) UEFI中的EDID完全是静态配置的。虽然看代码由动态流程,很多都是废代码,海思在这方面的实现仅仅是为了和系统代码的复用,导致uefi存在大量冗余代码,带来困扰。

例如: 此文件中也有时序,而通常的逻辑可能以为是从接口层获取EDID时序参数。但实际用的

\uefi\VendorPkg\Drivers\Gop\Hdmitx\drv_hdmitx_modes.c

static struct hdmitx_timing_mode g_timing_mode_table[] = {

hdmi_get_hdmi_mode_config

3)目前BIOS配置菜单还不能显示,提示如下

800x600 这个频率也不支持。

采用HDMI转EDP,原本经常连接外部显示接口的HDMI ,变为连接内嵌屏幕的EDP接口。导致时序参数调整带来较多工作。

4)在走读DTS及代码时,我们发现: pixel_format=<SOCT_PIXEL_FORMAT_ARG8888>;而根据之前走读手册知晓,4K60HZ在此像素格式时,需要采用放大功能,那么如何配置放大功能呢?

后续对于BIOS 配置菜单的显示 及像素格式带来的放大功能配置将做进一步研究。

相关推荐
yao0003712 天前
基于QEMU+OpenSBI+edk2的riscv启动流程解析
qemu·riscv·uefi·bios·固件·opensbi
tianyuanwo2 个月前
深度解析:Linux ISO引导配置与安装模式设计
linux·uefi·iso·isolinux.cfg·grub.cfg
阿源-2 个月前
UEFI 中的杂项知识总结-Protocol Handle 机制的详细介绍
嵌入式·uefi·edk2·固件
REDcker2 个月前
UEFI BIOS深度解析:现代固件架构的革命性突破
架构·操作系统·uefi·bios
阿源-3 个月前
UEFI - FV/FFS/FDF 的关系
嵌入式·uefi·edk2·固件
阿源-3 个月前
UEFI-PEI 阶段的深层介绍
嵌入式·uefi·x86·edk2·固件
阿源-3 个月前
BIOS/UEFI 与其分别使用的磁盘分区形式 MBR/GPT
嵌入式·uefi·固件
阿源-4 个月前
UEFI 启动的各阶段介绍
嵌入式·uefi·edk2·固件
yao000374 个月前
【5】理解GUID和Handle:解锁UEFI驱动和应用程序的钥匙
uefi·bios·固件