ARM: soc: general cleanups

This is a large branch that contains a handful of different cleanups:
 
 - Fixing up the I/O space remapping on PCI on ARM. This is a series
   from Rob Herring that restructures how all pci devices allocate I/O
   space, and it's part of the work to allow multiplatform kernels.
 - A number of cleanup series for OMAP, moving and removing some
   headers, sparse irq rework and in general preparation for
   multiplatform.
 - Final removal of all non-DT boards for Tegra, it is now
   device-tree-only!
 - Removal of a stale platform, nxp4008. It's an old mobile chipset
   that is no longer in use, and was very likely never really used with
   a mainline kernel. We have not been able to find anyone interested
   in keeping it around in the kernel.
 - Removal of the legacy dmaengine driver on tegra
 
 + A handful of other things that I haven't described above.
 -----BEGIN PGP SIGNATURE-----
 Version: GnuPG v1.4.11 (GNU/Linux)
 
 iQIcBAABAgAGBQJQaO1fAAoJEIwa5zzehBx3IPgP/jxoO1flVGNVf0reqqyDro/w
 prZmp8cNVH9uv8xG9n9vawObrMQ8M6jCJ449fEWuAZ58EXrpIPd0kkm/MOmxp8K1
 LNs+q2aXxWpD488+b3RK55g3fksqZutTbn3y6HNuCoLG9l8yT/95KX4IIzfEP2Ch
 1TCNHdkTbf37nTBOmKN0x1kahGpWDrOkf9ysHQq+DXAGF4uwNwtR194dqz3HbDND
 hZqRq7qCLn9OwGRGNicPFoB6UcxwZ/+/+u5sX7nqPGoiPofg977mhWk1DFO15EM3
 S+A6g0dZ+XLsL+fFtOl4snSmrG5Et6qTOP0/ItQJgTG+5YdCS09ohCWJwRCBHbgj
 M5arOkyGFdVAlvX7cUux374sMe0AcqUsEmt79mYuBpIE+pBJaRUoCgDcs9FDZeUB
 U6WcE4AkxMtW7DtmVW+mF4ls9/K6cRXgWMuHCUmt1o3m3Ly9ITT7j+ntXnD9nuYk
 ndoVLR6Vxk2BzlkD0JEtg7FRAS9Wgo2DBix05qM1Qkut2iIZRhFQlqJQpNbeNdii
 /3Lg/hqpAVTZKGCd+paegHez61meyFz2PB2IiE0JKANhKHRCWTWRGgKIXkGyCiXk
 wJ2iRCOlMEpmpJgCBzfI32ER/hnW4s64iDjgksEwz6pEt7xCbhwgmwrpf0H0KsSF
 rLroHOMqyISd/Ha52Vin
 =ck1u
 -----END PGP SIGNATURE-----

Merge tag 'cleanup' of git://git.kernel.org/pub/scm/linux/kernel/git/arm/arm-soc

Pull ARM soc general cleanups from Olof Johansson:
 "This is a large branch that contains a handful of different cleanups:

   - Fixing up the I/O space remapping on PCI on ARM.  This is a series
     from Rob Herring that restructures how all pci devices allocate I/O
     space, and it's part of the work to allow multiplatform kernels.
   - A number of cleanup series for OMAP, moving and removing some
     headers, sparse irq rework and in general preparation for
     multiplatform.
   - Final removal of all non-DT boards for Tegra, it is now
     device-tree-only!
   - Removal of a stale platform, nxp4008.  It's an old mobile chipset
     that is no longer in use, and was very likely never really used
     with a mainline kernel.  We have not been able to find anyone
     interested in keeping it around in the kernel.
   - Removal of the legacy dmaengine driver on tegra

  + A handful of other things that I haven't described above."

Fix up some conflicts with the staging tree (and because nxp4008 was
removed)

* tag 'cleanup' of git://git.kernel.org/pub/scm/linux/kernel/git/arm/arm-soc: (184 commits)
  ARM: OMAP2+: serial: Change MAX_HSUART_PORTS to 6
  ARM: OMAP4: twl-common: Support for additional devices on i2c1 bus
  ARM: mmp: using for_each_set_bit to simplify the code
  ARM: tegra: harmony: fix ldo7 regulator-name
  ARM: OMAP2+: Make omap4-keypad.h local
  ARM: OMAP2+: Make l4_3xxx.h local
  ARM: OMAP2+: Make l4_2xxx.h local
  ARM: OMAP2+: Make l3_3xxx.h local
  ARM: OMAP2+: Make l3_2xxx.h local
  ARM: OMAP1: Move irda.h from plat to mach
  ARM: OMAP2+: Make hdq1w.h local
  ARM: OMAP2+: Make gpmc-smsc911x.h local
  ARM: OMAP2+: Make gpmc-smc91x.h local
  ARM: OMAP1: Move flash.h from plat to mach
  ARM: OMAP2+: Make debug-devices.h local
  ARM: OMAP1: Move board-voiceblue.h from plat to mach
  ARM: OMAP1: Move board-sx1.h from plat to mach
  ARM: OMAP2+: Make omap-wakeupgen.h local
  ARM: OMAP2+: Make omap-secure.h local
  ARM: OMAP2+: Make ctrl_module_wkup_44xx.h local
  ...
This commit is contained in:
Linus Torvalds 2012-10-01 18:19:05 -07:00
commit 61464c8357
623 changed files with 4618 additions and 15490 deletions

View file

@ -23,11 +23,15 @@
#include <linux/mtd/mtd.h>
#include <linux/mtd/nand.h>
#include <linux/mtd/partitions.h>
#include <asm/io.h>
#include <mach/hardware.h>
#include <asm/sizes.h>
#include <linux/gpio.h>
#include <plat/board-ams-delta.h>
#include <linux/platform_data/gpio-omap.h>
#include <asm/io.h>
#include <asm/sizes.h>
#include <mach/board-ams-delta.h>
#include <mach/hardware.h>
/*
* MTD structure for E3 (Delta)

View file

@ -249,20 +249,20 @@ static int nand_dev_ready(struct mtd_info *mtd)
int bcm_umi_nand_inithw(void)
{
/* Configure nand timing parameters */
REG_UMI_NAND_TCR &= ~0x7ffff;
REG_UMI_NAND_TCR |= HW_CFG_NAND_TCR;
writel(readl(&REG_UMI_NAND_TCR) & ~0x7ffff, &REG_UMI_NAND_TCR);
writel(readl(&REG_UMI_NAND_TCR) | HW_CFG_NAND_TCR, &REG_UMI_NAND_TCR);
#if !defined(CONFIG_MTD_NAND_BCM_UMI_HWCS)
/* enable software control of CS */
REG_UMI_NAND_TCR |= REG_UMI_NAND_TCR_CS_SWCTRL;
writel(readl(&REG_UMI_NAND_TCR) | REG_UMI_NAND_TCR_CS_SWCTRL, &REG_UMI_NAND_TCR);
#endif
/* keep NAND chip select asserted */
REG_UMI_NAND_RCSR |= REG_UMI_NAND_RCSR_CS_ASSERTED;
writel(readl(&REG_UMI_NAND_RCSR) | REG_UMI_NAND_RCSR_CS_ASSERTED, &REG_UMI_NAND_RCSR);
REG_UMI_NAND_TCR &= ~REG_UMI_NAND_TCR_WORD16;
writel(readl(&REG_UMI_NAND_TCR) & ~REG_UMI_NAND_TCR_WORD16, &REG_UMI_NAND_TCR);
/* enable writes to flash */
REG_UMI_MMD_ICR |= REG_UMI_MMD_ICR_FLASH_WP;
writel(readl(&REG_UMI_MMD_ICR) | REG_UMI_MMD_ICR_FLASH_WP, &REG_UMI_MMD_ICR);
writel(NAND_CMD_RESET, bcm_umi_io_base + REG_NAND_CMD_OFFSET);
nand_bcm_umi_wait_till_ready();

View file

@ -17,7 +17,7 @@
/* ---- Include Files ---------------------------------------------------- */
#include <mach/reg_umi.h>
#include <mach/reg_nand.h>
#include <cfg_global.h>
#include <mach/cfg_global.h>
/* ---- Constants and Types ---------------------------------------------- */
#if (CFG_GLOBAL_CHIP_FAMILY == CFG_GLOBAL_CHIP_FAMILY_BCMRING)
@ -48,7 +48,7 @@ int nand_bcm_umi_bch_correct_page(uint8_t *datap, uint8_t *readEccData,
/* Check in device is ready */
static inline int nand_bcm_umi_dev_ready(void)
{
return REG_UMI_NAND_RCSR & REG_UMI_NAND_RCSR_RDY;
return readl(&REG_UMI_NAND_RCSR) & REG_UMI_NAND_RCSR_RDY;
}
/* Wait until device is ready */
@ -62,10 +62,11 @@ static inline void nand_bcm_umi_wait_till_ready(void)
static inline void nand_bcm_umi_hamming_enable_hwecc(void)
{
/* disable and reset ECC, 512 byte page */
REG_UMI_NAND_ECC_CSR &= ~(REG_UMI_NAND_ECC_CSR_ECC_ENABLE |
REG_UMI_NAND_ECC_CSR_256BYTE);
writel(readl(&REG_UMI_NAND_ECC_CSR) & ~(REG_UMI_NAND_ECC_CSR_ECC_ENABLE |
REG_UMI_NAND_ECC_CSR_256BYTE), &REG_UMI_NAND_ECC_CSR);
/* enable ECC */
REG_UMI_NAND_ECC_CSR |= REG_UMI_NAND_ECC_CSR_ECC_ENABLE;
writel(readl(&REG_UMI_NAND_ECC_CSR) | REG_UMI_NAND_ECC_CSR_ECC_ENABLE,
&REG_UMI_NAND_ECC_CSR);
}
#if NAND_ECC_BCH
@ -76,18 +77,18 @@ static inline void nand_bcm_umi_hamming_enable_hwecc(void)
static inline void nand_bcm_umi_bch_enable_read_hwecc(void)
{
/* disable and reset ECC */
REG_UMI_BCH_CTRL_STATUS = REG_UMI_BCH_CTRL_STATUS_RD_ECC_VALID;
writel(REG_UMI_BCH_CTRL_STATUS_RD_ECC_VALID, &REG_UMI_BCH_CTRL_STATUS);
/* Turn on ECC */
REG_UMI_BCH_CTRL_STATUS = REG_UMI_BCH_CTRL_STATUS_ECC_RD_EN;
writel(REG_UMI_BCH_CTRL_STATUS_ECC_RD_EN, &REG_UMI_BCH_CTRL_STATUS);
}
/* Enable BCH Write ECC */
static inline void nand_bcm_umi_bch_enable_write_hwecc(void)
{
/* disable and reset ECC */
REG_UMI_BCH_CTRL_STATUS = REG_UMI_BCH_CTRL_STATUS_WR_ECC_VALID;
writel(REG_UMI_BCH_CTRL_STATUS_WR_ECC_VALID, &REG_UMI_BCH_CTRL_STATUS);
/* Turn on ECC */
REG_UMI_BCH_CTRL_STATUS = REG_UMI_BCH_CTRL_STATUS_ECC_WR_EN;
writel(REG_UMI_BCH_CTRL_STATUS_ECC_WR_EN, &REG_UMI_BCH_CTRL_STATUS);
}
/* Config number of BCH ECC bytes */
@ -99,9 +100,9 @@ static inline void nand_bcm_umi_bch_config_ecc(uint8_t numEccBytes)
uint32_t numBits = numEccBytes * 8;
/* disable and reset ECC */
REG_UMI_BCH_CTRL_STATUS =
REG_UMI_BCH_CTRL_STATUS_WR_ECC_VALID |
REG_UMI_BCH_CTRL_STATUS_RD_ECC_VALID;
writel(REG_UMI_BCH_CTRL_STATUS_WR_ECC_VALID |
REG_UMI_BCH_CTRL_STATUS_RD_ECC_VALID,
&REG_UMI_BCH_CTRL_STATUS);
/* Every correctible bit requires 13 ECC bits */
tValue = (uint32_t) (numBits / ECC_BITS_PER_CORRECTABLE_BIT);
@ -113,23 +114,21 @@ static inline void nand_bcm_umi_bch_config_ecc(uint8_t numEccBytes)
kValue = nValue - (tValue * ECC_BITS_PER_CORRECTABLE_BIT);
/* Write the settings */
REG_UMI_BCH_N = nValue;
REG_UMI_BCH_T = tValue;
REG_UMI_BCH_K = kValue;
writel(nValue, &REG_UMI_BCH_N);
writel(tValue, &REG_UMI_BCH_T);
writel(kValue, &REG_UMI_BCH_K);
}
/* Pause during ECC read calculation to skip bytes in OOB */
static inline void nand_bcm_umi_bch_pause_read_ecc_calc(void)
{
REG_UMI_BCH_CTRL_STATUS =
REG_UMI_BCH_CTRL_STATUS_ECC_RD_EN |
REG_UMI_BCH_CTRL_STATUS_PAUSE_ECC_DEC;
writel(REG_UMI_BCH_CTRL_STATUS_ECC_RD_EN | REG_UMI_BCH_CTRL_STATUS_PAUSE_ECC_DEC, &REG_UMI_BCH_CTRL_STATUS);
}
/* Resume during ECC read calculation after skipping bytes in OOB */
static inline void nand_bcm_umi_bch_resume_read_ecc_calc(void)
{
REG_UMI_BCH_CTRL_STATUS = REG_UMI_BCH_CTRL_STATUS_ECC_RD_EN;
writel(REG_UMI_BCH_CTRL_STATUS_ECC_RD_EN, &REG_UMI_BCH_CTRL_STATUS);
}
/* Poll read ECC calc to check when hardware completes */
@ -139,7 +138,7 @@ static inline uint32_t nand_bcm_umi_bch_poll_read_ecc_calc(void)
do {
/* wait for ECC to be valid */
regVal = REG_UMI_BCH_CTRL_STATUS;
regVal = readl(&REG_UMI_BCH_CTRL_STATUS);
} while ((regVal & REG_UMI_BCH_CTRL_STATUS_RD_ECC_VALID) == 0);
return regVal;
@ -149,7 +148,7 @@ static inline uint32_t nand_bcm_umi_bch_poll_read_ecc_calc(void)
static inline void nand_bcm_umi_bch_poll_write_ecc_calc(void)
{
/* wait for ECC to be valid */
while ((REG_UMI_BCH_CTRL_STATUS & REG_UMI_BCH_CTRL_STATUS_WR_ECC_VALID)
while ((readl(&REG_UMI_BCH_CTRL_STATUS) & REG_UMI_BCH_CTRL_STATUS_WR_ECC_VALID)
== 0)
;
}
@ -170,9 +169,9 @@ static inline void nand_bcm_umi_bch_read_oobEcc(uint32_t pageSize,
if (pageSize != NAND_DATA_ACCESS_SIZE) {
/* skip BI */
#if defined(__KERNEL__) && !defined(STANDALONE)
*oobp++ = REG_NAND_DATA8;
*oobp++ = readb(&REG_NAND_DATA8);
#else
REG_NAND_DATA8;
readb(&REG_NAND_DATA8);
#endif
numToRead--;
}
@ -180,9 +179,9 @@ static inline void nand_bcm_umi_bch_read_oobEcc(uint32_t pageSize,
while (numToRead > numEccBytes) {
/* skip free oob region */
#if defined(__KERNEL__) && !defined(STANDALONE)
*oobp++ = REG_NAND_DATA8;
*oobp++ = readb(&REG_NAND_DATA8);
#else
REG_NAND_DATA8;
readb(&REG_NAND_DATA8);
#endif
numToRead--;
}
@ -193,11 +192,11 @@ static inline void nand_bcm_umi_bch_read_oobEcc(uint32_t pageSize,
while (numToRead > 11) {
#if defined(__KERNEL__) && !defined(STANDALONE)
*oobp = REG_NAND_DATA8;
*oobp = readb(&REG_NAND_DATA8);
eccCalc[eccPos++] = *oobp;
oobp++;
#else
eccCalc[eccPos++] = REG_NAND_DATA8;
eccCalc[eccPos++] = readb(&REG_NAND_DATA8);
#endif
numToRead--;
}
@ -207,9 +206,9 @@ static inline void nand_bcm_umi_bch_read_oobEcc(uint32_t pageSize,
if (numToRead == 11) {
/* read BI */
#if defined(__KERNEL__) && !defined(STANDALONE)
*oobp++ = REG_NAND_DATA8;
*oobp++ = readb(&REG_NAND_DATA8);
#else
REG_NAND_DATA8;
readb(&REG_NAND_DATA8);
#endif
numToRead--;
}
@ -219,11 +218,11 @@ static inline void nand_bcm_umi_bch_read_oobEcc(uint32_t pageSize,
nand_bcm_umi_bch_resume_read_ecc_calc();
while (numToRead) {
#if defined(__KERNEL__) && !defined(STANDALONE)
*oobp = REG_NAND_DATA8;
*oobp = readb(&REG_NAND_DATA8);
eccCalc[eccPos++] = *oobp;
oobp++;
#else
eccCalc[eccPos++] = REG_NAND_DATA8;
eccCalc[eccPos++] = readb(&REG_NAND_DATA8);
#endif
numToRead--;
}
@ -255,7 +254,7 @@ static inline void nand_bcm_umi_bch_write_oobEcc(uint32_t pageSize,
if (pageSize == NAND_DATA_ACCESS_SIZE) {
/* Now fill in the ECC bytes */
if (numEccBytes >= 13)
eccVal = REG_UMI_BCH_WR_ECC_3;
eccVal = readl(&REG_UMI_BCH_WR_ECC_3);
/* Usually we skip CM in oob[0,1] */
NAND_BCM_UMI_ECC_WRITE(numEccBytes, 15, &oobp[0],
@ -268,7 +267,7 @@ static inline void nand_bcm_umi_bch_write_oobEcc(uint32_t pageSize,
eccVal & 0xff); /* ECC 12 */
if (numEccBytes >= 9)
eccVal = REG_UMI_BCH_WR_ECC_2;
eccVal = readl(&REG_UMI_BCH_WR_ECC_2);
NAND_BCM_UMI_ECC_WRITE(numEccBytes, 12, &oobp[3],
(eccVal >> 24) & 0xff); /* ECC11 */
@ -281,7 +280,7 @@ static inline void nand_bcm_umi_bch_write_oobEcc(uint32_t pageSize,
/* Now fill in the ECC bytes */
if (numEccBytes >= 13)
eccVal = REG_UMI_BCH_WR_ECC_3;
eccVal = readl(&REG_UMI_BCH_WR_ECC_3);
/* Usually skip CM in oob[1,2] */
NAND_BCM_UMI_ECC_WRITE(numEccBytes, 15, &oobp[1],
@ -294,7 +293,7 @@ static inline void nand_bcm_umi_bch_write_oobEcc(uint32_t pageSize,
eccVal & 0xff); /* ECC12 */
if (numEccBytes >= 9)
eccVal = REG_UMI_BCH_WR_ECC_2;
eccVal = readl(&REG_UMI_BCH_WR_ECC_2);
NAND_BCM_UMI_ECC_WRITE(numEccBytes, 12, &oobp[4],
(eccVal >> 24) & 0xff); /* ECC11 */
@ -309,7 +308,7 @@ static inline void nand_bcm_umi_bch_write_oobEcc(uint32_t pageSize,
eccVal & 0xff); /* ECC8 */
if (numEccBytes >= 5)
eccVal = REG_UMI_BCH_WR_ECC_1;
eccVal = readl(&REG_UMI_BCH_WR_ECC_1);
NAND_BCM_UMI_ECC_WRITE(numEccBytes, 8, &oobp[8],
(eccVal >> 24) & 0xff); /* ECC7 */
@ -321,7 +320,7 @@ static inline void nand_bcm_umi_bch_write_oobEcc(uint32_t pageSize,
eccVal & 0xff); /* ECC4 */
if (numEccBytes >= 1)
eccVal = REG_UMI_BCH_WR_ECC_0;
eccVal = readl(&REG_UMI_BCH_WR_ECC_0);
NAND_BCM_UMI_ECC_WRITE(numEccBytes, 4, &oobp[12],
(eccVal >> 24) & 0xff); /* ECC3 */

View file

@ -29,7 +29,7 @@
#include <plat/dma.h>
#include <plat/gpmc.h>
#include <plat/nand.h>
#include <linux/platform_data/mtd-nand-omap2.h>
#define DRIVER_NAME "omap2-nand"
#define OMAP_NAND_TIMEOUT_MS 5000
@ -101,6 +101,16 @@
#define P4e_s(a) (TF(a & NAND_Ecc_P4e) << 0)
#define P4o_s(a) (TF(a & NAND_Ecc_P4o) << 1)
#define PREFETCH_CONFIG1_CS_SHIFT 24
#define ECC_CONFIG_CS_SHIFT 1
#define CS_MASK 0x7
#define ENABLE_PREFETCH (0x1 << 7)
#define DMA_MPU_MODE_SHIFT 2
#define ECCSIZE1_SHIFT 22
#define ECC1RESULTSIZE 0x1
#define ECCCLEAR 0x100
#define ECC1 0x1
/* oob info generated runtime depending on ecc algorithm and layout selected */
static struct nand_ecclayout omap_oobinfo;
/* Define some generic bad / good block scan pattern which are used
@ -124,15 +134,18 @@ struct omap_nand_info {
int gpmc_cs;
unsigned long phys_base;
unsigned long mem_size;
struct completion comp;
struct dma_chan *dma;
int gpmc_irq;
int gpmc_irq_fifo;
int gpmc_irq_count;
enum {
OMAP_NAND_IO_READ = 0, /* read */
OMAP_NAND_IO_WRITE, /* write */
} iomode;
u_char *buf;
int buf_len;
struct gpmc_nand_regs reg;
#ifdef CONFIG_MTD_NAND_OMAP_BCH
struct bch_control *bch;
@ -140,6 +153,63 @@ struct omap_nand_info {
#endif
};
/**
* omap_prefetch_enable - configures and starts prefetch transfer
* @cs: cs (chip select) number
* @fifo_th: fifo threshold to be used for read/ write
* @dma_mode: dma mode enable (1) or disable (0)
* @u32_count: number of bytes to be transferred
* @is_write: prefetch read(0) or write post(1) mode
*/
static int omap_prefetch_enable(int cs, int fifo_th, int dma_mode,
unsigned int u32_count, int is_write, struct omap_nand_info *info)
{
u32 val;
if (fifo_th > PREFETCH_FIFOTHRESHOLD_MAX)
return -1;
if (readl(info->reg.gpmc_prefetch_control))
return -EBUSY;
/* Set the amount of bytes to be prefetched */
writel(u32_count, info->reg.gpmc_prefetch_config2);
/* Set dma/mpu mode, the prefetch read / post write and
* enable the engine. Set which cs is has requested for.
*/
val = ((cs << PREFETCH_CONFIG1_CS_SHIFT) |
PREFETCH_FIFOTHRESHOLD(fifo_th) | ENABLE_PREFETCH |
(dma_mode << DMA_MPU_MODE_SHIFT) | (0x1 & is_write));
writel(val, info->reg.gpmc_prefetch_config1);
/* Start the prefetch engine */
writel(0x1, info->reg.gpmc_prefetch_control);
return 0;
}
/**
* omap_prefetch_reset - disables and stops the prefetch engine
*/
static int omap_prefetch_reset(int cs, struct omap_nand_info *info)
{
u32 config1;
/* check if the same module/cs is trying to reset */
config1 = readl(info->reg.gpmc_prefetch_config1);
if (((config1 >> PREFETCH_CONFIG1_CS_SHIFT) & CS_MASK) != cs)
return -EINVAL;
/* Stop the PFPW engine */
writel(0x0, info->reg.gpmc_prefetch_control);
/* Reset/disable the PFPW engine */
writel(0x0, info->reg.gpmc_prefetch_config1);
return 0;
}
/**
* omap_hwcontrol - hardware specific access to control-lines
* @mtd: MTD device structure
@ -158,13 +228,13 @@ static void omap_hwcontrol(struct mtd_info *mtd, int cmd, unsigned int ctrl)
if (cmd != NAND_CMD_NONE) {
if (ctrl & NAND_CLE)
gpmc_nand_write(info->gpmc_cs, GPMC_NAND_COMMAND, cmd);
writeb(cmd, info->reg.gpmc_nand_command);
else if (ctrl & NAND_ALE)
gpmc_nand_write(info->gpmc_cs, GPMC_NAND_ADDRESS, cmd);
writeb(cmd, info->reg.gpmc_nand_address);
else /* NAND_NCE */
gpmc_nand_write(info->gpmc_cs, GPMC_NAND_DATA, cmd);
writeb(cmd, info->reg.gpmc_nand_data);
}
}
@ -198,7 +268,8 @@ static void omap_write_buf8(struct mtd_info *mtd, const u_char *buf, int len)
iowrite8(*p++, info->nand.IO_ADDR_W);
/* wait until buffer is available for write */
do {
status = gpmc_read_status(GPMC_STATUS_BUFFER);
status = readl(info->reg.gpmc_status) &
GPMC_STATUS_BUFF_EMPTY;
} while (!status);
}
}
@ -235,7 +306,8 @@ static void omap_write_buf16(struct mtd_info *mtd, const u_char * buf, int len)
iowrite16(*p++, info->nand.IO_ADDR_W);
/* wait until buffer is available for write */
do {
status = gpmc_read_status(GPMC_STATUS_BUFFER);
status = readl(info->reg.gpmc_status) &
GPMC_STATUS_BUFF_EMPTY;
} while (!status);
}
}
@ -265,8 +337,8 @@ static void omap_read_buf_pref(struct mtd_info *mtd, u_char *buf, int len)
}
/* configure and start prefetch transfer */
ret = gpmc_prefetch_enable(info->gpmc_cs,
PREFETCH_FIFOTHRESHOLD_MAX, 0x0, len, 0x0);
ret = omap_prefetch_enable(info->gpmc_cs,
PREFETCH_FIFOTHRESHOLD_MAX, 0x0, len, 0x0, info);
if (ret) {
/* PFPW engine is busy, use cpu copy method */
if (info->nand.options & NAND_BUSWIDTH_16)
@ -275,14 +347,15 @@ static void omap_read_buf_pref(struct mtd_info *mtd, u_char *buf, int len)
omap_read_buf8(mtd, (u_char *)p, len);
} else {
do {
r_count = gpmc_read_status(GPMC_PREFETCH_FIFO_CNT);
r_count = readl(info->reg.gpmc_prefetch_status);
r_count = GPMC_PREFETCH_STATUS_FIFO_CNT(r_count);
r_count = r_count >> 2;
ioread32_rep(info->nand.IO_ADDR_R, p, r_count);
p += r_count;
len -= r_count << 2;
} while (len);
/* disable and stop the PFPW engine */
gpmc_prefetch_reset(info->gpmc_cs);
omap_prefetch_reset(info->gpmc_cs, info);
}
}
@ -301,6 +374,7 @@ static void omap_write_buf_pref(struct mtd_info *mtd,
int i = 0, ret = 0;
u16 *p = (u16 *)buf;
unsigned long tim, limit;
u32 val;
/* take care of subpage writes */
if (len % 2 != 0) {
@ -310,8 +384,8 @@ static void omap_write_buf_pref(struct mtd_info *mtd,
}
/* configure and start prefetch transfer */
ret = gpmc_prefetch_enable(info->gpmc_cs,
PREFETCH_FIFOTHRESHOLD_MAX, 0x0, len, 0x1);
ret = omap_prefetch_enable(info->gpmc_cs,
PREFETCH_FIFOTHRESHOLD_MAX, 0x0, len, 0x1, info);
if (ret) {
/* PFPW engine is busy, use cpu copy method */
if (info->nand.options & NAND_BUSWIDTH_16)
@ -320,7 +394,8 @@ static void omap_write_buf_pref(struct mtd_info *mtd,
omap_write_buf8(mtd, (u_char *)p, len);
} else {
while (len) {
w_count = gpmc_read_status(GPMC_PREFETCH_FIFO_CNT);
w_count = readl(info->reg.gpmc_prefetch_status);
w_count = GPMC_PREFETCH_STATUS_FIFO_CNT(w_count);
w_count = w_count >> 1;
for (i = 0; (i < w_count) && len; i++, len -= 2)
iowrite16(*p++, info->nand.IO_ADDR_W);
@ -329,11 +404,14 @@ static void omap_write_buf_pref(struct mtd_info *mtd,
tim = 0;
limit = (loops_per_jiffy *
msecs_to_jiffies(OMAP_NAND_TIMEOUT_MS));
while (gpmc_read_status(GPMC_PREFETCH_COUNT) && (tim++ < limit))
do {
cpu_relax();
val = readl(info->reg.gpmc_prefetch_status);
val = GPMC_PREFETCH_STATUS_COUNT(val);
} while (val && (tim++ < limit));
/* disable and stop the PFPW engine */
gpmc_prefetch_reset(info->gpmc_cs);
omap_prefetch_reset(info->gpmc_cs, info);
}
}
@ -365,6 +443,7 @@ static inline int omap_nand_dma_transfer(struct mtd_info *mtd, void *addr,
unsigned long tim, limit;
unsigned n;
int ret;
u32 val;
if (addr >= high_memory) {
struct page *p1;
@ -396,9 +475,9 @@ static inline int omap_nand_dma_transfer(struct mtd_info *mtd, void *addr,
tx->callback_param = &info->comp;
dmaengine_submit(tx);
/* configure and start prefetch transfer */
ret = gpmc_prefetch_enable(info->gpmc_cs,
PREFETCH_FIFOTHRESHOLD_MAX, 0x1, len, is_write);
/* configure and start prefetch transfer */
ret = omap_prefetch_enable(info->gpmc_cs,
PREFETCH_FIFOTHRESHOLD_MAX, 0x1, len, is_write, info);
if (ret)
/* PFPW engine is busy, use cpu copy method */
goto out_copy_unmap;
@ -410,11 +489,15 @@ static inline int omap_nand_dma_transfer(struct mtd_info *mtd, void *addr,
wait_for_completion(&info->comp);
tim = 0;
limit = (loops_per_jiffy * msecs_to_jiffies(OMAP_NAND_TIMEOUT_MS));
while (gpmc_read_status(GPMC_PREFETCH_COUNT) && (tim++ < limit))
do {
cpu_relax();
val = readl(info->reg.gpmc_prefetch_status);
val = GPMC_PREFETCH_STATUS_COUNT(val);
} while (val && (tim++ < limit));
/* disable and stop the PFPW engine */
gpmc_prefetch_reset(info->gpmc_cs);
omap_prefetch_reset(info->gpmc_cs, info);
dma_unmap_sg(info->dma->device->dev, &sg, 1, dir);
return 0;
@ -471,13 +554,12 @@ static irqreturn_t omap_nand_irq(int this_irq, void *dev)
{
struct omap_nand_info *info = (struct omap_nand_info *) dev;
u32 bytes;
u32 irq_stat;
irq_stat = gpmc_read_status(GPMC_GET_IRQ_STATUS);
bytes = gpmc_read_status(GPMC_PREFETCH_FIFO_CNT);
bytes = readl(info->reg.gpmc_prefetch_status);
bytes = GPMC_PREFETCH_STATUS_FIFO_CNT(bytes);
bytes = bytes & 0xFFFC; /* io in multiple of 4 bytes */
if (info->iomode == OMAP_NAND_IO_WRITE) { /* checks for write io */
if (irq_stat & 0x2)
if (this_irq == info->gpmc_irq_count)
goto done;
if (info->buf_len && (info->buf_len < bytes))
@ -494,20 +576,17 @@ static irqreturn_t omap_nand_irq(int this_irq, void *dev)
(u32 *)info->buf, bytes >> 2);
info->buf = info->buf + bytes;
if (irq_stat & 0x2)
if (this_irq == info->gpmc_irq_count)
goto done;
}
gpmc_cs_configure(info->gpmc_cs, GPMC_SET_IRQ_STATUS, irq_stat);
return IRQ_HANDLED;
done:
complete(&info->comp);
/* disable irq */
gpmc_cs_configure(info->gpmc_cs, GPMC_ENABLE_IRQ, 0);
/* clear status */
gpmc_cs_configure(info->gpmc_cs, GPMC_SET_IRQ_STATUS, irq_stat);
disable_irq_nosync(info->gpmc_irq_fifo);
disable_irq_nosync(info->gpmc_irq_count);
return IRQ_HANDLED;
}
@ -534,22 +613,22 @@ static void omap_read_buf_irq_pref(struct mtd_info *mtd, u_char *buf, int len)
init_completion(&info->comp);
/* configure and start prefetch transfer */
ret = gpmc_prefetch_enable(info->gpmc_cs,
PREFETCH_FIFOTHRESHOLD_MAX/2, 0x0, len, 0x0);
ret = omap_prefetch_enable(info->gpmc_cs,
PREFETCH_FIFOTHRESHOLD_MAX/2, 0x0, len, 0x0, info);
if (ret)
/* PFPW engine is busy, use cpu copy method */
goto out_copy;
info->buf_len = len;
/* enable irq */
gpmc_cs_configure(info->gpmc_cs, GPMC_ENABLE_IRQ,
(GPMC_IRQ_FIFOEVENTENABLE | GPMC_IRQ_COUNT_EVENT));
enable_irq(info->gpmc_irq_count);
enable_irq(info->gpmc_irq_fifo);
/* waiting for read to complete */
wait_for_completion(&info->comp);
/* disable and stop the PFPW engine */
gpmc_prefetch_reset(info->gpmc_cs);
omap_prefetch_reset(info->gpmc_cs, info);
return;
out_copy:
@ -572,6 +651,7 @@ static void omap_write_buf_irq_pref(struct mtd_info *mtd,
struct omap_nand_info, mtd);
int ret = 0;
unsigned long tim, limit;
u32 val;
if (len <= mtd->oobsize) {
omap_write_buf_pref(mtd, buf, len);
@ -583,27 +663,31 @@ static void omap_write_buf_irq_pref(struct mtd_info *mtd,
init_completion(&info->comp);
/* configure and start prefetch transfer : size=24 */
ret = gpmc_prefetch_enable(info->gpmc_cs,
(PREFETCH_FIFOTHRESHOLD_MAX * 3) / 8, 0x0, len, 0x1);
ret = omap_prefetch_enable(info->gpmc_cs,
(PREFETCH_FIFOTHRESHOLD_MAX * 3) / 8, 0x0, len, 0x1, info);
if (ret)
/* PFPW engine is busy, use cpu copy method */
goto out_copy;
info->buf_len = len;
/* enable irq */
gpmc_cs_configure(info->gpmc_cs, GPMC_ENABLE_IRQ,
(GPMC_IRQ_FIFOEVENTENABLE | GPMC_IRQ_COUNT_EVENT));
enable_irq(info->gpmc_irq_count);
enable_irq(info->gpmc_irq_fifo);
/* waiting for write to complete */
wait_for_completion(&info->comp);
/* wait for data to flushed-out before reset the prefetch */
tim = 0;
limit = (loops_per_jiffy * msecs_to_jiffies(OMAP_NAND_TIMEOUT_MS));
while (gpmc_read_status(GPMC_PREFETCH_COUNT) && (tim++ < limit))
do {
val = readl(info->reg.gpmc_prefetch_status);
val = GPMC_PREFETCH_STATUS_COUNT(val);
cpu_relax();
} while (val && (tim++ < limit));
/* disable and stop the PFPW engine */
gpmc_prefetch_reset(info->gpmc_cs);
omap_prefetch_reset(info->gpmc_cs, info);
return;
out_copy:
@ -843,7 +927,20 @@ static int omap_calculate_ecc(struct mtd_info *mtd, const u_char *dat,
{
struct omap_nand_info *info = container_of(mtd, struct omap_nand_info,
mtd);
return gpmc_calculate_ecc(info->gpmc_cs, dat, ecc_code);
u32 val;
val = readl(info->reg.gpmc_ecc_config);
if (((val >> ECC_CONFIG_CS_SHIFT) & ~CS_MASK) != info->gpmc_cs)
return -EINVAL;
/* read ecc result */
val = readl(info->reg.gpmc_ecc1_result);
*ecc_code++ = val; /* P128e, ..., P1e */
*ecc_code++ = val >> 16; /* P128o, ..., P1o */
/* P2048o, P1024o, P512o, P256o, P2048e, P1024e, P512e, P256e */
*ecc_code++ = ((val >> 8) & 0x0f) | ((val >> 20) & 0xf0);
return 0;
}
/**
@ -857,8 +954,34 @@ static void omap_enable_hwecc(struct mtd_info *mtd, int mode)
mtd);
struct nand_chip *chip = mtd->priv;
unsigned int dev_width = (chip->options & NAND_BUSWIDTH_16) ? 1 : 0;
u32 val;
gpmc_enable_hwecc(info->gpmc_cs, mode, dev_width, info->nand.ecc.size);
/* clear ecc and enable bits */
val = ECCCLEAR | ECC1;
writel(val, info->reg.gpmc_ecc_control);
/* program ecc and result sizes */
val = ((((info->nand.ecc.size >> 1) - 1) << ECCSIZE1_SHIFT) |
ECC1RESULTSIZE);
writel(val, info->reg.gpmc_ecc_size_config);
switch (mode) {
case NAND_ECC_READ:
case NAND_ECC_WRITE:
writel(ECCCLEAR | ECC1, info->reg.gpmc_ecc_control);
break;
case NAND_ECC_READSYN:
writel(ECCCLEAR, info->reg.gpmc_ecc_control);
break;
default:
dev_info(&info->pdev->dev,
"error: unrecognized Mode[%d]!\n", mode);
break;
}
/* (ECC 16 or 8 bit col) | ( CS ) | ECC Enable */
val = (dev_width << 7) | (info->gpmc_cs << 1) | (0x1);
writel(val, info->reg.gpmc_ecc_config);
}
/**
@ -886,10 +1009,9 @@ static int omap_wait(struct mtd_info *mtd, struct nand_chip *chip)
else
timeo += (HZ * 20) / 1000;
gpmc_nand_write(info->gpmc_cs,
GPMC_NAND_COMMAND, (NAND_CMD_STATUS & 0xFF));
writeb(NAND_CMD_STATUS & 0xFF, info->reg.gpmc_nand_command);
while (time_before(jiffies, timeo)) {
status = gpmc_nand_read(info->gpmc_cs, GPMC_NAND_DATA);
status = readb(info->reg.gpmc_nand_data);
if (status & NAND_STATUS_READY)
break;
cond_resched();
@ -909,22 +1031,13 @@ static int omap_dev_ready(struct mtd_info *mtd)
struct omap_nand_info *info = container_of(mtd, struct omap_nand_info,
mtd);
val = gpmc_read_status(GPMC_GET_IRQ_STATUS);
if ((val & 0x100) == 0x100) {
/* Clear IRQ Interrupt */
val |= 0x100;
val &= ~(0x0);
gpmc_cs_configure(info->gpmc_cs, GPMC_SET_IRQ_STATUS, val);
} else {
unsigned int cnt = 0;
while (cnt++ < 0x1FF) {
if ((val & 0x100) == 0x100)
return 0;
val = gpmc_read_status(GPMC_GET_IRQ_STATUS);
}
}
val = readl(info->reg.gpmc_status);
return 1;
if ((val & 0x100) == 0x100) {
return 1;
} else {
return 0;
}
}
#ifdef CONFIG_MTD_NAND_OMAP_BCH
@ -1155,6 +1268,7 @@ static int __devinit omap_nand_probe(struct platform_device *pdev)
int i, offset;
dma_cap_mask_t mask;
unsigned sig;
struct resource *res;
pdata = pdev->dev.platform_data;
if (pdata == NULL) {
@ -1174,7 +1288,7 @@ static int __devinit omap_nand_probe(struct platform_device *pdev)
info->pdev = pdev;
info->gpmc_cs = pdata->cs;
info->phys_base = pdata->phys_base;
info->reg = pdata->reg;
info->mtd.priv = &info->nand;
info->mtd.name = dev_name(&pdev->dev);
@ -1183,16 +1297,23 @@ static int __devinit omap_nand_probe(struct platform_device *pdev)
info->nand.options = pdata->devsize;
info->nand.options |= NAND_SKIP_BBTSCAN;
/* NAND write protect off */
gpmc_cs_configure(info->gpmc_cs, GPMC_CONFIG_WP, 0);
res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
if (res == NULL) {
err = -EINVAL;
dev_err(&pdev->dev, "error getting memory resource\n");
goto out_free_info;
}
if (!request_mem_region(info->phys_base, NAND_IO_SIZE,
info->phys_base = res->start;
info->mem_size = resource_size(res);
if (!request_mem_region(info->phys_base, info->mem_size,
pdev->dev.driver->name)) {
err = -EBUSY;
goto out_free_info;
}
info->nand.IO_ADDR_R = ioremap(info->phys_base, NAND_IO_SIZE);
info->nand.IO_ADDR_R = ioremap(info->phys_base, info->mem_size);
if (!info->nand.IO_ADDR_R) {
err = -ENOMEM;
goto out_release_mem_region;
@ -1265,17 +1386,39 @@ static int __devinit omap_nand_probe(struct platform_device *pdev)
break;
case NAND_OMAP_PREFETCH_IRQ:
err = request_irq(pdata->gpmc_irq,
omap_nand_irq, IRQF_SHARED, "gpmc-nand", info);
info->gpmc_irq_fifo = platform_get_irq(pdev, 0);
if (info->gpmc_irq_fifo <= 0) {
dev_err(&pdev->dev, "error getting fifo irq\n");
err = -ENODEV;
goto out_release_mem_region;
}
err = request_irq(info->gpmc_irq_fifo, omap_nand_irq,
IRQF_SHARED, "gpmc-nand-fifo", info);
if (err) {
dev_err(&pdev->dev, "requesting irq(%d) error:%d",
pdata->gpmc_irq, err);
info->gpmc_irq_fifo, err);
info->gpmc_irq_fifo = 0;
goto out_release_mem_region;
} else {
info->gpmc_irq = pdata->gpmc_irq;
info->nand.read_buf = omap_read_buf_irq_pref;
info->nand.write_buf = omap_write_buf_irq_pref;
}
info->gpmc_irq_count = platform_get_irq(pdev, 1);
if (info->gpmc_irq_count <= 0) {
dev_err(&pdev->dev, "error getting count irq\n");
err = -ENODEV;
goto out_release_mem_region;
}
err = request_irq(info->gpmc_irq_count, omap_nand_irq,
IRQF_SHARED, "gpmc-nand-count", info);
if (err) {
dev_err(&pdev->dev, "requesting irq(%d) error:%d",
info->gpmc_irq_count, err);
info->gpmc_irq_count = 0;
goto out_release_mem_region;
}
info->nand.read_buf = omap_read_buf_irq_pref;
info->nand.write_buf = omap_write_buf_irq_pref;
break;
default:
@ -1363,7 +1506,11 @@ static int __devinit omap_nand_probe(struct platform_device *pdev)
out_release_mem_region:
if (info->dma)
dma_release_channel(info->dma);
release_mem_region(info->phys_base, NAND_IO_SIZE);
if (info->gpmc_irq_count > 0)
free_irq(info->gpmc_irq_count, info);
if (info->gpmc_irq_fifo > 0)
free_irq(info->gpmc_irq_fifo, info);
release_mem_region(info->phys_base, info->mem_size);
out_free_info:
kfree(info);
@ -1381,8 +1528,10 @@ static int omap_nand_remove(struct platform_device *pdev)
if (info->dma)
dma_release_channel(info->dma);
if (info->gpmc_irq)
free_irq(info->gpmc_irq, info);
if (info->gpmc_irq_count > 0)
free_irq(info->gpmc_irq_count, info);
if (info->gpmc_irq_fifo > 0)
free_irq(info->gpmc_irq_fifo, info);
/* Release NAND device, its internal structures and partitions */
nand_release(&info->mtd);

View file

@ -39,22 +39,21 @@
#include <asm/mach/flash.h>
#include <plat/gpmc.h>
#include <plat/onenand.h>
#include <linux/platform_data/mtd-onenand-omap2.h>
#include <asm/gpio.h>
#include <plat/dma.h>
#include <plat/board.h>
#include <plat/cpu.h>
#define DRIVER_NAME "omap2-onenand"
#define ONENAND_IO_SIZE SZ_128K
#define ONENAND_BUFRAM_SIZE (1024 * 5)
struct omap2_onenand {
struct platform_device *pdev;
int gpmc_cs;
unsigned long phys_base;
unsigned int mem_size;
int gpio_irq;
struct mtd_info mtd;
struct onenand_chip onenand;
@ -626,6 +625,7 @@ static int __devinit omap2_onenand_probe(struct platform_device *pdev)
struct omap2_onenand *c;
struct onenand_chip *this;
int r;
struct resource *res;
pdata = pdev->dev.platform_data;
if (pdata == NULL) {
@ -647,20 +647,24 @@ static int __devinit omap2_onenand_probe(struct platform_device *pdev)
c->gpio_irq = 0;
}
r = gpmc_cs_request(c->gpmc_cs, ONENAND_IO_SIZE, &c->phys_base);
if (r < 0) {
dev_err(&pdev->dev, "Cannot request GPMC CS\n");
res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
if (res == NULL) {
r = -EINVAL;
dev_err(&pdev->dev, "error getting memory resource\n");
goto err_kfree;
}
if (request_mem_region(c->phys_base, ONENAND_IO_SIZE,
c->phys_base = res->start;
c->mem_size = resource_size(res);
if (request_mem_region(c->phys_base, c->mem_size,
pdev->dev.driver->name) == NULL) {
dev_err(&pdev->dev, "Cannot reserve memory region at 0x%08lx, "
"size: 0x%x\n", c->phys_base, ONENAND_IO_SIZE);
dev_err(&pdev->dev, "Cannot reserve memory region at 0x%08lx, size: 0x%x\n",
c->phys_base, c->mem_size);
r = -EBUSY;
goto err_free_cs;
goto err_kfree;
}
c->onenand.base = ioremap(c->phys_base, ONENAND_IO_SIZE);
c->onenand.base = ioremap(c->phys_base, c->mem_size);
if (c->onenand.base == NULL) {
r = -ENOMEM;
goto err_release_mem_region;
@ -776,9 +780,7 @@ err_release_gpio:
err_iounmap:
iounmap(c->onenand.base);
err_release_mem_region:
release_mem_region(c->phys_base, ONENAND_IO_SIZE);
err_free_cs:
gpmc_cs_free(c->gpmc_cs);
release_mem_region(c->phys_base, c->mem_size);
err_kfree:
kfree(c);
@ -800,7 +802,7 @@ static int __devexit omap2_onenand_remove(struct platform_device *pdev)
gpio_free(c->gpio_irq);
}
iounmap(c->onenand.base);
release_mem_region(c->phys_base, ONENAND_IO_SIZE);
release_mem_region(c->phys_base, c->mem_size);
gpmc_cs_free(c->gpmc_cs);
kfree(c);