Hey Xin,
On Fri, 9 Apr 2021 at 07:35, Xin Ji xji@analogixsemi.com wrote:
Send DPCD command to downstream before anx7625 power down, tell downstream into standby mode.
Signed-off-by: Xin Ji xji@analogixsemi.com
drivers/gpu/drm/bridge/analogix/anx7625.c | 75 +++++++++++++++++++++++ 1 file changed, 75 insertions(+)
diff --git a/drivers/gpu/drm/bridge/analogix/anx7625.c b/drivers/gpu/drm/bridge/analogix/anx7625.c index 65cc05982f82..53d2f0d0ee30 100644 --- a/drivers/gpu/drm/bridge/analogix/anx7625.c +++ b/drivers/gpu/drm/bridge/analogix/anx7625.c @@ -124,6 +124,23 @@ static int anx7625_reg_write(struct anx7625_data *ctx, return ret; }
+static int anx7625_reg_block_write(struct anx7625_data *ctx,
struct i2c_client *client,
u8 reg_addr, u8 len, u8 *buf)
+{
int ret;
struct device *dev = &client->dev;
i2c_access_workaround(ctx, client);
ret = i2c_smbus_write_i2c_block_data(client, reg_addr, len, buf);
if (ret < 0)
DRM_DEV_ERROR(dev, "write i2c block failed id=%x\n:%x",
client->addr, reg_addr);
return ret;
+}
static int anx7625_write_or(struct anx7625_data *ctx, struct i2c_client *client, u8 offset, u8 mask) @@ -195,6 +212,55 @@ static int wait_aux_op_finish(struct anx7625_data *ctx) return val; }
+static int anx7625_aux_dpcd_write(struct anx7625_data *ctx,
u8 addrh, u8 addrm, u8 addrl,
u8 len, u8 *buf)
+{
struct device *dev = &ctx->client->dev;
int ret;
u8 cmd;
if (len > MAX_DPCD_BUFFER_SIZE) {
DRM_DEV_ERROR(dev, "exceed aux buffer len.\n");
return -EINVAL;
}
cmd = ((len - 1) << 4) | 0x08;
/* Set command and length */
ret = anx7625_reg_write(ctx, ctx->i2c.rx_p0_client,
AP_AUX_COMMAND, cmd);
/* Set aux access address */
ret |= anx7625_reg_write(ctx, ctx->i2c.rx_p0_client,
AP_AUX_ADDR_7_0, addrl);
ret |= anx7625_reg_write(ctx, ctx->i2c.rx_p0_client,
AP_AUX_ADDR_15_8, addrm);
ret |= anx7625_write_and(ctx, ctx->i2c.rx_p0_client,
AP_AUX_ADDR_19_16, addrh);
/* Set write data */
ret |= anx7625_reg_block_write(ctx, ctx->i2c.rx_p0_client,
AP_AUX_BUFF_START, len, buf);
/* Enable aux access */
ret |= anx7625_write_or(ctx, ctx->i2c.rx_p0_client,
AP_AUX_CTRL_STATUS, AP_AUX_CTRL_OP_EN);
if (ret < 0) {
DRM_DEV_ERROR(dev, "cannot access aux related register.\n");
return -EIO;
}
usleep_range(2000, 2100);
ret = wait_aux_op_finish(ctx);
if (ret) {
DRM_DEV_ERROR(dev, "aux IO error: wait aux op finish.\n");
return ret;
}
return 0;
+}
static int anx7625_video_mute_control(struct anx7625_data *ctx, u8 status) { @@ -617,6 +683,7 @@ static void anx7625_dp_stop(struct anx7625_data *ctx) { struct device *dev = &ctx->client->dev; int ret;
u8 data; DRM_DEV_DEBUG_DRIVER(dev, "stop dp output\n");
@@ -628,8 +695,16 @@ static void anx7625_dp_stop(struct anx7625_data *ctx) ret |= anx7625_write_and(ctx, ctx->i2c.tx_p2_client, 0x08, 0x7f);
ret |= anx7625_video_mute_control(ctx, 1);
DRM_DEV_DEBUG_DRIVER(dev, "notify downstream enter into standby\n");
/* Downstream monitor enter into standby mode */
data = 2;
ret |= anx7625_aux_dpcd_write(ctx, 0x00, 0x06, 0x00, 1, &data); if (ret < 0) DRM_DEV_ERROR(dev, "IO error : mute video fail\n");
return;
}
Reviewed-by: Robert Foss robert.foss@linaro.org