v4l2: ISP update irq handler
authorliuxl0327 <liuxl0327@starfivetech.com>
Mon, 21 Mar 2022 08:08:04 +0000 (16:08 +0800)
committermason.huo <mason.huo@starfivetech.com>
Fri, 1 Jul 2022 07:05:38 +0000 (15:05 +0800)
Signed-off-by: mason.huo <mason.huo@starfivetech.com>
arch/riscv/boot/dts/starfive/jh7110.dtsi
drivers/media/platform/starfive/v4l2_driver/stf_isp.h
drivers/media/platform/starfive/v4l2_driver/stf_vin.c [changed mode: 0755->0644]
drivers/media/platform/starfive/v4l2_driver/stf_vin.h
drivers/media/platform/starfive/v4l2_driver/stf_vin_hw_ops.c [changed mode: 0755->0644]
drivers/media/platform/starfive/v4l2_driver/stfcamss.c [changed mode: 0755->0644]
include/video/stf-vin.h

index 5fae7e1..c0599e3 100755 (executable)
                                "rst_pixel_clk_if1", "rst_pixel_clk_if2", "rst_pixel_clk_if3",
                                "rst_m31dphy_hw", "rst_m31dphy_b09_always_on",
                                "rst_isp_top_n", "rst_isp_top_axi";
-                       interrupts = <92 87>;
                        power-domains = <&pwrc JH7110_PD_ISP>;
+                       /* jh7110 hasn't isp1, duplicate isp0 irq nr, will remove it later */
+                       interrupts = <92 87 88 89 87 88 89 90 90>;
                        status = "disabled";
                };
 
index 65b467d..926e79d 100644 (file)
@@ -12,6 +12,8 @@
 #include <video/stf-vin.h>
 
 #define STF_ISP_NAME "stf_isp"
+
+//#define ISP_USE_CSI_AND_SC_DONE_INTERRUPT  1
 #define STF_ISP_PAD_SINK     0
 #define STF_ISP_PAD_SRC      1
 #define STF_ISP_PADS_NUM     2
 #define ISP_REG_DUMP_CFG_1      0x00000028
 #define ISP_REG_IESHD_ADDR      0x00000A50
 
+enum {
+       EN_INT_NONE                 = 0,
+       EN_INT_ISP_DONE             = (0x1 << 24),
+       EN_INT_CSI_DONE             = (0x1 << 25),
+       EN_INT_SC_DONE              = (0x1 << 26),
+       EN_INT_LINE_INT             = (0x1 << 27),
+       EN_INT_ALL                  = (0xF << 24),
+};
+
 struct isp_format {
        u32 code;
        u8 bpp;
old mode 100755 (executable)
new mode 100644 (file)
index 7ef2916..9a46913
@@ -32,6 +32,7 @@ static const struct vin2_format vin2_formats_st7110[] = {
 };
 
 static void vin_buffer_done(struct vin_line *line, struct vin_params *params);
+static void vin_change_buffer(struct vin_line *line);
 static struct stfcamss_buffer *vin_buf_get_pending(struct vin_output *output);
 static void vin_output_init_addrs(struct vin_line *line);
 static void vin_init_outputs(struct vin_line *line);
@@ -73,6 +74,7 @@ int stf_vin_subdev_init(struct stfcamss *stfcamss)
        vin_dev->stfcamss = stfcamss;
        vin_dev->hw_ops = &vin_ops;
        vin_dev->hw_ops->isr_buffer_done = vin_buffer_done;
+       vin_dev->hw_ops->isr_change_buffer = vin_change_buffer;
 
        vin = stfcamss->vin;
        atomic_set(&vin_dev->ref_count, 0);
@@ -102,6 +104,59 @@ int stf_vin_subdev_init(struct stfcamss *stfcamss)
                goto out;
        }
 
+       st_info(ST_CAMSS, "%s, %d!\n", __func__, __LINE__);
+#ifdef ISP_USE_CSI_AND_SC_DONE_INTERRUPT
+       ret = devm_request_irq(dev,
+                       vin->isp0_csi_irq, vin_dev->hw_ops->vin_isp_csi_irq_handler,
+                       0, "vin_isp0_csi_irq", vin_dev);
+       if (ret) {
+               st_err(ST_VIN, "failed to request isp0 raw irq\n");
+               goto out;
+       }
+
+       ret = devm_request_irq(dev,
+                       vin->isp1_csi_irq, vin_dev->hw_ops->vin_isp_csi_irq_handler,
+                       0, "vin_isp1_csi_irq", vin_dev);
+       if (ret) {
+               st_err(ST_VIN, "failed to request isp1 raw irq\n");
+               goto out;
+       }
+
+       ret = devm_request_irq(dev,
+                       vin->isp0_scd_irq, vin_dev->hw_ops->vin_isp_scd_irq_handler,
+                       0, "vin_isp0_scd_irq", vin_dev);
+       if (ret) {
+               st_err(ST_VIN, "failed to request isp0 scd irq\n");
+               goto out;
+       }
+
+       ret = devm_request_irq(dev,
+                       vin->isp1_scd_irq, vin_dev->hw_ops->vin_isp_scd_irq_handler,
+                       0, "vin_isp1_scd_irq", vin_dev);
+       if (ret) {
+               st_err(ST_VIN, "failed to request isp1 scd irq\n");
+               goto out;
+       }
+
+#endif
+       st_info(ST_CAMSS, "%s, %d!\n", __func__, __LINE__);
+       ret = devm_request_irq(dev,
+                       vin->isp0_irq_csiline, vin_dev->hw_ops->vin_isp_irq_csiline_handler,
+                       0, "vin_isp0_irq_csiline", vin_dev);
+       if (ret) {
+               st_err(ST_VIN, "failed to request isp0 irq csiline\n");
+               goto out;
+       }
+
+       st_info(ST_CAMSS, "%s, %d!\n", __func__, __LINE__);
+       ret = devm_request_irq(dev,
+                       vin->isp1_irq_csiline, vin_dev->hw_ops->vin_isp_irq_csiline_handler,
+                       0, "vin_isp1_irq_csiline", vin_dev);
+       if (ret) {
+               st_err(ST_VIN, "failed to request isp1 irq csiline\n");
+               goto out;
+       }
+
        vin_dev->hw_ops->vin_wr_irq_enable(vin_dev, 1);
        vin_dev->hw_ops->vin_wr_irq_enable(vin_dev, 0);
 
@@ -516,6 +571,28 @@ static void vin_init_outputs(struct vin_line *line)
        output->buf[1] = NULL;
        output->active_buf = 0;
        INIT_LIST_HEAD(&output->pending_bufs);
+       INIT_LIST_HEAD(&output->ready_bufs);
+}
+
+static void vin_buf_add_ready(struct vin_output *output,
+                               struct stfcamss_buffer *buffer)
+{
+       INIT_LIST_HEAD(&buffer->queue);
+       list_add_tail(&buffer->queue, &output->ready_bufs);
+}
+
+static struct stfcamss_buffer *vin_buf_get_ready(struct vin_output *output)
+{
+       struct stfcamss_buffer *buffer = NULL;
+
+       if (!list_empty(&output->ready_bufs)) {
+               buffer = list_first_entry(&output->ready_bufs,
+                                       struct stfcamss_buffer,
+                                       queue);
+               list_del(&buffer->queue);
+       }
+
+       return buffer;
 }
 
 static void vin_buf_add_pending(struct vin_output *output,
@@ -675,7 +752,7 @@ static void vin_buf_update_on_new(struct vin_line *line,
        }
 }
 
-static void vin_buf_flush_pending(struct vin_output *output,
+static void vin_buf_flush(struct vin_output *output,
                                enum vb2_buffer_state state)
 {
        struct stfcamss_buffer *buf;
@@ -685,35 +762,55 @@ static void vin_buf_flush_pending(struct vin_output *output,
                vb2_buffer_done(&buf->vb.vb2_buf, state);
                list_del(&buf->queue);
        }
+       list_for_each_entry_safe(buf, t, &output->ready_bufs, queue) {
+               vb2_buffer_done(&buf->vb.vb2_buf, state);
+               list_del(&buf->queue);
+       }
 }
 
 static void vin_buffer_done(struct vin_line *line, struct vin_params *params)
 {
        struct stfcamss_buffer *ready_buf;
        struct vin_output *output = &line->output;
+       unsigned long flags;
+       u64 ts = ktime_get_ns();
+
+       if (output->state == VIN_OUTPUT_OFF
+               || output->state == VIN_OUTPUT_RESERVED)
+               return;
+
+       spin_lock_irqsave(&line->output_lock, flags);
+
+       while ((ready_buf = vin_buf_get_ready(output))) {
+               ready_buf->vb.vb2_buf.timestamp = ts;
+               ready_buf->vb.sequence = output->sequence++;
+               vb2_buffer_done(&ready_buf->vb.vb2_buf, VB2_BUF_STATE_DONE);
+       }
+
+       spin_unlock_irqrestore(&line->output_lock, flags);
+}
+
+static void vin_change_buffer(struct vin_line *line)
+{
+       struct stfcamss_buffer *ready_buf;
+       struct vin_output *output = &line->output;
        struct stf_vin2_dev *vin_dev = line_to_vin2_dev(line);
        dma_addr_t *new_addr;
        unsigned long flags;
        u32 active_index;
-       u64 ts = ktime_get_ns();
 
        if (output->state == VIN_OUTPUT_OFF
                || output->state == VIN_OUTPUT_STOPPING
                || output->state == VIN_OUTPUT_RESERVED
                || output->state == VIN_OUTPUT_IDLE) {
-               st_warn(ST_VIN,
-                               "output state no ready %d!, %d\n",
-                               output->state, line->id);
+               st_err_ratelimited(ST_VIN,
+                               "%s: output state no ready %d!, %d\n",
+                               __func__, output->state, line->id);
                return;
        }
 
        spin_lock_irqsave(&line->output_lock, flags);
 
-       if (output->frame_skip) {
-               output->frame_skip--;
-               goto out_unlock;
-       }
-
        active_index = output->active_buf;
 
        ready_buf = output->buf[active_index];
@@ -742,8 +839,11 @@ static void vin_buffer_done(struct vin_line *line, struct vin_params *params)
                vin_buf_update_on_next(line);
        }
 
-       switch (line->id) {
-       case VIN_LINE_WR:  // wr
+       if (output->state == VIN_OUTPUT_STOPPING)
+               output->last_buffer = ready_buf;
+       else {
+               switch (line->id) {
+               case VIN_LINE_WR:  // wr
 #ifdef VIN_TWO_BUFFER
                if (active_index)
                        vin_dev->hw_ops->vin_wr_set_pong_addr(vin_dev,
@@ -774,12 +874,7 @@ static void vin_buffer_done(struct vin_line *line, struct vin_params *params)
                break;
        }
 
-       if (output->state == VIN_OUTPUT_STOPPING)
-               output->last_buffer = ready_buf;
-       else {
-               ready_buf->vb.vb2_buf.timestamp = ts;
-               ready_buf->vb.sequence = output->sequence++;
-               vb2_buffer_done(&ready_buf->vb.vb2_buf, VB2_BUF_STATE_DONE);
+               vin_buf_add_ready(output, ready_buf);
        }
 
        spin_unlock_irqrestore(&line->output_lock, flags);
@@ -817,7 +912,7 @@ static int vin_flush_buffers(struct stfcamss_video *vid,
 
        spin_lock_irqsave(&line->output_lock, flags);
 
-       vin_buf_flush_pending(output, state);
+       vin_buf_flush(output, state);
        if (output->buf[0])
                vb2_buffer_done(&output->buf[0]->vb.vb2_buf, state);
 
index 7232230..584d1e6 100755 (executable)
@@ -36,6 +36,7 @@ struct vin_output {
        struct stfcamss_buffer *buf[2];
        struct stfcamss_buffer *last_buffer;
        struct list_head pending_bufs;
+       struct list_head ready_bufs;
        enum vin_output_state state;
        unsigned int sequence;
        unsigned int frame_skip;
@@ -95,8 +96,12 @@ struct vin_hw_ops {
                        int isp_id, dma_addr_t raw_addr);
        irqreturn_t (*vin_wr_irq_handler)(int irq, void *priv);
        irqreturn_t (*vin_isp_irq_handler)(int irq, void *priv);
+       irqreturn_t (*vin_isp_csi_irq_handler)(int irq, void *priv);
+       irqreturn_t (*vin_isp_scd_irq_handler)(int irq, void *priv);
+       irqreturn_t (*vin_isp_irq_csiline_handler)(int irq, void *priv);
        void (*isr_buffer_done)(struct vin_line *line,
                        struct vin_params *params);
+       void (*isr_change_buffer)(struct vin_line *line);
 };
 
 struct stf_vin2_dev {
old mode 100755 (executable)
new mode 100644 (file)
index 09dfc40..3766589
@@ -26,6 +26,7 @@ static irqreturn_t stf_vin_wr_irq_handler(int irq, void *priv)
        struct stf_vin2_dev *vin_dev = priv;
        struct stf_vin_dev *vin = vin_dev->stfcamss->vin;
 
+       vin_dev->hw_ops->isr_change_buffer(&vin_dev->line[VIN_LINE_WR]);
        vin_dev->hw_ops->isr_buffer_done(&vin_dev->line[VIN_LINE_WR], &params);
        vin_intr_clear(vin->sysctrl_base);
 
@@ -38,7 +39,7 @@ static irqreturn_t stf_vin_isp_irq_handler(int irq, void *priv)
        struct stf_vin2_dev *vin_dev = priv;
        struct stf_vin_dev *vin = vin_dev->stfcamss->vin;
        void __iomem *ispbase;
-       u32 int_status, value;
+       u32 int_status;
        int isp_id = irq == vin->isp0_irq ? 0 : 1;
 
        if (isp_id == 0)
@@ -48,21 +49,122 @@ static irqreturn_t stf_vin_isp_irq_handler(int irq, void *priv)
 
        int_status = reg_read(ispbase, ISP_REG_ISP_CTRL_0);
 
-       // if (int_status & BIT(24))
-       vin_dev->hw_ops->isr_buffer_done(
-               &vin_dev->line[VIN_LINE_ISP0 + isp_id], &params);
+       if (int_status & BIT(24)) {
+               if ((int_status & BIT(20)))
+                       vin_dev->hw_ops->isr_buffer_done(
+                               &vin_dev->line[VIN_LINE_ISP0 + isp_id], &params);
+
+#ifndef ISP_USE_CSI_AND_SC_DONE_INTERRUPT
+               if (int_status & BIT(25))
+                       vin_dev->hw_ops->isr_buffer_done(
+                               &vin_dev->line[VIN_LINE_ISP0_RAW + isp_id], &params);
+
+               /* clear interrupt */
+               reg_write(ispbase, ISP_REG_ISP_CTRL_0, (int_status & ~EN_INT_ALL)
+                               | EN_INT_ISP_DONE | EN_INT_CSI_DONE | EN_INT_SC_DONE);
+#else
+               /* clear interrupt */
+               reg_write(ispbase, ISP_REG_ISP_CTRL_0,
+                       (int_status & ~EN_INT_ALL) | EN_INT_ISP_DONE);
+#endif
+       } else
+               st_debug(ST_VIN, "%s, Unknown interrupt!!!\n", __func__);
+
+       return IRQ_HANDLED;
+}
+
+static irqreturn_t stf_vin_isp_csi_irq_handler(int irq, void *priv)
+{
+       struct stf_vin2_dev *vin_dev = priv;
+       struct stf_vin_dev *vin = vin_dev->stfcamss->vin;
+       void __iomem *ispbase;
+       u32 int_status;
+       int isp_id = irq == vin->isp0_csi_irq ? 0 : 1;
+
+       if (isp_id == 0)
+               ispbase = vin->isp_isp0_base;
+       else
+               ispbase = vin->isp_isp1_base;
 
-       value = reg_read(ispbase, ISP_REG_CIS_MODULE_CFG);
-       if ((value & BIT(19)) && (int_status & BIT(25)))
-               vin_dev->hw_ops->isr_buffer_done(
-                       &vin_dev->line[VIN_LINE_ISP0_RAW + isp_id], &params);
+       int_status = reg_read(ispbase, ISP_REG_ISP_CTRL_0);
 
-       /* clear interrupt */
-       reg_write(ispbase, ISP_REG_ISP_CTRL_0, int_status);
+       if (int_status & BIT(25)) {
+               /* clear interrupt */
+               reg_write(ispbase, ISP_REG_ISP_CTRL_0,
+                       (int_status & ~EN_INT_ALL) | EN_INT_CSI_DONE);
+       } else
+               st_debug(ST_VIN, "%s, Unknown interrupt!!!\n", __func__);
 
        return IRQ_HANDLED;
 }
 
+static irqreturn_t stf_vin_isp_scd_irq_handler(int irq, void *priv)
+{
+       struct stf_vin2_dev *vin_dev = priv;
+       struct stf_vin_dev *vin = vin_dev->stfcamss->vin;
+       void __iomem *ispbase;
+       u32 int_status;
+       int isp_id = irq == vin->isp0_scd_irq ? 0 : 1;
+
+       if (isp_id == 0)
+               ispbase = vin->isp_isp0_base;
+       else
+               ispbase = vin->isp_isp1_base;
+
+       int_status = reg_read(ispbase, ISP_REG_ISP_CTRL_0);
+
+       if (int_status & BIT(26)) {
+               /* clear interrupt */
+               reg_write(ispbase, ISP_REG_ISP_CTRL_0, (int_status & ~EN_INT_ALL) | EN_INT_SC_DONE);
+       } else
+               st_debug(ST_VIN, "%s, Unknown interrupt!!!\n", __func__);
+
+       return IRQ_HANDLED;
+}
+
+static irqreturn_t stf_vin_isp_irq_csiline_handler(int irq, void *priv)
+{
+       struct stf_vin2_dev *vin_dev = priv;
+       struct stf_vin_dev *vin = vin_dev->stfcamss->vin;
+       struct stf_isp_dev *isp_dev;
+       void __iomem *ispbase;
+       u32 int_status, value;
+       int isp_id = irq == vin->isp0_irq_csiline ? 0 : 1;
+
+       if (isp_id == 0)
+               ispbase = vin->isp_isp0_base;
+       else
+               ispbase = vin->isp_isp1_base;
+       isp_dev = &vin_dev->stfcamss->isp_dev[isp_id];
+
+       int_status = reg_read(ispbase, ISP_REG_ISP_CTRL_0);
+       if (int_status & BIT(27)) {
+               if (!atomic_read(&isp_dev->shadow_count)) {
+                       if ((int_status & BIT(20)))
+                               vin_dev->hw_ops->isr_change_buffer(
+                                       &vin_dev->line[VIN_LINE_ISP0 + isp_id]);
+
+                       value = reg_read(ispbase, ISP_REG_CSI_MODULE_CFG);
+                       if ((value & BIT(19)))
+                               vin_dev->hw_ops->isr_change_buffer(
+                                       &vin_dev->line[VIN_LINE_ISP0_RAW + isp_id]);
+
+                       /* shadow update */
+                       reg_set_bit(ispbase, ISP_REG_CSIINTS_ADDR, 0x30000, 0x30000);
+                       reg_set_bit(ispbase, ISP_REG_IESHD_ADDR, BIT(1) | BIT(0), 0x3);
+               } else {
+                       st_err_ratelimited(ST_VIN,
+                               "isp%d shadow_lock locked. skip this frame\n", isp_id);
+               }
+
+               /* clear interrupt */
+               reg_write(ispbase, ISP_REG_ISP_CTRL_0,
+                       (int_status & ~EN_INT_ALL) | EN_INT_LINE_INT);
+       } else
+               st_debug(ST_VIN, "%s, Unknown interrupt!!!\n", __func__);
+
+       return IRQ_HANDLED;
+}
 
 static int stf_vin_top_clk_init(struct stf_vin2_dev *vin_dev)
 {
@@ -215,8 +317,7 @@ void stf_vin_isp_set_yuv_addr(struct stf_vin2_dev *vin_dev, int isp_id,
 
        reg_write(ispbase, ISP_REG_Y_PLANE_START_ADDR, y_addr);
        reg_write(ispbase, ISP_REG_UV_PLANE_START_ADDR, uv_addr);
-       // shadow update
-       //reg_set_bit(ispbase, ISP_REG_IESHD_ADDR, BIT(1) | BIT(0), 0x3);    //fw no configure  2021 1110
+       // reg_set_bit(ispbase, ISP_REG_ISP_CTRL_0, BIT(0), 1);
 }
 
 void stf_vin_isp_set_raw_addr(struct stf_vin2_dev *vin_dev, int isp_id,
@@ -263,4 +364,7 @@ struct vin_hw_ops vin_ops = {
        .vin_isp_set_raw_addr  = stf_vin_isp_set_raw_addr,
        .vin_wr_irq_handler    = stf_vin_wr_irq_handler,
        .vin_isp_irq_handler   = stf_vin_isp_irq_handler,
+       .vin_isp_csi_irq_handler   = stf_vin_isp_csi_irq_handler,
+       .vin_isp_scd_irq_handler   = stf_vin_isp_scd_irq_handler,
+       .vin_isp_irq_csiline_handler   = stf_vin_isp_irq_csiline_handler,
 };
old mode 100755 (executable)
new mode 100644 (file)
index 5f4dd4d..c12ce0a
@@ -1037,13 +1037,43 @@ static int stfcamss_probe(struct platform_device *pdev)
                goto err_cam;
        }
 
-#ifdef UNUSED_CODE
-       vin->isp1_irq = platform_get_irq(pdev, 2);
-       if (vin->isp1_irq <= 0) {
-               st_err(ST_CAMSS, "Could not get isp1 irq\n");
+       vin->isp0_csi_irq = platform_get_irq(pdev, 2);
+       if (vin->isp0_csi_irq <= 0) {
+               st_err(ST_CAMSS, "Could not get isp0 csi irq\n");
+               goto err_cam;
+       }
+
+       vin->isp0_scd_irq = platform_get_irq(pdev, 3);
+       if (vin->isp0_scd_irq <= 0) {
+               st_err(ST_CAMSS, "Could not get isp0 scd irq\n");
+               goto err_cam;
+       }
+
+       vin->isp1_irq = platform_get_irq(pdev, 4);
+
+       vin->isp1_csi_irq = platform_get_irq(pdev, 5);
+       if (vin->isp1_csi_irq <= 0) {
+               st_err(ST_CAMSS, "Could not get isp1 csi irq\n");
+               goto err_cam;
+       }
+
+       vin->isp1_scd_irq = platform_get_irq(pdev, 6);
+       if (vin->isp1_scd_irq <= 0) {
+               st_err(ST_CAMSS, "Could not get isp1 scd irq\n");
+               goto err_cam;
+       }
+
+       vin->isp0_irq_csiline = platform_get_irq(pdev, 7);
+       if (vin->isp0_irq_csiline <= 0) {
+               st_err(ST_CAMSS, "Could not get isp0 irq csiline\n");
+               goto err_cam;
+       }
+
+       vin->isp1_irq_csiline = platform_get_irq(pdev, 8);
+       if (vin->isp1_irq_csiline <= 0) {
+               st_err(ST_CAMSS, "Could not get isp1 irq csiline\n");
                goto err_cam;
        }
-#endif
 
        stfcamss->nclks = ARRAY_SIZE(stfcamss_clocks);
        stfcamss->sys_clk = stfcamss_clocks;
index 843e26f..3d22ecf 100755 (executable)
 #define ISP_REG_RGB_TO_YUV_COVERSION6       0x00000E58
 #define ISP_REG_RGB_TO_YUV_COVERSION7       0x00000E5C
 #define ISP_REG_RGB_TO_YUV_COVERSION8       0x00000E60
-#define ISP_REG_CIS_MODULE_CFG              0x00000010
+#define ISP_REG_CSI_MODULE_CFG              0x00000010
 #define ISP_REG_ISP_CTRL_1                  0x00000A08
 #define ISP_REG_ISP_CTRL_0                  0x00000A00
 #define ISP_REG_DC_AXI_ID                   0x00000044
@@ -431,7 +431,13 @@ struct stf_vin_dev {
        bool isp0;
        bool isp1;
        int isp0_irq;
+       int isp0_csi_irq;
+       int isp0_scd_irq;
+       int isp0_irq_csiline;
        int isp1_irq;
+       int isp1_csi_irq;
+       int isp1_scd_irq;
+       int isp1_irq_csiline;
        u32 major;
        struct vin_buf buf;