Commit ef677df9 authored by Hans Verkuil's avatar Hans Verkuil Committed by Mauro Carvalho Chehab

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: default avatarHans Verkuil <hverkuil-cisco@xs4all.nl>
Signed-off-by: default avatarMauro Carvalho Chehab <mchehab+huawei@kernel.org>
parent d84b9202
...@@ -98,12 +98,12 @@ struct adv7842_state { ...@@ -98,12 +98,12 @@ struct adv7842_state {
v4l2_std_id norm; v4l2_std_id norm;
struct { struct {
u8 edid[256]; u8 edid[512];
u32 blocks; u32 blocks;
u32 present; u32 present;
} hdmi_edid; } hdmi_edid;
struct { struct {
u8 edid[256]; u8 edid[128];
u32 blocks; u32 blocks;
u32 present; u32 present;
} vga_edid; } vga_edid;
...@@ -720,6 +720,9 @@ static int edid_write_vga_segment(struct v4l2_subdev *sd) ...@@ -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__); 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 */ /* HPA disable on port A and B */
io_write_and_or(sd, 0x20, 0xcf, 0x00); io_write_and_or(sd, 0x20, 0xcf, 0x00);
...@@ -763,7 +766,7 @@ static int edid_write_hdmi_segment(struct v4l2_subdev *sd, u8 port) ...@@ -763,7 +766,7 @@ static int edid_write_hdmi_segment(struct v4l2_subdev *sd, u8 port)
struct adv7842_state *state = to_state(sd); struct adv7842_state *state = to_state(sd);
const u8 *edid = state->hdmi_edid.edid; const u8 *edid = state->hdmi_edid.edid;
u32 blocks = state->hdmi_edid.blocks; u32 blocks = state->hdmi_edid.blocks;
int spa_loc; unsigned int spa_loc;
u16 pa, parent_pa; u16 pa, parent_pa;
int err = 0; int err = 0;
int i; int i;
...@@ -796,12 +799,14 @@ static int edid_write_hdmi_segment(struct v4l2_subdev *sd, u8 port) ...@@ -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]; 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, err = i2c_smbus_write_i2c_block_data(state->i2c_edid, i,
I2C_SMBUS_BLOCK_MAX, edid + i); I2C_SMBUS_BLOCK_MAX, edid + i);
}
if (err) if (err)
return err; return err;
...@@ -2491,9 +2496,17 @@ static int adv7842_get_edid(struct v4l2_subdev *sd, struct v4l2_edid *edid) ...@@ -2491,9 +2496,17 @@ static int adv7842_get_edid(struct v4l2_subdev *sd, struct v4l2_edid *edid)
return 0; 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) static int adv7842_set_edid(struct v4l2_subdev *sd, struct v4l2_edid *e)
{ {
struct adv7842_state *state = to_state(sd); struct adv7842_state *state = to_state(sd);
unsigned int max_blocks = e->pad == ADV7842_EDID_PORT_VGA ? 1 : 4;
int err = 0; int err = 0;
memset(e->reserved, 0, sizeof(e->reserved)); memset(e->reserved, 0, sizeof(e->reserved));
...@@ -2502,8 +2515,12 @@ static int adv7842_set_edid(struct v4l2_subdev *sd, struct v4l2_edid *e) ...@@ -2502,8 +2515,12 @@ static int adv7842_set_edid(struct v4l2_subdev *sd, struct v4l2_edid *e)
return -EINVAL; return -EINVAL;
if (e->start_block != 0) if (e->start_block != 0)
return -EINVAL; return -EINVAL;
if (e->blocks > 2) { if (e->pad < ADV7842_EDID_PORT_VGA && state->vga_edid.blocks)
e->blocks = 2; 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; return -E2BIG;
} }
...@@ -2514,7 +2531,7 @@ static int adv7842_set_edid(struct v4l2_subdev *sd, struct v4l2_edid *e) ...@@ -2514,7 +2531,7 @@ static int adv7842_set_edid(struct v4l2_subdev *sd, struct v4l2_edid *e)
switch (e->pad) { switch (e->pad) {
case ADV7842_EDID_PORT_VGA: 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.blocks = e->blocks;
state->vga_edid.present = e->blocks ? 0x1 : 0x0; state->vga_edid.present = e->blocks ? 0x1 : 0x0;
if (e->blocks) if (e->blocks)
...@@ -2523,7 +2540,7 @@ static int adv7842_set_edid(struct v4l2_subdev *sd, struct v4l2_edid *e) ...@@ -2523,7 +2540,7 @@ static int adv7842_set_edid(struct v4l2_subdev *sd, struct v4l2_edid *e)
break; break;
case ADV7842_EDID_PORT_A: case ADV7842_EDID_PORT_A:
case ADV7842_EDID_PORT_B: 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; state->hdmi_edid.blocks = e->blocks;
if (e->blocks) { if (e->blocks) {
state->hdmi_edid.present |= 0x04 << e->pad; state->hdmi_edid.present |= 0x04 << e->pad;
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment