| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217 | /* * GPMC support functions * * Copyright (C) 2005-2006 Nokia Corporation * * Author: Juha Yrjola * * Copyright (C) 2009 Texas Instruments * Added OMAP4 support - 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. */#undef DEBUG#include <linux/irq.h>#include <linux/kernel.h>#include <linux/init.h>#include <linux/err.h>#include <linux/clk.h>#include <linux/ioport.h>#include <linux/spinlock.h>#include <linux/io.h>#include <linux/module.h>#include <linux/interrupt.h>#include <linux/platform_device.h>#include <linux/platform_data/mtd-nand-omap2.h>#include <asm/mach-types.h>#include "soc.h"#include "common.h"#include "omap_device.h"#include "gpmc.h"#define	DEVICE_NAME		"omap-gpmc"/* GPMC register offsets */#define GPMC_REVISION		0x00#define GPMC_SYSCONFIG		0x10#define GPMC_SYSSTATUS		0x14#define GPMC_IRQSTATUS		0x18#define GPMC_IRQENABLE		0x1c#define GPMC_TIMEOUT_CONTROL	0x40#define GPMC_ERR_ADDRESS	0x44#define GPMC_ERR_TYPE		0x48#define GPMC_CONFIG		0x50#define GPMC_STATUS		0x54#define GPMC_PREFETCH_CONFIG1	0x1e0#define GPMC_PREFETCH_CONFIG2	0x1e4#define GPMC_PREFETCH_CONTROL	0x1ec#define GPMC_PREFETCH_STATUS	0x1f0#define GPMC_ECC_CONFIG		0x1f4#define GPMC_ECC_CONTROL	0x1f8#define GPMC_ECC_SIZE_CONFIG	0x1fc#define GPMC_ECC1_RESULT        0x200#define GPMC_ECC_BCH_RESULT_0   0x240   /* not available on OMAP2 */#define	GPMC_ECC_BCH_RESULT_1	0x244	/* not available on OMAP2 */#define	GPMC_ECC_BCH_RESULT_2	0x248	/* not available on OMAP2 */#define	GPMC_ECC_BCH_RESULT_3	0x24c	/* not available on OMAP2 *//* GPMC ECC control settings */#define GPMC_ECC_CTRL_ECCCLEAR		0x100#define GPMC_ECC_CTRL_ECCDISABLE	0x000#define GPMC_ECC_CTRL_ECCREG1		0x001#define GPMC_ECC_CTRL_ECCREG2		0x002#define GPMC_ECC_CTRL_ECCREG3		0x003#define GPMC_ECC_CTRL_ECCREG4		0x004#define GPMC_ECC_CTRL_ECCREG5		0x005#define GPMC_ECC_CTRL_ECCREG6		0x006#define GPMC_ECC_CTRL_ECCREG7		0x007#define GPMC_ECC_CTRL_ECCREG8		0x008#define GPMC_ECC_CTRL_ECCREG9		0x009#define	GPMC_CONFIG2_CSEXTRADELAY		BIT(7)#define	GPMC_CONFIG3_ADVEXTRADELAY		BIT(7)#define	GPMC_CONFIG4_OEEXTRADELAY		BIT(7)#define	GPMC_CONFIG4_WEEXTRADELAY		BIT(23)#define	GPMC_CONFIG6_CYCLE2CYCLEDIFFCSEN	BIT(6)#define	GPMC_CONFIG6_CYCLE2CYCLESAMECSEN	BIT(7)#define GPMC_CS0_OFFSET		0x60#define GPMC_CS_SIZE		0x30#define	GPMC_BCH_SIZE		0x10#define GPMC_MEM_START		0x00000000#define GPMC_MEM_END		0x3FFFFFFF#define BOOT_ROM_SPACE		0x100000	/* 1MB */#define GPMC_CHUNK_SHIFT	24		/* 16 MB */#define GPMC_SECTION_SHIFT	28		/* 128 MB */#define CS_NUM_SHIFT		24#define ENABLE_PREFETCH		(0x1 << 7)#define DMA_MPU_MODE		2#define	GPMC_REVISION_MAJOR(l)		((l >> 4) & 0xf)#define	GPMC_REVISION_MINOR(l)		(l & 0xf)#define	GPMC_HAS_WR_ACCESS		0x1#define	GPMC_HAS_WR_DATA_MUX_BUS	0x2/* XXX: Only NAND irq has been considered,currently these are the only ones used */#define	GPMC_NR_IRQ		2struct gpmc_client_irq	{	unsigned		irq;	u32			bitmask;};/* Structure to save gpmc cs context */struct gpmc_cs_config {	u32 config1;	u32 config2;	u32 config3;	u32 config4;	u32 config5;	u32 config6;	u32 config7;	int is_valid;};/* * Structure to save/restore gpmc context * to support core off on OMAP3 */struct omap3_gpmc_regs {	u32 sysconfig;	u32 irqenable;	u32 timeout_ctrl;	u32 config;	u32 prefetch_config1;	u32 prefetch_config2;	u32 prefetch_control;	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);static unsigned int gpmc_cs_map;	/* flag for cs which are initialized */static struct device *gpmc_dev;static int gpmc_irq;static resource_size_t phys_base, mem_size;static unsigned gpmc_capability;static void __iomem *gpmc_base;static struct clk *gpmc_l3_clk;static irqreturn_t gpmc_handle_irq(int irq, void *dev);static void gpmc_write_reg(int idx, u32 val){	__raw_writel(val, gpmc_base + idx);}static u32 gpmc_read_reg(int idx){	return __raw_readl(gpmc_base + idx);}void gpmc_cs_write_reg(int cs, int idx, u32 val){	void __iomem *reg_addr;	reg_addr = gpmc_base + GPMC_CS0_OFFSET + (cs * GPMC_CS_SIZE) + idx;	__raw_writel(val, reg_addr);}u32 gpmc_cs_read_reg(int cs, int idx){	void __iomem *reg_addr;	reg_addr = gpmc_base + GPMC_CS0_OFFSET + (cs * GPMC_CS_SIZE) + idx;	return __raw_readl(reg_addr);}/* TODO: Add support for gpmc_fck to clock framework and use it */unsigned long gpmc_get_fclk_period(void){	unsigned long rate = clk_get_rate(gpmc_l3_clk);	if (rate == 0) {		printk(KERN_WARNING "gpmc_l3_clk not enabled\n");		return 0;	}	rate /= 1000;	rate = 1000000000 / rate;	/* In picoseconds */	return rate;}unsigned int gpmc_ns_to_ticks(unsigned int time_ns){	unsigned long tick_ps;	/* Calculate in picosecs to yield more exact results */	tick_ps = gpmc_get_fclk_period();	return (time_ns * 1000 + tick_ps - 1) / tick_ps;}unsigned int gpmc_ps_to_ticks(unsigned int time_ps){	unsigned long tick_ps;	/* Calculate in picosecs to yield more exact results */	tick_ps = gpmc_get_fclk_period();
 |