|
@@ -52,3 +52,94 @@ static struct irq_chip_generic **prcm_irq_chips;
|
|
|
* that calls omap_prcm_register_chain_handler().
|
|
|
*/
|
|
|
static struct omap_prcm_irq_setup *prcm_irq_setup;
|
|
|
+
|
|
|
+/* prm_base: base virtual address of the PRM IP block */
|
|
|
+void __iomem *prm_base;
|
|
|
+
|
|
|
+/*
|
|
|
+ * prm_ll_data: function pointers to SoC-specific implementations of
|
|
|
+ * common PRM functions
|
|
|
+ */
|
|
|
+static struct prm_ll_data null_prm_ll_data;
|
|
|
+static struct prm_ll_data *prm_ll_data = &null_prm_ll_data;
|
|
|
+
|
|
|
+/* Private functions */
|
|
|
+
|
|
|
+/*
|
|
|
+ * Move priority events from events to priority_events array
|
|
|
+ */
|
|
|
+static void omap_prcm_events_filter_priority(unsigned long *events,
|
|
|
+ unsigned long *priority_events)
|
|
|
+{
|
|
|
+ int i;
|
|
|
+
|
|
|
+ for (i = 0; i < prcm_irq_setup->nr_regs; i++) {
|
|
|
+ priority_events[i] =
|
|
|
+ events[i] & prcm_irq_setup->priority_mask[i];
|
|
|
+ events[i] ^= priority_events[i];
|
|
|
+ }
|
|
|
+}
|
|
|
+
|
|
|
+/*
|
|
|
+ * PRCM Interrupt Handler
|
|
|
+ *
|
|
|
+ * This is a common handler for the OMAP PRCM interrupts. Pending
|
|
|
+ * interrupts are detected by a call to prcm_pending_events and
|
|
|
+ * dispatched accordingly. Clearing of the wakeup events should be
|
|
|
+ * done by the SoC specific individual handlers.
|
|
|
+ */
|
|
|
+static void omap_prcm_irq_handler(unsigned int irq, struct irq_desc *desc)
|
|
|
+{
|
|
|
+ unsigned long pending[OMAP_PRCM_MAX_NR_PENDING_REG];
|
|
|
+ unsigned long priority_pending[OMAP_PRCM_MAX_NR_PENDING_REG];
|
|
|
+ struct irq_chip *chip = irq_desc_get_chip(desc);
|
|
|
+ unsigned int virtirq;
|
|
|
+ int nr_irq = prcm_irq_setup->nr_regs * 32;
|
|
|
+
|
|
|
+ /*
|
|
|
+ * If we are suspended, mask all interrupts from PRCM level,
|
|
|
+ * this does not ack them, and they will be pending until we
|
|
|
+ * re-enable the interrupts, at which point the
|
|
|
+ * omap_prcm_irq_handler will be executed again. The
|
|
|
+ * _save_and_clear_irqen() function must ensure that the PRM
|
|
|
+ * write to disable all IRQs has reached the PRM before
|
|
|
+ * returning, or spurious PRCM interrupts may occur during
|
|
|
+ * suspend.
|
|
|
+ */
|
|
|
+ if (prcm_irq_setup->suspended) {
|
|
|
+ prcm_irq_setup->save_and_clear_irqen(prcm_irq_setup->saved_mask);
|
|
|
+ prcm_irq_setup->suspend_save_flag = true;
|
|
|
+ }
|
|
|
+
|
|
|
+ /*
|
|
|
+ * Loop until all pending irqs are handled, since
|
|
|
+ * generic_handle_irq() can cause new irqs to come
|
|
|
+ */
|
|
|
+ while (!prcm_irq_setup->suspended) {
|
|
|
+ prcm_irq_setup->read_pending_irqs(pending);
|
|
|
+
|
|
|
+ /* No bit set, then all IRQs are handled */
|
|
|
+ if (find_first_bit(pending, nr_irq) >= nr_irq)
|
|
|
+ break;
|
|
|
+
|
|
|
+ omap_prcm_events_filter_priority(pending, priority_pending);
|
|
|
+
|
|
|
+ /*
|
|
|
+ * Loop on all currently pending irqs so that new irqs
|
|
|
+ * cannot starve previously pending irqs
|
|
|
+ */
|
|
|
+
|
|
|
+ /* Serve priority events first */
|
|
|
+ for_each_set_bit(virtirq, priority_pending, nr_irq)
|
|
|
+ generic_handle_irq(prcm_irq_setup->base_irq + virtirq);
|
|
|
+
|
|
|
+ /* Serve normal events next */
|
|
|
+ for_each_set_bit(virtirq, pending, nr_irq)
|
|
|
+ generic_handle_irq(prcm_irq_setup->base_irq + virtirq);
|
|
|
+ }
|
|
|
+ if (chip->irq_ack)
|
|
|
+ chip->irq_ack(&desc->irq_data);
|
|
|
+ if (chip->irq_eoi)
|
|
|
+ chip->irq_eoi(&desc->irq_data);
|
|
|
+ chip->irq_unmask(&desc->irq_data);
|
|
|
+
|