mirror of
https://github.com/Fishwaldo/u-boot.git
synced 2025-03-18 21:21:37 +00:00
- 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:
commit
2937f71206
3 changed files with 72 additions and 88 deletions
|
@ -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);
|
||||
|
|
|
@ -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))
|
||||
|
|
|
@ -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) = {
|
||||
|
|
Loading…
Add table
Reference in a new issue