|  | @@ -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);
 | 
	
		
			
				|  |  | +
 |