diff --git a/common/edid.c b/common/edid.c index 553ab8fd01..fa85bcd6a1 100644 --- a/common/edid.c +++ b/common/edid.c @@ -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); diff --git a/drivers/video/sunxi/sunxi_de2.c b/drivers/video/sunxi/sunxi_de2.c index a3e21aa5f1..e02d359cd2 100644 --- a/drivers/video/sunxi/sunxi_de2.c +++ b/drivers/video/sunxi/sunxi_de2.c @@ -19,8 +19,6 @@ #include #include #include -#include -#include #include #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)) diff --git a/drivers/video/sunxi/sunxi_dw_hdmi.c b/drivers/video/sunxi/sunxi_dw_hdmi.c index 0b8cefc311..19ed80b48a 100644 --- a/drivers/video/sunxi/sunxi_dw_hdmi.c +++ b/drivers/video/sunxi/sunxi_dw_hdmi.c @@ -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) = {