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>
This commit is contained in:
parent
d84b9202d7
commit
ef677df92e
|
@ -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;
|
||||
|
|
Loading…
Reference in New Issue