diff options
author | Andrey Smirnov <andrew.smirnov@gmail.com> | 2019-06-18 22:27:16 -0700 |
---|---|---|
committer | Andrzej Hajda <a.hajda@samsung.com> | 2019-06-27 13:38:24 +0200 |
commit | fdb29b738017672069f95747c48eac947b9beba2 (patch) | |
tree | ed4ab2f6c2d23debd87ec885210b82157b4c9460 /drivers/gpu/drm/bridge/tc358767.c | |
parent | 32d3621996aa70f4db9bbf862e400471eed81e34 (diff) |
drm/bridge: tc358767: Add support for address-only I2C transfers
Transfer size of zero means a request to do an address-only
transfer. Since the HW support this, we probably shouldn't be just
ignoring such requests. While at it allow DP_AUX_I2C_MOT flag to pass
through, since it is supported by the HW as well.
Signed-off-by: Andrey Smirnov <andrew.smirnov@gmail.com>
Reviewed-by: Andrzej Hajda <a.hajda@samsung.com>
Reviewed-by: Tomi Valkeinen <tomi.valkeinen@ti.com>
Cc: Andrzej Hajda <a.hajda@samsung.com>
Cc: Laurent Pinchart <Laurent.pinchart@ideasonboard.com>
Cc: Tomi Valkeinen <tomi.valkeinen@ti.com>
Cc: Andrey Gusakov <andrey.gusakov@cogentembedded.com>
Cc: Philipp Zabel <p.zabel@pengutronix.de>
Cc: Cory Tusar <cory.tusar@zii.aero>
Cc: Chris Healy <cphealy@gmail.com>
Cc: Lucas Stach <l.stach@pengutronix.de>
Cc: dri-devel@lists.freedesktop.org
Cc: linux-kernel@vger.kernel.org
Signed-off-by: Andrzej Hajda <a.hajda@samsung.com>
Link: https://patchwork.freedesktop.org/patch/msgid/20190619052716.16831-16-andrew.smirnov@gmail.com
Diffstat (limited to 'drivers/gpu/drm/bridge/tc358767.c')
-rw-r--r-- | drivers/gpu/drm/bridge/tc358767.c | 42 |
1 files changed, 31 insertions, 11 deletions
diff --git a/drivers/gpu/drm/bridge/tc358767.c b/drivers/gpu/drm/bridge/tc358767.c index 38f15e740b70..e1ce4954e6af 100644 --- a/drivers/gpu/drm/bridge/tc358767.c +++ b/drivers/gpu/drm/bridge/tc358767.c @@ -136,6 +136,8 @@ /* AUX channel */ #define DP0_AUXCFG0 0x0660 +#define DP0_AUXCFG0_BSIZE GENMASK(11, 8) +#define DP0_AUXCFG0_ADDR_ONLY BIT(4) #define DP0_AUXCFG1 0x0664 #define AUX_RX_FILTER_EN BIT(16) @@ -317,6 +319,18 @@ static int tc_aux_read_data(struct tc_data *tc, void *data, size_t size) return size; } +static u32 tc_auxcfg0(struct drm_dp_aux_msg *msg, size_t size) +{ + u32 auxcfg0 = msg->request; + + if (size) + auxcfg0 |= FIELD_PREP(DP0_AUXCFG0_BSIZE, size - 1); + else + auxcfg0 |= DP0_AUXCFG0_ADDR_ONLY; + + return auxcfg0; +} + static ssize_t tc_aux_transfer(struct drm_dp_aux *aux, struct drm_dp_aux_msg *msg) { @@ -326,9 +340,6 @@ static ssize_t tc_aux_transfer(struct drm_dp_aux *aux, u32 auxstatus; int ret; - if (size == 0) - return 0; - ret = tc_aux_wait_busy(tc); if (ret) return ret; @@ -339,9 +350,11 @@ static ssize_t tc_aux_transfer(struct drm_dp_aux *aux, break; case DP_AUX_NATIVE_WRITE: case DP_AUX_I2C_WRITE: - ret = tc_aux_write_data(tc, msg->buffer, size); - if (ret < 0) - return ret; + if (size) { + ret = tc_aux_write_data(tc, msg->buffer, size); + if (ret < 0) + return ret; + } break; default: return -EINVAL; @@ -352,8 +365,7 @@ static ssize_t tc_aux_transfer(struct drm_dp_aux *aux, if (ret) return ret; /* Start transfer */ - ret = regmap_write(tc->regmap, DP0_AUXCFG0, - ((size - 1) << 8) | request); + ret = regmap_write(tc->regmap, DP0_AUXCFG0, tc_auxcfg0(msg, size)); if (ret) return ret; @@ -367,14 +379,22 @@ static ssize_t tc_aux_transfer(struct drm_dp_aux *aux, if (auxstatus & AUX_TIMEOUT) return -ETIMEDOUT; - - size = FIELD_GET(AUX_BYTES, auxstatus); + /* + * For some reason address-only DP_AUX_I2C_WRITE (MOT), still + * reports 1 byte transferred in its status. To deal we that + * we ignore aux_bytes field if we know that this was an + * address-only transfer + */ + if (size) + size = FIELD_GET(AUX_BYTES, auxstatus); msg->reply = FIELD_GET(AUX_STATUS, auxstatus); switch (request) { case DP_AUX_NATIVE_READ: case DP_AUX_I2C_READ: - return tc_aux_read_data(tc, msg->buffer, size); + if (size) + return tc_aux_read_data(tc, msg->buffer, size); + break; } return size; |