mirror of
https://github.com/hardkernel/linux.git
synced 2026-06-08 03:40:35 +09:00
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:
@@ -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;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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;
|
||||
|
||||
|
||||
@@ -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 */
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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");
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
|
||||
@@ -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)
|
||||
|
||||
Reference in New Issue
Block a user