return 0;
}
-static int read_edid(struct omap_hdmi *hdmi, u8 *buf, int len)
-{
- int r;
-
- mutex_lock(&hdmi->lock);
-
- r = hdmi_runtime_get(hdmi);
- BUG_ON(r);
-
- r = hdmi4_read_edid(&hdmi->core, buf, len);
-
- hdmi_runtime_put(hdmi);
- mutex_unlock(&hdmi->lock);
-
- return r;
-}
-
static void hdmi_start_audio_stream(struct omap_hdmi *hd)
{
hdmi_wp_audio_enable(&hd->wp, true);
#define MAX_EDID 512
-static struct edid *hdmi_read_edid(struct omap_dss_device *dssdev)
+static struct edid *hdmi_read_edid_data(struct omap_hdmi *hdmi)
{
- struct omap_hdmi *hdmi = dssdev_to_hdmi(dssdev);
- bool need_enable;
u8 *edid;
int r;
if (!edid)
return NULL;
+ r = hdmi4_core_ddc_read(&hdmi->core, edid, 0, EDID_LENGTH);
+ if (r)
+ goto error;
+
+ if (edid[0x7e] > 0) {
+ char checksum = 0;
+ unsigned int i;
+
+ r = hdmi4_core_ddc_read(&hdmi->core, edid + EDID_LENGTH, 1,
+ EDID_LENGTH);
+ if (r)
+ goto error;
+
+ for (i = 0; i < EDID_LENGTH; ++i)
+ checksum += edid[EDID_LENGTH + i];
+
+ if (checksum != 0) {
+ DSSERR("E-EDID checksum failed!!\n");
+ goto error;
+ }
+ }
+
+ return (struct edid *)edid;
+
+error:
+ kfree(edid);
+ return NULL;
+}
+
+static struct edid *hdmi_read_edid(struct omap_dss_device *dssdev)
+{
+ struct omap_hdmi *hdmi = dssdev_to_hdmi(dssdev);
+ struct edid *edid = NULL;
+ unsigned int cec_addr;
+ bool need_enable;
+ int r;
+
need_enable = hdmi->core_enabled == false;
if (need_enable) {
r = hdmi4_core_enable(&hdmi->core);
- if (r) {
- kfree(edid);
+ if (r)
return NULL;
- }
}
- r = read_edid(hdmi, edid, MAX_EDID);
- if (r < 0) {
- kfree(edid);
- edid = NULL;
- } else {
- unsigned int cec_addr;
+ mutex_lock(&hdmi->lock);
+ r = hdmi_runtime_get(hdmi);
+ BUG_ON(r);
+
+ r = hdmi4_core_ddc_init(&hdmi->core);
+ if (r)
+ goto done;
- cec_addr = r >= 256 ? cec_get_edid_phys_addr(edid, r, NULL)
- : CEC_PHYS_ADDR_INVALID;
- hdmi4_cec_set_phys_addr(&hdmi->core, cec_addr);
+ edid = hdmi_read_edid_data(hdmi);
+
+done:
+ hdmi_runtime_put(hdmi);
+ mutex_unlock(&hdmi->lock);
+
+ if (edid && edid->extensions) {
+ unsigned int len = (edid->extensions + 1) * EDID_LENGTH;
+
+ cec_addr = cec_get_edid_phys_addr((u8 *)edid, len, NULL);
+ } else {
+ cec_addr = CEC_PHYS_ADDR_INVALID;
}
+ hdmi4_cec_set_phys_addr(&hdmi->core, cec_addr);
+
if (need_enable)
hdmi4_core_disable(&hdmi->core);
- return (struct edid *)edid;
+ return edid;
}
static void hdmi_lost_hotplug(struct omap_dss_device *dssdev)
return core->base + HDMI_CORE_AV;
}
-static int hdmi_core_ddc_init(struct hdmi_core_data *core)
+int hdmi4_core_ddc_init(struct hdmi_core_data *core)
{
void __iomem *base = core->base;
return 0;
}
-static int hdmi_core_ddc_edid(struct hdmi_core_data *core,
- u8 *pedid, int ext)
+int hdmi4_core_ddc_read(void *data, u8 *buf, unsigned int block, size_t len)
{
+ struct hdmi_core_data *core = data;
void __iomem *base = core->base;
u32 i;
- char checksum;
- u32 offset = 0;
/* HDMI_CORE_DDC_STATUS_IN_PROG */
if (hdmi_wait_for_bit_change(base, HDMI_CORE_DDC_STATUS,
return -ETIMEDOUT;
}
- if (ext % 2 != 0)
- offset = 0x80;
-
/* Load Segment Address Register */
- REG_FLD_MOD(base, HDMI_CORE_DDC_SEGM, ext / 2, 7, 0);
+ REG_FLD_MOD(base, HDMI_CORE_DDC_SEGM, block / 2, 7, 0);
/* Load Slave Address Register */
REG_FLD_MOD(base, HDMI_CORE_DDC_ADDR, 0xA0 >> 1, 7, 1);
/* Load Offset Address Register */
- REG_FLD_MOD(base, HDMI_CORE_DDC_OFFSET, offset, 7, 0);
+ REG_FLD_MOD(base, HDMI_CORE_DDC_OFFSET, block % 2 ? 0x80 : 0, 7, 0);
/* Load Byte Count */
- REG_FLD_MOD(base, HDMI_CORE_DDC_COUNT1, 0x80, 7, 0);
+ REG_FLD_MOD(base, HDMI_CORE_DDC_COUNT1, len, 7, 0);
REG_FLD_MOD(base, HDMI_CORE_DDC_COUNT2, 0x0, 1, 0);
/* Set DDC_CMD */
- if (ext)
+ if (block)
REG_FLD_MOD(base, HDMI_CORE_DDC_CMD, 0x4, 3, 0);
else
REG_FLD_MOD(base, HDMI_CORE_DDC_CMD, 0x2, 3, 0);
return -EIO;
}
- for (i = 0; i < 0x80; ++i) {
+ for (i = 0; i < len; ++i) {
int t;
/* IN_PROG */
udelay(1);
}
- pedid[i] = REG_GET(base, HDMI_CORE_DDC_DATA, 7, 0);
- }
-
- checksum = 0;
- for (i = 0; i < 0x80; ++i)
- checksum += pedid[i];
-
- if (checksum != 0) {
- DSSERR("E-EDID checksum failed!!\n");
- return -EIO;
+ buf[i] = REG_GET(base, HDMI_CORE_DDC_DATA, 7, 0);
}
return 0;
}
-int hdmi4_read_edid(struct hdmi_core_data *core, u8 *edid, int len)
-{
- int r, l;
-
- if (len < 128)
- return -EINVAL;
-
- r = hdmi_core_ddc_init(core);
- if (r)
- return r;
-
- r = hdmi_core_ddc_edid(core, edid, 0);
- if (r)
- return r;
-
- l = 128;
-
- if (len >= 128 * 2 && edid[0x7e] > 0) {
- r = hdmi_core_ddc_edid(core, edid + 0x80, 1);
- if (r)
- return r;
- l += 128;
- }
-
- return l;
-}
-
static void hdmi_core_init(struct hdmi_core_video_config *video_cfg)
{
DSSDBG("Enter hdmi_core_init\n");