drm/bridge: ti-sn65dsi86: Combine register accesses in ti_sn_aux_transfer()
authorStephen Boyd <swboyd@chromium.org>
Mon, 2 Nov 2020 18:11:41 +0000 (10:11 -0800)
committerSam Ravnborg <sam@ravnborg.org>
Sat, 7 Nov 2020 11:06:03 +0000 (12:06 +0100)
These register reads and writes are sometimes directly next to each
other in the register address space. Let's use regmap bulk read/write
APIs to get the data with one transfer instead of multiple i2c
transfers. This helps cut down on the number of transfers in the case of
something like reading an EDID where we read in blocks of 16 bytes at a
time and the last for loop here is sending an i2c transfer for each of
those 16 bytes, one at a time. Ouch!

Changes in v3:
 - Undid changes in v2

Changes in v2:
 - Combined AUX_CMD register write

Reviewed-by: Douglas Anderson <dianders@chromium.org>
Cc: Laurent Pinchart <Laurent.pinchart@ideasonboard.com>
Cc: Jonas Karlman <jonas@kwiboo.se>
Cc: Jernej Skrabec <jernej.skrabec@siol.net>
Cc: Sean Paul <seanpaul@chromium.org>
Acked-by: Sam Ravnborg <sam@ravnborg.org>
Signed-off-by: Stephen Boyd <swboyd@chromium.org>
Signed-off-by: Sam Ravnborg <sam@ravnborg.org>
Link: https://patchwork.freedesktop.org/patch/msgid/20201102181144.3469197-2-swboyd@chromium.org
drivers/gpu/drm/bridge/ti-sn65dsi86.c

index 6ca1debd0f88d7b3946a184f0a0fb6d0b41ea5d2..6e2d286a8221dce94a2a4da7e05c5cc0417ce278 100644 (file)
@@ -17,6 +17,8 @@
 #include <linux/regmap.h>
 #include <linux/regulator/consumer.h>
 
+#include <asm/unaligned.h>
+
 #include <drm/drm_atomic.h>
 #include <drm/drm_atomic_helper.h>
 #include <drm/drm_bridge.h>
@@ -72,6 +74,7 @@
 #define SN_AUX_ADDR_19_16_REG                  0x74
 #define SN_AUX_ADDR_15_8_REG                   0x75
 #define SN_AUX_ADDR_7_0_REG                    0x76
+#define SN_AUX_ADDR_MASK                       GENMASK(19, 0)
 #define SN_AUX_LENGTH_REG                      0x77
 #define SN_AUX_CMD_REG                         0x78
 #define  AUX_CMD_SEND                          BIT(0)
@@ -858,11 +861,13 @@ static ssize_t ti_sn_aux_transfer(struct drm_dp_aux *aux,
        struct ti_sn_bridge *pdata = aux_to_ti_sn_bridge(aux);
        u32 request = msg->request & ~DP_AUX_I2C_MOT;
        u32 request_val = AUX_CMD_REQ(msg->request);
-       u8 *buf = (u8 *)msg->buffer;
+       u8 *buf = msg->buffer;
+       unsigned int len = msg->size;
        unsigned int val;
-       int ret, i;
+       int ret;
+       u8 addr_len[SN_AUX_LENGTH_REG + 1 - SN_AUX_ADDR_19_16_REG];
 
-       if (msg->size > SN_AUX_MAX_PAYLOAD_BYTES)
+       if (len > SN_AUX_MAX_PAYLOAD_BYTES)
                return -EINVAL;
 
        switch (request) {
@@ -876,19 +881,14 @@ static ssize_t ti_sn_aux_transfer(struct drm_dp_aux *aux,
                return -EINVAL;
        }
 
-       regmap_write(pdata->regmap, SN_AUX_ADDR_19_16_REG,
-                    (msg->address >> 16) & 0xF);
-       regmap_write(pdata->regmap, SN_AUX_ADDR_15_8_REG,
-                    (msg->address >> 8) & 0xFF);
-       regmap_write(pdata->regmap, SN_AUX_ADDR_7_0_REG, msg->address & 0xFF);
-
-       regmap_write(pdata->regmap, SN_AUX_LENGTH_REG, msg->size);
+       BUILD_BUG_ON(sizeof(addr_len) != sizeof(__be32));
+       put_unaligned_be32((msg->address & SN_AUX_ADDR_MASK) << 8 | len,
+                          addr_len);
+       regmap_bulk_write(pdata->regmap, SN_AUX_ADDR_19_16_REG, addr_len,
+                         ARRAY_SIZE(addr_len));
 
-       if (request == DP_AUX_NATIVE_WRITE || request == DP_AUX_I2C_WRITE) {
-               for (i = 0; i < msg->size; i++)
-                       regmap_write(pdata->regmap, SN_AUX_WDATA_REG(i),
-                                    buf[i]);
-       }
+       if (request == DP_AUX_NATIVE_WRITE || request == DP_AUX_I2C_WRITE)
+               regmap_bulk_write(pdata->regmap, SN_AUX_WDATA_REG(0), buf, len);
 
        /* Clear old status bits before start so we don't get confused */
        regmap_write(pdata->regmap, SN_AUX_CMD_STATUS_REG,
@@ -912,21 +912,15 @@ static ssize_t ti_sn_aux_transfer(struct drm_dp_aux *aux,
                 || (val & AUX_IRQ_STATUS_AUX_SHORT))
                return -ENXIO;
 
-       if (request == DP_AUX_NATIVE_WRITE || request == DP_AUX_I2C_WRITE)
-               return msg->size;
+       if (request == DP_AUX_NATIVE_WRITE || request == DP_AUX_I2C_WRITE ||
+           len == 0)
+               return len;
 
-       for (i = 0; i < msg->size; i++) {
-               unsigned int val;
-               ret = regmap_read(pdata->regmap, SN_AUX_RDATA_REG(i),
-                                 &val);
-               if (ret)
-                       return ret;
-
-               WARN_ON(val & ~0xFF);
-               buf[i] = (u8)(val & 0xFF);
-       }
+       ret = regmap_bulk_read(pdata->regmap, SN_AUX_RDATA_REG(0), buf, len);
+       if (ret)
+               return ret;
 
-       return msg->size;
+       return len;
 }
 
 static int ti_sn_bridge_parse_dsi_host(struct ti_sn_bridge *pdata)