mirror of https://lore.kernel.org/lkml/
 help / color / mirror / Atom feed
* [PATCH 1/2] drm: rcar-du: rzg2l_mipi_dsi: Implement host transfers
@ 2025-05-20 17:10 Hugo Villeneuve
  2025-05-21  7:43 ` Biju Das
  2025-05-22  4:25 ` kernel test robot
  0 siblings, 2 replies; 4+ messages in thread
From: Hugo Villeneuve @ 2025-05-20 17:10 UTC (permalink / raw)
  To: biju.das.jz, maarten.lankhorst, mripard, tzimmermann, airlied, simona
  Cc: dri-devel, linux-renesas-soc, linux-kernel, hugo,
	Hugo Villeneuve, Chris Brandt

From: Hugo Villeneuve <hvilleneuve@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.jz@bp.renesas.com>
Cc: Chris Brandt <chris.brandt@renesas.com>
Signed-off-by: Hugo Villeneuve <hvilleneuve@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;
+
+	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
+
+/* Sequence Channel 0 Status Register */
+#define SQCH0SR				0x5d0
+#define SQCH0SR_RUNNING			BIT(2)
+#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)
+#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 */
+#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)
+
+/* Sequence Channel 0 Descriptor 0-D Register */
+#define SQCH0DSC0DR			0x78c
+
 #endif /* __RZG2L_MIPI_DSI_REGS_H__ */
-- 
2.39.5


^ permalink raw reply	[flat|nested] 4+ messages in thread

* RE: [PATCH 1/2] drm: rcar-du: rzg2l_mipi_dsi: Implement host transfers
  2025-05-20 17:10 [PATCH 1/2] drm: rcar-du: rzg2l_mipi_dsi: Implement host transfers Hugo Villeneuve
@ 2025-05-21  7:43 ` Biju Das
  2025-05-21 18:51   ` Hugo Villeneuve
  2025-05-22  4:25 ` kernel test robot
  1 sibling, 1 reply; 4+ messages in thread
From: Biju Das @ 2025-05-21  7:43 UTC (permalink / raw)
  To: Hugo Villeneuve, maarten.lankhorst, mripard, tzimmermann,
	airlied, simona
  Cc: dri-devel, linux-renesas-soc, linux-kernel, Hugo Villeneuve,
	Chris Brandt

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-hugo@hugovil.com/

> -----Original Message-----
> From: Hugo Villeneuve <hugo@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

> 
> From: Hugo Villeneuve <hvilleneuve@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.jz@bp.renesas.com>
> Cc: Chris Brandt <chris.brandt@renesas.com>
> Signed-off-by: Hugo Villeneuve <hvilleneuve@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.
 
> +
> +	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.

> +
> +/* 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


^ permalink raw reply	[flat|nested] 4+ messages in thread

* Re: [PATCH 1/2] drm: rcar-du: rzg2l_mipi_dsi: Implement host transfers
  2025-05-21  7:43 ` Biju Das
@ 2025-05-21 18:51   ` Hugo Villeneuve
  0 siblings, 0 replies; 4+ messages in thread
From: Hugo Villeneuve @ 2025-05-21 18:51 UTC (permalink / raw)
  To: Biju Das
  Cc: maarten.lankhorst, mripard, tzimmermann, airlied, simona,
	dri-devel, linux-renesas-soc, linux-kernel, Hugo Villeneuve,
	Chris Brandt

Hi Biju,

On Wed, 21 May 2025 07:43:08 +0000
Biju Das <biju.das.jz@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-hugo@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 <hugo@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 <hvilleneuve@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.jz@bp.renesas.com>
> > Cc: Chris Brandt <chris.brandt@renesas.com>
> > Signed-off-by: Hugo Villeneuve <hvilleneuve@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

^ permalink raw reply	[flat|nested] 4+ messages in thread

* Re: [PATCH 1/2] drm: rcar-du: rzg2l_mipi_dsi: Implement host transfers
  2025-05-20 17:10 [PATCH 1/2] drm: rcar-du: rzg2l_mipi_dsi: Implement host transfers Hugo Villeneuve
  2025-05-21  7:43 ` Biju Das
@ 2025-05-22  4:25 ` kernel test robot
  1 sibling, 0 replies; 4+ messages in thread
From: kernel test robot @ 2025-05-22  4:25 UTC (permalink / raw)
  To: Hugo Villeneuve, biju.das.jz, maarten.lankhorst, mripard,
	tzimmermann, airlied, simona
  Cc: oe-kbuild-all, dri-devel, linux-renesas-soc, linux-kernel, hugo,
	Hugo Villeneuve, Chris Brandt

Hi Hugo,

kernel test robot noticed the following build errors:

[auto build test ERROR on 7c1a9408ce5f34ded5a85db81cf80e0975901685]

url:    https://github.com/intel-lab-lkp/linux/commits/Hugo-Villeneuve/drm-rcar-du-rzg2l_mipi_dsi-Implement-host-transfers/20250521-011613
base:   7c1a9408ce5f34ded5a85db81cf80e0975901685
patch link:    https://lore.kernel.org/r/20250520171034.3488482-2-hugo%40hugovil.com
patch subject: [PATCH 1/2] drm: rcar-du: rzg2l_mipi_dsi: Implement host transfers
config: m68k-allmodconfig (https://download.01.org/0day-ci/archive/20250522/202505221231.A6G8HqGd-lkp@intel.com/config)
compiler: m68k-linux-gcc (GCC) 14.2.0
reproduce (this is a W=1 build): (https://download.01.org/0day-ci/archive/20250522/202505221231.A6G8HqGd-lkp@intel.com/reproduce)

If you fix the issue in a separate patch/commit (i.e. not just a new version of
the same patch/commit), kindly add following tags
| Reported-by: kernel test robot <lkp@intel.com>
| Closes: https://lore.kernel.org/oe-kbuild-all/202505221231.A6G8HqGd-lkp@intel.com/

All errors (new ones prefixed by >>):

   drivers/gpu/drm/renesas/rz-du/rzg2l_mipi_dsi.c: In function 'rzg2l_mipi_dsi_read_response':
>> drivers/gpu/drm/renesas/rz-du/rzg2l_mipi_dsi.c:684:20: error: implicit declaration of function 'FIELD_GET' [-Wimplicit-function-declaration]
     684 |         datatype = FIELD_GET(RXRSS0R_DT, result);
         |                    ^~~~~~~~~
   drivers/gpu/drm/renesas/rz-du/rzg2l_mipi_dsi.c: In function 'rzg2l_mipi_dsi_host_transfer':
>> drivers/gpu/drm/renesas/rz-du/rzg2l_mipi_dsi.c:742:26: error: implicit declaration of function 'FIELD_PREP' [-Wimplicit-function-declaration]
     742 |                 value |= FIELD_PREP(SQCH0DSC0AR_BTA, SQCH0DSC0AR_BTA_NON_READ);
         |                          ^~~~~~~~~~


vim +/FIELD_GET +684 drivers/gpu/drm/renesas/rz-du/rzg2l_mipi_dsi.c

   661	
   662	static ssize_t rzg2l_mipi_dsi_read_response(struct rzg2l_mipi_dsi *dsi,
   663						    const struct mipi_dsi_msg *msg)
   664	{
   665		u8 *msg_rx = msg->rx_buf;
   666		u16 size;
   667		u8 datatype;
   668		u32 result;
   669	
   670		result = rzg2l_mipi_dsi_link_read(dsi, RXRSS0R);
   671		if (result & RXRSS0R_RXPKTDFAIL) {
   672			dev_err(dsi->dev, "packet rx data did not save correctly\n");
   673			return -EPROTO;
   674		}
   675	
   676		if (result & RXRSS0R_RXFAIL) {
   677			dev_err(dsi->dev, "packet rx failure\n");
   678			return -EPROTO;
   679		}
   680	
   681		if (!(result & RXRSS0R_RXSUC))
   682			return -EPROTO;
   683	
 > 684		datatype = FIELD_GET(RXRSS0R_DT, result);
   685	
   686		switch (datatype) {
   687		case 0:
   688			dev_dbg(dsi->dev, "ACK\n");
   689			return 0;
   690		case MIPI_DSI_RX_END_OF_TRANSMISSION:
   691			dev_dbg(dsi->dev, "EoTp\n");
   692			return 0;
   693		case MIPI_DSI_RX_ACKNOWLEDGE_AND_ERROR_REPORT:
   694			dev_dbg(dsi->dev, "Acknowledge and error report: $%02x%02x\n",
   695				(u8)FIELD_GET(RXRSS0R_DATA1, result),
   696				(u8)FIELD_GET(RXRSS0R_DATA0, result));
   697			return 0;
   698		case MIPI_DSI_RX_DCS_SHORT_READ_RESPONSE_1BYTE:
   699		case MIPI_DSI_RX_GENERIC_SHORT_READ_RESPONSE_1BYTE:
   700			msg_rx[0] = FIELD_GET(RXRSS0R_DATA0, result);
   701			return 1;
   702		case MIPI_DSI_RX_DCS_SHORT_READ_RESPONSE_2BYTE:
   703		case MIPI_DSI_RX_GENERIC_SHORT_READ_RESPONSE_2BYTE:
   704			msg_rx[0] = FIELD_GET(RXRSS0R_DATA0, result);
   705			msg_rx[1] = FIELD_GET(RXRSS0R_DATA1, result);
   706			return 2;
   707		case MIPI_DSI_RX_GENERIC_LONG_READ_RESPONSE:
   708		case MIPI_DSI_RX_DCS_LONG_READ_RESPONSE:
   709			size = FIELD_GET(RXRSS0R_WC, result);
   710	
   711			if (size > msg->rx_len) {
   712				dev_err(dsi->dev, "rx buffer too small");
   713				return -ENOSPC;
   714			}
   715	
   716			memcpy(msg_rx, dsi->dcs_buf_virt, size);
   717			return size;
   718		default:
   719			dev_err(dsi->dev, "unhandled response type: %02x\n", datatype);
   720			return -EPROTO;
   721		}
   722	}
   723	
   724	static ssize_t rzg2l_mipi_dsi_host_transfer(struct mipi_dsi_host *host,
   725						    const struct mipi_dsi_msg *msg)
   726	{
   727		struct rzg2l_mipi_dsi *dsi = host_to_rzg2l_mipi_dsi(host);
   728		struct mipi_dsi_packet packet;
   729		bool need_bta;
   730		u32 value;
   731		int ret;
   732	
   733		ret = mipi_dsi_create_packet(&packet, msg);
   734		if (ret < 0)
   735			return ret;
   736	
   737		/* Terminate operation after this descriptor is finished */
   738		value = SQCH0DSC0AR_NXACT_TERM;
   739	
   740		if (msg->flags & MIPI_DSI_MSG_REQ_ACK) {
   741			need_bta = true; /* Message with explicitly requested ACK */
 > 742			value |= FIELD_PREP(SQCH0DSC0AR_BTA, SQCH0DSC0AR_BTA_NON_READ);
   743		} else if (msg->rx_buf && msg->rx_len > 0) {
   744			need_bta = true; /* Read request */
   745			value |= FIELD_PREP(SQCH0DSC0AR_BTA, SQCH0DSC0AR_BTA_READ);
   746		} else {
   747			need_bta = false;
   748			value |= FIELD_PREP(SQCH0DSC0AR_BTA, SQCH0DSC0AR_BTA_NONE);
   749		}
   750	
   751		/* Set transmission speed */
   752		if (msg->flags & MIPI_DSI_MSG_USE_LPM)
   753			value |= SQCH0DSC0AR_SPD_LOW;
   754		else
   755			value |= SQCH0DSC0AR_SPD_HIGH;
   756	
   757		/* Write TX packet header */
   758		value |= FIELD_PREP(SQCH0DSC0AR_DT, packet.header[0]) |
   759			FIELD_PREP(SQCH0DSC0AR_DATA0, packet.header[1]) |
   760			FIELD_PREP(SQCH0DSC0AR_DATA1, packet.header[2]);
   761	
   762		if (mipi_dsi_packet_format_is_long(msg->type)) {
   763			value |= SQCH0DSC0AR_FMT_LONG;
   764	
   765			if (packet.payload_length > RZG2L_DCS_BUF_SIZE) {
   766				dev_err(dsi->dev, "Packet Tx payload size (%d) too large",
   767					(unsigned int)packet.payload_length);
   768				return -ENOSPC;
   769			}
   770	
   771			/* Copy TX packet payload data to memory space */
   772			memcpy(dsi->dcs_buf_virt, packet.payload, packet.payload_length);
   773		} else {
   774			value |= SQCH0DSC0AR_FMT_SHORT;
   775		}
   776	
   777		rzg2l_mipi_dsi_link_write(dsi, SQCH0DSC0AR, value);
   778	
   779		/*
   780		 * Write: specify payload data source location, only used for
   781		 *        long packet.
   782		 * Read:  specify payload data storage location of response
   783		 *        packet. Note: a read packet is always a short packet.
   784		 *        If the response packet is a short packet or a long packet
   785		 *        with WC = 0 (no payload), DTSEL is meaningless.
   786		 */
   787		rzg2l_mipi_dsi_link_write(dsi, SQCH0DSC0BR, SQCH0DSC0BR_DTSEL_MEM_SPACE);
   788	
   789		/*
   790		 * Set SQCHxSR.AACTFIN bit when descriptor actions are finished.
   791		 * Read: set Rx result save slot number to 0 (ACTCODE).
   792		 */
   793		rzg2l_mipi_dsi_link_write(dsi, SQCH0DSC0CR, SQCH0DSC0CR_FINACT);
   794	
   795		/* Set rx/tx payload data address, only relevant for long packet. */
   796		rzg2l_mipi_dsi_link_write(dsi, SQCH0DSC0DR, (u32)dsi->dcs_buf_phys);
   797	
   798		/* Start sequence 0 operation */
   799		value = rzg2l_mipi_dsi_link_read(dsi, SQCH0SET0R);
   800		value |= SQCH0SET0R_START;
   801		rzg2l_mipi_dsi_link_write(dsi, SQCH0SET0R, value);
   802	
   803		/* Wait for operation to finish */
   804		ret = read_poll_timeout(rzg2l_mipi_dsi_link_read,
   805					value, value & SQCH0SR_ADESFIN,
   806					2000, 20000, false, dsi, SQCH0SR);
   807		if (ret == 0) {
   808			/* Success: clear status bit */
   809			rzg2l_mipi_dsi_link_write(dsi, SQCH0SCR, SQCH0SCR_ADESFIN);
   810	
   811			if (need_bta)
   812				ret = rzg2l_mipi_dsi_read_response(dsi, msg);
   813			else
   814				ret = packet.payload_length;
   815		}
   816	
   817		return ret;
   818	}
   819	

-- 
0-DAY CI Kernel Test Service
https://github.com/intel/lkp-tests/wiki

^ permalink raw reply	[flat|nested] 4+ messages in thread

end of thread, other threads:[~2025-05-22  4:27 UTC | newest]

Thread overview: 4+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2025-05-20 17:10 [PATCH 1/2] drm: rcar-du: rzg2l_mipi_dsi: Implement host transfers Hugo Villeneuve
2025-05-21  7:43 ` Biju Das
2025-05-21 18:51   ` Hugo Villeneuve
2025-05-22  4:25 ` kernel test robot

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox

all inboxes | Powered by JetHome®