From 982f589bde7a7f4c8a9f5d4c94fad02a9e8dcf3e Mon Sep 17 00:00:00 2001 From: Stephen Boyd Date: Mon, 2 Nov 2020 10:11:44 -0800 Subject: [PATCH] drm/bridge: ti-sn65dsi86: Update reply on aux failures We should be setting the drm_dp_aux_msg::reply field if a NACK or a SHORT reply happens. Update the error bit handling logic in ti_sn_aux_transfer() to handle these cases and notify upper layers that such errors have happened. This helps the retry logic understand that a timeout has happened, or to shorten the read length if the panel isn't able to handle the longest read possible. Note: I don't have any hardware that exhibits these code paths so this is written based on reading the datasheet for this bridge and inspecting the code and how this is called. Changes in v2: - Move WRITE_STATUS_UPDATE check from case to assignment Changes in v2: - Handle WRITE_STATUS_UPDATE properly Reviewed-by: Douglas Anderson Cc: Laurent Pinchart Cc: Jonas Karlman Cc: Jernej Skrabec Cc: Sean Paul Acked-by: Sam Ravnborg Signed-off-by: Stephen Boyd Signed-off-by: Sam Ravnborg Link: https://patchwork.freedesktop.org/patch/msgid/20201102181144.3469197-5-swboyd@chromium.org --- drivers/gpu/drm/bridge/ti-sn65dsi86.c | 35 +++++++++++++++++++++++---- 1 file changed, 30 insertions(+), 5 deletions(-) diff --git a/drivers/gpu/drm/bridge/ti-sn65dsi86.c b/drivers/gpu/drm/bridge/ti-sn65dsi86.c index 22d38df27a11..f27306c51e4d 100644 --- a/drivers/gpu/drm/bridge/ti-sn65dsi86.c +++ b/drivers/gpu/drm/bridge/ti-sn65dsi86.c @@ -878,7 +878,7 @@ static ssize_t ti_sn_aux_transfer(struct drm_dp_aux *aux, struct drm_dp_aux_msg *msg) { struct ti_sn_bridge *pdata = aux_to_ti_sn_bridge(aux); - u32 request = msg->request & ~DP_AUX_I2C_MOT; + u32 request = msg->request & ~(DP_AUX_I2C_MOT | DP_AUX_I2C_WRITE_STATUS_UPDATE); u32 request_val = AUX_CMD_REQ(msg->request); u8 *buf = msg->buffer; unsigned int len = msg->size; @@ -895,6 +895,8 @@ static ssize_t ti_sn_aux_transfer(struct drm_dp_aux *aux, case DP_AUX_NATIVE_READ: case DP_AUX_I2C_READ: regmap_write(pdata->regmap, SN_AUX_CMD_REG, request_val); + /* Assume it's good */ + msg->reply = 0; break; default: return -EINVAL; @@ -926,10 +928,33 @@ static ssize_t ti_sn_aux_transfer(struct drm_dp_aux *aux, ret = regmap_read(pdata->regmap, SN_AUX_CMD_STATUS_REG, &val); if (ret) return ret; - else if ((val & AUX_IRQ_STATUS_NAT_I2C_FAIL) - || (val & AUX_IRQ_STATUS_AUX_RPLY_TOUT) - || (val & AUX_IRQ_STATUS_AUX_SHORT)) - return -ENXIO; + + if (val & AUX_IRQ_STATUS_AUX_RPLY_TOUT) { + /* + * The hardware tried the message seven times per the DP spec + * but it hit a timeout. We ignore defers here because they're + * handled in hardware. + */ + return -ETIMEDOUT; + } + + if (val & AUX_IRQ_STATUS_AUX_SHORT) { + ret = regmap_read(pdata->regmap, SN_AUX_LENGTH_REG, &len); + if (ret) + return ret; + } else if (val & AUX_IRQ_STATUS_NAT_I2C_FAIL) { + switch (request) { + case DP_AUX_I2C_WRITE: + case DP_AUX_I2C_READ: + msg->reply |= DP_AUX_I2C_REPLY_NACK; + break; + case DP_AUX_NATIVE_READ: + case DP_AUX_NATIVE_WRITE: + msg->reply |= DP_AUX_NATIVE_REPLY_NACK; + break; + } + return 0; + } if (request == DP_AUX_NATIVE_WRITE || request == DP_AUX_I2C_WRITE || len == 0)