LCD DMA underflow interrupt routine

1 post / 0 new
Author
Message
#1
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

I'm trying to fix the recurring problem on this forum regarding lcd dma / fifo underrun.

I've added the HMATRIX priority hack but I'm still getting varying amounts of display problems.

The various suggestions on this forum state that you should turn the dma engine and lcd core off, then back on.

Below is the code I'm using (cobbled together from existing examples) ...

static irqreturn_t atmel_lcdfb_interrupt(int irq, void *dev_id)
{
	struct fb_info *info = dev_id;
	struct atmel_lcdfb_info *sinfo = info->par;
	u32 status;

	status = lcdc_readl(sinfo, ATMEL_LCDC_ISR);
	while (status)
	{
		if (status & (ATMEL_LCDC_UFLWI | ATMEL_LCDC_OWRI | ATMEL_LCDC_MERI))
		{
			//printk("DMA ISSUE\n");
			lcdc_writel(sinfo, ATMEL_LCDC_ICR, ATMEL_LCDC_UFLWI | ATMEL_LCDC_OWRI | ATMEL_LCDC_MERI);

			// turn off lcd controller and dma engine
			lcdc_writel(sinfo, ATMEL_LCDC_PWRCON, 0 << ATMEL_LCDC_GUARDT_OFFSET);
			lcdc_writel(sinfo, ATMEL_LCDC_DMACON, 0);

			// reset the dma controller
			lcdc_writel(sinfo, ATMEL_LCDC_DMACON, ATMEL_LCDC_DMARST);

			/* ...wait for DMA engine to become idle... */
			while (lcdc_readl(sinfo, ATMEL_LCDC_DMACON) & ATMEL_LCDC_DMABUSY)
			{
				//printk("DMA busy\n");
				//msleep(1);
			}

			// re-enable irqs
			lcdc_writel(sinfo, ATMEL_LCDC_IER, ATMEL_LCDC_UFLWI);

			/* ...and enable it with updated configuration */
			lcdc_writel(sinfo, ATMEL_LCDC_DMACON, sinfo->default_dmacon);
			lcdc_writel(sinfo, ATMEL_LCDC_PWRCON,
				(0 << ATMEL_LCDC_GUARDT_OFFSET) | ATMEL_LCDC_PWR);

			status &= ~(ATMEL_LCDC_UFLWI | ATMEL_LCDC_OWRI | ATMEL_LCDC_MERI);
		}
		if (status)
		{
			printk(KERN_ERR "LCDC: INTERRUPT PENDING: 0x%x\n", status);
			lcdc_writel(sinfo, ATMEL_LCDC_IDR, status);
		}

		status = lcdc_readl(sinfo, ATMEL_LCDC_ISR);
	}

	return IRQ_HANDLED;
}

This almost works, but there's a nasty, very noticeable flicker when the lcd core is turned off, and back on again.

This seems obvious since, while the lcd core is off, nothing is driving the lcd signals. Hence we'll get a screen flickers.

But other postings claim that we should be able to do this "restart" without seeing any change in the displayed image.

After the interrupt routine has finished, the display appears as before (i.e. no vertical and / or horizontal scrolling), so I'm guessing the dma and lcd are being restarted okay.

So why do I get the noticeable flicker ?

Does anyone else have a working version of this code (or hint as to what I might have missed out, if anything) ?

Or have I done all I can, and I'm just hitting the limits of the internal bandwidth ?

FYI, I'm driving a 640x480 18bpp lcd module on a 150MHz custom version of the NGW100 platform.

If I've hit the limits, I guess my only options are a lower resolution, or use 16bpp ?

The 16bpp would be my personal choice, since you're only losing 2 bits of colour, but only having to transfer 2 bytes per pixel rather than 3, freeing up a large chunk of bandwidth.

Thanks for any help.
Mark