media: rockchip: isp: add monitor to restart if abnormal

enable monitor:
add rockchip,restart-monitor-en to rkisp node on dts or
echo Y > /sys/module/video_rkisp/parameters/monitor
NOTE: shouldn't enable this when porting camera!!!

Change-Id: I35fa45488136e2e0ec16c4e6179a39f34cf5ebc9
Signed-off-by: Cai YiWei <cyw@rock-chips.com>
This commit is contained in:
Cai YiWei
2021-04-12 17:41:33 +08:00
committed by Tao Huang
parent 0fca9e8350
commit 3e8baf6650
11 changed files with 404 additions and 42 deletions

View File

@@ -2226,7 +2226,7 @@ void rkisp_mi_v20_isr(u32 mis_val, struct rkisp_device *dev)
end_tx0 = false;
end_tx1 = false;
end_tx2 = false;
rkisp_trigger_read_back(&dev->csi_dev, false, false);
rkisp_trigger_read_back(&dev->csi_dev, false, false, false);
}
}
}
@@ -2244,11 +2244,18 @@ void rkisp_mipi_v20_isr(unsigned int phy, unsigned int packet,
v4l2_dbg(3, rkisp_debug, &dev->v4l2_dev,
"csi state:0x%x\n", state);
if (phy && (dev->isp_inp & INP_CSI))
dev->csi_dev.irq_cnt++;
if (phy && (dev->isp_inp & INP_CSI) &&
dev->csi_dev.err_cnt++ < RKISP_CONTI_ERR_MAX)
v4l2_warn(v4l2_dev, "MIPI error: phy: 0x%08x\n", phy);
if (packet && (dev->isp_inp & INP_CSI))
if (packet && (dev->isp_inp & INP_CSI) &&
dev->csi_dev.err_cnt < RKISP_CONTI_ERR_MAX) {
if (packet & 0xfff)
dev->csi_dev.err_cnt++;
v4l2_warn(v4l2_dev, "MIPI error: packet: 0x%08x\n", packet);
if (overflow)
}
if (overflow &&
dev->csi_dev.err_cnt++ < RKISP_CONTI_ERR_MAX)
v4l2_warn(v4l2_dev, "MIPI error: overflow: 0x%08x\n", overflow);
if (state & 0xeff00)
v4l2_warn(v4l2_dev, "MIPI error: size: 0x%08x\n", state);
@@ -2268,6 +2275,7 @@ void rkisp_mipi_v20_isr(unsigned int phy, unsigned int packet,
}
}
if (state & (RAW0_WR_FRAME | RAW1_WR_FRAME | RAW2_WR_FRAME)) {
dev->csi_dev.err_cnt = 0;
for (i = 0; i < HDR_DMA_MAX; i++) {
if (!((RAW0_WR_FRAME << i) & state))
continue;
@@ -2283,4 +2291,18 @@ void rkisp_mipi_v20_isr(unsigned int phy, unsigned int packet,
if (state & (RAW0_Y_STATE | RAW1_Y_STATE | RAW2_Y_STATE |
RAW0_WR_FRAME | RAW1_WR_FRAME | RAW2_WR_FRAME))
rkisp_luma_isr(&dev->luma_vdev, state);
if (dev->csi_dev.err_cnt > RKISP_CONTI_ERR_MAX) {
if (!(dev->isp_state & ISP_MIPI_ERROR)) {
dev->isp_state |= ISP_MIPI_ERROR;
rkisp_write(dev, CSI2RX_MASK_PHY, 0, true);
rkisp_write(dev, CSI2RX_MASK_PACKET, 0, true);
rkisp_write(dev, CSI2RX_MASK_OVERFLOW, 0, true);
if (dev->hw_dev->monitor.is_en) {
if (!completion_done(&dev->hw_dev->monitor.cmpl))
complete(&dev->hw_dev->monitor.cmpl);
dev->hw_dev->monitor.state |= ISP_MIPI_ERROR;
}
}
}
}

View File

@@ -1443,7 +1443,7 @@ void rkisp_mi_v21_isr(u32 mis_val, struct rkisp_device *dev)
(dev->hdr.op_mode == HDR_RDBK_FRAME2 && end_tx2 && end_tx0))) {
end_tx0 = false;
end_tx2 = false;
rkisp_trigger_read_back(&dev->csi_dev, false, false);
rkisp_trigger_read_back(&dev->csi_dev, false, false, false);
}
}
}
@@ -1476,11 +1476,17 @@ void rkisp_mipi_v21_isr(unsigned int phy, unsigned int packet,
v4l2_dbg(3, rkisp_debug, &dev->v4l2_dev,
"csi state:0x%x\n", state);
if (phy && (dev->isp_inp & INP_CSI))
dev->csi_dev.irq_cnt++;
if (phy && (dev->isp_inp & INP_CSI) &&
dev->csi_dev.err_cnt++ < RKISP_CONTI_ERR_MAX)
v4l2_warn(v4l2_dev, "MIPI error: phy: 0x%08x\n", phy);
if (packet && (dev->isp_inp & INP_CSI))
if (packet && (dev->isp_inp & INP_CSI) &&
dev->csi_dev.err_cnt < RKISP_CONTI_ERR_MAX) {
if (packet & 0xfff)
dev->csi_dev.err_cnt++;
v4l2_warn(v4l2_dev, "MIPI error: packet: 0x%08x\n", packet);
if (overflow)
}
if (overflow && dev->csi_dev.err_cnt++ < RKISP_CONTI_ERR_MAX)
v4l2_warn(v4l2_dev, "MIPI error: overflow: 0x%08x\n", overflow);
if (state & 0xeff00)
v4l2_warn(v4l2_dev, "MIPI error: size: 0x%08x\n", state);
@@ -1501,6 +1507,7 @@ void rkisp_mipi_v21_isr(unsigned int phy, unsigned int packet,
}
}
if (state & (RAW0_WR_FRAME | RAW1_WR_FRAME)) {
dev->csi_dev.err_cnt = 0;
for (i = 0; i < HDR_DMA_MAX - 1; i++) {
if (!((RAW0_WR_FRAME << i) & state))
continue;
@@ -1513,7 +1520,22 @@ void rkisp_mipi_v21_isr(unsigned int phy, unsigned int packet,
}
}
if (state & ISP21_RAW3_WR_FRAME) {
dev->csi_dev.err_cnt = 0;
stream = &dev->cap_dev.stream[RKISP_STREAM_DMATX3];
atomic_inc(&stream->sequence);
}
if (dev->csi_dev.err_cnt > RKISP_CONTI_ERR_MAX) {
if (!(dev->isp_state & ISP_MIPI_ERROR)) {
dev->isp_state |= ISP_MIPI_ERROR;
rkisp_write(dev, CSI2RX_MASK_PHY, 0, true);
rkisp_write(dev, CSI2RX_MASK_PACKET, 0, true);
rkisp_write(dev, CSI2RX_MASK_OVERFLOW, 0, true);
if (dev->hw_dev->monitor.is_en) {
if (!completion_done(&dev->hw_dev->monitor.cmpl))
complete(&dev->hw_dev->monitor.cmpl);
dev->hw_dev->monitor.state |= ISP_MIPI_ERROR;
}
}
}
}

View File

@@ -135,6 +135,7 @@ struct rkisp_dummy_buffer {
};
extern int rkisp_debug;
extern bool rkisp_monitor;
extern u64 rkisp_debug_reg;
extern struct platform_driver rkisp_plat_drv;

View File

@@ -133,6 +133,8 @@ static int rkisp_csi_s_stream(struct v4l2_subdev *sd, int on)
struct rkisp_csi_device *csi = v4l2_get_subdevdata(sd);
struct rkisp_device *dev = csi->ispdev;
csi->err_cnt = 0;
csi->irq_cnt = 0;
memset(csi->tx_first, 0, sizeof(csi->tx_first));
if (!IS_HDR_RDBK(dev->hdr.op_mode))
@@ -321,7 +323,7 @@ static int csi_config(struct rkisp_csi_device *csi)
rkisp_write(dev, CSI2RX_MASK_PHY, 0xF0FFFF, true);
rkisp_write(dev, CSI2RX_MASK_PACKET, 0xF1FFFFF, true);
rkisp_write(dev, CSI2RX_MASK_OVERFLOW, 0x7F7FF1, true);
rkisp_write(dev, CSI2RX_MASK_STAT, 0x7FFFFF7F, true);
rkisp_write(dev, CSI2RX_MASK_STAT, 0x7FFFFF0F, true);
/* hdr merge */
switch (dev->hdr.op_mode) {
@@ -463,10 +465,10 @@ int rkisp_csi_config_patch(struct rkisp_device *dev)
}
}
rkisp_write(dev, ISP_HDRMGE_BASE, val, false);
rkisp_write(dev, CSI2RX_MASK_STAT, 0x7FFFFF7F, true);
}
if (IS_HDR_RDBK(dev->hdr.op_mode)) {
rkisp_write(dev, CSI2RX_MASK_STAT, 0x700FFF0F, true);
rkisp_set_bits(dev, CTRL_SWS_CFG,
0, SW_MPIP_DROP_FRM_DIS, true);
}
@@ -483,7 +485,7 @@ int rkisp_csi_config_patch(struct rkisp_device *dev)
* for hdr read back mode, rawrd read back data
* this will update rawrd base addr to shadow.
*/
void rkisp_trigger_read_back(struct rkisp_csi_device *csi, u8 dma2frm, u32 mode)
void rkisp_trigger_read_back(struct rkisp_csi_device *csi, u8 dma2frm, u32 mode, bool is_try)
{
struct rkisp_device *dev = csi->ispdev;
struct rkisp_hw_dev *hw = dev->hw_dev;
@@ -523,7 +525,7 @@ void rkisp_trigger_read_back(struct rkisp_csi_device *csi, u8 dma2frm, u32 mode)
dev->skip_frame = 2;
is_upd = true;
}
if (dev->isp_ver == ISP_V20 && dev->dmarx_dev.trigger == T_MANUAL) {
if (dev->isp_ver == ISP_V20 && dev->dmarx_dev.trigger == T_MANUAL && !is_try) {
if (csi->rd_mode != rd_mode && dev->br_dev.en) {
tmp = dev->isp_sdev.in_crop.height;
val = rkisp_read(dev, CIF_DUAL_CROP_CTRL, false);
@@ -551,7 +553,7 @@ void rkisp_trigger_read_back(struct rkisp_csi_device *csi, u8 dma2frm, u32 mode)
dev->isp_sdev.quantization);
rkisp_params_cfg(params_vdev, cur_frame_id);
if (!hw->is_single) {
if (!hw->is_single && !is_try) {
rkisp_update_regs(dev, CTRL_VI_ISP_PATH, SUPER_IMP_COLOR_CR);
rkisp_update_regs(dev, DUAL_CROP_M_H_OFFS, DUAL_CROP_S_V_SIZE);
rkisp_update_regs(dev, ISP_ACQ_PROP, DUAL_CROP_CTRL);
@@ -637,6 +639,9 @@ static void rkisp_dev_trigger_handle(struct rkisp_device *dev, u32 cmd)
hw->is_idle = false;
if (!hw->is_idle)
goto end;
if (hw->monitor.state & ISP_MIPI_ERROR && hw->monitor.is_en)
goto end;
for (i = 0; i < hw->dev_num; i++) {
isp = hw->isp[i];
if (!(isp->isp_state & ISP_START))
@@ -667,7 +672,7 @@ static void rkisp_dev_trigger_handle(struct rkisp_device *dev, u32 cmd)
end:
spin_unlock_irqrestore(&hw->rdbk_lock, lock_flags);
if (times >= 0)
rkisp_trigger_read_back(&isp->csi_dev, times, mode);
rkisp_trigger_read_back(&isp->csi_dev, times, mode, false);
}
/* handle read back event from user or isp idle isr */

View File

@@ -86,6 +86,8 @@ struct rkisp_csi_device {
int frame_cnt_x1;
int frame_cnt_x2;
int frame_cnt_x3;
u32 err_cnt;
u32 irq_cnt;
u32 rd_mode;
u8 mipi_di[CSI_PAD_MAX - 1];
u8 filt_state[CSI_F_MAX];
@@ -98,7 +100,7 @@ int rkisp_register_csi_subdev(struct rkisp_device *dev,
void rkisp_unregister_csi_subdev(struct rkisp_device *dev);
int rkisp_csi_config_patch(struct rkisp_device *dev);
void rkisp_trigger_read_back(struct rkisp_csi_device *csi, u8 dma2frm, u32 mode);
void rkisp_trigger_read_back(struct rkisp_csi_device *csi, u8 dma2frm, u32 mode, bool is_try);
int rkisp_csi_trigger_event(struct rkisp_device *dev, u32 cmd, void *arg);
void rkisp_csi_sof(struct rkisp_device *dev, u8 id);
#endif

View File

@@ -59,6 +59,10 @@ int rkisp_debug;
module_param_named(debug, rkisp_debug, int, 0644);
MODULE_PARM_DESC(debug, "Debug level (0-1)");
bool rkisp_monitor;
module_param_named(monitor, rkisp_monitor, bool, 0644);
MODULE_PARM_DESC(monitor, "rkisp abnormal restart monitor");
static bool rkisp_clk_dbg;
module_param_named(clk_dbg, rkisp_clk_dbg, bool, 0644);
MODULE_PARM_DESC(clk_dbg, "rkisp clk set by user");

View File

@@ -88,6 +88,7 @@ enum rkisp_isp_state {
ISP_STOP = BIT(8),
ISP_START = BIT(9),
ISP_ERROR = BIT(10),
ISP_MIPI_ERROR = BIT(11),
};
enum rkisp_isp_inp {
@@ -202,7 +203,7 @@ struct rkisp_device {
int vs_irq;
struct gpio_desc *vs_irq_gpio;
struct rkisp_hdr hdr;
enum rkisp_isp_state isp_state;
unsigned int isp_state;
unsigned int isp_err_cnt;
unsigned int isp_isr_cnt;
unsigned int isp_inp;

View File

@@ -520,28 +520,38 @@ static inline bool is_iommu_enable(struct device *dev)
return true;
}
void rkisp_soft_reset(struct rkisp_hw_dev *dev)
void rkisp_soft_reset(struct rkisp_hw_dev *dev, bool is_secure)
{
void __iomem *base = dev->base_addr;
struct iommu_domain *domain = iommu_get_domain_for_dev(dev->dev);
if (domain)
iommu_detach_device(domain, dev->dev);
if (is_secure) {
/* if isp working, cru reset isn't secure.
* isp soft reset first to protect isp reset.
*/
writel(0xffff, base + CIF_IRCL);
udelay(10);
}
if (dev->reset) {
reset_control_assert(dev->reset);
udelay(10);
reset_control_deassert(dev->reset);
udelay(10);
}
/* reset for Dehaze */
writel(CIF_ISP_CTRL_ISP_MODE_BAYER_ITU601, base + CIF_ISP_CTRL);
writel(0xffff, base + CIF_IRCL);
udelay(10);
if (domain) {
#ifdef CONFIG_IOMMU_API
domain->ops->detach_dev(domain, dev->dev);
domain->ops->attach_dev(domain, dev->dev);
#endif
if (dev->isp_ver == ISP_V20) {
/* reset for Dehaze */
writel(CIF_ISP_CTRL_ISP_MODE_BAYER_ITU601, base + CIF_ISP_CTRL);
writel(0xffff, base + CIF_IRCL);
udelay(10);
}
if (domain)
iommu_attach_device(domain, dev->dev);
}
static void isp_config_clk(struct rkisp_hw_dev *dev, int on)
@@ -609,7 +619,7 @@ static int enable_sys_clk(struct rkisp_hw_dev *dev)
rkisp_set_clk_rate(dev->clks[0],
dev->clk_rate_tbl[0].clk_rate * 1000000UL);
rkisp_soft_reset(dev);
rkisp_soft_reset(dev, false);
isp_config_clk(dev, true);
if (dev->isp_ver == ISP_V12 || dev->isp_ver == ISP_V13) {
@@ -679,6 +689,8 @@ static int rkisp_hw_probe(struct platform_device *pdev)
goto err;
}
rkisp_monitor = device_property_read_bool(dev, "rockchip,restart-monitor-en");
match_data = match->data;
hw_dev->mipi_irq = -1;
@@ -795,6 +807,7 @@ static int __maybe_unused rkisp_runtime_resume(struct device *dev)
memcpy_fromio(buf, base, RKISP_ISP_SW_REG_SIZE);
default_sw_reg_flag(hw_dev->isp[i]);
}
hw_dev->monitor.is_en = rkisp_monitor;
return 0;
}

View File

@@ -7,6 +7,7 @@
#include "bridge.h"
#define RKISP_MAX_BUS_CLK 8
#define RKISP_MAX_RETRY_CNT 5
struct isp_clk_info {
u32 clk_rate;
@@ -23,6 +24,16 @@ struct isp_match_data {
int num_irqs;
};
struct rkisp_monitor {
struct rkisp_hw_dev *dev;
struct work_struct work;
struct completion cmpl;
int (*reset_handle)(struct rkisp_device *dev);
u32 state;
u8 retry;
bool is_en;
};
struct rkisp_hw_dev {
const struct isp_match_data *match_data;
struct platform_device *pdev;
@@ -55,6 +66,7 @@ struct rkisp_hw_dev {
struct list_head rpt_list;
struct rkisp_dummy_buffer dummy_buf;
const struct vb2_mem_ops *mem_ops;
struct rkisp_monitor monitor;
u64 iq_feature;
int buf_init_cnt;
bool is_feature_on;
@@ -69,5 +81,5 @@ struct rkisp_hw_dev {
};
int rkisp_register_irq(struct rkisp_hw_dev *dev);
void rkisp_soft_reset(struct rkisp_hw_dev *dev);
void rkisp_soft_reset(struct rkisp_hw_dev *dev, bool is_secure);
#endif

View File

@@ -303,6 +303,10 @@ static int isp_show(struct seq_file *p, void *v)
break;
}
seq_printf(p, "%-10s %s Cnt:%d\n",
"Monitor",
dev->hw_dev->monitor.is_en ? "ON" : "OFF",
dev->hw_dev->monitor.retry);
return 0;
}

View File

@@ -81,6 +81,12 @@
* +---------------------------------------------------------+
*/
struct backup_reg {
const u32 base;
const u32 shd;
u32 val;
};
static inline struct rkisp_device *sd_to_isp_dev(struct v4l2_subdev *sd)
{
return container_of(sd->v4l2_dev, struct rkisp_device, v4l2_dev);
@@ -459,6 +465,12 @@ void rkisp_check_idle(struct rkisp_device *dev, u32 irq)
v4l2_dbg(3, rkisp_debug, &dev->v4l2_dev,
"%s irq:0x%x ends:0x%x mask:0x%x\n",
__func__, irq, dev->irq_ends, dev->irq_ends_mask);
if (dev->irq_ends == dev->irq_ends_mask && dev->hw_dev->monitor.is_en) {
dev->hw_dev->monitor.retry = 0;
dev->hw_dev->monitor.state |= ISP_FRAME_END;
if (!completion_done(&dev->hw_dev->monitor.cmpl))
complete(&dev->hw_dev->monitor.cmpl);
}
if (dev->irq_ends != dev->irq_ends_mask || !IS_HDR_RDBK(dev->csi_dev.rd_mode))
return;
@@ -486,17 +498,16 @@ void rkisp_check_idle(struct rkisp_device *dev, u32 irq)
wake_up(&dev->sync_onoff);
}
static void rkisp_set_state(struct rkisp_device *dev, u32 state)
static void rkisp_set_state(u32 *state, u32 val)
{
u32 mask = 0xff;
if (state < ISP_STOP)
if (val < ISP_STOP)
mask = 0xff00;
dev->isp_state &= mask;
dev->isp_state |= state;
*state &= mask;
*state |= val;
}
/*
* Image Stabilization.
* This should only be called when configuring CIF
@@ -531,6 +542,243 @@ static void rkisp_config_ism(struct rkisp_device *dev)
writel(val, base + CIF_ISP_CTRL);
}
static int rkisp_reset_handle_v2x(struct rkisp_device *dev)
{
void __iomem *base = dev->base_addr;
void *reg_buf = NULL;
u32 *reg, *reg1, i;
struct backup_reg backup[] = {
{
.base = MI_MP_WR_Y_BASE,
.shd = MI_MP_WR_Y_BASE_SHD,
}, {
.base = MI_MP_WR_CB_BASE,
.shd = MI_MP_WR_CB_BASE_SHD,
}, {
.base = MI_MP_WR_CR_BASE,
.shd = MI_MP_WR_CR_BASE_SHD,
}, {
.base = MI_SP_WR_Y_BASE,
.shd = MI_SP_WR_Y_BASE_SHD,
}, {
.base = MI_SP_WR_CB_BASE,
.shd = MI_SP_WR_CB_BASE_AD_SHD,
}, {
.base = MI_SP_WR_CR_BASE,
.shd = MI_SP_WR_CR_BASE_AD_SHD,
}, {
.base = MI_RAW0_WR_BASE,
.shd = MI_RAW0_WR_BASE_SHD,
}, {
.base = MI_RAW1_WR_BASE,
.shd = MI_RAW1_WR_BASE_SHD,
}, {
.base = MI_RAW2_WR_BASE,
.shd = MI_RAW2_WR_BASE_SHD,
}, {
.base = MI_RAW3_WR_BASE,
.shd = MI_RAW3_WR_BASE_SHD,
}, {
.base = MI_RAW0_RD_BASE,
.shd = MI_RAW0_RD_BASE_SHD,
}, {
.base = MI_RAW1_RD_BASE,
.shd = MI_RAW1_RD_BASE_SHD,
}, {
.base = MI_RAW2_RD_BASE,
.shd = MI_RAW2_RD_BASE_SHD,
}, {
.base = MI_GAIN_WR_BASE,
.shd = MI_GAIN_WR_BASE_SHD,
}
};
reg_buf = kzalloc(RKISP_ISP_SW_REG_SIZE, GFP_KERNEL);
if (!reg_buf)
return -ENOMEM;
dev_info(dev->dev, "%s enter\n", __func__);
memcpy_fromio(reg_buf, base, RKISP_ISP_SW_REG_SIZE);
rkisp_soft_reset(dev->hw_dev, true);
/* process special reg */
reg = reg_buf + ISP_CTRL;
*reg &= ~(CIF_ISP_CTRL_ISP_ENABLE |
CIF_ISP_CTRL_ISP_INFORM_ENABLE |
CIF_ISP_CTRL_ISP_CFG_UPD);
reg = reg_buf + MI_WR_INIT;
*reg = 0;
reg = reg_buf + CSI2RX_CTRL0;
*reg &= ~SW_CSI2RX_EN;
/* skip mmu range */
memcpy_toio(base, reg_buf, ISP21_MI_BAY3D_RD_BASE_SHD);
memcpy_toio(base + CSI2RX_CTRL0, reg_buf + CSI2RX_CTRL0,
RKISP_ISP_SW_REG_SIZE - CSI2RX_CTRL0);
/* config shd_reg to base_reg */
for (i = 0; i < ARRAY_SIZE(backup); i++) {
reg = reg_buf + backup[i].base;
reg1 = reg_buf + backup[i].shd;
backup[i].val = *reg;
writel(*reg1, base + backup[i].base);
}
/* clear state */
dev->isp_err_cnt = 0;
dev->isp_state &= ~ISP_ERROR;
rkisp_set_state(&dev->isp_state, ISP_FRAME_END);
dev->hw_dev->monitor.state = ISP_FRAME_END;
/* update module */
reg = reg_buf + DUAL_CROP_CTRL;
if (*reg & 0xf)
writel(*reg | CIF_DUAL_CROP_CFG_UPD, base + DUAL_CROP_CTRL);
reg = reg_buf + SELF_RESIZE_CTRL;
if (*reg & 0xf)
writel(*reg | CIF_RSZ_CTRL_CFG_UPD, base + SELF_RESIZE_CTRL);
reg = reg_buf + MAIN_RESIZE_CTRL;
if (*reg & 0xf)
writel(*reg | CIF_RSZ_CTRL_CFG_UPD, base + MAIN_RESIZE_CTRL);
/* update mi and isp, base_reg will update to shd_reg */
force_cfg_update(dev);
reg = reg_buf + ISP_CTRL;
*reg |= CIF_ISP_CTRL_ISP_ENABLE |
CIF_ISP_CTRL_ISP_INFORM_ENABLE |
CIF_ISP_CTRL_ISP_CFG_UPD;
writel(*reg, base + ISP_CTRL);
udelay(50);
/* config base_reg */
for (i = 0; i < ARRAY_SIZE(backup); i++)
writel(backup[i].val, base + backup[i].base);
/* mpfbc base_reg = shd_reg, write is base but read is shd */
if (dev->isp_ver == ISP_V20)
writel(rkisp_read_reg_cache(dev, ISP_MPFBC_HEAD_PTR),
base + ISP_MPFBC_HEAD_PTR);
rkisp_set_bits(dev, CIF_ISP_IMSC, 0, CIF_ISP_DATA_LOSS | CIF_ISP_PIC_SIZE_ERROR, true);
if (IS_HDR_RDBK(dev->hdr.op_mode)) {
if (!dev->hw_dev->is_idle)
rkisp_trigger_read_back(&dev->csi_dev, 1, 0, true);
else
rkisp_csi_trigger_event(dev, T_CMD_QUEUE, NULL);
}
kfree(reg_buf);
dev_info(dev->dev, "%s exit\n", __func__);
return 0;
}
static void rkisp_restart_monitor(struct work_struct *work)
{
struct rkisp_monitor *monitor =
container_of(work, struct rkisp_monitor, work);
struct rkisp_hw_dev *hw = monitor->dev;
struct rkisp_device *isp;
struct rkisp_pipeline *p;
int ret, i, j, timeout = 5, mipi_irq_cnt = 0;
if (!monitor->reset_handle) {
monitor->is_en = false;
return;
}
dev_info(hw->dev, "%s enter\n", __func__);
while (!(monitor->state & ISP_STOP) && monitor->is_en) {
ret = wait_for_completion_timeout(&monitor->cmpl,
msecs_to_jiffies(100));
/* isp stop to exit
* isp err to reset
* mipi err wait isp idle, then reset
*/
if (monitor->state & ISP_STOP ||
(ret && !(monitor->state & ISP_ERROR)) ||
(!ret &&
monitor->state & ISP_FRAME_END &&
!(monitor->state & ISP_MIPI_ERROR))) {
for (i = 0; i < hw->dev_num; i++) {
isp = hw->isp[i];
if (!(isp->isp_inp & INP_CSI))
continue;
if (!(isp->isp_state & ISP_START))
break;
if (isp->csi_dev.irq_cnt != mipi_irq_cnt) {
mipi_irq_cnt = isp->csi_dev.irq_cnt;
timeout = 5;
} else if (mipi_irq_cnt && timeout-- == 0) {
/* mipi no input */
monitor->state |= ISP_MIPI_ERROR;
}
}
continue;
}
dev_info(hw->dev, "isp%d to restart state:0x%x try:%d mipi_irq_cnt:%d\n",
hw->cur_dev_id, monitor->state, monitor->retry, mipi_irq_cnt);
if (monitor->retry++ > RKISP_MAX_RETRY_CNT || hw->is_shutdown) {
monitor->is_en = false;
break;
}
for (i = 0; i < hw->dev_num; i++) {
isp = hw->isp[i];
if (isp->isp_inp & INP_CSI ||
isp->isp_inp & INP_DVP ||
isp->isp_inp & INP_LVDS) {
if (!(isp->isp_state & ISP_START))
break;
/* subdev stream off */
p = &isp->pipe;
for (j = p->num_subdevs - 1; j >= 0; j--)
v4l2_subdev_call(p->subdevs[j], video, s_stream, 0);
for (i = 0; i < ISP2X_MIPI_RAW_MAX; i++) {
isp->luma_vdev.ystat_isrcnt[i] = 0;
isp->luma_vdev.ystat_rdflg[i] = 0;
}
}
}
/* restart isp */
isp = hw->isp[hw->cur_dev_id];
ret = monitor->reset_handle(isp);
if (ret) {
monitor->is_en = false;
break;
}
for (i = 0; i < hw->dev_num; i++) {
isp = hw->isp[i];
if (isp->isp_inp & INP_CSI ||
isp->isp_inp & INP_DVP ||
isp->isp_inp & INP_LVDS) {
if (!(isp->isp_state & ISP_START))
break;
if (isp->isp_inp & INP_CSI) {
rkisp_write(isp, CSI2RX_MASK_PHY, 0xF0FFFF, true);
rkisp_write(isp, CSI2RX_MASK_PACKET, 0xF1FFFFF, true);
rkisp_write(isp, CSI2RX_MASK_OVERFLOW, 0x7F7FF1, true);
}
/* subdev stream on */
isp->csi_dev.err_cnt = 0;
isp->isp_state &= ~ISP_MIPI_ERROR;
p = &isp->pipe;
for (j = 0; j < p->num_subdevs; j++)
v4l2_subdev_call(p->subdevs[j], video, s_stream, 1);
}
}
}
dev_dbg(hw->dev, "%s exit\n", __func__);
}
static void rkisp_monitor_init(struct rkisp_device *dev)
{
struct rkisp_monitor *monitor = &dev->hw_dev->monitor;
monitor->dev = dev->hw_dev;
monitor->reset_handle = NULL;
if (dev->isp_ver == ISP_V20 || dev->isp_ver == ISP_V21)
monitor->reset_handle = rkisp_reset_handle_v2x;
init_completion(&monitor->cmpl);
INIT_WORK(&monitor->work, rkisp_restart_monitor);
}
/*
* configure isp blocks with input format, size......
*/
@@ -911,6 +1159,13 @@ static int rkisp_isp_stop(struct rkisp_device *dev)
if (atomic_read(&dev->hw_dev->refcnt) > 1)
goto end;
if (dev->hw_dev->monitor.is_en) {
dev->hw_dev->monitor.is_en = 0;
dev->hw_dev->monitor.state = ISP_STOP;
if (!completion_done(&dev->hw_dev->monitor.cmpl))
complete(&dev->hw_dev->monitor.cmpl);
}
/*
* ISP(mi) stop in mi frame end -> Stop ISP(mipi) ->
* Stop ISP(isp) ->wait for ISP isp off
@@ -982,7 +1237,7 @@ static int rkisp_isp_stop(struct rkisp_device *dev)
clk_set_rate(dev->hw_dev->clks[0], safe_rate);
udelay(100);
}
rkisp_soft_reset(dev->hw_dev);
rkisp_soft_reset(dev->hw_dev, false);
}
rkisp_write(dev, CTRL_VI_ISP_CLK_CTRL, val, true);
@@ -1001,7 +1256,7 @@ static int rkisp_isp_stop(struct rkisp_device *dev)
end:
dev->irq_ends_mask = 0;
dev->hdr.op_mode = 0;
rkisp_set_state(dev, ISP_STOP);
rkisp_set_state(&dev->isp_state, ISP_STOP);
if (dev->isp_ver == ISP_V20 || dev->isp_ver == ISP_V21)
kfifo_reset(&dev->csi_dev.rdbk_kfifo);
@@ -1073,6 +1328,11 @@ static int rkisp_isp_start(struct rkisp_device *dev)
"%s MI_CTRL 0x%08x ISP_CTRL 0x%08x\n", __func__,
readl(base + CIF_MI_CTRL), readl(base + CIF_ISP_CTRL));
if (dev->hw_dev->monitor.is_en && atomic_read(&dev->hw_dev->refcnt) < 2) {
dev->hw_dev->monitor.retry = 0;
dev->hw_dev->monitor.state = ISP_FRAME_END;
schedule_work(&dev->hw_dev->monitor.work);
}
rkisp_csi_trigger_event(dev, T_CMD_QUEUE, NULL);
return 0;
}
@@ -2122,6 +2382,7 @@ int rkisp_register_isp_subdev(struct rkisp_device *isp_dev,
isp_dev->hdr.sensor = NULL;
isp_dev->isp_state = ISP_STOP;
rkisp_monitor_init(isp_dev);
return 0;
err_cleanup_media_entity:
media_entity_cleanup(&sd->entity);
@@ -2334,7 +2595,12 @@ void rkisp_isp_isr(unsigned int isp_mis,
if (isp_mis & CIF_ISP_V_START) {
if (!(dev->isp_state & ISP_FRAME_VS))
dev->isp_sdev.dbg.timestamp = ktime_get_ns();
rkisp_set_state(dev, ISP_FRAME_VS);
rkisp_set_state(&dev->isp_state, ISP_FRAME_VS);
if (dev->hw_dev->monitor.is_en) {
rkisp_set_state(&dev->hw_dev->monitor.state, ISP_FRAME_VS);
if (!completion_done(&dev->hw_dev->monitor.cmpl))
complete(&dev->hw_dev->monitor.cmpl);
}
/* last vsync to config next buf */
if (!dev->csi_dev.filt_state[CSI_F_VS])
rkisp_bridge_update_mi(dev);
@@ -2398,10 +2664,19 @@ vs_skip:
}
if (dev->isp_err_cnt++ > RKISP_CONTI_ERR_MAX) {
rkisp_isp_stop(dev);
rkisp_set_state(dev, ISP_ERROR);
v4l2_err(&dev->v4l2_dev,
"Too many isp error, stop isp!\n");
if (!(dev->isp_state & ISP_ERROR)) {
rkisp_set_state(&dev->isp_state, ISP_ERROR);
rkisp_clear_bits(dev, CIF_ISP_IMSC,
CIF_ISP_DATA_LOSS |
CIF_ISP_PIC_SIZE_ERROR, true);
writel(CIF_ISP_PIC_SIZE_ERROR, base + CIF_ISP_ICR);
writel(CIF_ISP_DATA_LOSS, base + CIF_ISP_ICR);
if (dev->hw_dev->monitor.is_en) {
rkisp_set_state(&dev->hw_dev->monitor.state, ISP_ERROR);
if (!completion_done(&dev->hw_dev->monitor.cmpl))
complete(&dev->hw_dev->monitor.cmpl);
}
}
}
}
@@ -2416,7 +2691,7 @@ vs_skip:
/* sampled input frame is complete */
if (isp_mis & CIF_ISP_FRAME_IN) {
rkisp_set_state(dev, ISP_FRAME_IN);
rkisp_set_state(&dev->isp_state, ISP_FRAME_IN);
writel(CIF_ISP_FRAME_IN, base + CIF_ISP_ICR);
isp_mis_tmp = readl(base + CIF_ISP_MIS);
if (isp_mis_tmp & CIF_ISP_FRAME_IN)
@@ -2424,6 +2699,7 @@ vs_skip:
isp_mis_tmp);
dev->isp_err_cnt = 0;
dev->isp_state &= ~ISP_ERROR;
}
/* frame was completely put out */
@@ -2431,7 +2707,7 @@ vs_skip:
dev->isp_sdev.dbg.interval =
ktime_get_ns() - dev->isp_sdev.dbg.timestamp;
/* Clear Frame In (ISP) */
rkisp_set_state(dev, ISP_FRAME_END);
rkisp_set_state(&dev->isp_state, ISP_FRAME_END);
writel(CIF_ISP_FRAME, base + CIF_ISP_ICR);
isp_mis_tmp = readl(base + CIF_ISP_MIS);
if (isp_mis_tmp & CIF_ISP_FRAME)