[U-Boot] [PATCH 0/6] sunxi: video: Add hdmi output fmt support + misc fixes

Hi Anatolij & Ian,
Here is a second series of sunxi video support improvments.
Anatolij, can you please review the first patch of the series? You're input on the rest is welcome too of course :)
Regards,
Hans

Add a struct describing the (fixed) bits of cea681 edid extension blocks, and defines for accessing various bitfields.
Signed-off-by: Hans de Goede hdegoede@redhat.com --- include/edid.h | 19 +++++++++++++++++++ 1 file changed, 19 insertions(+)
diff --git a/include/edid.h b/include/edid.h index a69f43a..18ec1d5 100644 --- a/include/edid.h +++ b/include/edid.h @@ -230,6 +230,25 @@ struct edid1_info { unsigned char checksum; } __attribute__ ((__packed__));
+struct edid_cea861_info { + unsigned char extension_tag; +#define EDID_CEA861_EXTENSION_TAG 0x02 + unsigned char revision; + unsigned char dtd_offset; + unsigned char dtd_count; +#define EDID_CEA861_SUPPORTS_UNDERSCAN(_x) \ + GET_BIT(((_x).dtd_count), 7) +#define EDID_CEA861_SUPPORTS_BASIC_AUDIO(_x) \ + GET_BIT(((_x).dtd_count), 6) +#define EDID_CEA861_SUPPORTS_YUV444(_x) \ + GET_BIT(((_x).dtd_count), 5) +#define EDID_CEA861_SUPPORTS_YUV422(_x) \ + GET_BIT(((_x).dtd_count), 4) +#define EDID_CEA861_DTD_COUNT(_x) \ + GET_BITS(((_x).dtd_count), 3, 0) + unsigned char data[124]; +} __attribute__ ((__packed__)); + /** * Print the EDID info. *

On Sat, 20 Dec 2014 15:42:00 +0100 Hans de Goede hdegoede@redhat.com wrote:
Add a struct describing the (fixed) bits of cea681 edid extension blocks, and defines for accessing various bitfields.
Signed-off-by: Hans de Goede hdegoede@redhat.com

On Sat, 20 Dec 2014 15:42:00 +0100 Hans de Goede hdegoede@redhat.com wrote:
Add a struct describing the (fixed) bits of cea681 edid extension blocks, and defines for accessing various bitfields.
Signed-off-by: Hans de Goede hdegoede@redhat.com
Acked-by: Anatolij Gustschin agust@denx.de

So far we've been programming the hdmi-encoder to send out dvi data over the hdmi connector. This works well for most devices, including hdmi devices, but not all devices accept dvi data on a hdmi input.
Add support for sending proper hdmi data over the hdmi output found on most sunxi boards. This can be turned on by adding by adding monitor=hdmi as option to the video-mode env. variable.
A follow up patch will determine wether to send dvi or hdmi automatically when EDID is used.
Signed-off-by: Hans de Goede hdegoede@redhat.com --- arch/arm/include/asm/arch-sunxi/display.h | 33 +++++++++++----- drivers/video/sunxi_display.c | 66 ++++++++++++++++++++++++++++--- 2 files changed, 84 insertions(+), 15 deletions(-)
diff --git a/arch/arm/include/asm/arch-sunxi/display.h b/arch/arm/include/asm/arch-sunxi/display.h index 8c4835e..838b217 100644 --- a/arch/arm/include/asm/arch-sunxi/display.h +++ b/arch/arm/include/asm/arch-sunxi/display.h @@ -102,23 +102,30 @@ struct sunxi_hdmi_reg { u32 video_fp; /* 0x01c */ u32 video_spw; /* 0x020 */ u32 video_polarity; /* 0x024 */ - u8 res0[0x1d8]; /* 0x028 */ + u8 res0[0x58]; /* 0x028 */ + u8 avi_info_frame[0x14]; /* 0x080 */ + u8 res1[0x4c]; /* 0x094 */ + u32 qcp_packet0; /* 0x0e0 */ + u32 qcp_packet1; /* 0x0e4 */ + u8 res2[0x118]; /* 0x0e8 */ u32 pad_ctrl0; /* 0x200 */ u32 pad_ctrl1; /* 0x204 */ u32 pll_ctrl; /* 0x208 */ u32 pll_dbg0; /* 0x20c */ u32 pll_dbg1; /* 0x210 */ u32 hpd_cec; /* 0x214 */ - u8 res1[0x28]; /* 0x218 */ - u32 spd_pkt; /* 0x240 */ - u8 res2[0xac]; /* 0x244 */ + u8 res3[0x28]; /* 0x218 */ + u8 vendor_info_frame[0x14]; /* 0x240 */ + u8 res4[0x9c]; /* 0x254 */ u32 pkt_ctrl0; /* 0x2f0 */ u32 pkt_ctrl1; /* 0x2f4 */ - u8 res3[0x18]; /* 0x2f8 */ + u8 res5[0x8]; /* 0x2f8 */ + u32 unknown; /* 0x300 */ + u8 res6[0xc]; /* 0x304 */ u32 audio_sample_count; /* 0x310 */ - u8 res4[0xec]; /* 0x314 */ + u8 res7[0xec]; /* 0x314 */ u32 audio_tx_fifo; /* 0x400 */ - u8 res5[0xfc]; /* 0x404 */ + u8 res8[0xfc]; /* 0x404 */ #ifndef CONFIG_MACH_SUN6I u32 ddc_ctrl; /* 0x500 */ u32 ddc_addr; /* 0x504 */ @@ -131,7 +138,7 @@ struct sunxi_hdmi_reg { u32 ddc_cmnd; /* 0x520 */ u32 ddc_exreg; /* 0x524 */ u32 ddc_clock; /* 0x528 */ - u8 res6[0x14]; /* 0x52c */ + u8 res9[0x14]; /* 0x52c */ u32 ddc_line_ctrl; /* 0x540 */ #else u32 ddc_ctrl; /* 0x500 */ @@ -144,9 +151,9 @@ struct sunxi_hdmi_reg { u32 ddc_fifo_status; /* 0x51c */ u32 ddc_clock; /* 0x520 */ u32 ddc_timeout; /* 0x524 */ - u8 res6[0x18]; /* 0x528 */ + u8 res9[0x18]; /* 0x528 */ u32 ddc_dbg; /* 0x540 */ - u8 res7[0x3c]; /* 0x544 */ + u8 res10[0x3c]; /* 0x544 */ u32 ddc_fifo_data; /* 0x580 */ #endif }; @@ -191,9 +198,12 @@ struct sunxi_hdmi_reg { #define SUNXI_HDMI_IRQ_STATUS_BITS 0x73 #define SUNXI_HDMI_HPD_DETECT (1 << 0) #define SUNXI_HDMI_VIDEO_CTRL_ENABLE (1 << 31) +#define SUNXI_HDMI_VIDEO_CTRL_HDMI (1 << 30) #define SUNXI_HDMI_VIDEO_POL_HOR (1 << 0) #define SUNXI_HDMI_VIDEO_POL_VER (1 << 1) #define SUNXI_HDMI_VIDEO_POL_TX_CLK (0x3e0 << 16) +#define SUNXI_HDMI_QCP_PACKET0 3 +#define SUNXI_HDMI_QCP_PACKET1 0
#ifdef CONFIG_MACH_SUN6I #define SUNXI_HDMI_PAD_CTRL0_HDP 0x7e80000f @@ -224,6 +234,9 @@ struct sunxi_hdmi_reg { #define SUNXI_HDMI_PLL_DBG0_PLL3 (0 << 21) #define SUNXI_HDMI_PLL_DBG0_PLL7 (1 << 21)
+#define SUNXI_HDMI_PKT_CTRL0 0x00000f21 +#define SUNXI_HDMI_PKT_CTRL1 0x0000000f + #ifdef CONFIG_MACH_SUN6I #define SUNXI_HMDI_DDC_CTRL_ENABLE (1 << 0) #define SUNXI_HMDI_DDC_CTRL_SCL_ENABLE (1 << 4) diff --git a/drivers/video/sunxi_display.c b/drivers/video/sunxi_display.c index 0997740..394153a 100644 --- a/drivers/video/sunxi_display.c +++ b/drivers/video/sunxi_display.c @@ -403,8 +403,55 @@ static void sunxi_drc_init(void) } #endif
+static void sunxi_hdmi_setup_info_frames(const struct ctfb_res_modes *mode) +{ + struct sunxi_hdmi_reg * const hdmi = + (struct sunxi_hdmi_reg *)SUNXI_HDMI_BASE; + u8 checksum = 0; + u8 avi_info_frame[17] = { + 0x82, 0x02, 0x0d, 0x00, 0x12, 0x00, 0x88, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00 + }; + u8 vendor_info_frame[19] = { + 0x81, 0x01, 0x06, 0x29, 0x03, 0x0c, 0x00, 0x40, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00 + }; + int i; + + if (mode->pixclock_khz <= 27000) + avi_info_frame[5] = 0x40; /* SD-modes, ITU601 colorspace */ + else + avi_info_frame[5] = 0x80; /* HD-modes, ITU709 colorspace */ + + if (mode->xres * 100 / mode->yres < 156) + avi_info_frame[5] |= 0x18; /* 4 : 3 */ + else + avi_info_frame[5] |= 0x28; /* 16 : 9 */ + + for (i = 0; i < ARRAY_SIZE(avi_info_frame); i++) + checksum += avi_info_frame[i]; + + avi_info_frame[3] = 0x100 - checksum; + + for (i = 0; i < ARRAY_SIZE(avi_info_frame); i++) + writeb(avi_info_frame[i], &hdmi->avi_info_frame[i]); + + writel(SUNXI_HDMI_QCP_PACKET0, &hdmi->qcp_packet0); + writel(SUNXI_HDMI_QCP_PACKET1, &hdmi->qcp_packet1); + + for (i = 0; i < ARRAY_SIZE(vendor_info_frame); i++) + writeb(vendor_info_frame[i], &hdmi->vendor_info_frame[i]); + + writel(SUNXI_HDMI_PKT_CTRL0, &hdmi->pkt_ctrl0); + writel(SUNXI_HDMI_PKT_CTRL1, &hdmi->pkt_ctrl1); + + setbits_le32(&hdmi->video_ctrl, SUNXI_HDMI_VIDEO_CTRL_HDMI); +} + static void sunxi_hdmi_mode_set(const struct ctfb_res_modes *mode, - int clk_div, int clk_double) + bool hdmi_mode, int clk_div, int clk_double) { struct sunxi_hdmi_reg * const hdmi = (struct sunxi_hdmi_reg *)SUNXI_HDMI_BASE; @@ -413,6 +460,9 @@ static void sunxi_hdmi_mode_set(const struct ctfb_res_modes *mode, /* Write clear interrupt status bits */ writel(SUNXI_HDMI_IRQ_STATUS_BITS, &hdmi->irq);
+ if (hdmi_mode) + sunxi_hdmi_setup_info_frames(mode); + /* Init various registers, select pll3 as clock source */ writel(SUNXI_HDMI_VIDEO_POL_TX_CLK, &hdmi->video_polarity); writel(SUNXI_HDMI_PAD_CTRL0_RUN, &hdmi->pad_ctrl0); @@ -458,7 +508,8 @@ static void sunxi_engines_init(void) #endif }
-static void sunxi_mode_set(const struct ctfb_res_modes *mode, unsigned int address) +static void sunxi_mode_set(const struct ctfb_res_modes *mode, char *monitor, + unsigned int address) { struct sunxi_de_be_reg * const de_be = (struct sunxi_de_be_reg *)SUNXI_DE_BE0_BASE; @@ -468,6 +519,7 @@ static void sunxi_mode_set(const struct ctfb_res_modes *mode, unsigned int addre (struct sunxi_hdmi_reg *)SUNXI_HDMI_BASE; int clk_div, clk_double; int retries = 3; + bool hdmi_mode = strcmp(monitor, "hdmi") == 0;
retry: clrbits_le32(&hdmi->video_ctrl, SUNXI_HDMI_VIDEO_CTRL_ENABLE); @@ -476,7 +528,7 @@ retry:
sunxi_composer_mode_set(mode, address); sunxi_lcdc_mode_set(mode, &clk_div, &clk_double); - sunxi_hdmi_mode_set(mode, clk_div, clk_double); + sunxi_hdmi_mode_set(mode, hdmi_mode, clk_div, clk_double);
setbits_le32(&de_be->reg_ctrl, SUNXI_DE_BE_REG_CTRL_LOAD_REGS); setbits_le32(&de_be->mode, SUNXI_DE_BE_MODE_START); @@ -511,6 +563,7 @@ void *video_hw_init(void) const char *options; unsigned int depth; int ret, hpd, edid; + char monitor[16];
memset(&sunxi_display, 0, sizeof(struct sunxi_display));
@@ -521,6 +574,8 @@ void *video_hw_init(void) video_get_ctfb_res_modes(RES_MODE_1024x768, 24, &mode, &depth, &options); hpd = video_get_option_int(options, "hpd", 1); edid = video_get_option_int(options, "edid", 1); + video_get_option_string(options, "monitor", monitor, sizeof(monitor), + "dvi");
/* Always call hdp_detect, as it also enables various clocks, etc. */ ret = sunxi_hdmi_hpd_detect(); @@ -541,12 +596,13 @@ void *video_hw_init(void) printf("Only non-interlaced modes supported, falling back to 1024x768\n"); mode = &res_mode_init[RES_MODE_1024x768]; } else { - printf("Setting up a %dx%d console\n", mode->xres, mode->yres); + printf("Setting up a %dx%d %s console\n", + mode->xres, mode->yres, monitor); }
sunxi_display.enabled = true; sunxi_engines_init(); - sunxi_mode_set(mode, gd->fb_base - CONFIG_SYS_SDRAM_BASE); + sunxi_mode_set(mode, monitor, gd->fb_base - CONFIG_SYS_SDRAM_BASE);
/* * These are the only members of this structure that are used. All the

On Sat, 2014-12-20 at 15:42 +0100, Hans de Goede wrote:
So far we've been programming the hdmi-encoder to send out dvi data over the hdmi connector. This works well for most devices, including hdmi devices, but not all devices accept dvi data on a hdmi input.
Add support for sending proper hdmi data over the hdmi output found on most sunxi boards. This can be turned on by adding by adding monitor=hdmi as option to the video-mode env. variable.
A follow up patch will determine wether to send dvi or hdmi automatically when EDID is used.
Signed-off-by: Hans de Goede hdegoede@redhat.com
Acked-by: Ian Campbell ijc@hellion.org.uk
(you could const the char *monitor argument to one function though)

On Sat, 20 Dec 2014 15:42:01 +0100 Hans de Goede hdegoede@redhat.com wrote:
So far we've been programming the hdmi-encoder to send out dvi data over the hdmi connector. This works well for most devices, including hdmi devices, but not all devices accept dvi data on a hdmi input.
Add support for sending proper hdmi data over the hdmi output found on most sunxi boards. This can be turned on by adding by adding monitor=hdmi as option
"by adding" is duplicated here, please drop when applying.
to the video-mode env. variable.
A follow up patch will determine wether to send dvi or hdmi automatically when EDID is used.
s/wether/whether/
Signed-off-by: Hans de Goede hdegoede@redhat.com
Otherwise
Acked-by: Anatolij Gustschin agust@denx.de

Add a sunxi_hdmi_edid_get_block helper function, this is a preparation patch for adding support for parsing EDID extension blocks.
Signed-off-by: Hans de Goede hdegoede@redhat.com --- drivers/video/sunxi_display.c | 31 ++++++++++++++++++++----------- 1 file changed, 20 insertions(+), 11 deletions(-)
diff --git a/drivers/video/sunxi_display.c b/drivers/video/sunxi_display.c index 394153a..3048410 100644 --- a/drivers/video/sunxi_display.c +++ b/drivers/video/sunxi_display.c @@ -137,6 +137,24 @@ static int sunxi_hdmi_ddc_read(int offset, u8 *buf, int count) return 0; }
+static int sunxi_hdmi_edid_get_block(int block, u8 *buf) +{ + int r, retries = 2; + + do { + r = sunxi_hdmi_ddc_read(block * 128, buf, 128); + if (r) + continue; + r = edid_check_checksum(buf); + if (r) { + printf("EDID block %d: checksum error%s\n", + block, retries ? ", retrying" : ""); + } + } while (r && retries--); + + return r; +} + static int sunxi_hdmi_edid_get_mode(struct ctfb_res_modes *mode) { struct edid1_info edid1; @@ -146,7 +164,7 @@ static int sunxi_hdmi_edid_get_mode(struct ctfb_res_modes *mode) (struct sunxi_hdmi_reg *)SUNXI_HDMI_BASE; struct sunxi_ccm_reg * const ccm = (struct sunxi_ccm_reg *)SUNXI_CCM_BASE; - int i, r, retries = 2; + int i, r;
/* SUNXI_HDMI_CTRL_ENABLE & PAD_CTRL0 are already set by hpd_detect */ writel(SUNXI_HDMI_PAD_CTRL1 | SUNXI_HDMI_PAD_CTRL1_HALVE, @@ -170,16 +188,7 @@ static int sunxi_hdmi_edid_get_mode(struct ctfb_res_modes *mode) SUNXI_HMDI_DDC_LINE_CTRL_SCL_ENABLE, &hdmi->ddc_line_ctrl); #endif
- do { - r = sunxi_hdmi_ddc_read(0, (u8 *)&edid1, 128); - if (r) - continue; - r = edid_check_checksum((u8 *)&edid1); - if (r) { - printf("EDID: checksum error%s\n", - retries ? ", retrying" : ""); - } - } while (r && retries--); + r = sunxi_hdmi_edid_get_block(0, (u8 *)&edid1);
/* Disable DDC engine, no longer needed */ clrbits_le32(&hdmi->ddc_ctrl, SUNXI_HMDI_DDC_CTRL_ENABLE);

On Sat, 2014-12-20 at 15:42 +0100, Hans de Goede wrote:
Add a sunxi_hdmi_edid_get_block helper function, this is a preparation patch for adding support for parsing EDID extension blocks.
Signed-off-by: Hans de Goede hdegoede@redhat.com
Acked-by: Ian Campbell ijc@hellion.org.uk

On Sat, 20 Dec 2014 15:42:02 +0100 Hans de Goede hdegoede@redhat.com wrote:
Add a sunxi_hdmi_edid_get_block helper function, this is a preparation patch for adding support for parsing EDID extension blocks.
Signed-off-by: Hans de Goede hdegoede@redhat.com
Acked-by: Anatolij Gustschin agust@denx.de

When using edid use CEA681 edid extension blocks to select between dvi and hdmi output formats, so that u-boot will automatically do the right thing.
Signed-off-by: Hans de Goede hdegoede@redhat.com --- drivers/video/sunxi_display.c | 43 ++++++++++++++++++++++++++++++++++--------- 1 file changed, 34 insertions(+), 9 deletions(-)
diff --git a/drivers/video/sunxi_display.c b/drivers/video/sunxi_display.c index 3048410..795835d 100644 --- a/drivers/video/sunxi_display.c +++ b/drivers/video/sunxi_display.c @@ -155,16 +155,17 @@ static int sunxi_hdmi_edid_get_block(int block, u8 *buf) return r; }
-static int sunxi_hdmi_edid_get_mode(struct ctfb_res_modes *mode) +static int sunxi_hdmi_edid_get_mode(struct ctfb_res_modes *mode, char *monitor) { struct edid1_info edid1; + struct edid_cea861_info cea681[4]; struct edid_detailed_timing *t = (struct edid_detailed_timing *)edid1.monitor_details.timing; struct sunxi_hdmi_reg * const hdmi = (struct sunxi_hdmi_reg *)SUNXI_HDMI_BASE; struct sunxi_ccm_reg * const ccm = (struct sunxi_ccm_reg *)SUNXI_CCM_BASE; - int i, r; + int i, r, ext_blocks = 0;
/* SUNXI_HDMI_CTRL_ENABLE & PAD_CTRL0 are already set by hpd_detect */ writel(SUNXI_HDMI_PAD_CTRL1 | SUNXI_HDMI_PAD_CTRL1_HALVE, @@ -189,6 +190,25 @@ static int sunxi_hdmi_edid_get_mode(struct ctfb_res_modes *mode) #endif
r = sunxi_hdmi_edid_get_block(0, (u8 *)&edid1); + if (r == 0) { + r = edid_check_info(&edid1); + if (r) { + printf("EDID: invalid EDID data\n"); + r = -EINVAL; + } + } + if (r == 0) { + ext_blocks = edid1.extension_flag; + if (ext_blocks > 4) + ext_blocks = 4; + for (i = 0; i < ext_blocks; i++) { + if (sunxi_hdmi_edid_get_block(1 + i, + (u8 *)&cea681[i]) != 0) { + ext_blocks = i; + break; + } + } + }
/* Disable DDC engine, no longer needed */ clrbits_le32(&hdmi->ddc_ctrl, SUNXI_HMDI_DDC_CTRL_ENABLE); @@ -197,12 +217,6 @@ static int sunxi_hdmi_edid_get_mode(struct ctfb_res_modes *mode) if (r) return r;
- r = edid_check_info(&edid1); - if (r) { - printf("EDID: invalid EDID data\n"); - return -EINVAL; - } - /* We want version 1.3 or 1.2 with detailed timing info */ if (edid1.version != 1 || (edid1.revision < 3 && !EDID1_INFO_FEATURE_PREFERRED_TIMING_MODE(edid1))) { @@ -222,6 +236,17 @@ static int sunxi_hdmi_edid_get_mode(struct ctfb_res_modes *mode) return -ENOENT; }
+ /* Check for basic audio support, if found enable hdmi output */ + strcpy(monitor, "dvi"); + for (i = 0; i < ext_blocks; i++) { + if (cea681[i].extension_tag != EDID_CEA861_EXTENSION_TAG || + cea681[i].revision < 2) + continue; + + if (EDID_CEA861_SUPPORTS_BASIC_AUDIO(cea681[i])) + strcpy(monitor, "hdmi"); + } + return 0; }
@@ -597,7 +622,7 @@ void *video_hw_init(void)
/* Check edid if requested and we've a cable plugged in */ if (edid && ret) { - if (sunxi_hdmi_edid_get_mode(&edid_mode) == 0) + if (sunxi_hdmi_edid_get_mode(&edid_mode, monitor) == 0) mode = &edid_mode; }

On Sat, 2014-12-20 at 15:42 +0100, Hans de Goede wrote:
When using edid use CEA681 edid extension blocks to select between dvi and hdmi output formats, so that u-boot will automatically do the right thing.
Signed-off-by: Hans de Goede hdegoede@redhat.com
Acked-by: Ian Campbell ijc@hellion.org.uk

On Sat, 20 Dec 2014 15:42:03 +0100 Hans de Goede hdegoede@redhat.com wrote:
When using edid use CEA681 edid extension blocks to select between dvi and hdmi output formats, so that u-boot will automatically do the right thing.
Signed-off-by: Hans de Goede hdegoede@redhat.com
Acked-by: Anatolij Gustschin agust@denx.de

When using a hdmi powered hdmi to vga dongle, and cold booting a sunxi device, the hpd detect code would not see the dongle (until a warm reboot), because the dongle needs some time to boot.
Testing has shown that this dongle needs 213ms to respond on a cold boot, so wait up to 300ms for a hpd signal to show up before giving up.
Signed-off-by: Hans de Goede hdegoede@redhat.com --- drivers/video/sunxi_display.c | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-)
diff --git a/drivers/video/sunxi_display.c b/drivers/video/sunxi_display.c index 795835d..5a14785 100644 --- a/drivers/video/sunxi_display.c +++ b/drivers/video/sunxi_display.c @@ -48,6 +48,7 @@ static int sunxi_hdmi_hpd_detect(void) (struct sunxi_ccm_reg *)SUNXI_CCM_BASE; struct sunxi_hdmi_reg * const hdmi = (struct sunxi_hdmi_reg *)SUNXI_HDMI_BASE; + unsigned long tmo = timer_get_us() + 300000;
/* Set pll3 to 300MHz */ clock_set_pll3(300000000); @@ -68,9 +69,12 @@ static int sunxi_hdmi_hpd_detect(void) writel(SUNXI_HDMI_CTRL_ENABLE, &hdmi->ctrl); writel(SUNXI_HDMI_PAD_CTRL0_HDP, &hdmi->pad_ctrl0);
- udelay(1000); + while (timer_get_us() < tmo) { + if (readl(&hdmi->hpd) & SUNXI_HDMI_HPD_DETECT) + return 1; + }
- return (readl(&hdmi->hpd) & SUNXI_HDMI_HPD_DETECT) ? 1 : 0; + return 0; }
static void sunxi_hdmi_shutdown(void)

On Sat, 2014-12-20 at 15:42 +0100, Hans de Goede wrote:
When using a hdmi powered hdmi to vga dongle, and cold booting a sunxi device, the hpd detect code would not see the dongle (until a warm reboot), because the dongle needs some time to boot.
Testing has shown that this dongle needs 213ms to respond on a cold boot, so wait up to 300ms for a hpd signal to show up before giving up.
Signed-off-by: Hans de Goede hdegoede@redhat.com
Acked-by: Ian Campbell ijc@hellion.org.uk

On 20/12/14 14:42, Hans de Goede wrote:
When using a hdmi powered hdmi to vga dongle, and cold booting a sunxi device, the hpd detect code would not see the dongle (until a warm reboot), because the dongle needs some time to boot.
Testing has shown that this dongle needs 213ms to respond on a cold boot, so wait up to 300ms for a hpd signal to show up before giving up.
Hi Hans,
I'm using a similar convertor but it sometimes takes longer to be ready, depending on what screen is connected. With an old VGA monitor, I've seen it take up to 1230ms before returning the HPD signal, presumably while it collects information from the monitor.
Would it be acceptable to increase the wait from 300ms to about 1500ms?
Thank you very much for all your work these past months on developing the display support and getting it into mainline. I greatly appreciate it.
Best wishes, B.R. Oake.
P.S. The convertor I'm using is from Cable Matters: http://www.cablematters.com/pc-428-79-cable-matters-active-hdmi-to-vga-male-...

Hi,
On 24-12-14 03:25, B.R. Oake wrote:
On 20/12/14 14:42, Hans de Goede wrote:
When using a hdmi powered hdmi to vga dongle, and cold booting a sunxi device, the hpd detect code would not see the dongle (until a warm reboot), because the dongle needs some time to boot.
Testing has shown that this dongle needs 213ms to respond on a cold boot, so wait up to 300ms for a hpd signal to show up before giving up.
Hi Hans,
I'm using a similar convertor but it sometimes takes longer to be ready, depending on what screen is connected. With an old VGA monitor, I've seen it take up to 1230ms before returning the HPD signal, presumably while it collects information from the monitor.
Would it be acceptable to increase the wait from 300ms to about 1500ms?
That means delaying the boot by another 1.2 seconds on all machines which have hdmi without a cable plugged in. I'm not sure I'm a fan of that.
Ian, what is your take on this ?
Regards,
Hans

On 24/12/14 16:13, Hans de Goede wrote:> On 24-12-14 03:25, B.R. Oake wrote:
Would it be acceptable to increase the wait from 300ms to about 1500ms?
That means delaying the boot by another 1.2 seconds on all machines which have hdmi without a cable plugged in. I'm not sure I'm a fan of that.
Yes. How about if sunxi_hdmi_hpd_detect() was split into two, firstly the initialisation part that always needs to be run, and secondly the actual hpd detection, which would only be run if the hpd option to video-mode was selected?
Another idea is that the hpd timeout value could be an additional option to video-mode.
Thanks, B.R.

Hi,
On 24-12-14 19:29, B.R. Oake wrote:
On 24/12/14 16:13, Hans de Goede wrote:> On 24-12-14 03:25, B.R. Oake wrote:
Would it be acceptable to increase the wait from 300ms to about 1500ms?
That means delaying the boot by another 1.2 seconds on all machines which have hdmi without a cable plugged in. I'm not sure I'm a fan of that.
Yes. How about if sunxi_hdmi_hpd_detect() was split into two, firstly the initialisation part that always needs to be run, and secondly the actual hpd detection, which would only be run if the hpd option to video-mode was selected?
That won't help since hpd=1 is the default, and we need to wait for the hpd signal before doing edid, and we want to do edid by default.
Another idea is that the hpd timeout value could be an additional option to video-mode.
That is probably the best solution, we may still need to tweak the default delay a bit so that it will just work in most cases, but 1.5 seconds is just too long IMHO. I've implemented this suggestion:
https://github.com/jwrdegoede/u-boot-sunxi/commit/d8f9051ca0562843435fa36c8d...
Regards,
Hans

On 28/12/14 08:40, Hans de Goede wrote:
On 24-12-14 19:29, B.R. Oake wrote:
Yes. How about if sunxi_hdmi_hpd_detect() was split into two, firstly the initialisation part that always needs to be run, and secondly the actual hpd detection, which would only be run if the hpd option to video-mode was selected?
That won't help since hpd=1 is the default, and we need to wait for the hpd signal before doing edid, and we want to do edid by default.
Yes, sorry, I was muddled there.
I've tested your hpd_delay patch with the long delay my old monitor needs, and it works fine; thanks very much!
Cheers, B.R.

On Sat, 20 Dec 2014 15:42:04 +0100 Hans de Goede hdegoede@redhat.com wrote:
When using a hdmi powered hdmi to vga dongle, and cold booting a sunxi device, the hpd detect code would not see the dongle (until a warm reboot), because the dongle needs some time to boot.
Testing has shown that this dongle needs 213ms to respond on a cold boot, so wait up to 300ms for a hpd signal to show up before giving up.
Signed-off-by: Hans de Goede hdegoede@redhat.com
Acked-by: Anatolij Gustschin agust@denx.de

Add a write to the "unknown" (*) register to enable auto input sync, when initially adding sunxi hdmi output support this magic write from the android kernel code was missed, causing lcdc -> hdmi encoder sync problems.
With this write added, we can drop the modesetting retries and the extra delays added to work around these sync problems.
*) "unknown" is the actual name of this register in the android kernel sources
Signed-off-by: Hans de Goede hdegoede@redhat.com --- arch/arm/include/asm/arch-sunxi/display.h | 1 + drivers/video/sunxi_display.c | 23 ++++------------------- 2 files changed, 5 insertions(+), 19 deletions(-)
diff --git a/arch/arm/include/asm/arch-sunxi/display.h b/arch/arm/include/asm/arch-sunxi/display.h index 838b217..00e3466 100644 --- a/arch/arm/include/asm/arch-sunxi/display.h +++ b/arch/arm/include/asm/arch-sunxi/display.h @@ -236,6 +236,7 @@ struct sunxi_hdmi_reg {
#define SUNXI_HDMI_PKT_CTRL0 0x00000f21 #define SUNXI_HDMI_PKT_CTRL1 0x0000000f +#define SUNXI_HDMI_UNKNOWN_INPUT_SYNC 0x08000000
#ifdef CONFIG_MACH_SUN6I #define SUNXI_HMDI_DDC_CTRL_ENABLE (1 << 0) diff --git a/drivers/video/sunxi_display.c b/drivers/video/sunxi_display.c index 5a14785..a0a0613 100644 --- a/drivers/video/sunxi_display.c +++ b/drivers/video/sunxi_display.c @@ -501,6 +501,9 @@ static void sunxi_hdmi_mode_set(const struct ctfb_res_modes *mode, if (hdmi_mode) sunxi_hdmi_setup_info_frames(mode);
+ /* Set input sync enable */ + writel(SUNXI_HDMI_UNKNOWN_INPUT_SYNC, &hdmi->unknown); + /* Init various registers, select pll3 as clock source */ writel(SUNXI_HDMI_VIDEO_POL_TX_CLK, &hdmi->video_polarity); writel(SUNXI_HDMI_PAD_CTRL0_RUN, &hdmi->pad_ctrl0); @@ -556,10 +559,8 @@ static void sunxi_mode_set(const struct ctfb_res_modes *mode, char *monitor, struct sunxi_hdmi_reg * const hdmi = (struct sunxi_hdmi_reg *)SUNXI_HDMI_BASE; int clk_div, clk_double; - int retries = 3; bool hdmi_mode = strcmp(monitor, "hdmi") == 0;
-retry: clrbits_le32(&hdmi->video_ctrl, SUNXI_HDMI_VIDEO_CTRL_ENABLE); clrbits_le32(&lcdc->ctrl, SUNXI_LCDC_CTRL_TCON_ENABLE); clrbits_le32(&de_be->mode, SUNXI_DE_BE_MODE_START); @@ -570,27 +571,11 @@ retry:
setbits_le32(&de_be->reg_ctrl, SUNXI_DE_BE_REG_CTRL_LOAD_REGS); setbits_le32(&de_be->mode, SUNXI_DE_BE_MODE_START); - - udelay(1000000 / mode->refresh + 500); - setbits_le32(&lcdc->ctrl, SUNXI_LCDC_CTRL_TCON_ENABLE);
- udelay(1000000 / mode->refresh + 500); + udelay(100);
setbits_le32(&hdmi->video_ctrl, SUNXI_HDMI_VIDEO_CTRL_ENABLE); - - udelay(1000000 / mode->refresh + 500); - - /* - * Sometimes the display pipeline does not sync up properly, if - * this happens the hdmi fifo underrun or overrun bits are set. - */ - if (readl(&hdmi->irq) & - (SUNXI_HDMI_IRQ_STATUS_FIFO_UF | SUNXI_HDMI_IRQ_STATUS_FIFO_OF)) { - if (retries--) - goto retry; - printf("HDMI fifo under or overrun\n"); - } }
void *video_hw_init(void)

On Sat, 2014-12-20 at 15:42 +0100, Hans de Goede wrote:
Add a write to the "unknown" (*) register to enable auto input sync, when initially adding sunxi hdmi output support this magic write from the android kernel code was missed, causing lcdc -> hdmi encoder sync problems.
With this write added, we can drop the modesetting retries and the extra delays added to work around these sync problems.
*) "unknown" is the actual name of this register in the android kernel sources
Signed-off-by: Hans de Goede hdegoede@redhat.com
Acked-by: Ian Campbell ijc@hellion.org.uk

On Sat, 20 Dec 2014 15:42:05 +0100 Hans de Goede hdegoede@redhat.com wrote:
Add a write to the "unknown" (*) register to enable auto input sync, when initially adding sunxi hdmi output support this magic write from the android kernel code was missed, causing lcdc -> hdmi encoder sync problems.
With this write added, we can drop the modesetting retries and the extra delays added to work around these sync problems.
*) "unknown" is the actual name of this register in the android kernel sources
Signed-off-by: Hans de Goede hdegoede@redhat.com
Acked-by: Anatolij Gustschin agust@denx.de

On Sat, 2014-12-20 at 15:41 +0100, Hans de Goede wrote:
Hi Anatolij & Ian,
Here is a second series of sunxi video support improvments.
Anatolij, can you please review the first patch of the series? You're input on the rest is welcome too of course :)
I've been through them and they look fine to me, but I'm not really a graphics person so any other eyes with the time to take a look would be a good idea IMHO.
Ian.
participants (4)
-
Anatolij Gustschin
-
B.R. Oake
-
Hans de Goede
-
Ian Campbell