mirror of
https://github.com/torvalds/linux.git
synced 2024-11-07 12:41:55 +00:00
fbdev: sh_mobile_lcdc: Don't acknowlege interrupts unintentionally
The LDINTR register caries both interrupt enable and interrupt status bits. When setting or clearing interrupt enable bits, write all status bits to 1 to avoid acknowledging interrupts by mistake. When acknowledging interrupts, write 1 to all non-triggered interrupt bits to avoid losing interrupts. Signed-off-by: Laurent Pinchart <laurent.pinchart@ideasonboard.com>
This commit is contained in:
parent
ce1c0b0873
commit
dc48665fae
@ -318,19 +318,13 @@ static irqreturn_t sh_mobile_lcdc_irq(int irq, void *data)
|
|||||||
{
|
{
|
||||||
struct sh_mobile_lcdc_priv *priv = data;
|
struct sh_mobile_lcdc_priv *priv = data;
|
||||||
struct sh_mobile_lcdc_chan *ch;
|
struct sh_mobile_lcdc_chan *ch;
|
||||||
unsigned long tmp;
|
|
||||||
unsigned long ldintr;
|
unsigned long ldintr;
|
||||||
int is_sub;
|
int is_sub;
|
||||||
int k;
|
int k;
|
||||||
|
|
||||||
/* acknowledge interrupt */
|
/* Acknowledge interrupts and disable further VSYNC End IRQs. */
|
||||||
ldintr = tmp = lcdc_read(priv, _LDINTR);
|
ldintr = lcdc_read(priv, _LDINTR);
|
||||||
/*
|
lcdc_write(priv, _LDINTR, (ldintr ^ LDINTR_STATUS_MASK) & ~LDINTR_VEE);
|
||||||
* disable further VSYNC End IRQs, preserve all other enabled IRQs,
|
|
||||||
* write 0 to bits 0-6 to ack all triggered IRQs.
|
|
||||||
*/
|
|
||||||
tmp &= ~LDINTR_STATUS_MASK & ~LDINTR_VEE;
|
|
||||||
lcdc_write(priv, _LDINTR, tmp);
|
|
||||||
|
|
||||||
/* figure out if this interrupt is for main or sub lcd */
|
/* figure out if this interrupt is for main or sub lcd */
|
||||||
is_sub = (lcdc_read(priv, _LDSR) & LDSR_MSS) ? 1 : 0;
|
is_sub = (lcdc_read(priv, _LDSR) & LDSR_MSS) ? 1 : 0;
|
||||||
@ -342,7 +336,7 @@ static irqreturn_t sh_mobile_lcdc_irq(int irq, void *data)
|
|||||||
if (!ch->enabled)
|
if (!ch->enabled)
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
/* Frame Start */
|
/* Frame End */
|
||||||
if (ldintr & LDINTR_FS) {
|
if (ldintr & LDINTR_FS) {
|
||||||
if (is_sub == lcdc_chan_is_sublcd(ch)) {
|
if (is_sub == lcdc_chan_is_sublcd(ch)) {
|
||||||
ch->frame_end = 1;
|
ch->frame_end = 1;
|
||||||
@ -971,9 +965,11 @@ static int sh_mobile_wait_for_vsync(struct fb_info *info)
|
|||||||
unsigned long ldintr;
|
unsigned long ldintr;
|
||||||
int ret;
|
int ret;
|
||||||
|
|
||||||
/* Enable VSync End interrupt */
|
/* Enable VSync End interrupt and be careful not to acknowledge any
|
||||||
|
* pending interrupt.
|
||||||
|
*/
|
||||||
ldintr = lcdc_read(ch->lcdc, _LDINTR);
|
ldintr = lcdc_read(ch->lcdc, _LDINTR);
|
||||||
ldintr |= LDINTR_VEE;
|
ldintr |= LDINTR_VEE | LDINTR_STATUS_MASK;
|
||||||
lcdc_write(ch->lcdc, _LDINTR, ldintr);
|
lcdc_write(ch->lcdc, _LDINTR, ldintr);
|
||||||
|
|
||||||
ret = wait_for_completion_interruptible_timeout(&ch->vsync_completion,
|
ret = wait_for_completion_interruptible_timeout(&ch->vsync_completion,
|
||||||
|
Loading…
Reference in New Issue
Block a user