| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142 | /* * OMAP WakeupGen Source file * * OMAP WakeupGen is the interrupt controller extension used along * with ARM GIC to wake the CPU out from low power states on * external interrupts. It is responsible for generating wakeup * event from the incoming interrupts and enable bits. It is * implemented in MPU always ON power domain. During normal operation, * WakeupGen delivers external interrupts directly to the GIC. * * Copyright (C) 2011 Texas Instruments, Inc. *	Santosh Shilimkar <santosh.shilimkar@ti.com> * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 as * published by the Free Software Foundation. */#include <linux/kernel.h>#include <linux/init.h>#include <linux/io.h>#include <linux/irq.h>#include <linux/platform_device.h>#include <linux/cpu.h>#include <linux/notifier.h>#include <linux/cpu_pm.h>#include <asm/hardware/gic.h>#include "omap-wakeupgen.h"#include "omap-secure.h"#include "soc.h"#include "omap4-sar-layout.h"#include "common.h"#define MAX_NR_REG_BANKS	5#define MAX_IRQS		160#define WKG_MASK_ALL		0x00000000#define WKG_UNMASK_ALL		0xffffffff#define CPU_ENA_OFFSET		0x400#define CPU0_ID			0x0#define CPU1_ID			0x1#define OMAP4_NR_BANKS		4#define OMAP4_NR_IRQS		128static void __iomem *wakeupgen_base;static void __iomem *sar_base;static DEFINE_SPINLOCK(wakeupgen_lock);static unsigned int irq_target_cpu[MAX_IRQS];static unsigned int irq_banks = MAX_NR_REG_BANKS;static unsigned int max_irqs = MAX_IRQS;static unsigned int omap_secure_apis;/* * Static helper functions. */static inline u32 wakeupgen_readl(u8 idx, u32 cpu){	return __raw_readl(wakeupgen_base + OMAP_WKG_ENB_A_0 +				(cpu * CPU_ENA_OFFSET) + (idx * 4));}static inline void wakeupgen_writel(u32 val, u8 idx, u32 cpu){	__raw_writel(val, wakeupgen_base + OMAP_WKG_ENB_A_0 +				(cpu * CPU_ENA_OFFSET) + (idx * 4));}static inline void sar_writel(u32 val, u32 offset, u8 idx){	__raw_writel(val, sar_base + offset + (idx * 4));}static inline int _wakeupgen_get_irq_info(u32 irq, u32 *bit_posn, u8 *reg_index){	unsigned int spi_irq;	/*	 * PPIs and SGIs are not supported.	 */	if (irq < OMAP44XX_IRQ_GIC_START)		return -EINVAL;	/*	 * Subtract the GIC offset.	 */	spi_irq = irq - OMAP44XX_IRQ_GIC_START;	if (spi_irq > MAX_IRQS) {		pr_err("omap wakeupGen: Invalid IRQ%d\n", irq);		return -EINVAL;	}	/*	 * Each WakeupGen register controls 32 interrupt.	 * i.e. 1 bit per SPI IRQ	 */	*reg_index = spi_irq >> 5;	*bit_posn = spi_irq %= 32;	return 0;}static void _wakeupgen_clear(unsigned int irq, unsigned int cpu){	u32 val, bit_number;	u8 i;	if (_wakeupgen_get_irq_info(irq, &bit_number, &i))		return;	val = wakeupgen_readl(i, cpu);	val &= ~BIT(bit_number);	wakeupgen_writel(val, i, cpu);}static void _wakeupgen_set(unsigned int irq, unsigned int cpu){	u32 val, bit_number;	u8 i;	if (_wakeupgen_get_irq_info(irq, &bit_number, &i))		return;	val = wakeupgen_readl(i, cpu);	val |= BIT(bit_number);	wakeupgen_writel(val, i, cpu);}/* * Architecture specific Mask extension */static void wakeupgen_mask(struct irq_data *d){	unsigned long flags;	spin_lock_irqsave(&wakeupgen_lock, flags);	_wakeupgen_clear(d->irq, irq_target_cpu[d->irq]);	spin_unlock_irqrestore(&wakeupgen_lock, flags);}/*
 |