Skip to content

Commit 360cb34

Browse files
warped-rudijnettlet
authored andcommitted
mxc: ipu: Change order of stripe processing from up->down to down->up
When the output picture is too large to be handled the IPU hardware, it is split into stripes that are processed independently by any of the IPUs present in the SoC. There are some situations where the up (top) and the down (bottom) stripe overlap by a few lines. While this is not a problem for progressive frames, it may introduce a visible tearing line in the middle of the screen when deinterlacing is in effect. Patch ENGR00161315 provides a workaround for this. However, due to recent changes in the kernel memory management, the original ENGR00161315 will crash. This patch removes ENGR00161315 and implements a more efficient solution to this problem by changing the processing order of the stripes. Now the down (bottom) stripe is scheduled first so that the up (top) stripe will overwrite the area covered by both. Signed-off-by: Rudi <[email protected]>
1 parent f3e3692 commit 360cb34

File tree

1 file changed

+12
-223
lines changed

1 file changed

+12
-223
lines changed

drivers/mxc/ipu3/ipu_device.c

Lines changed: 12 additions & 223 deletions
Original file line numberDiff line numberDiff line change
@@ -304,11 +304,6 @@ struct ipu_task_entry {
304304
atomic_t res_get;
305305

306306
struct ipu_task_entry *parent;
307-
char *vditmpbuf[2];
308-
u32 old_save_lines;
309-
u32 old_size;
310-
bool buf1filled;
311-
bool buf0filled;
312307

313308
vdoa_handle_t vdoa_handle;
314309
struct vdoa_output_mem {
@@ -1721,7 +1716,7 @@ static int queue_split_task(struct ipu_task_entry *t,
17211716
{
17221717
int err[4];
17231718
int ret = 0;
1724-
int i, j;
1719+
int i, j, invert;
17251720
struct ipu_task_entry *tsk = NULL;
17261721
struct mutex *lock = &t->split_lock;
17271722
struct mutex *vdic_lock = &t->vdic_lock;
@@ -1738,6 +1733,11 @@ static int queue_split_task(struct ipu_task_entry *t,
17381733
sp_task[j].task_no = t->task_no;
17391734
}
17401735

1736+
/* Note: When deinterlace is active, insert UP_STRIPE before DOWN_STRIPE.
1737+
* This will avoid the "tearing line" problem formerly addressed by ENGR00161315
1738+
*/
1739+
invert = (t->input.deinterlace.enable) ? (UP_STRIPE | DOWN_STRIPE) : 0;
1740+
17411741
if (t->set.split_mode == RL_SPLIT) {
17421742
i = 0;
17431743
err[i] = create_split_task(RIGHT_STRIPE, &sp_task[i]);
@@ -1747,26 +1747,26 @@ static int queue_split_task(struct ipu_task_entry *t,
17471747
err[i] = create_split_task(LEFT_STRIPE, &sp_task[i]);
17481748
} else if (t->set.split_mode == UD_SPLIT) {
17491749
i = 0;
1750-
err[i] = create_split_task(DOWN_STRIPE, &sp_task[i]);
1750+
err[i] = create_split_task(DOWN_STRIPE ^ invert, &sp_task[i]);
17511751
if (err[i] < 0)
17521752
goto err_start;
17531753
i = 1;
1754-
err[i] = create_split_task(UP_STRIPE, &sp_task[i]);
1754+
err[i] = create_split_task(UP_STRIPE ^ invert, &sp_task[i]);
17551755
} else {
17561756
i = 0;
1757-
err[i] = create_split_task(RIGHT_STRIPE | DOWN_STRIPE, &sp_task[i]);
1757+
err[i] = create_split_task((RIGHT_STRIPE | DOWN_STRIPE) ^ invert, &sp_task[i]);
17581758
if (err[i] < 0)
17591759
goto err_start;
17601760
i = 1;
1761-
err[i] = create_split_task(LEFT_STRIPE | DOWN_STRIPE, &sp_task[i]);
1761+
err[i] = create_split_task((LEFT_STRIPE | DOWN_STRIPE) ^ invert, &sp_task[i]);
17621762
if (err[i] < 0)
17631763
goto err_start;
17641764
i = 2;
1765-
err[i] = create_split_task(RIGHT_STRIPE | UP_STRIPE, &sp_task[i]);
1765+
err[i] = create_split_task((RIGHT_STRIPE | UP_STRIPE) ^ invert, &sp_task[i]);
17661766
if (err[i] < 0)
17671767
goto err_start;
17681768
i = 3;
1769-
err[i] = create_split_task(LEFT_STRIPE | UP_STRIPE, &sp_task[i]);
1769+
err[i] = create_split_task((LEFT_STRIPE | UP_STRIPE) ^ invert, &sp_task[i]);
17701770
}
17711771

17721772
err_start:
@@ -2407,219 +2407,11 @@ static irqreturn_t task_irq_handler(int irq, void *dev_id)
24072407
return IRQ_HANDLED;
24082408
}
24092409

2410-
/* Fix deinterlace up&down split mode medium line */
2411-
static void vdi_split_process(struct ipu_soc *ipu, struct ipu_task_entry *t)
2412-
{
2413-
u32 vdi_size;
2414-
u32 vdi_save_lines;
2415-
u32 stripe_mode;
2416-
u32 task_no;
2417-
u32 i, offset_addr;
2418-
u32 line_size;
2419-
unsigned char *base_off;
2420-
struct ipu_task_entry *parent = t->parent;
2421-
struct mutex *lock = &parent->vdic_lock;
2422-
2423-
if (!parent) {
2424-
dev_err(t->dev, "ERR[0x%x]invalid parent\n", t->task_no);
2425-
return;
2426-
}
2427-
mutex_lock(lock);
2428-
stripe_mode = t->task_no & 0xf;
2429-
task_no = t->task_no >> 4;
2430-
2431-
/* Save both luma and chroma part for interleaved YUV(e.g. YUYV).
2432-
* Save luma part for non-interleaved and partial-interleaved
2433-
* YUV format (e.g NV12 and YV12). */
2434-
if (t->output.format == IPU_PIX_FMT_YUYV ||
2435-
t->output.format == IPU_PIX_FMT_UYVY)
2436-
line_size = t->output.crop.w * fmt_to_bpp(t->output.format)/8;
2437-
else
2438-
line_size = t->output.crop.w;
2439-
2440-
vdi_save_lines = (t->output.crop.h - t->set.sp_setting.ud_split_line)/2;
2441-
vdi_size = vdi_save_lines * line_size;
2442-
if (vdi_save_lines <= 0) {
2443-
dev_err(t->dev, "[0x%p] vdi_save_line error\n", (void *)t);
2444-
mutex_unlock(lock);
2445-
return;
2446-
}
2447-
2448-
/*check vditmpbuf buffer have alloced or buffer size is changed */
2449-
if ((vdi_save_lines != parent->old_save_lines) ||
2450-
(vdi_size != parent->old_size)) {
2451-
if (parent->vditmpbuf[0] != NULL)
2452-
kfree(parent->vditmpbuf[0]);
2453-
if (parent->vditmpbuf[1] != NULL)
2454-
kfree(parent->vditmpbuf[1]);
2455-
2456-
parent->vditmpbuf[0] = kmalloc(vdi_size, GFP_KERNEL);
2457-
if (parent->vditmpbuf[0] == NULL) {
2458-
dev_err(t->dev,
2459-
"[0x%p]Falied Alloc vditmpbuf[0]\n", (void *)t);
2460-
mutex_unlock(lock);
2461-
return;
2462-
}
2463-
memset(parent->vditmpbuf[0], 0, vdi_size);
2464-
2465-
parent->vditmpbuf[1] = kmalloc(vdi_size, GFP_KERNEL);
2466-
if (parent->vditmpbuf[1] == NULL) {
2467-
dev_err(t->dev,
2468-
"[0x%p]Falied Alloc vditmpbuf[1]\n", (void *)t);
2469-
mutex_unlock(lock);
2470-
return;
2471-
}
2472-
memset(parent->vditmpbuf[1], 0, vdi_size);
2473-
2474-
parent->old_save_lines = vdi_save_lines;
2475-
parent->old_size = vdi_size;
2476-
}
2477-
2478-
if (pfn_valid(t->output.paddr >> PAGE_SHIFT)) {
2479-
base_off = page_address(pfn_to_page(t->output.paddr >> PAGE_SHIFT));
2480-
base_off += t->output.paddr & ((1 << PAGE_SHIFT) - 1);
2481-
} else {
2482-
base_off = (char *)ioremap_nocache(t->output.paddr,
2483-
t->output.width * t->output.height *
2484-
fmt_to_bpp(t->output.format)/8);
2485-
}
2486-
if (base_off == NULL) {
2487-
dev_err(t->dev, "ERR[0x%p]Failed get virtual address\n", t);
2488-
mutex_unlock(lock);
2489-
return;
2490-
}
2491-
2492-
/* UP stripe or UP&LEFT stripe */
2493-
if ((stripe_mode == UP_STRIPE) ||
2494-
(stripe_mode == (UP_STRIPE | LEFT_STRIPE))) {
2495-
if (!parent->buf0filled) {
2496-
offset_addr = t->set.o_off +
2497-
t->set.sp_setting.ud_split_line*t->set.ostride;
2498-
dmac_flush_range(base_off + offset_addr,
2499-
base_off + offset_addr + vdi_size);
2500-
outer_flush_range(t->output.paddr + offset_addr,
2501-
t->output.paddr + offset_addr + vdi_size);
2502-
2503-
for (i = 0; i < vdi_save_lines; i++)
2504-
memcpy(parent->vditmpbuf[0] + i*line_size,
2505-
base_off + offset_addr +
2506-
i*t->set.ostride, line_size);
2507-
parent->buf0filled = true;
2508-
} else {
2509-
offset_addr = t->set.o_off + (t->output.crop.h -
2510-
vdi_save_lines) * t->set.ostride;
2511-
for (i = 0; i < vdi_save_lines; i++)
2512-
memcpy(base_off + offset_addr + i*t->set.ostride,
2513-
parent->vditmpbuf[0] + i*line_size, line_size);
2514-
2515-
dmac_flush_range(base_off + offset_addr,
2516-
base_off + offset_addr + i*t->set.ostride);
2517-
outer_flush_range(t->output.paddr + offset_addr,
2518-
t->output.paddr + offset_addr + i*t->set.ostride);
2519-
parent->buf0filled = false;
2520-
}
2521-
}
2522-
/*Down stripe or Down&Left stripe*/
2523-
else if ((stripe_mode == DOWN_STRIPE) ||
2524-
(stripe_mode == (DOWN_STRIPE | LEFT_STRIPE))) {
2525-
if (!parent->buf0filled) {
2526-
offset_addr = t->set.o_off + vdi_save_lines*t->set.ostride;
2527-
dmac_flush_range(base_off + offset_addr,
2528-
base_off + offset_addr + vdi_size);
2529-
outer_flush_range(t->output.paddr + offset_addr,
2530-
t->output.paddr + offset_addr + vdi_size);
2531-
2532-
for (i = 0; i < vdi_save_lines; i++)
2533-
memcpy(parent->vditmpbuf[0] + i*line_size,
2534-
base_off + offset_addr + i*t->set.ostride,
2535-
line_size);
2536-
parent->buf0filled = true;
2537-
} else {
2538-
offset_addr = t->set.o_off;
2539-
for (i = 0; i < vdi_save_lines; i++)
2540-
memcpy(base_off + offset_addr + i*t->set.ostride,
2541-
parent->vditmpbuf[0] + i*line_size,
2542-
line_size);
2543-
2544-
dmac_flush_range(base_off + offset_addr,
2545-
base_off + offset_addr + i*t->set.ostride);
2546-
outer_flush_range(t->output.paddr + offset_addr,
2547-
t->output.paddr + offset_addr + i*t->set.ostride);
2548-
parent->buf0filled = false;
2549-
}
2550-
}
2551-
/*Up&Right stripe*/
2552-
else if (stripe_mode == (UP_STRIPE | RIGHT_STRIPE)) {
2553-
if (!parent->buf1filled) {
2554-
offset_addr = t->set.o_off +
2555-
t->set.sp_setting.ud_split_line*t->set.ostride;
2556-
dmac_flush_range(base_off + offset_addr,
2557-
base_off + offset_addr + vdi_size);
2558-
outer_flush_range(t->output.paddr + offset_addr,
2559-
t->output.paddr + offset_addr + vdi_size);
2560-
2561-
for (i = 0; i < vdi_save_lines; i++)
2562-
memcpy(parent->vditmpbuf[1] + i*line_size,
2563-
base_off + offset_addr + i*t->set.ostride,
2564-
line_size);
2565-
parent->buf1filled = true;
2566-
} else {
2567-
offset_addr = t->set.o_off +
2568-
(t->output.crop.h - vdi_save_lines)*t->set.ostride;
2569-
for (i = 0; i < vdi_save_lines; i++)
2570-
memcpy(base_off + offset_addr + i*t->set.ostride,
2571-
parent->vditmpbuf[1] + i*line_size,
2572-
line_size);
2573-
2574-
dmac_flush_range(base_off + offset_addr,
2575-
base_off + offset_addr + i*t->set.ostride);
2576-
outer_flush_range(t->output.paddr + offset_addr,
2577-
t->output.paddr + offset_addr + i*t->set.ostride);
2578-
parent->buf1filled = false;
2579-
}
2580-
}
2581-
/*Down stripe or Down&Right stript*/
2582-
else if (stripe_mode == (DOWN_STRIPE | RIGHT_STRIPE)) {
2583-
if (!parent->buf1filled) {
2584-
offset_addr = t->set.o_off + vdi_save_lines*t->set.ostride;
2585-
dmac_flush_range(base_off + offset_addr,
2586-
base_off + offset_addr + vdi_save_lines*t->set.ostride);
2587-
outer_flush_range(t->output.paddr + offset_addr,
2588-
t->output.paddr + offset_addr + vdi_save_lines*t->set.ostride);
2589-
2590-
for (i = 0; i < vdi_save_lines; i++)
2591-
memcpy(parent->vditmpbuf[1] + i*line_size,
2592-
base_off + offset_addr + i*t->set.ostride,
2593-
line_size);
2594-
parent->buf1filled = true;
2595-
} else {
2596-
offset_addr = t->set.o_off;
2597-
for (i = 0; i < vdi_save_lines; i++)
2598-
memcpy(base_off + offset_addr + i*t->set.ostride,
2599-
parent->vditmpbuf[1] + i*line_size,
2600-
line_size);
2601-
2602-
dmac_flush_range(base_off + offset_addr,
2603-
base_off + offset_addr + vdi_save_lines*t->set.ostride);
2604-
outer_flush_range(t->output.paddr + offset_addr,
2605-
t->output.paddr + offset_addr + vdi_save_lines*t->set.ostride);
2606-
parent->buf1filled = false;
2607-
}
2608-
}
2609-
if (!pfn_valid(t->output.paddr >> PAGE_SHIFT))
2610-
iounmap(base_off);
2611-
mutex_unlock(lock);
2612-
}
2613-
26142410
static void do_task_release(struct ipu_task_entry *t, int fail)
26152411
{
26162412
int ret;
26172413
struct ipu_soc *ipu = t->ipu;
26182414

2619-
if (t->input.deinterlace.enable && !fail &&
2620-
(t->task_no & (UP_STRIPE | DOWN_STRIPE)))
2621-
vdi_split_process(ipu, t);
2622-
26232415
ipu_free_irq(ipu, t->irq, t);
26242416

26252417
if (t->vdoa_dma.vaddr)
@@ -3180,9 +2972,6 @@ static void wait_split_task_complete(struct ipu_task_entry *parent,
31802972
kref_put(&tsk->refcount, task_mem_free);
31812973
}
31822974

3183-
kfree(parent->vditmpbuf[0]);
3184-
kfree(parent->vditmpbuf[1]);
3185-
31862975
if (ret < 0)
31872976
parent->state = STATE_TIMEOUT;
31882977
else

0 commit comments

Comments
 (0)