diff options
Diffstat (limited to 'arch/arm/mach-omap2/gpmc.c')
| -rw-r--r-- | arch/arm/mach-omap2/gpmc.c | 167 | 
1 files changed, 147 insertions, 20 deletions
diff --git a/arch/arm/mach-omap2/gpmc.c b/arch/arm/mach-omap2/gpmc.c index f682e071c66..72428bd45ef 100644 --- a/arch/arm/mach-omap2/gpmc.c +++ b/arch/arm/mach-omap2/gpmc.c @@ -28,8 +28,13 @@  #include <asm/mach-types.h>  #include <plat/gpmc.h> +#include <plat/cpu.h> +#include <plat/gpmc.h>  #include <plat/sdrc.h> +#include "soc.h" +#include "common.h" +  /* GPMC register offsets */  #define GPMC_REVISION		0x00  #define GPMC_SYSCONFIG		0x10 @@ -78,6 +83,15 @@  #define ENABLE_PREFETCH		(0x1 << 7)  #define DMA_MPU_MODE		2 +/* XXX: Only NAND irq has been considered,currently these are the only ones used + */ +#define	GPMC_NR_IRQ		2 + +struct gpmc_client_irq	{ +	unsigned		irq; +	u32			bitmask; +}; +  /* Structure to save gpmc cs context */  struct gpmc_cs_config {  	u32 config1; @@ -105,6 +119,10 @@ struct omap3_gpmc_regs {  	struct gpmc_cs_config cs_context[GPMC_CS_NUM];  }; +static struct gpmc_client_irq gpmc_client_irq[GPMC_NR_IRQ]; +static struct irq_chip gpmc_irq_chip; +static unsigned gpmc_irq_start; +  static struct resource	gpmc_mem_root;  static struct resource	gpmc_cs_mem[GPMC_CS_NUM];  static DEFINE_SPINLOCK(gpmc_mem_lock); @@ -682,6 +700,117 @@ int gpmc_prefetch_reset(int cs)  }  EXPORT_SYMBOL(gpmc_prefetch_reset); +void gpmc_update_nand_reg(struct gpmc_nand_regs *reg, int cs) +{ +	reg->gpmc_status = gpmc_base + GPMC_STATUS; +	reg->gpmc_nand_command = gpmc_base + GPMC_CS0_OFFSET + +				GPMC_CS_NAND_COMMAND + GPMC_CS_SIZE * cs; +	reg->gpmc_nand_address = gpmc_base + GPMC_CS0_OFFSET + +				GPMC_CS_NAND_ADDRESS + GPMC_CS_SIZE * cs; +	reg->gpmc_nand_data = gpmc_base + GPMC_CS0_OFFSET + +				GPMC_CS_NAND_DATA + GPMC_CS_SIZE * cs; +	reg->gpmc_prefetch_config1 = gpmc_base + GPMC_PREFETCH_CONFIG1; +	reg->gpmc_prefetch_config2 = gpmc_base + GPMC_PREFETCH_CONFIG2; +	reg->gpmc_prefetch_control = gpmc_base + GPMC_PREFETCH_CONTROL; +	reg->gpmc_prefetch_status = gpmc_base + GPMC_PREFETCH_STATUS; +	reg->gpmc_ecc_config = gpmc_base + GPMC_ECC_CONFIG; +	reg->gpmc_ecc_control = gpmc_base + GPMC_ECC_CONTROL; +	reg->gpmc_ecc_size_config = gpmc_base + GPMC_ECC_SIZE_CONFIG; +	reg->gpmc_ecc1_result = gpmc_base + GPMC_ECC1_RESULT; +	reg->gpmc_bch_result0 = gpmc_base + GPMC_ECC_BCH_RESULT_0; +} + +int gpmc_get_client_irq(unsigned irq_config) +{ +	int i; + +	if (hweight32(irq_config) > 1) +		return 0; + +	for (i = 0; i < GPMC_NR_IRQ; i++) +		if (gpmc_client_irq[i].bitmask & irq_config) +			return gpmc_client_irq[i].irq; + +	return 0; +} + +static int gpmc_irq_endis(unsigned irq, bool endis) +{ +	int i; +	u32 regval; + +	for (i = 0; i < GPMC_NR_IRQ; i++) +		if (irq == gpmc_client_irq[i].irq) { +			regval = gpmc_read_reg(GPMC_IRQENABLE); +			if (endis) +				regval |= gpmc_client_irq[i].bitmask; +			else +				regval &= ~gpmc_client_irq[i].bitmask; +			gpmc_write_reg(GPMC_IRQENABLE, regval); +			break; +		} + +	return 0; +} + +static void gpmc_irq_disable(struct irq_data *p) +{ +	gpmc_irq_endis(p->irq, false); +} + +static void gpmc_irq_enable(struct irq_data *p) +{ +	gpmc_irq_endis(p->irq, true); +} + +static void gpmc_irq_noop(struct irq_data *data) { } + +static unsigned int gpmc_irq_noop_ret(struct irq_data *data) { return 0; } + +static int gpmc_setup_irq(int gpmc_irq) +{ +	int i; +	u32 regval; + +	if (!gpmc_irq) +		return -EINVAL; + +	gpmc_irq_start = irq_alloc_descs(-1, 0, GPMC_NR_IRQ, 0); +	if (IS_ERR_VALUE(gpmc_irq_start)) { +		pr_err("irq_alloc_descs failed\n"); +		return gpmc_irq_start; +	} + +	gpmc_irq_chip.name = "gpmc"; +	gpmc_irq_chip.irq_startup = gpmc_irq_noop_ret; +	gpmc_irq_chip.irq_enable = gpmc_irq_enable; +	gpmc_irq_chip.irq_disable = gpmc_irq_disable; +	gpmc_irq_chip.irq_shutdown = gpmc_irq_noop; +	gpmc_irq_chip.irq_ack = gpmc_irq_noop; +	gpmc_irq_chip.irq_mask = gpmc_irq_noop; +	gpmc_irq_chip.irq_unmask = gpmc_irq_noop; + +	gpmc_client_irq[0].bitmask = GPMC_IRQ_FIFOEVENTENABLE; +	gpmc_client_irq[1].bitmask = GPMC_IRQ_COUNT_EVENT; + +	for (i = 0; i < GPMC_NR_IRQ; i++) { +		gpmc_client_irq[i].irq = gpmc_irq_start + i; +		irq_set_chip_and_handler(gpmc_client_irq[i].irq, +					&gpmc_irq_chip, handle_simple_irq); +		set_irq_flags(gpmc_client_irq[i].irq, +				IRQF_VALID | IRQF_NOAUTOEN); +	} + +	/* Disable interrupts */ +	gpmc_write_reg(GPMC_IRQENABLE, 0); + +	/* clear interrupts */ +	regval = gpmc_read_reg(GPMC_IRQSTATUS); +	gpmc_write_reg(GPMC_IRQSTATUS, regval); + +	return request_irq(gpmc_irq, gpmc_handle_irq, 0, "gpmc", NULL); +} +  static void __init gpmc_mem_init(void)  {  	int cs; @@ -711,8 +840,8 @@ static void __init gpmc_mem_init(void)  static int __init gpmc_init(void)  { -	u32 l, irq; -	int cs, ret = -EINVAL; +	u32 l; +	int ret = -EINVAL;  	int gpmc_irq;  	char *ck = NULL; @@ -722,16 +851,16 @@ static int __init gpmc_init(void)  			l = OMAP2420_GPMC_BASE;  		else  			l = OMAP34XX_GPMC_BASE; -		gpmc_irq = INT_34XX_GPMC_IRQ; +		gpmc_irq = 20 + OMAP_INTC_START;  	} else if (cpu_is_omap34xx()) {  		ck = "gpmc_fck";  		l = OMAP34XX_GPMC_BASE; -		gpmc_irq = INT_34XX_GPMC_IRQ; +		gpmc_irq = 20 + OMAP_INTC_START;  	} else if (cpu_is_omap44xx() || soc_is_omap54xx()) {  		/* Base address and irq number are same for OMAP4/5 */  		ck = "gpmc_ck";  		l = OMAP44XX_GPMC_BASE; -		gpmc_irq = OMAP44XX_IRQ_GPMC; +		gpmc_irq = 20 + OMAP44XX_IRQ_GIC_START;  	}  	if (WARN_ON(!ck)) @@ -761,16 +890,7 @@ static int __init gpmc_init(void)  	gpmc_write_reg(GPMC_SYSCONFIG, l);  	gpmc_mem_init(); -	/* initalize the irq_chained */ -	irq = OMAP_GPMC_IRQ_BASE; -	for (cs = 0; cs < GPMC_CS_NUM; cs++) { -		irq_set_chip_and_handler(irq, &dummy_irq_chip, -						handle_simple_irq); -		set_irq_flags(irq, IRQF_VALID); -		irq++; -	} - -	ret = request_irq(gpmc_irq, gpmc_handle_irq, IRQF_SHARED, "gpmc", NULL); +	ret = gpmc_setup_irq(gpmc_irq);  	if (ret)  		pr_err("gpmc: irq-%d could not claim: err %d\n",  						gpmc_irq, ret); @@ -780,12 +900,19 @@ postcore_initcall(gpmc_init);  static irqreturn_t gpmc_handle_irq(int irq, void *dev)  { -	u8 cs; +	int i; +	u32 regval; + +	regval = gpmc_read_reg(GPMC_IRQSTATUS); + +	if (!regval) +		return IRQ_NONE; + +	for (i = 0; i < GPMC_NR_IRQ; i++) +		if (regval & gpmc_client_irq[i].bitmask) +			generic_handle_irq(gpmc_client_irq[i].irq); -	/* check cs to invoke the irq */ -	cs = ((gpmc_read_reg(GPMC_PREFETCH_CONFIG1)) >> CS_NUM_SHIFT) & 0x7; -	if (OMAP_GPMC_IRQ_BASE+cs <= OMAP_GPMC_IRQ_END) -		generic_handle_irq(OMAP_GPMC_IRQ_BASE+cs); +	gpmc_write_reg(GPMC_IRQSTATUS, regval);  	return IRQ_HANDLED;  }  |