Currently, the driver supports register access mode for DSI command
transfer, which limits both TX and RX to only 16 Bytes long packets.
Implement support for DSI command TX using AXI memory access mode,
which extends the packet transfer length up to 128 Bytes long in LP
and 1024 Bytes long in HS. Support for DSI command RX using the AXI
access mode is not implemented due to missing test hardware.

The implementation allocates a DMAble 4k page. In case the command
transfer is longer than 16 Bytes, the payload is copied into the
page and sent out using the AXI access mode, otherwise the register
access mode is used.

Signed-off-by: Marek Vasut <[email protected]>
---
Cc: David Airlie <[email protected]>
Cc: Geert Uytterhoeven <[email protected]>
Cc: Kieran Bingham <[email protected]>
Cc: Laurent Pinchart <[email protected]>
Cc: Maarten Lankhorst <[email protected]>
Cc: Magnus Damm <[email protected]>
Cc: Maxime Ripard <[email protected]>
Cc: Simona Vetter <[email protected]>
Cc: Thomas Zimmermann <[email protected]>
Cc: Tomi Valkeinen <[email protected]>
Cc: [email protected]
Cc: [email protected]
Cc: [email protected]
---
 .../gpu/drm/renesas/rcar-du/rcar_mipi_dsi.c   | 42 +++++++++++++++----
 1 file changed, 35 insertions(+), 7 deletions(-)

diff --git a/drivers/gpu/drm/renesas/rcar-du/rcar_mipi_dsi.c 
b/drivers/gpu/drm/renesas/rcar-du/rcar_mipi_dsi.c
index 6e46d6d99f3c0..c25218ca4320a 100644
--- a/drivers/gpu/drm/renesas/rcar-du/rcar_mipi_dsi.c
+++ b/drivers/gpu/drm/renesas/rcar-du/rcar_mipi_dsi.c
@@ -8,6 +8,7 @@
 #include <linux/bitfield.h>
 #include <linux/clk.h>
 #include <linux/delay.h>
+#include <linux/dma-mapping.h>
 #include <linux/io.h>
 #include <linux/iopoll.h>
 #include <linux/math64.h>
@@ -75,6 +76,9 @@ struct rcar_mipi_dsi {
        unsigned long mode_flags;
        unsigned int num_data_lanes;
        unsigned int lanes;
+
+       void *cmd_axi_cpu;
+       dma_addr_t cmd_axi_dma;
 };
 
 struct dsi_setup_info {
@@ -977,6 +981,7 @@ static ssize_t rcar_mipi_dsi_host_tx_transfer(struct 
mipi_dsi_host *host,
                                              bool is_rx_xfer)
 {
        const bool is_tx_long = mipi_dsi_packet_format_is_long(msg->type);
+       const bool is_tx_axi = !is_rx_xfer && is_tx_long && (msg->tx_len > 16);
        struct rcar_mipi_dsi *dsi = host_to_rcar_mipi_dsi(host);
        struct mipi_dsi_packet packet;
        u8 payload[16] = { 0 };
@@ -987,9 +992,14 @@ static ssize_t rcar_mipi_dsi_host_tx_transfer(struct 
mipi_dsi_host *host,
        if (ret)
                return ret;
 
-       /* Configure LP or HS command transfer. */
-       rcar_mipi_dsi_write(dsi, TXCMSETR, (msg->flags & MIPI_DSI_MSG_USE_LPM) ?
-                                          TXCMSETR_SPDTYP : 0);
+       /* Configure LP or HS and register or AXI command transfer. */
+       rcar_mipi_dsi_write(dsi, TXCMSETR, ((msg->flags & MIPI_DSI_MSG_USE_LPM) 
?
+                                           TXCMSETR_SPDTYP : 0) |
+                                          (is_tx_axi ? TXCMSETR_LPPDACC : 0));
+
+       /* Configure DMA source address for AXI command transfer. */
+       if (is_tx_axi)
+               rcar_mipi_dsi_write(dsi, TXCMADDRSET0R, dsi->cmd_axi_dma);
 
        /* Register access mode for RX transfer. */
        if (is_rx_xfer)
@@ -1011,7 +1021,10 @@ static ssize_t rcar_mipi_dsi_host_tx_transfer(struct 
mipi_dsi_host *host,
                            TXCMPHDR_DATA1(packet.header[2]) |
                            TXCMPHDR_DATA0(packet.header[1]));
 
-       if (is_tx_long) {
+       if (is_tx_axi) {
+               memcpy(dsi->cmd_axi_cpu, packet.payload,
+                      min(msg->tx_len, 128));
+       } else if (is_tx_long) {
                memcpy(payload, packet.payload,
                       min(msg->tx_len, sizeof(payload)));
 
@@ -1162,10 +1175,16 @@ static ssize_t rcar_mipi_dsi_host_transfer(struct 
mipi_dsi_host *host,
        struct rcar_mipi_dsi *dsi = host_to_rcar_mipi_dsi(host);
        int ret;
 
-       if (msg->tx_len > 16 || msg->rx_len > 16) {
-               /* ToDo: Implement Memory on AXI bus command mode. */
+       if (msg->tx_len > 1024 || msg->rx_len > 16) {
+               /* ToDo: Implement Memory on AXI bus RX command mode. */
                dev_warn(dsi->dev,
-                        "Register-based command mode supports only up to 16 
Bytes long payload\n");
+                        "Command mode supports only up to 1024B long TX and 
16B long RX payload\n");
+               return -EOPNOTSUPP;
+       }
+
+       if ((msg->flags & MIPI_DSI_MSG_USE_LPM) && msg->tx_len > 128) {
+               dev_warn(dsi->dev,
+                        "Command mode in LP supports only up to 128B long TX 
payload\n");
                return -EOPNOTSUPP;
        }
 
@@ -1276,6 +1295,13 @@ static int rcar_mipi_dsi_probe(struct platform_device 
*pdev)
        dsi->dev = &pdev->dev;
        dsi->info = of_device_get_match_data(&pdev->dev);
 
+       dsi->cmd_axi_cpu = dma_alloc_coherent(&pdev->dev, SZ_4K, 
&dsi->cmd_axi_dma,
+                                             GFP_KERNEL | GFP_DMA32);
+       if (!dsi->cmd_axi_cpu) {
+               return dev_err_probe(&pdev->dev, -ENOMEM,
+                                    "Failed to allocate DSI AXI Access command 
buffer\n");
+       }
+
        ret = rcar_mipi_dsi_parse_dt(dsi);
        if (ret < 0)
                return ret;
@@ -1309,6 +1335,8 @@ static void rcar_mipi_dsi_remove(struct platform_device 
*pdev)
 {
        struct rcar_mipi_dsi *dsi = platform_get_drvdata(pdev);
 
+       dma_free_coherent(&pdev->dev, SZ_4K, dsi->cmd_axi_cpu, 
dsi->cmd_axi_dma);
+
        mipi_dsi_host_unregister(&dsi->host);
 }
 
-- 
2.53.0

Reply via email to