Hey Xin, On Fri, 9 Apr 2021 at 07:35, Xin Ji <xji@xxxxxxxxxxxxxxxx> wrote: > > Send DPCD command to downstream before anx7625 power down, > tell downstream into standby mode. > > Signed-off-by: Xin Ji <xji@xxxxxxxxxxxxxxxx> > --- > 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@xxxxxxxxxx> _______________________________________________ devel mailing list devel@xxxxxxxxxxxxxxxxxxxxxx http://driverdev.linuxdriverproject.org/mailman/listinfo/driverdev-devel