diff options
Diffstat (limited to 'drivers')
-rw-r--r-- | drivers/video/omap2/dss/ti_hdmi_4xxx_ip.c | 117 |
1 files changed, 67 insertions, 50 deletions
diff --git a/drivers/video/omap2/dss/ti_hdmi_4xxx_ip.c b/drivers/video/omap2/dss/ti_hdmi_4xxx_ip.c index d4cdfc2e6c5e..ecf854e2596c 100644 --- a/drivers/video/omap2/dss/ti_hdmi_4xxx_ip.c +++ b/drivers/video/omap2/dss/ti_hdmi_4xxx_ip.c @@ -264,92 +264,105 @@ void ti_hdmi_4xxx_phy_disable(struct hdmi_ip_data *ip_data) hdmi_set_phy_pwr(ip_data, HDMI_PHYPWRCMD_OFF); } -static int hdmi_core_ddc_edid(struct hdmi_ip_data *ip_data, - u8 *pedid, int ext) +static int hdmi_core_ddc_init(struct hdmi_ip_data *ip_data) { - u32 i, j; - char checksum = 0; - u32 offset = 0; - void __iomem *core_sys_base = hdmi_core_sys_base(ip_data); + void __iomem *base = hdmi_core_sys_base(ip_data); /* Turn on CLK for DDC */ - REG_FLD_MOD(hdmi_av_base(ip_data), HDMI_CORE_AV_DPD, 0x7, 2, 0); + REG_FLD_MOD(base, HDMI_CORE_AV_DPD, 0x7, 2, 0); + + /* IN_PROG */ + if (REG_GET(base, HDMI_CORE_DDC_STATUS, 4, 4) == 1) { + /* Abort transaction */ + REG_FLD_MOD(base, HDMI_CORE_DDC_CMD, 0xf, 3, 0); + /* IN_PROG */ + if (hdmi_wait_for_bit_change(base, HDMI_CORE_DDC_STATUS, + 4, 4, 0) != 0) { + DSSERR("Timeout aborting DDC transaction\n"); + return -ETIMEDOUT; + } + } - /* - * SW HACK : Without the Delay DDC(i2c bus) reads 0 values / - * right shifted values( The behavior is not consistent and seen only - * with some TV's) - */ - usleep_range(800, 1000); + /* Clk SCL Devices */ + REG_FLD_MOD(base, HDMI_CORE_DDC_CMD, 0xA, 3, 0); + + /* HDMI_CORE_DDC_STATUS_IN_PROG */ + if (hdmi_wait_for_bit_change(base, HDMI_CORE_DDC_STATUS, + 4, 4, 0) != 0) { + DSSERR("Timeout starting SCL clock\n"); + return -ETIMEDOUT; + } - if (!ext) { - /* Clk SCL Devices */ - REG_FLD_MOD(core_sys_base, HDMI_CORE_DDC_CMD, 0xA, 3, 0); + /* Clear FIFO */ + REG_FLD_MOD(base, HDMI_CORE_DDC_CMD, 0x9, 3, 0); - /* HDMI_CORE_DDC_STATUS_IN_PROG */ - if (hdmi_wait_for_bit_change(core_sys_base, - HDMI_CORE_DDC_STATUS, 4, 4, 0) != 0) { - pr_err("Failed to program DDC\n"); - return -ETIMEDOUT; - } + /* HDMI_CORE_DDC_STATUS_IN_PROG */ + if (hdmi_wait_for_bit_change(base, HDMI_CORE_DDC_STATUS, + 4, 4, 0) != 0) { + DSSERR("Timeout clearing DDC fifo\n"); + return -ETIMEDOUT; + } - /* Clear FIFO */ - REG_FLD_MOD(core_sys_base, HDMI_CORE_DDC_CMD, 0x9, 3, 0); + return 0; +} - /* HDMI_CORE_DDC_STATUS_IN_PROG */ - if (hdmi_wait_for_bit_change(core_sys_base, - HDMI_CORE_DDC_STATUS, 4, 4, 0) != 0) { - pr_err("Failed to program DDC\n"); - return -ETIMEDOUT; - } +static int hdmi_core_ddc_edid(struct hdmi_ip_data *ip_data, + u8 *pedid, int ext) +{ + void __iomem *base = hdmi_core_sys_base(ip_data); + u32 i, j; + char checksum = 0; + u32 offset = 0; - } else { - if (ext % 2 != 0) - offset = 0x80; + /* HDMI_CORE_DDC_STATUS_IN_PROG */ + if (hdmi_wait_for_bit_change(base, HDMI_CORE_DDC_STATUS, + 4, 4, 0) != 0) { + DSSERR("Timeout waiting DDC to be ready\n"); + return -ETIMEDOUT; } + if (ext % 2 != 0) + offset = 0x80; + /* Load Segment Address Register */ - REG_FLD_MOD(core_sys_base, HDMI_CORE_DDC_SEGM, ext/2, 7, 0); + REG_FLD_MOD(base, HDMI_CORE_DDC_SEGM, ext / 2, 7, 0); /* Load Slave Address Register */ - REG_FLD_MOD(core_sys_base, HDMI_CORE_DDC_ADDR, 0xA0 >> 1, 7, 1); + REG_FLD_MOD(base, HDMI_CORE_DDC_ADDR, 0xA0 >> 1, 7, 1); /* Load Offset Address Register */ - REG_FLD_MOD(core_sys_base, HDMI_CORE_DDC_OFFSET, offset, 7, 0); + REG_FLD_MOD(base, HDMI_CORE_DDC_OFFSET, offset, 7, 0); /* Load Byte Count */ - REG_FLD_MOD(core_sys_base, HDMI_CORE_DDC_COUNT1, 0x80, 7, 0); - REG_FLD_MOD(core_sys_base, HDMI_CORE_DDC_COUNT2, 0x0, 1, 0); + REG_FLD_MOD(base, HDMI_CORE_DDC_COUNT1, 0x80, 7, 0); + REG_FLD_MOD(base, HDMI_CORE_DDC_COUNT2, 0x0, 1, 0); /* Set DDC_CMD */ if (ext) - REG_FLD_MOD(core_sys_base, HDMI_CORE_DDC_CMD, 0x4, 3, 0); + REG_FLD_MOD(base, HDMI_CORE_DDC_CMD, 0x4, 3, 0); else - REG_FLD_MOD(core_sys_base, HDMI_CORE_DDC_CMD, 0x2, 3, 0); + REG_FLD_MOD(base, HDMI_CORE_DDC_CMD, 0x2, 3, 0); /* HDMI_CORE_DDC_STATUS_BUS_LOW */ - if (REG_GET(core_sys_base, - HDMI_CORE_DDC_STATUS, 6, 6) == 1) { + if (REG_GET(base, HDMI_CORE_DDC_STATUS, 6, 6) == 1) { pr_err("I2C Bus Low?\n"); return -EIO; } /* HDMI_CORE_DDC_STATUS_NO_ACK */ - if (REG_GET(core_sys_base, - HDMI_CORE_DDC_STATUS, 5, 5) == 1) { + if (REG_GET(base, HDMI_CORE_DDC_STATUS, 5, 5) == 1) { pr_err("I2C No Ack\n"); return -EIO; } i = ext * 128; j = 0; - while (((REG_GET(core_sys_base, HDMI_CORE_DDC_STATUS, 4, 4) == 1) || - (REG_GET(core_sys_base, - HDMI_CORE_DDC_STATUS, 2, 2) == 0)) && j < 128) { + while (((REG_GET(base, HDMI_CORE_DDC_STATUS, 4, 4) == 1) || + (REG_GET(base, HDMI_CORE_DDC_STATUS, 2, 2) == 0)) && + j < 128) { - if (REG_GET(core_sys_base, HDMI_CORE_DDC_STATUS, 2, 2) == 0) { + if (REG_GET(base, HDMI_CORE_DDC_STATUS, 2, 2) == 0) { /* FIFO not empty */ - pedid[i++] = REG_GET(core_sys_base, - HDMI_CORE_DDC_DATA, 7, 0); + pedid[i++] = REG_GET(base, HDMI_CORE_DDC_DATA, 7, 0); j++; } } @@ -372,6 +385,10 @@ int ti_hdmi_4xxx_read_edid(struct hdmi_ip_data *ip_data, int max_ext_blocks = (max_length / 128) - 1; int len; + r = hdmi_core_ddc_init(ip_data); + if (r) + return r; + r = hdmi_core_ddc_edid(ip_data, pedid, 0); if (r) return r; |