diff options
Diffstat (limited to 'recipes/linux/linux-omap-pm/dss2/0070-DSS2-fix-irq1.diff')
-rw-r--r-- | recipes/linux/linux-omap-pm/dss2/0070-DSS2-fix-irq1.diff | 221 |
1 files changed, 221 insertions, 0 deletions
diff --git a/recipes/linux/linux-omap-pm/dss2/0070-DSS2-fix-irq1.diff b/recipes/linux/linux-omap-pm/dss2/0070-DSS2-fix-irq1.diff new file mode 100644 index 0000000000..8f384dfe2d --- /dev/null +++ b/recipes/linux/linux-omap-pm/dss2/0070-DSS2-fix-irq1.diff @@ -0,0 +1,221 @@ +From 093988f36ffcb0201927f8b452e546e1141aa0fa Mon Sep 17 00:00:00 2001 +From: Tomi Valkeinen <tomi.valkeinen@nokia.com> +Date: Sat, 23 May 2009 15:00:21 +0000 +Subject: DSS2: DISPC: fix irq handling locking + +--- +diff --git a/drivers/video/omap2/dss/dispc.c b/drivers/video/omap2/dss/dispc.c +index b0e4960..b3685b2 100644 +--- a/drivers/video/omap2/dss/dispc.c ++++ b/drivers/video/omap2/dss/dispc.c +@@ -154,23 +154,20 @@ static struct { + + struct clk *dpll4_m4_ck; + +- spinlock_t irq_lock; +- + unsigned long cache_req_pck; + unsigned long cache_prate; + struct dispc_clock_info cache_cinfo; + +- u32 irq_error_mask; ++ spinlock_t irq_lock; ++ u32 irq_error_mask; + struct omap_dispc_isr_data registered_isr[DISPC_MAX_NR_ISRS]; +- +- spinlock_t error_lock; + u32 error_irqs; + struct work_struct error_work; + + u32 ctx[DISPC_SZ_REGS / sizeof(u32)]; + } dispc; + +-static void omap_dispc_set_irqs(void); ++static void _omap_dispc_set_irqs(void); + + static inline void dispc_write_reg(const struct dispc_reg idx, u32 val) + { +@@ -1691,10 +1688,13 @@ void dispc_enable_digit_out(bool enable) + } + + if (enable) { ++ unsigned long flags; + /* When we enable digit output, we'll get an extra digit + * sync lost interrupt, that we need to ignore */ ++ spin_lock_irqsave(&dispc.irq_lock, flags); + dispc.irq_error_mask &= ~DISPC_IRQ_SYNC_LOST_DIGIT; +- omap_dispc_set_irqs(); ++ _omap_dispc_set_irqs(); ++ spin_unlock_irqrestore(&dispc.irq_lock, flags); + } + + /* When we disable digit output, we need to wait until fields are done. +@@ -1728,9 +1728,12 @@ void dispc_enable_digit_out(bool enable) + DSSERR("failed to unregister EVSYNC isr\n"); + + if (enable) { ++ unsigned long flags; ++ spin_lock_irqsave(&dispc.irq_lock, flags); + dispc.irq_error_mask = DISPC_IRQ_MASK_ERROR; + dispc_write_reg(DISPC_IRQSTATUS, DISPC_IRQ_SYNC_LOST_DIGIT); +- omap_dispc_set_irqs(); ++ _omap_dispc_set_irqs(); ++ spin_unlock_irqrestore(&dispc.irq_lock, flags); + } + + enable_clocks(0); +@@ -2508,14 +2511,14 @@ int dispc_get_clock_div(struct dispc_clock_info *cinfo) + return 0; + } + +-static void omap_dispc_set_irqs(void) ++/* dispc.irq_lock has to be locked by the caller */ ++static void _omap_dispc_set_irqs(void) + { +- unsigned long flags; +- u32 mask = dispc.irq_error_mask; ++ u32 mask; + int i; + struct omap_dispc_isr_data *isr_data; + +- spin_lock_irqsave(&dispc.irq_lock, flags); ++ mask = dispc.irq_error_mask; + + for (i = 0; i < DISPC_MAX_NR_ISRS; i++) { + isr_data = &dispc.registered_isr[i]; +@@ -2528,9 +2531,8 @@ static void omap_dispc_set_irqs(void) + + enable_clocks(1); + dispc_write_reg(DISPC_IRQENABLE, mask); +- enable_clocks(0); + +- spin_unlock_irqrestore(&dispc.irq_lock, flags); ++ enable_clocks(0); + } + + int omap_dispc_register_isr(omap_dispc_isr_t isr, void *arg, u32 mask) +@@ -2571,11 +2573,14 @@ int omap_dispc_register_isr(omap_dispc_isr_t isr, void *arg, u32 mask) + + break; + } +-err: ++ ++ _omap_dispc_set_irqs(); ++ + spin_unlock_irqrestore(&dispc.irq_lock, flags); + +- if (ret == 0) +- omap_dispc_set_irqs(); ++ return 0; ++err: ++ spin_unlock_irqrestore(&dispc.irq_lock, flags); + + return ret; + } +@@ -2606,10 +2611,10 @@ int omap_dispc_unregister_isr(omap_dispc_isr_t isr, void *arg, u32 mask) + break; + } + +- spin_unlock_irqrestore(&dispc.irq_lock, flags); +- + if (ret == 0) +- omap_dispc_set_irqs(); ++ _omap_dispc_set_irqs(); ++ ++ spin_unlock_irqrestore(&dispc.irq_lock, flags); + + return ret; + } +@@ -2645,11 +2650,15 @@ static void print_irq_status(u32 status) + void dispc_irq_handler(void) + { + int i; +- u32 irqstatus = dispc_read_reg(DISPC_IRQSTATUS); ++ u32 irqstatus; + u32 handledirqs = 0; + u32 unhandled_errors; + struct omap_dispc_isr_data *isr_data; + ++ spin_lock(&dispc.irq_lock); ++ ++ irqstatus = dispc_read_reg(DISPC_IRQSTATUS); ++ + #ifdef DEBUG + if (dss_debug) + print_irq_status(irqstatus); +@@ -2673,15 +2682,15 @@ void dispc_irq_handler(void) + unhandled_errors = irqstatus & ~handledirqs & dispc.irq_error_mask; + + if (unhandled_errors) { +- spin_lock(&dispc.error_lock); + dispc.error_irqs |= unhandled_errors; +- spin_unlock(&dispc.error_lock); + + dispc.irq_error_mask &= ~unhandled_errors; +- omap_dispc_set_irqs(); ++ _omap_dispc_set_irqs(); + + schedule_work(&dispc.error_work); + } ++ ++ spin_unlock(&dispc.irq_lock); + } + + static void dispc_error_worker(struct work_struct *work) +@@ -2690,10 +2699,10 @@ static void dispc_error_worker(struct work_struct *work) + u32 errors; + unsigned long flags; + +- spin_lock_irqsave(&dispc.error_lock, flags); ++ spin_lock_irqsave(&dispc.irq_lock, flags); + errors = dispc.error_irqs; + dispc.error_irqs = 0; +- spin_unlock_irqrestore(&dispc.error_lock, flags); ++ spin_unlock_irqrestore(&dispc.irq_lock, flags); + + if (errors & DISPC_IRQ_GFX_FIFO_UNDERFLOW) { + DSSERR("GFX_FIFO_UNDERFLOW, disabling GFX\n"); +@@ -2836,8 +2845,10 @@ static void dispc_error_worker(struct work_struct *work) + } + } + ++ spin_lock_irqsave(&dispc.irq_lock, flags); + dispc.irq_error_mask |= errors; +- omap_dispc_set_irqs(); ++ _omap_dispc_set_irqs(); ++ spin_unlock_irqrestore(&dispc.irq_lock, flags); + } + + int omap_dispc_wait_for_irq_timeout(u32 irqmask, unsigned long timeout) +@@ -2921,6 +2932,10 @@ void dispc_fake_vsync_irq(void) + + static void _omap_dispc_initialize_irq(void) + { ++ unsigned long flags; ++ ++ spin_lock_irqsave(&dispc.irq_lock, flags); ++ + memset(dispc.registered_isr, 0, sizeof(dispc.registered_isr)); + + dispc.irq_error_mask = DISPC_IRQ_MASK_ERROR; +@@ -2929,7 +2944,9 @@ static void _omap_dispc_initialize_irq(void) + * so clear it */ + dispc_write_reg(DISPC_IRQSTATUS, dispc_read_reg(DISPC_IRQSTATUS)); + +- omap_dispc_set_irqs(); ++ _omap_dispc_set_irqs(); ++ ++ spin_unlock_irqrestore(&dispc.irq_lock, flags); + } + + void dispc_enable_sidle(void) +@@ -2970,7 +2987,6 @@ int dispc_init(void) + u32 rev; + + spin_lock_init(&dispc.irq_lock); +- spin_lock_init(&dispc.error_lock); + + INIT_WORK(&dispc.error_work, dispc_error_worker); + +-- +cgit v0.8.2.1-10-g45e7 |