"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";
};
#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;
};
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);
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);
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);
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,
}
}
-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;
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];
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,
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);
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);
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;
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 {
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], ¶ms);
vin_intr_clear(vin->sysctrl_base);
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)
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], ¶ms);
+ 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], ¶ms);
+
+#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], ¶ms);
+
+ /* 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], ¶ms);
+ 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)
{
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,
.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,
};
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;
#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
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;