* [PATCH v2 0/2] media: Add line end IRQ to imx-mipi-csis driver
@ 2025-06-06 15:44 Isaac Scott
2025-06-06 15:44 ` [PATCH v2 1/2] media: platform: Refactor interrupt status registers Isaac Scott
` (2 more replies)
0 siblings, 3 replies; 6+ messages in thread
From: Isaac Scott @ 2025-06-06 15:44 UTC (permalink / raw)
To: laurent.pinchart
Cc: kieran.bingham, rmfrfs, martink, kernel, mchehab, shawnguo,
s.hauer, kernel, festevam, linux-media, imx, linux-arm-kernel,
linux-kernel, Isaac Scott
Many boards, such as the NXP i.MX 8M Plus, feature multiple interrupt
registers. This series refactors interrupt status register debug handling to make
it more intuitive to add other registers such as LINE_END, which has an
entire register containing only one interrupt. Previously, the
mipi_csi_events[] list contained a debug enable field, and this replaces
that with a status_index, which indicates which status register contains
the mask for the interrupt.
The second patch adds the user line interrupt, which is useful for
debugging, as it allows a user to trigger an interrupt after the MIPI
CSI receiver has counted a configurable number of lines. This can make
it possible to discern the true resolution of the image stream reaching
the CSI receiver. It adds an entry to debugfs which lets users choose
how many lines are needed to trigger the interrupt, and can be disabled
both within and outside streaming by setting the value to 0.
---
Changes since v1:
- Moved from magic number to enum in status_index
- Clear INT_MSK_1 in enable_interrupts() when on == false
- use local variable in set_params() as in the interrupt handler
- move interrupt handling code outside of spinlock
Isaac Scott (2):
media: platform: Refactor interrupt status registers
media: platform: Add user line interrupt to imx-mipi-csis driver
drivers/media/platform/nxp/imx-mipi-csis.c | 107 ++++++++++++++-------
1 file changed, 74 insertions(+), 33 deletions(-)
--
2.43.0
^ permalink raw reply [flat|nested] 6+ messages in thread
* [PATCH v2 1/2] media: platform: Refactor interrupt status registers
2025-06-06 15:44 [PATCH v2 0/2] media: Add line end IRQ to imx-mipi-csis driver Isaac Scott
@ 2025-06-06 15:44 ` Isaac Scott
2025-06-07 18:38 ` Laurent Pinchart
2025-06-06 15:44 ` [PATCH v2 2/2] media: platform: Add user line interrupt to imx-mipi-csis driver Isaac Scott
2025-06-06 16:17 ` [PATCH v2 0/2] media: Add line end IRQ " Rui Miguel Silva
2 siblings, 1 reply; 6+ messages in thread
From: Isaac Scott @ 2025-06-06 15:44 UTC (permalink / raw)
To: laurent.pinchart
Cc: kieran.bingham, rmfrfs, martink, kernel, mchehab, shawnguo,
s.hauer, kernel, festevam, linux-media, imx, linux-arm-kernel,
linux-kernel, Isaac Scott
The NXP i.MX 8 MP CSI-2 receiver features multiple interrupt and debug
status sources which span multiple registers. The driver currently
supports two interrupt source registers, and attributes the
mipi_csis_event event entries to those registers through a boolean debug
field that indicate if the event relates to the main interrupt status
(false) or debug interrupt status (true) register. To make it easier to
add new event fields, replace the debug bool with a 'status index'
integer than indicates the index of the corresponding status register.
Signed-off-by: Isaac Scott <isaac.scott@ideasonboard.com>
Reviewed-by: Laurent Pinchart <laurent.pinchart@ideasonboard.com>
---
Changes since v1:
- Switched from magic numbers to enum.
---
drivers/media/platform/nxp/imx-mipi-csis.c | 69 +++++++++++-----------
1 file changed, 36 insertions(+), 33 deletions(-)
diff --git a/drivers/media/platform/nxp/imx-mipi-csis.c b/drivers/media/platform/nxp/imx-mipi-csis.c
index d060eadebc7a..394987d72c64 100644
--- a/drivers/media/platform/nxp/imx-mipi-csis.c
+++ b/drivers/media/platform/nxp/imx-mipi-csis.c
@@ -248,8 +248,13 @@
#define MIPI_CSI2_DATA_TYPE_RAW14 0x2d
#define MIPI_CSI2_DATA_TYPE_USER(x) (0x30 + (x))
+enum mipi_csis_event_type {
+ MAIN = 0,
+ DEBUG = 1,
+};
+
struct mipi_csis_event {
- bool debug;
+ enum mipi_csis_event_type status_index;
u32 mask;
const char * const name;
unsigned int counter;
@@ -257,30 +262,30 @@ struct mipi_csis_event {
static const struct mipi_csis_event mipi_csis_events[] = {
/* Errors */
- { false, MIPI_CSIS_INT_SRC_ERR_SOT_HS, "SOT Error" },
- { false, MIPI_CSIS_INT_SRC_ERR_LOST_FS, "Lost Frame Start Error" },
- { false, MIPI_CSIS_INT_SRC_ERR_LOST_FE, "Lost Frame End Error" },
- { false, MIPI_CSIS_INT_SRC_ERR_OVER, "FIFO Overflow Error" },
- { false, MIPI_CSIS_INT_SRC_ERR_WRONG_CFG, "Wrong Configuration Error" },
- { false, MIPI_CSIS_INT_SRC_ERR_ECC, "ECC Error" },
- { false, MIPI_CSIS_INT_SRC_ERR_CRC, "CRC Error" },
- { false, MIPI_CSIS_INT_SRC_ERR_UNKNOWN, "Unknown Error" },
- { true, MIPI_CSIS_DBG_INTR_SRC_DT_NOT_SUPPORT, "Data Type Not Supported" },
- { true, MIPI_CSIS_DBG_INTR_SRC_DT_IGNORE, "Data Type Ignored" },
- { true, MIPI_CSIS_DBG_INTR_SRC_ERR_FRAME_SIZE, "Frame Size Error" },
- { true, MIPI_CSIS_DBG_INTR_SRC_TRUNCATED_FRAME, "Truncated Frame" },
- { true, MIPI_CSIS_DBG_INTR_SRC_EARLY_FE, "Early Frame End" },
- { true, MIPI_CSIS_DBG_INTR_SRC_EARLY_FS, "Early Frame Start" },
+ { MAIN, MIPI_CSIS_INT_SRC_ERR_SOT_HS, "SOT Error"},
+ { MAIN, MIPI_CSIS_INT_SRC_ERR_LOST_FS, "Lost Frame Start Error"},
+ { MAIN, MIPI_CSIS_INT_SRC_ERR_LOST_FE, "Lost Frame End Error"},
+ { MAIN, MIPI_CSIS_INT_SRC_ERR_OVER, "FIFO Overflow Error"},
+ { MAIN, MIPI_CSIS_INT_SRC_ERR_WRONG_CFG, "Wrong Configuration Error"},
+ { MAIN, MIPI_CSIS_INT_SRC_ERR_ECC, "ECC Error"},
+ { MAIN, MIPI_CSIS_INT_SRC_ERR_CRC, "CRC Error"},
+ { MAIN, MIPI_CSIS_INT_SRC_ERR_UNKNOWN, "Unknown Error"},
+ { DEBUG, MIPI_CSIS_DBG_INTR_SRC_DT_NOT_SUPPORT, "Data Type Not Supported"},
+ { DEBUG, MIPI_CSIS_DBG_INTR_SRC_DT_IGNORE, "Data Type Ignored"},
+ { DEBUG, MIPI_CSIS_DBG_INTR_SRC_ERR_FRAME_SIZE, "Frame Size Error"},
+ { DEBUG, MIPI_CSIS_DBG_INTR_SRC_TRUNCATED_FRAME, "Truncated Frame"},
+ { DEBUG, MIPI_CSIS_DBG_INTR_SRC_EARLY_FE, "Early Frame End"},
+ { DEBUG, MIPI_CSIS_DBG_INTR_SRC_EARLY_FS, "Early Frame Start"},
/* Non-image data receive events */
- { false, MIPI_CSIS_INT_SRC_EVEN_BEFORE, "Non-image data before even frame" },
- { false, MIPI_CSIS_INT_SRC_EVEN_AFTER, "Non-image data after even frame" },
- { false, MIPI_CSIS_INT_SRC_ODD_BEFORE, "Non-image data before odd frame" },
- { false, MIPI_CSIS_INT_SRC_ODD_AFTER, "Non-image data after odd frame" },
+ { MAIN, MIPI_CSIS_INT_SRC_EVEN_BEFORE, "Non-image data before even frame"},
+ { MAIN, MIPI_CSIS_INT_SRC_EVEN_AFTER, "Non-image data after even frame"},
+ { MAIN, MIPI_CSIS_INT_SRC_ODD_BEFORE, "Non-image data before odd frame"},
+ { MAIN, MIPI_CSIS_INT_SRC_ODD_AFTER, "Non-image data after odd frame"},
/* Frame start/end */
- { false, MIPI_CSIS_INT_SRC_FRAME_START, "Frame Start" },
- { false, MIPI_CSIS_INT_SRC_FRAME_END, "Frame End" },
- { true, MIPI_CSIS_DBG_INTR_SRC_CAM_VSYNC_FALL, "VSYNC Falling Edge" },
- { true, MIPI_CSIS_DBG_INTR_SRC_CAM_VSYNC_RISE, "VSYNC Rising Edge" },
+ { MAIN, MIPI_CSIS_INT_SRC_FRAME_START, "Frame Start"},
+ { MAIN, MIPI_CSIS_INT_SRC_FRAME_END, "Frame End"},
+ { DEBUG, MIPI_CSIS_DBG_INTR_SRC_CAM_VSYNC_FALL, "VSYNC Falling Edge"},
+ { DEBUG, MIPI_CSIS_DBG_INTR_SRC_CAM_VSYNC_RISE, "VSYNC Rising Edge"},
};
#define MIPI_CSIS_NUM_EVENTS ARRAY_SIZE(mipi_csis_events)
@@ -765,32 +770,30 @@ static irqreturn_t mipi_csis_irq_handler(int irq, void *dev_id)
struct mipi_csis_device *csis = dev_id;
unsigned long flags;
unsigned int i;
- u32 status;
- u32 dbg_status;
+ u32 status[2];
- status = mipi_csis_read(csis, MIPI_CSIS_INT_SRC);
- dbg_status = mipi_csis_read(csis, MIPI_CSIS_DBG_INTR_SRC);
+ status[MAIN] = mipi_csis_read(csis, MIPI_CSIS_INT_SRC);
+ status[DEBUG] = mipi_csis_read(csis, MIPI_CSIS_DBG_INTR_SRC);
spin_lock_irqsave(&csis->slock, flags);
/* Update the event/error counters */
- if ((status & MIPI_CSIS_INT_SRC_ERRORS) || csis->debug.enable) {
+ if ((status[MAIN] & MIPI_CSIS_INT_SRC_ERRORS) || csis->debug.enable) {
for (i = 0; i < MIPI_CSIS_NUM_EVENTS; i++) {
struct mipi_csis_event *event = &csis->events[i];
- if ((!event->debug && (status & event->mask)) ||
- (event->debug && (dbg_status & event->mask)))
+ if (status[event->status_index] & event->mask)
event->counter++;
}
}
- if (status & MIPI_CSIS_INT_SRC_FRAME_START)
+ if (status[MAIN] & MIPI_CSIS_INT_SRC_FRAME_START)
mipi_csis_queue_event_sof(csis);
spin_unlock_irqrestore(&csis->slock, flags);
- mipi_csis_write(csis, MIPI_CSIS_INT_SRC, status);
- mipi_csis_write(csis, MIPI_CSIS_DBG_INTR_SRC, dbg_status);
+ mipi_csis_write(csis, MIPI_CSIS_INT_SRC, status[MAIN]);
+ mipi_csis_write(csis, MIPI_CSIS_DBG_INTR_SRC, status[DEBUG]);
return IRQ_HANDLED;
}
--
2.43.0
^ permalink raw reply related [flat|nested] 6+ messages in thread
* [PATCH v2 2/2] media: platform: Add user line interrupt to imx-mipi-csis driver
2025-06-06 15:44 [PATCH v2 0/2] media: Add line end IRQ to imx-mipi-csis driver Isaac Scott
2025-06-06 15:44 ` [PATCH v2 1/2] media: platform: Refactor interrupt status registers Isaac Scott
@ 2025-06-06 15:44 ` Isaac Scott
2025-06-07 18:45 ` Laurent Pinchart
2025-06-06 16:17 ` [PATCH v2 0/2] media: Add line end IRQ " Rui Miguel Silva
2 siblings, 1 reply; 6+ messages in thread
From: Isaac Scott @ 2025-06-06 15:44 UTC (permalink / raw)
To: laurent.pinchart
Cc: kieran.bingham, rmfrfs, martink, kernel, mchehab, shawnguo,
s.hauer, kernel, festevam, linux-media, imx, linux-arm-kernel,
linux-kernel, Isaac Scott
The NXP i.MX 8M Plus features an interrupt that triggers after the MIPI
CSI receiver counts a user-configurable number of lines. This is useful
for debugging, as it allows users to check if the amount of lines per
frame equals what they are expecting.
Add support for this interrupt in the driver, and an entry into debugfs
to allow the user to configure whether the interrupt is enabled, as well
as the number of lines after which to trigger the interrupt.
This debugfs control can be altered while a stream is in progress, with
0 disabling the interrupt and >0 setting a new desired line count.
Signed-off-by: Isaac Scott <isaac.scott@ideasonboard.com>
---
Changes since v1:
- Moved from magic number to enum in status_index
- Clear INT_MSK_1 in enable_interrupts() when on == false
- use local variable in set_params() as in the interrupt handler
- move interrupt handling code outside of spinlock
---
drivers/media/platform/nxp/imx-mipi-csis.c | 40 +++++++++++++++++++++-
1 file changed, 39 insertions(+), 1 deletion(-)
diff --git a/drivers/media/platform/nxp/imx-mipi-csis.c b/drivers/media/platform/nxp/imx-mipi-csis.c
index 394987d72c64..1b71f6c19fa8 100644
--- a/drivers/media/platform/nxp/imx-mipi-csis.c
+++ b/drivers/media/platform/nxp/imx-mipi-csis.c
@@ -88,6 +88,10 @@
#define MIPI_CSIS_INT_MSK_ERR_CRC BIT(1)
#define MIPI_CSIS_INT_MSK_ERR_UNKNOWN BIT(0)
+/* CSIS Interrupt mask 1 */
+#define MIPI_CSIS_INT_MSK_1 0x18
+#define MIPI_CSIS_INT_MSK_1_LINE_END BIT(0)
+
/* CSIS Interrupt source */
#define MIPI_CSIS_INT_SRC 0x14
#define MIPI_CSIS_INT_SRC_EVEN_BEFORE BIT(31)
@@ -109,6 +113,10 @@
#define MIPI_CSIS_INT_SRC_ERR_UNKNOWN BIT(0)
#define MIPI_CSIS_INT_SRC_ERRORS 0xfffff
+/* CSIS Interrupt source 1 */
+#define MIPI_CSIS_INT_SRC_1 0x1c
+#define MIPI_CSIS_INT_SRC_1_LINE_END BIT(0)
+
/* D-PHY status control */
#define MIPI_CSIS_DPHY_STATUS 0x20
#define MIPI_CSIS_DPHY_STATUS_ULPS_DAT BIT(8)
@@ -221,6 +229,7 @@
#define MIPI_CSIS_DBG_INTR_SRC_CAM_VSYNC_RISE BIT(0)
#define MIPI_CSIS_FRAME_COUNTER_CH(n) (0x0100 + (n) * 4)
+#define MIPI_CSIS_LINE_INTERRUPT_RATIO(n) (0x0110 + (n) * 4)
/* Non-image packet data buffers */
#define MIPI_CSIS_PKTDATA_ODD 0x2000
@@ -251,6 +260,7 @@
enum mipi_csis_event_type {
MAIN = 0,
DEBUG = 1,
+ USER = 2,
};
struct mipi_csis_event {
@@ -286,6 +296,8 @@ static const struct mipi_csis_event mipi_csis_events[] = {
{ MAIN, MIPI_CSIS_INT_SRC_FRAME_END, "Frame End"},
{ DEBUG, MIPI_CSIS_DBG_INTR_SRC_CAM_VSYNC_FALL, "VSYNC Falling Edge"},
{ DEBUG, MIPI_CSIS_DBG_INTR_SRC_CAM_VSYNC_RISE, "VSYNC Rising Edge"},
+ /* User Line interrupt */
+ { USER, MIPI_CSIS_INT_SRC_1_LINE_END, "Line End"}
};
#define MIPI_CSIS_NUM_EVENTS ARRAY_SIZE(mipi_csis_events)
@@ -338,11 +350,14 @@ struct mipi_csis_device {
spinlock_t slock; /* Protect events */
struct mipi_csis_event events[MIPI_CSIS_NUM_EVENTS];
+
struct dentry *debugfs_root;
struct {
bool enable;
u32 hs_settle;
u32 clk_settle;
+ u32 int_line;
+ u32 last_int_line;
} debug;
};
@@ -533,6 +548,8 @@ static void mipi_csis_enable_interrupts(struct mipi_csis_device *csis, bool on)
{
mipi_csis_write(csis, MIPI_CSIS_INT_MSK, on ? 0xffffffff : 0);
mipi_csis_write(csis, MIPI_CSIS_DBG_INTR_MSK, on ? 0xffffffff : 0);
+ mipi_csis_write(csis, MIPI_CSIS_INT_MSK_1,
+ on ? MIPI_CSIS_INT_MSK_1_LINE_END : 0);
}
static void mipi_csis_sw_reset(struct mipi_csis_device *csis)
@@ -655,6 +672,7 @@ static void mipi_csis_set_params(struct mipi_csis_device *csis,
const struct csis_pix_format *csis_fmt)
{
int lanes = csis->bus.num_data_lanes;
+ u32 int_lines;
u32 val;
val = mipi_csis_read(csis, MIPI_CSIS_CMN_CTRL);
@@ -691,6 +709,13 @@ static void mipi_csis_set_params(struct mipi_csis_device *csis,
MIPI_CSIS_DPHY_BCTRL_L_B_DPHYCTRL(20000000));
mipi_csis_write(csis, MIPI_CSIS_DPHY_BCTRL_H, 0);
+ int_lines = READ_ONCE(csis->debug.int_line);
+ if (int_lines > 0)
+ mipi_csis_write(csis, MIPI_CSIS_LINE_INTERRUPT_RATIO(0),
+ max(int_lines, 1U) - 1);
+
+ csis->debug.last_int_line = int_lines;
+
/* Update the shadow register. */
val = mipi_csis_read(csis, MIPI_CSIS_CMN_CTRL);
mipi_csis_write(csis, MIPI_CSIS_CMN_CTRL,
@@ -770,10 +795,12 @@ static irqreturn_t mipi_csis_irq_handler(int irq, void *dev_id)
struct mipi_csis_device *csis = dev_id;
unsigned long flags;
unsigned int i;
- u32 status[2];
+ u32 int_lines;
+ u32 status[3];
status[MAIN] = mipi_csis_read(csis, MIPI_CSIS_INT_SRC);
status[DEBUG] = mipi_csis_read(csis, MIPI_CSIS_DBG_INTR_SRC);
+ status[USER] = mipi_csis_read(csis, MIPI_CSIS_INT_SRC_1);
spin_lock_irqsave(&csis->slock, flags);
@@ -792,8 +819,16 @@ static irqreturn_t mipi_csis_irq_handler(int irq, void *dev_id)
spin_unlock_irqrestore(&csis->slock, flags);
+ int_lines = READ_ONCE(csis->debug.int_line);
+ if (int_lines != csis->debug.last_int_line) {
+ mipi_csis_write(csis, MIPI_CSIS_LINE_INTERRUPT_RATIO(0),
+ max(int_lines, 1U) - 1);
+ csis->debug.last_int_line = int_lines;
+ }
+
mipi_csis_write(csis, MIPI_CSIS_INT_SRC, status[MAIN]);
mipi_csis_write(csis, MIPI_CSIS_DBG_INTR_SRC, status[DEBUG]);
+ mipi_csis_write(csis, MIPI_CSIS_INT_SRC_1, status[USER]);
return IRQ_HANDLED;
}
@@ -933,6 +968,7 @@ static void mipi_csis_debugfs_init(struct mipi_csis_device *csis)
{
csis->debug.hs_settle = UINT_MAX;
csis->debug.clk_settle = UINT_MAX;
+ csis->debug.int_line = 0;
csis->debugfs_root = debugfs_create_dir(dev_name(csis->dev), NULL);
@@ -944,6 +980,8 @@ static void mipi_csis_debugfs_init(struct mipi_csis_device *csis)
&csis->debug.clk_settle);
debugfs_create_u32("ths_settle", 0600, csis->debugfs_root,
&csis->debug.hs_settle);
+ debugfs_create_u32("int_line_0", 0600, csis->debugfs_root,
+ &csis->debug.int_line);
}
static void mipi_csis_debugfs_exit(struct mipi_csis_device *csis)
--
2.43.0
^ permalink raw reply related [flat|nested] 6+ messages in thread
* Re: [PATCH v2 0/2] media: Add line end IRQ to imx-mipi-csis driver
2025-06-06 15:44 [PATCH v2 0/2] media: Add line end IRQ to imx-mipi-csis driver Isaac Scott
2025-06-06 15:44 ` [PATCH v2 1/2] media: platform: Refactor interrupt status registers Isaac Scott
2025-06-06 15:44 ` [PATCH v2 2/2] media: platform: Add user line interrupt to imx-mipi-csis driver Isaac Scott
@ 2025-06-06 16:17 ` Rui Miguel Silva
2 siblings, 0 replies; 6+ messages in thread
From: Rui Miguel Silva @ 2025-06-06 16:17 UTC (permalink / raw)
To: Isaac Scott, laurent.pinchart
Cc: kieran.bingham, rmfrfs, martink, kernel, mchehab, shawnguo,
s.hauer, kernel, festevam, linux-media, imx, linux-arm-kernel,
linux-kernel
Hi Isaac,
Many thanks for the patches.
On Fri Jun 6, 2025 at 4:44 PM WEST, Isaac Scott wrote:
> Many boards, such as the NXP i.MX 8M Plus, feature multiple interrupt
> registers. This series refactors interrupt status register debug handling to make
> it more intuitive to add other registers such as LINE_END, which has an
> entire register containing only one interrupt. Previously, the
> mipi_csi_events[] list contained a debug enable field, and this replaces
> that with a status_index, which indicates which status register contains
> the mask for the interrupt.
>
> The second patch adds the user line interrupt, which is useful for
> debugging, as it allows a user to trigger an interrupt after the MIPI
> CSI receiver has counted a configurable number of lines. This can make
> it possible to discern the true resolution of the image stream reaching
> the CSI receiver. It adds an entry to debugfs which lets users choose
> how many lines are needed to trigger the interrupt, and can be disabled
> both within and outside streaming by setting the value to 0.
LGTM.
for the all series:
Reviewed-by: Rui Miguel Silva <rui.silva@linaro.org>
Cheers,
Rui
>
> ---
>
> Changes since v1:
> - Moved from magic number to enum in status_index
> - Clear INT_MSK_1 in enable_interrupts() when on == false
> - use local variable in set_params() as in the interrupt handler
> - move interrupt handling code outside of spinlock
>
> Isaac Scott (2):
> media: platform: Refactor interrupt status registers
> media: platform: Add user line interrupt to imx-mipi-csis driver
>
> drivers/media/platform/nxp/imx-mipi-csis.c | 107 ++++++++++++++-------
> 1 file changed, 74 insertions(+), 33 deletions(-)
>
> --
> 2.43.0
^ permalink raw reply [flat|nested] 6+ messages in thread
* Re: [PATCH v2 1/2] media: platform: Refactor interrupt status registers
2025-06-06 15:44 ` [PATCH v2 1/2] media: platform: Refactor interrupt status registers Isaac Scott
@ 2025-06-07 18:38 ` Laurent Pinchart
0 siblings, 0 replies; 6+ messages in thread
From: Laurent Pinchart @ 2025-06-07 18:38 UTC (permalink / raw)
To: Isaac Scott
Cc: kieran.bingham, rmfrfs, martink, kernel, mchehab, shawnguo,
s.hauer, kernel, festevam, linux-media, imx, linux-arm-kernel,
linux-kernel
Hi Isaac,
Thank you for the patch.
The subject line should start with "media: imx-mipi-csis: ".
On Fri, Jun 06, 2025 at 04:44:13PM +0100, Isaac Scott wrote:
> The NXP i.MX 8 MP CSI-2 receiver features multiple interrupt and debug
> status sources which span multiple registers. The driver currently
> supports two interrupt source registers, and attributes the
> mipi_csis_event event entries to those registers through a boolean debug
> field that indicate if the event relates to the main interrupt status
> (false) or debug interrupt status (true) register. To make it easier to
> add new event fields, replace the debug bool with a 'status index'
> integer than indicates the index of the corresponding status register.
>
> Signed-off-by: Isaac Scott <isaac.scott@ideasonboard.com>
> Reviewed-by: Laurent Pinchart <laurent.pinchart@ideasonboard.com>
>
> ---
>
> Changes since v1:
> - Switched from magic numbers to enum.
> ---
> drivers/media/platform/nxp/imx-mipi-csis.c | 69 +++++++++++-----------
> 1 file changed, 36 insertions(+), 33 deletions(-)
>
> diff --git a/drivers/media/platform/nxp/imx-mipi-csis.c b/drivers/media/platform/nxp/imx-mipi-csis.c
> index d060eadebc7a..394987d72c64 100644
> --- a/drivers/media/platform/nxp/imx-mipi-csis.c
> +++ b/drivers/media/platform/nxp/imx-mipi-csis.c
> @@ -248,8 +248,13 @@
> #define MIPI_CSI2_DATA_TYPE_RAW14 0x2d
> #define MIPI_CSI2_DATA_TYPE_USER(x) (0x30 + (x))
>
> +enum mipi_csis_event_type {
> + MAIN = 0,
> + DEBUG = 1,
Those names are too generic and prone to namespace clashes.
MIPI_CSIS_EVENT_TYPE_MAIN and MIPI_CSIS_EVENT_TYPE_DEBUG would be
better.
No need to resubmit for this, I'll update the code when applying.
> +};
> +
> struct mipi_csis_event {
> - bool debug;
> + enum mipi_csis_event_type status_index;
> u32 mask;
> const char * const name;
> unsigned int counter;
> @@ -257,30 +262,30 @@ struct mipi_csis_event {
>
> static const struct mipi_csis_event mipi_csis_events[] = {
> /* Errors */
> - { false, MIPI_CSIS_INT_SRC_ERR_SOT_HS, "SOT Error" },
> - { false, MIPI_CSIS_INT_SRC_ERR_LOST_FS, "Lost Frame Start Error" },
> - { false, MIPI_CSIS_INT_SRC_ERR_LOST_FE, "Lost Frame End Error" },
> - { false, MIPI_CSIS_INT_SRC_ERR_OVER, "FIFO Overflow Error" },
> - { false, MIPI_CSIS_INT_SRC_ERR_WRONG_CFG, "Wrong Configuration Error" },
> - { false, MIPI_CSIS_INT_SRC_ERR_ECC, "ECC Error" },
> - { false, MIPI_CSIS_INT_SRC_ERR_CRC, "CRC Error" },
> - { false, MIPI_CSIS_INT_SRC_ERR_UNKNOWN, "Unknown Error" },
> - { true, MIPI_CSIS_DBG_INTR_SRC_DT_NOT_SUPPORT, "Data Type Not Supported" },
> - { true, MIPI_CSIS_DBG_INTR_SRC_DT_IGNORE, "Data Type Ignored" },
> - { true, MIPI_CSIS_DBG_INTR_SRC_ERR_FRAME_SIZE, "Frame Size Error" },
> - { true, MIPI_CSIS_DBG_INTR_SRC_TRUNCATED_FRAME, "Truncated Frame" },
> - { true, MIPI_CSIS_DBG_INTR_SRC_EARLY_FE, "Early Frame End" },
> - { true, MIPI_CSIS_DBG_INTR_SRC_EARLY_FS, "Early Frame Start" },
> + { MAIN, MIPI_CSIS_INT_SRC_ERR_SOT_HS, "SOT Error"},
> + { MAIN, MIPI_CSIS_INT_SRC_ERR_LOST_FS, "Lost Frame Start Error"},
> + { MAIN, MIPI_CSIS_INT_SRC_ERR_LOST_FE, "Lost Frame End Error"},
> + { MAIN, MIPI_CSIS_INT_SRC_ERR_OVER, "FIFO Overflow Error"},
> + { MAIN, MIPI_CSIS_INT_SRC_ERR_WRONG_CFG, "Wrong Configuration Error"},
> + { MAIN, MIPI_CSIS_INT_SRC_ERR_ECC, "ECC Error"},
> + { MAIN, MIPI_CSIS_INT_SRC_ERR_CRC, "CRC Error"},
> + { MAIN, MIPI_CSIS_INT_SRC_ERR_UNKNOWN, "Unknown Error"},
> + { DEBUG, MIPI_CSIS_DBG_INTR_SRC_DT_NOT_SUPPORT, "Data Type Not Supported"},
> + { DEBUG, MIPI_CSIS_DBG_INTR_SRC_DT_IGNORE, "Data Type Ignored"},
> + { DEBUG, MIPI_CSIS_DBG_INTR_SRC_ERR_FRAME_SIZE, "Frame Size Error"},
> + { DEBUG, MIPI_CSIS_DBG_INTR_SRC_TRUNCATED_FRAME, "Truncated Frame"},
> + { DEBUG, MIPI_CSIS_DBG_INTR_SRC_EARLY_FE, "Early Frame End"},
> + { DEBUG, MIPI_CSIS_DBG_INTR_SRC_EARLY_FS, "Early Frame Start"},
> /* Non-image data receive events */
> - { false, MIPI_CSIS_INT_SRC_EVEN_BEFORE, "Non-image data before even frame" },
> - { false, MIPI_CSIS_INT_SRC_EVEN_AFTER, "Non-image data after even frame" },
> - { false, MIPI_CSIS_INT_SRC_ODD_BEFORE, "Non-image data before odd frame" },
> - { false, MIPI_CSIS_INT_SRC_ODD_AFTER, "Non-image data after odd frame" },
> + { MAIN, MIPI_CSIS_INT_SRC_EVEN_BEFORE, "Non-image data before even frame"},
> + { MAIN, MIPI_CSIS_INT_SRC_EVEN_AFTER, "Non-image data after even frame"},
> + { MAIN, MIPI_CSIS_INT_SRC_ODD_BEFORE, "Non-image data before odd frame"},
> + { MAIN, MIPI_CSIS_INT_SRC_ODD_AFTER, "Non-image data after odd frame"},
> /* Frame start/end */
> - { false, MIPI_CSIS_INT_SRC_FRAME_START, "Frame Start" },
> - { false, MIPI_CSIS_INT_SRC_FRAME_END, "Frame End" },
> - { true, MIPI_CSIS_DBG_INTR_SRC_CAM_VSYNC_FALL, "VSYNC Falling Edge" },
> - { true, MIPI_CSIS_DBG_INTR_SRC_CAM_VSYNC_RISE, "VSYNC Rising Edge" },
> + { MAIN, MIPI_CSIS_INT_SRC_FRAME_START, "Frame Start"},
> + { MAIN, MIPI_CSIS_INT_SRC_FRAME_END, "Frame End"},
> + { DEBUG, MIPI_CSIS_DBG_INTR_SRC_CAM_VSYNC_FALL, "VSYNC Falling Edge"},
> + { DEBUG, MIPI_CSIS_DBG_INTR_SRC_CAM_VSYNC_RISE, "VSYNC Rising Edge"},
> };
>
> #define MIPI_CSIS_NUM_EVENTS ARRAY_SIZE(mipi_csis_events)
> @@ -765,32 +770,30 @@ static irqreturn_t mipi_csis_irq_handler(int irq, void *dev_id)
> struct mipi_csis_device *csis = dev_id;
> unsigned long flags;
> unsigned int i;
> - u32 status;
> - u32 dbg_status;
> + u32 status[2];
>
> - status = mipi_csis_read(csis, MIPI_CSIS_INT_SRC);
> - dbg_status = mipi_csis_read(csis, MIPI_CSIS_DBG_INTR_SRC);
> + status[MAIN] = mipi_csis_read(csis, MIPI_CSIS_INT_SRC);
> + status[DEBUG] = mipi_csis_read(csis, MIPI_CSIS_DBG_INTR_SRC);
>
> spin_lock_irqsave(&csis->slock, flags);
>
> /* Update the event/error counters */
> - if ((status & MIPI_CSIS_INT_SRC_ERRORS) || csis->debug.enable) {
> + if ((status[MAIN] & MIPI_CSIS_INT_SRC_ERRORS) || csis->debug.enable) {
> for (i = 0; i < MIPI_CSIS_NUM_EVENTS; i++) {
> struct mipi_csis_event *event = &csis->events[i];
>
> - if ((!event->debug && (status & event->mask)) ||
> - (event->debug && (dbg_status & event->mask)))
> + if (status[event->status_index] & event->mask)
> event->counter++;
> }
> }
>
> - if (status & MIPI_CSIS_INT_SRC_FRAME_START)
> + if (status[MAIN] & MIPI_CSIS_INT_SRC_FRAME_START)
> mipi_csis_queue_event_sof(csis);
>
> spin_unlock_irqrestore(&csis->slock, flags);
>
> - mipi_csis_write(csis, MIPI_CSIS_INT_SRC, status);
> - mipi_csis_write(csis, MIPI_CSIS_DBG_INTR_SRC, dbg_status);
> + mipi_csis_write(csis, MIPI_CSIS_INT_SRC, status[MAIN]);
> + mipi_csis_write(csis, MIPI_CSIS_DBG_INTR_SRC, status[DEBUG]);
>
> return IRQ_HANDLED;
> }
--
Regards,
Laurent Pinchart
^ permalink raw reply [flat|nested] 6+ messages in thread
* Re: [PATCH v2 2/2] media: platform: Add user line interrupt to imx-mipi-csis driver
2025-06-06 15:44 ` [PATCH v2 2/2] media: platform: Add user line interrupt to imx-mipi-csis driver Isaac Scott
@ 2025-06-07 18:45 ` Laurent Pinchart
0 siblings, 0 replies; 6+ messages in thread
From: Laurent Pinchart @ 2025-06-07 18:45 UTC (permalink / raw)
To: Isaac Scott
Cc: kieran.bingham, rmfrfs, martink, kernel, mchehab, shawnguo,
s.hauer, kernel, festevam, linux-media, imx, linux-arm-kernel,
linux-kernel
Hi Isaac,
Thank you for the patch.
As for 1/2, The subject line should start with "media: imx-mipi-csis: ".
On Fri, Jun 06, 2025 at 04:44:14PM +0100, Isaac Scott wrote:
> The NXP i.MX 8M Plus features an interrupt that triggers after the MIPI
> CSI receiver counts a user-configurable number of lines. This is useful
> for debugging, as it allows users to check if the amount of lines per
> frame equals what they are expecting.
>
> Add support for this interrupt in the driver, and an entry into debugfs
> to allow the user to configure whether the interrupt is enabled, as well
> as the number of lines after which to trigger the interrupt.
>
> This debugfs control can be altered while a stream is in progress, with
> 0 disabling the interrupt and >0 setting a new desired line count.
>
> Signed-off-by: Isaac Scott <isaac.scott@ideasonboard.com>
>
> ---
>
> Changes since v1:
> - Moved from magic number to enum in status_index
> - Clear INT_MSK_1 in enable_interrupts() when on == false
You also modified the logic to enable the interrupt there. I don't think
that's a good idea, as it means the interrupt will always be enabled,
even when the feature isn't used. It can increase the load on the
system.
> - use local variable in set_params() as in the interrupt handler
> - move interrupt handling code outside of spinlock
> ---
> drivers/media/platform/nxp/imx-mipi-csis.c | 40 +++++++++++++++++++++-
> 1 file changed, 39 insertions(+), 1 deletion(-)
>
> diff --git a/drivers/media/platform/nxp/imx-mipi-csis.c b/drivers/media/platform/nxp/imx-mipi-csis.c
> index 394987d72c64..1b71f6c19fa8 100644
> --- a/drivers/media/platform/nxp/imx-mipi-csis.c
> +++ b/drivers/media/platform/nxp/imx-mipi-csis.c
> @@ -88,6 +88,10 @@
> #define MIPI_CSIS_INT_MSK_ERR_CRC BIT(1)
> #define MIPI_CSIS_INT_MSK_ERR_UNKNOWN BIT(0)
>
> +/* CSIS Interrupt mask 1 */
> +#define MIPI_CSIS_INT_MSK_1 0x18
> +#define MIPI_CSIS_INT_MSK_1_LINE_END BIT(0)
> +
> /* CSIS Interrupt source */
> #define MIPI_CSIS_INT_SRC 0x14
> #define MIPI_CSIS_INT_SRC_EVEN_BEFORE BIT(31)
> @@ -109,6 +113,10 @@
> #define MIPI_CSIS_INT_SRC_ERR_UNKNOWN BIT(0)
> #define MIPI_CSIS_INT_SRC_ERRORS 0xfffff
>
> +/* CSIS Interrupt source 1 */
> +#define MIPI_CSIS_INT_SRC_1 0x1c
> +#define MIPI_CSIS_INT_SRC_1_LINE_END BIT(0)
> +
> /* D-PHY status control */
> #define MIPI_CSIS_DPHY_STATUS 0x20
> #define MIPI_CSIS_DPHY_STATUS_ULPS_DAT BIT(8)
> @@ -221,6 +229,7 @@
> #define MIPI_CSIS_DBG_INTR_SRC_CAM_VSYNC_RISE BIT(0)
>
> #define MIPI_CSIS_FRAME_COUNTER_CH(n) (0x0100 + (n) * 4)
> +#define MIPI_CSIS_LINE_INTERRUPT_RATIO(n) (0x0110 + (n) * 4)
>
> /* Non-image packet data buffers */
> #define MIPI_CSIS_PKTDATA_ODD 0x2000
> @@ -251,6 +260,7 @@
> enum mipi_csis_event_type {
> MAIN = 0,
> DEBUG = 1,
> + USER = 2,
I don't think "USER" really fits. The MIPI_CSI1_INTERRUPT_SOURCE_1
register is just the second interrupt source register. MAIN0 and MAIN1
may be a better fit.
> };
>
> struct mipi_csis_event {
> @@ -286,6 +296,8 @@ static const struct mipi_csis_event mipi_csis_events[] = {
> { MAIN, MIPI_CSIS_INT_SRC_FRAME_END, "Frame End"},
> { DEBUG, MIPI_CSIS_DBG_INTR_SRC_CAM_VSYNC_FALL, "VSYNC Falling Edge"},
> { DEBUG, MIPI_CSIS_DBG_INTR_SRC_CAM_VSYNC_RISE, "VSYNC Rising Edge"},
> + /* User Line interrupt */
> + { USER, MIPI_CSIS_INT_SRC_1_LINE_END, "Line End"}
> };
>
> #define MIPI_CSIS_NUM_EVENTS ARRAY_SIZE(mipi_csis_events)
> @@ -338,11 +350,14 @@ struct mipi_csis_device {
>
> spinlock_t slock; /* Protect events */
> struct mipi_csis_event events[MIPI_CSIS_NUM_EVENTS];
> +
> struct dentry *debugfs_root;
> struct {
> bool enable;
> u32 hs_settle;
> u32 clk_settle;
> + u32 int_line;
> + u32 last_int_line;
> } debug;
> };
>
> @@ -533,6 +548,8 @@ static void mipi_csis_enable_interrupts(struct mipi_csis_device *csis, bool on)
> {
> mipi_csis_write(csis, MIPI_CSIS_INT_MSK, on ? 0xffffffff : 0);
> mipi_csis_write(csis, MIPI_CSIS_DBG_INTR_MSK, on ? 0xffffffff : 0);
> + mipi_csis_write(csis, MIPI_CSIS_INT_MSK_1,
> + on ? MIPI_CSIS_INT_MSK_1_LINE_END : 0);
> }
>
> static void mipi_csis_sw_reset(struct mipi_csis_device *csis)
> @@ -655,6 +672,7 @@ static void mipi_csis_set_params(struct mipi_csis_device *csis,
> const struct csis_pix_format *csis_fmt)
> {
> int lanes = csis->bus.num_data_lanes;
> + u32 int_lines;
> u32 val;
>
> val = mipi_csis_read(csis, MIPI_CSIS_CMN_CTRL);
> @@ -691,6 +709,13 @@ static void mipi_csis_set_params(struct mipi_csis_device *csis,
> MIPI_CSIS_DPHY_BCTRL_L_B_DPHYCTRL(20000000));
> mipi_csis_write(csis, MIPI_CSIS_DPHY_BCTRL_H, 0);
>
> + int_lines = READ_ONCE(csis->debug.int_line);
> + if (int_lines > 0)
> + mipi_csis_write(csis, MIPI_CSIS_LINE_INTERRUPT_RATIO(0),
> + max(int_lines, 1U) - 1);
The "int_lines > 0" condition and max(int_lines, 1U) are redundant. I'd
drop the former, in order to set the MIPI_CSIS_LINE_INTERRUPT_RATIO
register to 0 when int_line is 0, to match the logic in
mipi_csis_irq_handler().
> +
> + csis->debug.last_int_line = int_lines;
> +
> /* Update the shadow register. */
> val = mipi_csis_read(csis, MIPI_CSIS_CMN_CTRL);
> mipi_csis_write(csis, MIPI_CSIS_CMN_CTRL,
> @@ -770,10 +795,12 @@ static irqreturn_t mipi_csis_irq_handler(int irq, void *dev_id)
> struct mipi_csis_device *csis = dev_id;
> unsigned long flags;
> unsigned int i;
> - u32 status[2];
> + u32 int_lines;
> + u32 status[3];
>
> status[MAIN] = mipi_csis_read(csis, MIPI_CSIS_INT_SRC);
> status[DEBUG] = mipi_csis_read(csis, MIPI_CSIS_DBG_INTR_SRC);
> + status[USER] = mipi_csis_read(csis, MIPI_CSIS_INT_SRC_1);
>
> spin_lock_irqsave(&csis->slock, flags);
>
> @@ -792,8 +819,16 @@ static irqreturn_t mipi_csis_irq_handler(int irq, void *dev_id)
>
> spin_unlock_irqrestore(&csis->slock, flags);
>
> + int_lines = READ_ONCE(csis->debug.int_line);
> + if (int_lines != csis->debug.last_int_line) {
> + mipi_csis_write(csis, MIPI_CSIS_LINE_INTERRUPT_RATIO(0),
> + max(int_lines, 1U) - 1);
> + csis->debug.last_int_line = int_lines;
> + }
> +
> mipi_csis_write(csis, MIPI_CSIS_INT_SRC, status[MAIN]);
> mipi_csis_write(csis, MIPI_CSIS_DBG_INTR_SRC, status[DEBUG]);
> + mipi_csis_write(csis, MIPI_CSIS_INT_SRC_1, status[USER]);
>
> return IRQ_HANDLED;
> }
> @@ -933,6 +968,7 @@ static void mipi_csis_debugfs_init(struct mipi_csis_device *csis)
> {
> csis->debug.hs_settle = UINT_MAX;
> csis->debug.clk_settle = UINT_MAX;
> + csis->debug.int_line = 0;
>
> csis->debugfs_root = debugfs_create_dir(dev_name(csis->dev), NULL);
>
> @@ -944,6 +980,8 @@ static void mipi_csis_debugfs_init(struct mipi_csis_device *csis)
> &csis->debug.clk_settle);
> debugfs_create_u32("ths_settle", 0600, csis->debugfs_root,
> &csis->debug.hs_settle);
> + debugfs_create_u32("int_line_0", 0600, csis->debugfs_root,
> + &csis->debug.int_line);
> }
>
> static void mipi_csis_debugfs_exit(struct mipi_csis_device *csis)
--
Regards,
Laurent Pinchart
^ permalink raw reply [flat|nested] 6+ messages in thread
end of thread, other threads:[~2025-06-07 18:45 UTC | newest]
Thread overview: 6+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2025-06-06 15:44 [PATCH v2 0/2] media: Add line end IRQ to imx-mipi-csis driver Isaac Scott
2025-06-06 15:44 ` [PATCH v2 1/2] media: platform: Refactor interrupt status registers Isaac Scott
2025-06-07 18:38 ` Laurent Pinchart
2025-06-06 15:44 ` [PATCH v2 2/2] media: platform: Add user line interrupt to imx-mipi-csis driver Isaac Scott
2025-06-07 18:45 ` Laurent Pinchart
2025-06-06 16:17 ` [PATCH v2 0/2] media: Add line end IRQ " Rui Miguel Silva
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).