Commit 3e86aa85 authored by Mats Randgaard's avatar Mats Randgaard Committed by Mauro Carvalho Chehab

[media] adv7604: set CEC address (SPA) in EDID

Signed-off-by: default avatarMats Randgaard <matrandg@cisco.com>
Signed-off-by: default avatarHans Verkuil <hans.verkuil@cisco.com>
Signed-off-by: default avatarMauro Carvalho Chehab <m.chehab@samsung.com>
parent d261e842
...@@ -72,6 +72,7 @@ struct adv7604_state { ...@@ -72,6 +72,7 @@ struct adv7604_state {
u32 present; u32 present;
unsigned blocks; unsigned blocks;
} edid; } edid;
u16 spa_port_a;
struct v4l2_fract aspect_ratio; struct v4l2_fract aspect_ratio;
u32 rgb_quantization_range; u32 rgb_quantization_range;
struct workqueue_struct *work_queues; struct workqueue_struct *work_queues;
...@@ -531,9 +532,6 @@ static inline int edid_write_block(struct v4l2_subdev *sd, ...@@ -531,9 +532,6 @@ static inline int edid_write_block(struct v4l2_subdev *sd,
v4l2_dbg(2, debug, sd, "%s: write EDID block (%d byte)\n", __func__, len); v4l2_dbg(2, debug, sd, "%s: write EDID block (%d byte)\n", __func__, len);
/* Disables I2C access to internal EDID ram from DDC port */
rep_write_and_or(sd, 0x77, 0xf0, 0x0);
for (i = 0; !err && i < len; i += I2C_SMBUS_BLOCK_MAX) for (i = 0; !err && i < len; i += I2C_SMBUS_BLOCK_MAX)
err = adv_smbus_write_i2c_block_data(state->i2c_edid, i, err = adv_smbus_write_i2c_block_data(state->i2c_edid, i,
I2C_SMBUS_BLOCK_MAX, val + i); I2C_SMBUS_BLOCK_MAX, val + i);
...@@ -1623,9 +1621,39 @@ static int adv7604_get_edid(struct v4l2_subdev *sd, struct v4l2_subdev_edid *edi ...@@ -1623,9 +1621,39 @@ static int adv7604_get_edid(struct v4l2_subdev *sd, struct v4l2_subdev_edid *edi
return 0; return 0;
} }
static int get_edid_spa_location(struct v4l2_subdev *sd, const u8 *edid)
{
u8 d;
if ((edid[0x7e] != 1) ||
(edid[0x80] != 0x02) ||
(edid[0x81] != 0x03)) {
return -1;
}
/* search Vendor Specific Data Block (tag 3) */
d = edid[0x82] & 0x7f;
if (d > 4) {
int i = 0x84;
int end = 0x80 + d;
do {
u8 tag = edid[i] >> 5;
u8 len = edid[i] & 0x1f;
if ((tag == 3) && (len >= 5))
return i + 4;
i += len + 1;
} while (i < end);
}
return -1;
}
static int adv7604_set_edid(struct v4l2_subdev *sd, struct v4l2_subdev_edid *edid) static int adv7604_set_edid(struct v4l2_subdev *sd, struct v4l2_subdev_edid *edid)
{ {
struct adv7604_state *state = to_state(sd); struct adv7604_state *state = to_state(sd);
int spa_loc = get_edid_spa_location(sd, edid->edid);
int tmp = 0;
int err; int err;
if (edid->pad > ADV7604_EDID_PORT_D) if (edid->pad > ADV7604_EDID_PORT_D)
...@@ -1633,16 +1661,20 @@ static int adv7604_set_edid(struct v4l2_subdev *sd, struct v4l2_subdev_edid *edi ...@@ -1633,16 +1661,20 @@ static int adv7604_set_edid(struct v4l2_subdev *sd, struct v4l2_subdev_edid *edi
if (edid->start_block != 0) if (edid->start_block != 0)
return -EINVAL; return -EINVAL;
if (edid->blocks == 0) { if (edid->blocks == 0) {
/* Pull down the hotplug pin */ /* Disable hotplug and I2C access to EDID RAM from DDC port */
state->edid.present &= ~(1 << edid->pad); state->edid.present &= ~(1 << edid->pad);
v4l2_subdev_notify(sd, ADV7604_HOTPLUG, (void *)&state->edid.present); v4l2_subdev_notify(sd, ADV7604_HOTPLUG, (void *)&state->edid.present);
/* Disables I2C access to internal EDID ram from DDC port */ rep_write_and_or(sd, 0x77, 0xf0, state->edid.present);
rep_write_and_or(sd, 0x77, 0xf0, 0x0);
state->edid.blocks = 0;
/* Fall back to a 16:9 aspect ratio */ /* Fall back to a 16:9 aspect ratio */
state->aspect_ratio.numerator = 16; state->aspect_ratio.numerator = 16;
state->aspect_ratio.denominator = 9; state->aspect_ratio.denominator = 9;
v4l2_dbg(2, debug, sd, "%s: clear edid\n", __func__);
if (!state->edid.present)
state->edid.blocks = 0;
v4l2_dbg(2, debug, sd, "%s: clear EDID pad %d, edid.present = 0x%x\n",
__func__, edid->pad, state->edid.present);
return 0; return 0;
} }
if (edid->blocks > 2) { if (edid->blocks > 2) {
...@@ -1652,19 +1684,45 @@ static int adv7604_set_edid(struct v4l2_subdev *sd, struct v4l2_subdev_edid *edi ...@@ -1652,19 +1684,45 @@ static int adv7604_set_edid(struct v4l2_subdev *sd, struct v4l2_subdev_edid *edi
if (!edid->edid) if (!edid->edid)
return -EINVAL; return -EINVAL;
/* Disable hotplug and I2C access to EDID RAM from DDC port */
cancel_delayed_work_sync(&state->delayed_work_enable_hotplug); cancel_delayed_work_sync(&state->delayed_work_enable_hotplug);
state->edid.present &= ~(1 << edid->pad); v4l2_subdev_notify(sd, ADV7604_HOTPLUG, (void *)&tmp);
v4l2_subdev_notify(sd, ADV7604_HOTPLUG, (void *)&state->edid.present); rep_write_and_or(sd, 0x77, 0xf0, 0x00);
v4l2_dbg(2, debug, sd, "%s: write EDID pad %d, edid.present = 0x%x\n",
__func__, edid->pad, state->edid.present);
switch (edid->pad) {
case ADV7604_EDID_PORT_A:
state->spa_port_a = edid->edid[spa_loc];
break;
case ADV7604_EDID_PORT_B:
rep_write(sd, 0x70, (spa_loc < 0) ? 0 : edid->edid[spa_loc]);
rep_write(sd, 0x71, (spa_loc < 0) ? 0 : edid->edid[spa_loc + 1]);
break;
case ADV7604_EDID_PORT_C:
rep_write(sd, 0x72, (spa_loc < 0) ? 0 : edid->edid[spa_loc]);
rep_write(sd, 0x73, (spa_loc < 0) ? 0 : edid->edid[spa_loc + 1]);
break;
case ADV7604_EDID_PORT_D:
rep_write(sd, 0x74, (spa_loc < 0) ? 0 : edid->edid[spa_loc]);
rep_write(sd, 0x75, (spa_loc < 0) ? 0 : edid->edid[spa_loc + 1]);
break;
}
rep_write(sd, 0x76, (spa_loc < 0) ? 0x00 : spa_loc);
rep_write_and_or(sd, 0x77, 0xbf, (spa_loc < 0) ? 0x00 : (spa_loc >> 2) & 0x40);
if (spa_loc > 0)
edid->edid[spa_loc] = state->spa_port_a;
memcpy(state->edid.edid, edid->edid, 128 * edid->blocks); memcpy(state->edid.edid, edid->edid, 128 * edid->blocks);
state->edid.blocks = edid->blocks; state->edid.blocks = edid->blocks;
state->aspect_ratio = v4l2_calc_aspect_ratio(edid->edid[0x15], state->aspect_ratio = v4l2_calc_aspect_ratio(edid->edid[0x15],
edid->edid[0x16]); edid->edid[0x16]);
state->edid.present |= edid->pad; state->edid.present |= 1 << edid->pad;
err = edid_write_block(sd, 128 * edid->blocks, state->edid.edid); err = edid_write_block(sd, 128 * edid->blocks, state->edid.edid);
if (err < 0) { if (err < 0) {
v4l2_err(sd, "error %d writing edid\n", err); v4l2_err(sd, "error %d writing edid pad %d\n", err, edid->pad);
return err; return err;
} }
...@@ -1984,7 +2042,6 @@ static int adv7604_core_init(struct v4l2_subdev *sd) ...@@ -1984,7 +2042,6 @@ static int adv7604_core_init(struct v4l2_subdev *sd)
ADI recommended setting [REF_01, c. 2.3.3] */ ADI recommended setting [REF_01, c. 2.3.3] */
cp_write(sd, 0xc9, 0x2d); /* use prim_mode and vid_std as free run resolution cp_write(sd, 0xc9, 0x2d); /* use prim_mode and vid_std as free run resolution
for digital formats */ for digital formats */
rep_write(sd, 0x76, 0xc0); /* SPA location for port B, C and D */
/* TODO from platform data */ /* TODO from platform data */
afe_write(sd, 0xb5, 0x01); /* Setting MCLK to 256Fs */ afe_write(sd, 0xb5, 0x01); /* Setting MCLK to 256Fs */
......
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