I'm using the IPU on the IMX.6Q (silicon rev 1.2) to place an overlay on to video before encoding in the VPU. I have a number of other IPU tasks handling deinterlace, colour space conversion, and display.
After a period running, having submitted this IPU task successfully thousands of times, the application crashes. In this state, all other applications (including the IPU examples) fail with a timeout when they submit an IPU task. The problem is only cured by a reboot.
I think I now need advice on how to modify the IPU driver so that I can reset the relevant parts of the IPU when I detect this condition, ideally without disrupting the display. I'm not sure whether this is a kernel bug or silicon problem.
By inserting debug into the driver, I can tell the following about the state. This is my IPU task:
imx-ipuv3 imx-ipuv3.0: [0xbafbf000]input:
imx-ipuv3 imx-ipuv3.0: [0xbafbf000] format = 0x32315559
imx-ipuv3 imx-ipuv3.0: [0xbafbf000] width = 720
imx-ipuv3 imx-ipuv3.0: [0xbafbf000] height = 576
imx-ipuv3 imx-ipuv3.0: [0xbafbf000] crop.w = 720
imx-ipuv3 imx-ipuv3.0: [0xbafbf000] crop.h = 576
imx-ipuv3 imx-ipuv3.0: [0xbafbf000] crop.pos.x = 0
imx-ipuv3 imx-ipuv3.0: [0xbafbf000] crop.pos.y = 0
imx-ipuv3 imx-ipuv3.0: [0xbafbf000]input buffer:
imx-ipuv3 imx-ipuv3.0: [0xbafbf000] paddr = 0x18000000
imx-ipuv3 imx-ipuv3.0: [0xbafbf000] i_off = 0x0
imx-ipuv3 imx-ipuv3.0: [0xbafbf000] i_uoff = 0x65400
imx-ipuv3 imx-ipuv3.0: [0xbafbf000] i_voff = 0x7e900
imx-ipuv3 imx-ipuv3.0: [0xbafbf000] istride = 720
imx-ipuv3 imx-ipuv3.0: [0xbafbf000]output:
imx-ipuv3 imx-ipuv3.0: [0xbafbf000] format = 0x33424752
imx-ipuv3 imx-ipuv3.0: [0xbafbf000] width = 720
imx-ipuv3 imx-ipuv3.0: [0xbafbf000] height = 576
imx-ipuv3 imx-ipuv3.0: [0xbafbf000] crop.w = 720
imx-ipuv3 imx-ipuv3.0: [0xbafbf000] crop.h = 576
imx-ipuv3 imx-ipuv3.0: [0xbafbf000] crop.pos.x = 0
imx-ipuv3 imx-ipuv3.0: [0xbafbf000] crop.pos.y = 0
imx-ipuv3 imx-ipuv3.0: [0xbafbf000] rotate = 0
imx-ipuv3 imx-ipuv3.0: [0xbafbf000]output buffer:
imx-ipuv3 imx-ipuv3.0: [0xbafbf000] paddr = 0x18a00000
imx-ipuv3 imx-ipuv3.0: [0xbafbf000] o_off = 0x0
imx-ipuv3 imx-ipuv3.0: [0xbafbf000] o_uoff = 0x0
imx-ipuv3 imx-ipuv3.0: [0xbafbf000] o_voff = 0x0
imx-ipuv3 imx-ipuv3.0: [0xbafbf000] ostride = 2160
imx-ipuv3 imx-ipuv3.0: [0xbafbf000]overlay:
imx-ipuv3 imx-ipuv3.0: [0xbafbf000] format = 0x41524742
imx-ipuv3 imx-ipuv3.0: [0xbafbf000] width = 720
imx-ipuv3 imx-ipuv3.0: [0xbafbf000] height = 576
imx-ipuv3 imx-ipuv3.0: [0xbafbf000] crop.w = 720
imx-ipuv3 imx-ipuv3.0: [0xbafbf000] crop.h = 576
imx-ipuv3 imx-ipuv3.0: [0xbafbf000] crop.pos.x = 0
imx-ipuv3 imx-ipuv3.0: [0xbafbf000] crop.pos.y = 0
imx-ipuv3 imx-ipuv3.0: [0xbafbf000]overlay buffer:
imx-ipuv3 imx-ipuv3.0: [0xbafbf000] paddr = 0x18e00000
imx-ipuv3 imx-ipuv3.0: [0xbafbf000] ov_off = 0x0
imx-ipuv3 imx-ipuv3.0: [0xbafbf000] ov_uoff = 0x0
imx-ipuv3 imx-ipuv3.0: [0xbafbf000] ov_voff = 0x0
imx-ipuv3 imx-ipuv3.0: [0xbafbf000] ovstride = 2880
imx-ipuv3 imx-ipuv3.0: [0xbafbf000]local alpha enabled with:
imx-ipuv3 imx-ipuv3.0: [0xbafbf000] paddr = 0x0
imx-ipuv3 imx-ipuv3.0: [0xbafbf000] ov_alpha_off = 0x0
imx-ipuv3 imx-ipuv3.0: [0xbafbf000] ov_alpha_stride = 720
imx-ipuv3 imx-ipuv3.0: [0xbafbf000]want task_id = 1
imx-ipuv3 imx-ipuv3.0: [0xbafbf000]want task mode is 0x1
imx-ipuv3 imx-ipuv3.0: [0xbafbf000] IC_MODE = 0x1
imx-ipuv3 imx-ipuv3.0: [0xbafbf000] ROT_MODE = 0x2
imx-ipuv3 imx-ipuv3.0: [0xbafbf000] VDI_MODE = 0x4
imx-ipuv3 imx-ipuv3.0: [0xbafbf000] Task_no = 0x740
These are the channel parameters:
imx-ipuv3 imx-ipuv3.0: ch 14 word 0 - 10000000 00003000 00000000 E0000000 0008FC59
imx-ipuv3 imx-ipuv3.0: ch 14 word 1 - 031C0000 00000000 20E3C000 FFF2CFC0 00006208
imx-ipuv3 imx-ipuv3.0: PFS 0x7,
imx-ipuv3 imx-ipuv3.0: BPP 0x0,
imx-ipuv3 imx-ipuv3.0: NPB 0xf
imx-ipuv3 imx-ipuv3.0: FW 719,
imx-ipuv3 imx-ipuv3.0: FH 575,
imx-ipuv3 imx-ipuv3.0: EBA0 0x18e00000
imx-ipuv3 imx-ipuv3.0: EBA1 0x0
imx-ipuv3 imx-ipuv3.0: Stride 2879
imx-ipuv3 imx-ipuv3.0: scan_order 0
imx-ipuv3 imx-ipuv3.0: uv_stride 8712
imx-ipuv3 imx-ipuv3.0: u_offset 0x0
imx-ipuv3 imx-ipuv3.0: v_offset 0x0
imx-ipuv3 imx-ipuv3.0: Width0 7+1,
imx-ipuv3 imx-ipuv3.0: Width1 7+1,
imx-ipuv3 imx-ipuv3.0: Width2 7+1,
imx-ipuv3 imx-ipuv3.0: Width3 7+1,
imx-ipuv3 imx-ipuv3.0: Offset0 8,
imx-ipuv3 imx-ipuv3.0: Offset1 16,
imx-ipuv3 imx-ipuv3.0: Offset2 24,
imx-ipuv3 imx-ipuv3.0: Offset3 0
These are the IPU registers:
imx-ipuv3 imx-ipuv3.0: IDMAC_CONF = 0x0000002F
imx-ipuv3 imx-ipuv3.0: IDMAC_CHA_EN1 = 0x00205000
imx-ipuv3 imx-ipuv3.0: IDMAC_CHA_EN2 = 0x00000000
imx-ipuv3 imx-ipuv3.0: IDMAC_CHA_PRI1 = 0x18800001
imx-ipuv3 imx-ipuv3.0: IDMAC_CHA_PRI2 = 0x00000000
imx-ipuv3 imx-ipuv3.0: IDMAC_BAND_EN1 = 0x00000000
imx-ipuv3 imx-ipuv3.0: IDMAC_BAND_EN2 = 0x00000000
imx-ipuv3 imx-ipuv3.0: IPU_CHA_DB_MODE_SEL0 = 0x00000000
imx-ipuv3 imx-ipuv3.0: IPU_CHA_DB_MODE_SEL1 = 0x00000000
imx-ipuv3 imx-ipuv3.0: IPU_CHA_TRB_MODE_SEL0 = 0x00000000
imx-ipuv3 imx-ipuv3.0: IPU_CHA_TRB_MODE_SEL1 = 0x00000000
imx-ipuv3 imx-ipuv3.0: DMFC_WR_CHAN = 0x00000090
imx-ipuv3 imx-ipuv3.0: DMFC_WR_CHAN_DEF = 0x202020F6
imx-ipuv3 imx-ipuv3.0: DMFC_DP_CHAN = 0x00009694
imx-ipuv3 imx-ipuv3.0: DMFC_DP_CHAN_DEF = 0x2020F6F6
imx-ipuv3 imx-ipuv3.0: DMFC_IC_CTRL = 0x00000002
imx-ipuv3 imx-ipuv3.0: IPU_FS_PROC_FLOW1 = 0x80000000
imx-ipuv3 imx-ipuv3.0: IPU_FS_PROC_FLOW2 = 0x00000000
imx-ipuv3 imx-ipuv3.0: IPU_FS_PROC_FLOW3 = 0x00000000
imx-ipuv3 imx-ipuv3.0: IPU_FS_DISP_FLOW1 = 0x00000000
imx-ipuv3 imx-ipuv3.0: IPU_VDIC_VDI_FSIZE = 0x00000000
imx-ipuv3 imx-ipuv3.0: IPU_VDIC_VDI_C = 0x00000000
imx-ipuv3 imx-ipuv3.0: IPU_IC_CONF = 0x40000B00
I have a workaround that greatly reduces the frequency of the lockup. This patch prevents the IPU driver executing two overlay operations at once - even though the operations should be independent, and I can find no suggestion in the datasheet that they might clash.
--- a/drivers/mxc/ipu3/ipu_device.c
+++ b/drivers/mxc/ipu3/ipu_device.c
@@ -327,6 +327,7 @@ struct ipu_channel_tabel {
struct mutex lock;
u8 used[MXC_IPU_MAX_NUM][MAX_PP_CH];
u8 vdoa_used;
+ u8 overlay_used;
};
struct ipu_thread_data {
@@ -1171,6 +1172,10 @@ static int _get_vdoa_ipu_res(struct ipu_task_entry *t)
goto out;
}
}
+
+ // Don't run two overlays at once. Don't know why
+ if (t->overlay_en && tbl->overlay_used)
+ goto out;
for (i = 0; i < max_ipu_no; i++) {
ipu = ipu_get_soc(i);
@@ -1229,6 +1234,8 @@ next:
t->ipu = ipu;
t->ipu_id = i;
t->dev = ipu->dev;
+ if (t->overlay_en)
+ tbl->overlay_used = 1;
if (atomic_inc_return(&t->res_get) == 2)
dev_err(t->dev,
"ERR no:0x%x,found_vdoa:%d,get ipu twice\n",
@@ -1269,6 +1276,8 @@ static void put_vdoa_ipu_res(struct ipu_task_entry *tsk, int vdoa_only)
goto out;
}
}
+ if (tsk->overlay_en)
+ tbl->overlay_used = 0;
tbl->used[tsk->ipu_id][tsk->task_id - 1] = 0;
rel_ipu = 1;
--