summaryrefslogtreecommitdiff
path: root/drivers/media/i2c
diff options
context:
space:
mode:
authorHans Verkuil <hverkuil-cisco@xs4all.nl>2021-05-06 15:06:57 +0300
committerMauro Carvalho Chehab <mchehab+huawei@kernel.org>2021-06-02 14:16:01 +0300
commitef677df92e450b90688828a5e44b94c8dc156e62 (patch)
treef65e65bf8ca0dfc3f72704dfd6037aec2fd83984 /drivers/media/i2c
parentd84b9202d712309840f8b5abee0ed272506563bd (diff)
downloadlinux-ef677df92e450b90688828a5e44b94c8dc156e62.tar.xz
media: adv7842: support EDIDs up to 4 blocks
The adv7842 driver didn't support EDIDs of 3 or 4 blocks, even though the hardware supports this. It is a bit more complicated due to the fact that the adv7842 can expose two EDIDs: one digital, one analog, for DVI-I connectors. In that case the VGA_EDID_ENABLE bit is set and blocks 0 and 1 of the EDID eeprom are used for the DVI-D part and block 2 is used for the DVI-A part of the DVI-I connector. Signed-off-by: Hans Verkuil <hverkuil-cisco@xs4all.nl> Signed-off-by: Mauro Carvalho Chehab <mchehab+huawei@kernel.org>
Diffstat (limited to 'drivers/media/i2c')
-rw-r--r--drivers/media/i2c/adv7842.c37
1 files changed, 27 insertions, 10 deletions
diff --git a/drivers/media/i2c/adv7842.c b/drivers/media/i2c/adv7842.c
index ff10af757b99..78e61fe6f2f0 100644
--- a/drivers/media/i2c/adv7842.c
+++ b/drivers/media/i2c/adv7842.c
@@ -98,12 +98,12 @@ struct adv7842_state {
v4l2_std_id norm;
struct {
- u8 edid[256];
+ u8 edid[512];
u32 blocks;
u32 present;
} hdmi_edid;
struct {
- u8 edid[256];
+ u8 edid[128];
u32 blocks;
u32 present;
} vga_edid;
@@ -720,6 +720,9 @@ static int edid_write_vga_segment(struct v4l2_subdev *sd)
v4l2_dbg(2, debug, sd, "%s: write EDID on VGA port\n", __func__);
+ if (!state->vga_edid.present)
+ return 0;
+
/* HPA disable on port A and B */
io_write_and_or(sd, 0x20, 0xcf, 0x00);
@@ -763,7 +766,7 @@ static int edid_write_hdmi_segment(struct v4l2_subdev *sd, u8 port)
struct adv7842_state *state = to_state(sd);
const u8 *edid = state->hdmi_edid.edid;
u32 blocks = state->hdmi_edid.blocks;
- int spa_loc;
+ unsigned int spa_loc;
u16 pa, parent_pa;
int err = 0;
int i;
@@ -796,12 +799,14 @@ static int edid_write_hdmi_segment(struct v4l2_subdev *sd, u8 port)
pa = (edid[spa_loc] << 8) | edid[spa_loc + 1];
}
- /* edid segment pointer '0' for HDMI ports */
- rep_write_and_or(sd, 0x77, 0xef, 0x00);
- for (i = 0; !err && i < blocks * 128; i += I2C_SMBUS_BLOCK_MAX)
+ for (i = 0; !err && i < blocks * 128; i += I2C_SMBUS_BLOCK_MAX) {
+ /* set edid segment pointer for HDMI ports */
+ if (i % 256 == 0)
+ rep_write_and_or(sd, 0x77, 0xef, i >= 256 ? 0x10 : 0x00);
err = i2c_smbus_write_i2c_block_data(state->i2c_edid, i,
I2C_SMBUS_BLOCK_MAX, edid + i);
+ }
if (err)
return err;
@@ -2491,9 +2496,17 @@ static int adv7842_get_edid(struct v4l2_subdev *sd, struct v4l2_edid *edid)
return 0;
}
+/*
+ * If the VGA_EDID_ENABLE bit is set (Repeater Map 0x7f, bit 7), then
+ * the first two blocks of the EDID are for the HDMI, and the first block
+ * of segment 1 (i.e. the third block of the EDID) is for VGA.
+ * So if a VGA EDID is installed, then the maximum size of the HDMI EDID
+ * is 2 blocks.
+ */
static int adv7842_set_edid(struct v4l2_subdev *sd, struct v4l2_edid *e)
{
struct adv7842_state *state = to_state(sd);
+ unsigned int max_blocks = e->pad == ADV7842_EDID_PORT_VGA ? 1 : 4;
int err = 0;
memset(e->reserved, 0, sizeof(e->reserved));
@@ -2502,8 +2515,12 @@ static int adv7842_set_edid(struct v4l2_subdev *sd, struct v4l2_edid *e)
return -EINVAL;
if (e->start_block != 0)
return -EINVAL;
- if (e->blocks > 2) {
- e->blocks = 2;
+ if (e->pad < ADV7842_EDID_PORT_VGA && state->vga_edid.blocks)
+ max_blocks = 2;
+ if (e->pad == ADV7842_EDID_PORT_VGA && state->hdmi_edid.blocks > 2)
+ return -EBUSY;
+ if (e->blocks > max_blocks) {
+ e->blocks = max_blocks;
return -E2BIG;
}
@@ -2514,7 +2531,7 @@ static int adv7842_set_edid(struct v4l2_subdev *sd, struct v4l2_edid *e)
switch (e->pad) {
case ADV7842_EDID_PORT_VGA:
- memset(&state->vga_edid.edid, 0, 256);
+ memset(&state->vga_edid.edid, 0, sizeof(state->vga_edid.edid));
state->vga_edid.blocks = e->blocks;
state->vga_edid.present = e->blocks ? 0x1 : 0x0;
if (e->blocks)
@@ -2523,7 +2540,7 @@ static int adv7842_set_edid(struct v4l2_subdev *sd, struct v4l2_edid *e)
break;
case ADV7842_EDID_PORT_A:
case ADV7842_EDID_PORT_B:
- memset(&state->hdmi_edid.edid, 0, 256);
+ memset(&state->hdmi_edid.edid, 0, sizeof(state->hdmi_edid.edid));
state->hdmi_edid.blocks = e->blocks;
if (e->blocks) {
state->hdmi_edid.present |= 0x04 << e->pad;