Hi Biju,

On Wed, 21 May 2025 07:43:08 +0000
Biju Das <biju.das...@bp.renesas.com> wrote:

> Hi Hugo,
> 
> Thanks for the patch.
> 
> For some reason, your cover letter is not showing link to this patch
> [1] https://lore.kernel.org/all/20250520164034.3453315-1-h...@hugovil.com/

My server had problems, and only sent the cover letter, forcing me to
manually send the two remaining patches thinking it would be ok :)

> 
> > -----Original Message-----
> > From: Hugo Villeneuve <h...@hugovil.com>
> > Sent: 20 May 2025 18:11
> > Subject: [PATCH 1/2] drm: rcar-du: rzg2l_mipi_dsi: Implement host transfers
> 
> rcar-du->rz-du

Yes, and other commits use "drm: renesas: rz-du:", so I will change it
to this prefix.


> > From: Hugo Villeneuve <hvillene...@dimonoff.com>
> > 
> > Add support for sending MIPI DSI command packets from the host to a 
> > peripheral. This is required for
> > panels that need configuration before they accept video data.
> > 
> > Based on Renesas Linux kernel v5.10 repos [1].
> 
> > 
> > Link: https://github.com/renesas-rz/rz_linux-cip.git
> > Cc: Biju Das <biju.das...@bp.renesas.com>
> > Cc: Chris Brandt <chris.bra...@renesas.com>
> > Signed-off-by: Hugo Villeneuve <hvillene...@dimonoff.com>
> > ---
> >  .../gpu/drm/renesas/rz-du/rzg2l_mipi_dsi.c    | 174 ++++++++++++++++++
> >  .../drm/renesas/rz-du/rzg2l_mipi_dsi_regs.h   |  56 ++++++
> >  2 files changed, 230 insertions(+)
> > 
> > diff --git a/drivers/gpu/drm/renesas/rz-du/rzg2l_mipi_dsi.c 
> > b/drivers/gpu/drm/renesas/rz-
> > du/rzg2l_mipi_dsi.c
> > index dc6ab012cdb69..77d3a31ff8e35 100644
> > --- a/drivers/gpu/drm/renesas/rz-du/rzg2l_mipi_dsi.c
> > +++ b/drivers/gpu/drm/renesas/rz-du/rzg2l_mipi_dsi.c
> > @@ -6,6 +6,7 @@
> >   */
> >  #include <linux/clk.h>
> >  #include <linux/delay.h>
> > +#include <linux/dma-mapping.h>
> >  #include <linux/io.h>
> >  #include <linux/iopoll.h>
> >  #include <linux/module.h>
> > @@ -23,9 +24,12 @@
> >  #include <drm/drm_of.h>
> >  #include <drm/drm_panel.h>
> >  #include <drm/drm_probe_helper.h>
> > +#include <video/mipi_display.h>
> > 
> >  #include "rzg2l_mipi_dsi_regs.h"
> > 
> > +#define RZG2L_DCS_BUF_SIZE 128 /* Maximum DCS buffer size in external 
> > memory. */
> > +
> >  struct rzg2l_mipi_dsi {
> >     struct device *dev;
> >     void __iomem *mmio;
> > @@ -44,6 +48,10 @@ struct rzg2l_mipi_dsi {
> >     unsigned int num_data_lanes;
> >     unsigned int lanes;
> >     unsigned long mode_flags;
> > +
> > +   /* DCS buffer pointers when using external memory. */
> > +   dma_addr_t dcs_buf_phys;
> > +   u8 *dcs_buf_virt;
> >  };
> > 
> >  static inline struct rzg2l_mipi_dsi *
> > @@ -651,9 +659,168 @@ static int rzg2l_mipi_dsi_host_detach(struct 
> > mipi_dsi_host *host,
> >     return 0;
> >  }
> > 
> > +static ssize_t rzg2l_mipi_dsi_read_response(struct rzg2l_mipi_dsi *dsi,
> > +                                       const struct mipi_dsi_msg *msg) {
> > +   u8 *msg_rx = msg->rx_buf;
> > +   u16 size;
> > +   u8 datatype;
> > +   u32 result;
> 
> Please arrange the variables in reverse xmas tree fashion.

Ok.

  
> > +
> > +   result = rzg2l_mipi_dsi_link_read(dsi, RXRSS0R);
> > +   if (result & RXRSS0R_RXPKTDFAIL) {
> > +           dev_err(dsi->dev, "packet rx data did not save correctly\n");
> > +           return -EPROTO;
> > +   }
> > +
> > +   if (result & RXRSS0R_RXFAIL) {
> > +           dev_err(dsi->dev, "packet rx failure\n");
> > +           return -EPROTO;
> > +   }
> > +
> > +   if (!(result & RXRSS0R_RXSUC))
> > +           return -EPROTO;
> > +
> > +   datatype = FIELD_GET(RXRSS0R_DT, result);
> > +
> > +   switch (datatype) {
> > +   case 0:
> > +           dev_dbg(dsi->dev, "ACK\n");
> > +           return 0;
> > +   case MIPI_DSI_RX_END_OF_TRANSMISSION:
> > +           dev_dbg(dsi->dev, "EoTp\n");
> > +           return 0;
> > +   case MIPI_DSI_RX_ACKNOWLEDGE_AND_ERROR_REPORT:
> > +           dev_dbg(dsi->dev, "Acknowledge and error report: $%02x%02x\n",
> > +                   (u8)FIELD_GET(RXRSS0R_DATA1, result),
> > +                   (u8)FIELD_GET(RXRSS0R_DATA0, result));
> > +           return 0;
> > +   case MIPI_DSI_RX_DCS_SHORT_READ_RESPONSE_1BYTE:
> > +   case MIPI_DSI_RX_GENERIC_SHORT_READ_RESPONSE_1BYTE:
> > +           msg_rx[0] = FIELD_GET(RXRSS0R_DATA0, result);
> > +           return 1;
> > +   case MIPI_DSI_RX_DCS_SHORT_READ_RESPONSE_2BYTE:
> > +   case MIPI_DSI_RX_GENERIC_SHORT_READ_RESPONSE_2BYTE:
> > +           msg_rx[0] = FIELD_GET(RXRSS0R_DATA0, result);
> > +           msg_rx[1] = FIELD_GET(RXRSS0R_DATA1, result);
> > +           return 2;
> > +   case MIPI_DSI_RX_GENERIC_LONG_READ_RESPONSE:
> > +   case MIPI_DSI_RX_DCS_LONG_READ_RESPONSE:
> > +           size = FIELD_GET(RXRSS0R_WC, result);
> > +
> > +           if (size > msg->rx_len) {
> > +                   dev_err(dsi->dev, "rx buffer too small");
> > +                   return -ENOSPC;
> > +           }
> > +
> > +           memcpy(msg_rx, dsi->dcs_buf_virt, size);
> > +           return size;
> > +   default:
> > +           dev_err(dsi->dev, "unhandled response type: %02x\n", datatype);
> > +           return -EPROTO;
> > +   }
> > +}
> > +
> > +static ssize_t rzg2l_mipi_dsi_host_transfer(struct mipi_dsi_host *host,
> > +                                       const struct mipi_dsi_msg *msg) {
> > +   struct rzg2l_mipi_dsi *dsi = host_to_rzg2l_mipi_dsi(host);
> > +   struct mipi_dsi_packet packet;
> > +   bool need_bta;
> > +   u32 value;
> > +   int ret;
> > +
> > +   ret = mipi_dsi_create_packet(&packet, msg);
> > +   if (ret < 0)
> > +           return ret;
> > +
> > +   /* Terminate operation after this descriptor is finished */
> > +   value = SQCH0DSC0AR_NXACT_TERM;
> > +
> > +   if (msg->flags & MIPI_DSI_MSG_REQ_ACK) {
> > +           need_bta = true; /* Message with explicitly requested ACK */
> > +           value |= FIELD_PREP(SQCH0DSC0AR_BTA, SQCH0DSC0AR_BTA_NON_READ);
> > +   } else if (msg->rx_buf && msg->rx_len > 0) {
> > +           need_bta = true; /* Read request */
> > +           value |= FIELD_PREP(SQCH0DSC0AR_BTA, SQCH0DSC0AR_BTA_READ);
> > +   } else {
> > +           need_bta = false;
> > +           value |= FIELD_PREP(SQCH0DSC0AR_BTA, SQCH0DSC0AR_BTA_NONE);
> > +   }
> > +
> > +   /* Set transmission speed */
> > +   if (msg->flags & MIPI_DSI_MSG_USE_LPM)
> > +           value |= SQCH0DSC0AR_SPD_LOW;
> > +   else
> > +           value |= SQCH0DSC0AR_SPD_HIGH;
> > +
> > +   /* Write TX packet header */
> > +   value |= FIELD_PREP(SQCH0DSC0AR_DT, packet.header[0]) |
> > +           FIELD_PREP(SQCH0DSC0AR_DATA0, packet.header[1]) |
> > +           FIELD_PREP(SQCH0DSC0AR_DATA1, packet.header[2]);
> > +
> > +   if (mipi_dsi_packet_format_is_long(msg->type)) {
> > +           value |= SQCH0DSC0AR_FMT_LONG;
> > +
> > +           if (packet.payload_length > RZG2L_DCS_BUF_SIZE) {
> > +                   dev_err(dsi->dev, "Packet Tx payload size (%d) too 
> > large",
> > +                           (unsigned int)packet.payload_length);
> > +                   return -ENOSPC;
> > +           }
> > +
> > +           /* Copy TX packet payload data to memory space */
> > +           memcpy(dsi->dcs_buf_virt, packet.payload, 
> > packet.payload_length);
> > +   } else {
> > +           value |= SQCH0DSC0AR_FMT_SHORT;
> > +   }
> > +
> > +   rzg2l_mipi_dsi_link_write(dsi, SQCH0DSC0AR, value);
> > +
> > +   /*
> > +    * Write: specify payload data source location, only used for
> > +    *        long packet.
> > +    * Read:  specify payload data storage location of response
> > +    *        packet. Note: a read packet is always a short packet.
> > +    *        If the response packet is a short packet or a long packet
> > +    *        with WC = 0 (no payload), DTSEL is meaningless.
> > +    */
> > +   rzg2l_mipi_dsi_link_write(dsi, SQCH0DSC0BR,
> > +SQCH0DSC0BR_DTSEL_MEM_SPACE);
> > +
> > +   /*
> > +    * Set SQCHxSR.AACTFIN bit when descriptor actions are finished.
> > +    * Read: set Rx result save slot number to 0 (ACTCODE).
> > +    */
> > +   rzg2l_mipi_dsi_link_write(dsi, SQCH0DSC0CR, SQCH0DSC0CR_FINACT);
> > +
> > +   /* Set rx/tx payload data address, only relevant for long packet. */
> > +   rzg2l_mipi_dsi_link_write(dsi, SQCH0DSC0DR, (u32)dsi->dcs_buf_phys);
> > +
> > +   /* Start sequence 0 operation */
> > +   value = rzg2l_mipi_dsi_link_read(dsi, SQCH0SET0R);
> > +   value |= SQCH0SET0R_START;
> > +   rzg2l_mipi_dsi_link_write(dsi, SQCH0SET0R, value);
> > +
> > +   /* Wait for operation to finish */
> > +   ret = read_poll_timeout(rzg2l_mipi_dsi_link_read,
> > +                           value, value & SQCH0SR_ADESFIN,
> > +                           2000, 20000, false, dsi, SQCH0SR);
> > +   if (ret == 0) {
> > +           /* Success: clear status bit */
> > +           rzg2l_mipi_dsi_link_write(dsi, SQCH0SCR, SQCH0SCR_ADESFIN);
> > +
> > +           if (need_bta)
> > +                   ret = rzg2l_mipi_dsi_read_response(dsi, msg);
> > +           else
> > +                   ret = packet.payload_length;
> > +   }
> > +
> > +   return ret;
> > +}
> > +
> >  static const struct mipi_dsi_host_ops rzg2l_mipi_dsi_host_ops = {
> >     .attach = rzg2l_mipi_dsi_host_attach,
> >     .detach = rzg2l_mipi_dsi_host_detach,
> > +   .transfer = rzg2l_mipi_dsi_host_transfer,
> >  };
> > 
> >  /* 
> > -----------------------------------------------------------------------------
> > @@ -771,6 +938,11 @@ static int rzg2l_mipi_dsi_probe(struct platform_device 
> > *pdev)
> >     if (ret < 0)
> >             goto err_pm_disable;
> > 
> > +   dsi->dcs_buf_virt = dma_alloc_coherent(dsi->host.dev, 
> > RZG2L_DCS_BUF_SIZE,
> > +                                          &dsi->dcs_buf_phys, GFP_KERNEL);
> > +   if (!dsi->dcs_buf_virt)
> > +           return -ENOMEM;
> > +
> >     return 0;
> > 
> >  err_phy:
> > @@ -785,6 +957,8 @@ static void rzg2l_mipi_dsi_remove(struct 
> > platform_device *pdev)  {
> >     struct rzg2l_mipi_dsi *dsi = platform_get_drvdata(pdev);
> > 
> > +   dma_free_coherent(dsi->host.dev, RZG2L_DCS_BUF_SIZE, dsi->dcs_buf_virt,
> > +                     dsi->dcs_buf_phys);
> >     mipi_dsi_host_unregister(&dsi->host);
> >     pm_runtime_disable(&pdev->dev);
> >  }
> > diff --git a/drivers/gpu/drm/renesas/rz-du/rzg2l_mipi_dsi_regs.h 
> > b/drivers/gpu/drm/renesas/rz-
> > du/rzg2l_mipi_dsi_regs.h
> > index 1dbc16ec64a4b..33cd669bc74b1 100644
> > --- a/drivers/gpu/drm/renesas/rz-du/rzg2l_mipi_dsi_regs.h
> > +++ b/drivers/gpu/drm/renesas/rz-du/rzg2l_mipi_dsi_regs.h
> > @@ -81,6 +81,16 @@
> >  #define RSTSR_SWRSTLP                      (1 << 1)
> >  #define RSTSR_SWRSTHS                      (1 << 0)
> > 
> > +/* Rx Result Save Slot 0 Register */
> > +#define RXRSS0R                            0x240
> > +#define RXRSS0R_RXPKTDFAIL         BIT(28)
> > +#define RXRSS0R_RXFAIL                     BIT(27)
> > +#define RXRSS0R_RXSUC                      BIT(25)
> > +#define RXRSS0R_DT                 GENMASK(21, 16)
> > +#define RXRSS0R_DATA1                      GENMASK(15, 8)
> > +#define RXRSS0R_DATA0                      GENMASK(7, 0)
> > +#define RXRSS0R_WC                 GENMASK(15, 0) /* Word count for long 
> > packet. */
> > +
> >  /* Clock Lane Stop Time Set Register */
> >  #define CLSTPTSETR                 0x314
> >  #define CLSTPTSETR_CLKKPT(x)               ((x) << 24)
> > @@ -148,4 +158,50 @@
> >  #define VICH1HPSETR_HFP(x)         (((x) & 0x1fff) << 16)
> >  #define VICH1HPSETR_HBP(x)         (((x) & 0x1fff) << 0)
> > 
> > +/* Sequence Channel 0 Set 0 Register */
> > +#define SQCH0SET0R                 0x5c0
> > +#define SQCH0SET0R_START           BIT(0)
> > +
> > +/* Sequence Channel 0 Set 1 Register */
> > +#define SQCH0SET1R                 0x5c4
> 
> Unused. Drop it.

Ok, will remove all unused macros.

> 
> > +
> > +/* Sequence Channel 0 Status Register */
> > +#define SQCH0SR                            0x5d0
> > +#define SQCH0SR_RUNNING                    BIT(2)
> Unused
> 
> > +#define SQCH0SR_ADESFIN                    BIT(8)
> > +
> > +/* Sequence Channel 0 Status Clear Register */
> > +#define SQCH0SCR                   0x5d4
> > +#define SQCH0SCR_ADESFIN           BIT(8)
> > +
> > +/* Sequence Channel 0 Descriptor 0-A Register */
> > +#define SQCH0DSC0AR                        0x780
> > +#define SQCH0DSC0AR_NXACT_TERM             0
> > +#define SQCH0DSC0AR_NXACT_OPER             BIT(28)
> Unused
> 
> > +#define SQCH0DSC0AR_BTA                    GENMASK(27, 26)
> > +#define SQCH0DSC0AR_BTA_NONE               0
> > +#define SQCH0DSC0AR_BTA_NON_READ   1
> > +#define SQCH0DSC0AR_BTA_READ               2
> > +#define SQCH0DSC0AR_BTA_ONLY               3
> > +#define SQCH0DSC0AR_SPD_HIGH               0
> > +#define SQCH0DSC0AR_SPD_LOW                BIT(25)
> > +#define SQCH0DSC0AR_FMT_SHORT              0
> > +#define SQCH0DSC0AR_FMT_LONG               BIT(24)
> > +#define SQCH0DSC0AR_DT                     GENMASK(21, 16)
> > +#define SQCH0DSC0AR_DATA1          GENMASK(15, 8)
> > +#define SQCH0DSC0AR_DATA0          GENMASK(7, 0)
> > +
> > +/* Sequence Channel 0 Descriptor 0-B Register */
> > +#define SQCH0DSC0BR                        0x784
> > +#define SQCH0DSC0BR_DTSEL_PAYLOAD_DR       0       /* Use packet payload 
> > data register */
> Unused
> 
> > +#define SQCH0DSC0BR_DTSEL_MEM_SPACE        BIT(24) /* Use external memory 
> > */
> > +
> > +/* Sequence Channel 0 Descriptor 0-C Register */
> > +#define SQCH0DSC0CR                        0x788
> > +#define SQCH0DSC0CR_FINACT         BIT(0)
> > +#define SQCH0DSC0CR_AUXOP          BIT(22)
> Unused
> 
> > +
> > +/* Sequence Channel 0 Descriptor 0-D Register */
> > +#define SQCH0DSC0DR                        0x78c
> > +
> 
> Cheers,
> Biju
> 
> >  #endif /* __RZG2L_MIPI_DSI_REGS_H__ */
> > --
> > 2.39.5
> 
> 


-- 
Hugo Villeneuve

Reply via email to