summaryrefslogtreecommitdiff
path: root/recipes/linux/linux-omap-pm/dss2/0070-DSS2-fix-irq1.diff
diff options
context:
space:
mode:
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.diff221
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