/*
* 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 <asm/mach-types.h>
#include <plat/gpmc.h>
#include <plat/sdrc.h>
/* 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 */
/* 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_CS0_OFFSET 0x60
#define GPMC_CS_SIZE 0x30
#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
/* 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 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 int gpmc_ecc_used = -EINVAL; /* cs using ecc engine */
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);
}
static void gpmc_cs_write_byte(int cs, int idx, u8 val)
{
void __iomem *reg_addr;
reg_addr = gpmc_base + GPMC_CS0_OFFSET + (cs * GPMC_CS_SIZE) + idx;
__raw_writeb(val, reg_addr);
}
static u8 gpmc_cs_read_byte(int cs, int idx)
{
void __iomem *reg_addr;
reg_addr = gpmc_base + GPMC_CS0_OFFSET + (cs * GPMC_CS_SIZE) + idx;
return __raw_readb(reg_addr);
}
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