- search for additional detailed timings in the EDID extension block

- rework sunxi DE2 driver and accompanying DW-HDMI platform driver
    to drop redundant device specific code, and later use the DT as a
    source of information
 -----BEGIN PGP SIGNATURE-----
 
 iGwEABECACwWIQSC4hxrSoIUVfFO0kRM6ATMmsalXAUCYIQmGw4cYWd1c3RAZGVu
 eC5kZQAKCRBM6ATMmsalXKPqAJsGVBUQ1+vFaUrdGKtGZk8TOjtyKwCfe9vuH/E6
 88T+ybssGrorMQwyOvQ=
 =hyBc
 -----END PGP SIGNATURE-----

Merge tag 'video-2021-07-rc1-2' of https://source.denx.de/u-boot/custodians/u-boot-video

 - search for additional detailed timings in the EDID extension block
 - rework sunxi DE2 driver and accompanying DW-HDMI platform driver
   to drop redundant device specific code, and later use the DT as a
   source of information
This commit is contained in:
Tom Rini 2021-04-24 13:30:57 -04:00
commit 2937f71206
3 changed files with 72 additions and 88 deletions

View File

@ -169,6 +169,29 @@ static bool cea_is_hdmi_vsdb_present(struct edid_cea861_info *info)
return false;
}
static bool edid_find_valid_timing(void *buf, int count,
struct display_timing *timing,
bool (*mode_valid)(void *priv,
const struct display_timing *timing),
void *mode_valid_priv)
{
struct edid_detailed_timing *t = buf;
bool found = false;
int i;
for (i = 0; i < count && !found; i++, t++)
if (EDID_DETAILED_TIMING_PIXEL_CLOCK(*t) != 0) {
decode_timing((u8 *)t, timing);
if (mode_valid)
found = mode_valid(mode_valid_priv,
timing);
else
found = true;
}
return found;
}
int edid_get_timing_validate(u8 *buf, int buf_size,
struct display_timing *timing,
int *panel_bits_per_colourp,
@ -177,44 +200,47 @@ int edid_get_timing_validate(u8 *buf, int buf_size,
void *mode_valid_priv)
{
struct edid1_info *edid = (struct edid1_info *)buf;
bool timing_done;
int i;
bool found;
if (buf_size < sizeof(*edid) || edid_check_info(edid)) {
debug("%s: Invalid buffer\n", __func__);
return -EINVAL;
}
if (!EDID1_INFO_VIDEO_INPUT_DIGITAL(*edid)) {
debug("%s: Not a digital display\n", __func__);
return -ENOSYS;
}
if (!EDID1_INFO_FEATURE_PREFERRED_TIMING_MODE(*edid)) {
debug("%s: No preferred timing\n", __func__);
return -ENOENT;
}
/* Look for detailed timing */
timing_done = false;
for (i = 0; i < 4; i++) {
struct edid_monitor_descriptor *desc;
/* Look for detailed timing in base EDID */
found = edid_find_valid_timing(edid->monitor_details.descriptor, 4,
timing, mode_valid, mode_valid_priv);
desc = &edid->monitor_details.descriptor[i];
if (desc->zero_flag_1 != 0) {
decode_timing((u8 *)desc, timing);
if (mode_valid)
timing_done = mode_valid(mode_valid_priv,
timing);
else
timing_done = true;
/* Look for detailed timing in CTA-861 Extension Block */
if (!found && edid->extension_flag && buf_size >= EDID_EXT_SIZE) {
struct edid_cea861_info *info =
(struct edid_cea861_info *)(buf + sizeof(*edid));
if (timing_done)
break;
if (info->extension_tag == EDID_CEA861_EXTENSION_TAG) {
int count = EDID_CEA861_DTD_COUNT(*info);
int offset = info->dtd_offset;
int size = count * sizeof(struct edid_detailed_timing);
if (offset >= 4 && offset + size < EDID_SIZE)
found = edid_find_valid_timing(
(u8 *)info + offset, count, timing,
mode_valid, mode_valid_priv);
}
}
if (!timing_done)
if (!found)
return -EINVAL;
if (!EDID1_INFO_VIDEO_INPUT_DIGITAL(*edid)) {
debug("%s: Not a digital display\n", __func__);
return -ENOSYS;
}
if (edid->version != 1 || edid->revision < 4) {
debug("%s: EDID version %d.%d does not have required info\n",
__func__, edid->version, edid->revision);

View File

@ -19,8 +19,6 @@
#include <asm/io.h>
#include <asm/arch/clock.h>
#include <asm/arch/display2.h>
#include <dm/device-internal.h>
#include <dm/uclass-internal.h>
#include <linux/bitops.h>
#include "simplefb_common.h"
@ -198,13 +196,6 @@ static int sunxi_de2_init(struct udevice *dev, ulong fbbase,
disp_uc_plat->source_id = mux;
ret = device_probe(disp);
if (ret) {
debug("%s: device '%s' display won't probe (ret=%d)\n",
__func__, dev->name, ret);
return ret;
}
ret = display_read_timing(disp, &timing);
if (ret) {
debug("%s: Failed to read timings\n", __func__);
@ -245,8 +236,8 @@ static int sunxi_de2_probe(struct udevice *dev)
if (!(gd->flags & GD_FLG_RELOC))
return 0;
ret = uclass_find_device_by_name(UCLASS_DISPLAY,
"sunxi_lcd", &disp);
ret = uclass_get_device_by_driver(UCLASS_DISPLAY,
DM_DRIVER_GET(sunxi_lcd), &disp);
if (!ret) {
int mux;
@ -262,8 +253,8 @@ static int sunxi_de2_probe(struct udevice *dev)
debug("%s: lcd display not found (ret=%d)\n", __func__, ret);
ret = uclass_find_device_by_name(UCLASS_DISPLAY,
"sunxi_dw_hdmi", &disp);
ret = uclass_get_device_by_driver(UCLASS_DISPLAY,
DM_DRIVER_GET(sunxi_dw_hdmi), &disp);
if (!ret) {
int mux;
if (IS_ENABLED(CONFIG_MACH_SUNXI_H3_H5))
@ -281,20 +272,7 @@ static int sunxi_de2_probe(struct udevice *dev)
debug("%s: hdmi display not found (ret=%d)\n", __func__, ret);
ret = uclass_find_device_by_name(UCLASS_DISPLAY,
"sunxi_tve", &disp);
if (ret) {
debug("%s: tv not found (ret=%d)\n", __func__, ret);
return ret;
}
ret = sunxi_de2_init(dev, plat->base, VIDEO_BPP32, disp, 1, true);
if (ret)
return ret;
video_set_flush_dcache(dev, 1);
return 0;
return -ENODEV;
}
static int sunxi_de2_bind(struct udevice *dev)
@ -345,8 +323,8 @@ int sunxi_simplefb_setup(void *blob)
mux = 1;
/* Skip simplefb setting if DE2 / HDMI is not present */
ret = uclass_find_device_by_name(UCLASS_VIDEO,
"sunxi_de2", &de2);
ret = uclass_get_device_by_driver(UCLASS_VIDEO,
DM_DRIVER_GET(sunxi_de2), &de2);
if (ret) {
debug("DE2 not present\n");
return 0;
@ -355,8 +333,8 @@ int sunxi_simplefb_setup(void *blob)
return 0;
}
ret = uclass_find_device_by_name(UCLASS_DISPLAY,
"sunxi_dw_hdmi", &hdmi);
ret = uclass_get_device_by_driver(UCLASS_DISPLAY,
DM_DRIVER_GET(sunxi_dw_hdmi), &hdmi);
if (ret) {
debug("HDMI not present\n");
} else if (device_active(hdmi)) {
@ -368,8 +346,8 @@ int sunxi_simplefb_setup(void *blob)
debug("HDMI present but not probed\n");
}
ret = uclass_find_device_by_name(UCLASS_DISPLAY,
"sunxi_lcd", &lcd);
ret = uclass_get_device_by_driver(UCLASS_DISPLAY,
DM_DRIVER_GET(sunxi_lcd), &lcd);
if (ret)
debug("LCD not present\n");
else if (device_active(lcd))

View File

@ -20,7 +20,6 @@
struct sunxi_dw_hdmi_priv {
struct dw_hdmi hdmi;
int mux;
};
struct sunxi_hdmi_phy {
@ -114,28 +113,6 @@ static void sunxi_dw_hdmi_phy_init(void)
writel(0x42494E47, &phy->unscramble);
}
static int sunxi_dw_hdmi_get_plug_in_status(void)
{
struct sunxi_hdmi_phy * const phy =
(struct sunxi_hdmi_phy *)(SUNXI_HDMI_BASE + HDMI_PHY_OFFS);
return !!(readl(&phy->status) & (1 << 19));
}
static int sunxi_dw_hdmi_wait_for_hpd(void)
{
ulong start;
start = get_timer(0);
do {
if (sunxi_dw_hdmi_get_plug_in_status())
return 0;
udelay(100);
} while (get_timer(start) < 300);
return -1;
}
static void sunxi_dw_hdmi_phy_set(uint clock, int phy_div)
{
struct sunxi_hdmi_phy * const phy =
@ -305,11 +282,18 @@ static int sunxi_dw_hdmi_read_edid(struct udevice *dev, u8 *buf, int buf_size)
return dw_hdmi_read_edid(&priv->hdmi, buf, buf_size);
}
static bool sunxi_dw_hdmi_mode_valid(struct udevice *dev,
const struct display_timing *timing)
{
return timing->pixelclock.typ <= 297000000;
}
static int sunxi_dw_hdmi_enable(struct udevice *dev, int panel_bpp,
const struct display_timing *edid)
{
struct sunxi_hdmi_phy * const phy =
(struct sunxi_hdmi_phy *)(SUNXI_HDMI_BASE + HDMI_PHY_OFFS);
struct display_plat *uc_plat = dev_get_uclass_plat(dev);
struct sunxi_dw_hdmi_priv *priv = dev_get_priv(dev);
int ret;
@ -317,7 +301,7 @@ static int sunxi_dw_hdmi_enable(struct udevice *dev, int panel_bpp,
if (ret)
return ret;
sunxi_dw_hdmi_lcdc_init(priv->mux, edid, panel_bpp);
sunxi_dw_hdmi_lcdc_init(uc_plat->source_id, edid, panel_bpp);
if (edid->flags & DISPLAY_FLAGS_VSYNC_LOW)
setbits_le32(&phy->pol, 0x200);
@ -340,7 +324,6 @@ static int sunxi_dw_hdmi_enable(struct udevice *dev, int panel_bpp,
static int sunxi_dw_hdmi_probe(struct udevice *dev)
{
struct display_plat *uc_plat = dev_get_uclass_plat(dev);
struct sunxi_dw_hdmi_priv *priv = dev_get_priv(dev);
struct sunxi_ccm_reg * const ccm =
(struct sunxi_ccm_reg *)SUNXI_CCM_BASE;
@ -364,21 +347,17 @@ static int sunxi_dw_hdmi_probe(struct udevice *dev)
sunxi_dw_hdmi_phy_init();
ret = sunxi_dw_hdmi_wait_for_hpd();
if (ret < 0) {
debug("hdmi can not get hpd signal\n");
return -1;
}
priv->hdmi.ioaddr = SUNXI_HDMI_BASE;
priv->hdmi.i2c_clk_high = 0xd8;
priv->hdmi.i2c_clk_low = 0xfe;
priv->hdmi.reg_io_width = 1;
priv->hdmi.phy_set = sunxi_dw_hdmi_phy_cfg;
priv->mux = uc_plat->source_id;
uclass_get_device_by_phandle(UCLASS_I2C, dev, "ddc-i2c-bus",
&priv->hdmi.ddc_bus);
ret = dw_hdmi_phy_wait_for_hpd(&priv->hdmi);
if (ret < 0) {
debug("hdmi can not get hpd signal\n");
return -1;
}
dw_hdmi_init(&priv->hdmi);
@ -388,6 +367,7 @@ static int sunxi_dw_hdmi_probe(struct udevice *dev)
static const struct dm_display_ops sunxi_dw_hdmi_ops = {
.read_edid = sunxi_dw_hdmi_read_edid,
.enable = sunxi_dw_hdmi_enable,
.mode_valid = sunxi_dw_hdmi_mode_valid,
};
U_BOOT_DRIVER(sunxi_dw_hdmi) = {