/*
* Copyright © 2004 Texas Instruments, Jian Zhang <jzhang@ti.com>
* Copyright © 2004 Micron Technology Inc.
* Copyright © 2004 David Brownell
*
* 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/platform_device.h>
#include <linux/dma-mapping.h>
#include <linux/delay.h>
#include <linux/module.h>
#include <linux/interrupt.h>
#include <linux/jiffies.h>
#include <linux/sched.h>
#include <linux/mtd/mtd.h>
#include <linux/mtd/nand.h>
#include <linux/mtd/partitions.h>
#include <linux/io.h>
#include <linux/slab.h>
#include <plat/dma.h>
#include <plat/gpmc.h>
#include <plat/nand.h>
#define DRIVER_NAME "omap2-nand"
#define OMAP_NAND_TIMEOUT_MS 5000
#define NAND_Ecc_P1e (1 << 0)
#define NAND_Ecc_P2e (1 << 1)
#define NAND_Ecc_P4e (1 << 2)
#define NAND_Ecc_P8e (1 << 3)
#define NAND_Ecc_P16e (1 << 4)
#define NAND_Ecc_P32e (1 << 5)
#define NAND_Ecc_P64e (1 << 6)
#define NAND_Ecc_P128e (1 << 7)
#define NAND_Ecc_P256e (1 << 8)
#define NAND_Ecc_P512e (1 << 9)
#define NAND_Ecc_P1024e (1 << 10)
#define NAND_Ecc_P2048e (1 << 11)
#define NAND_Ecc_P1o (1 << 16)
#define NAND_Ecc_P2o (1 << 17)
#define NAND_Ecc_P4o (1 << 18)
#define NAND_Ecc_P8o (1 << 19)
#define NAND_Ecc_P16o (1 << 20)
#define NAND_Ecc_P32o (1 << 21)
#define NAND_Ecc_P64o (1 << 22)
#define NAND_Ecc_P128o (1 << 23)
#define NAND_Ecc_P256o (1 << 24)
#define NAND_Ecc_P512o (1 << 25)
#define NAND_Ecc_P1024o (1 << 26)
#define NAND_Ecc_P2048o (1 << 27)
#define TF(value) (value ? 1 : 0)
#define P2048e(a) (TF(a & NAND_Ecc_P2048e) << 0)
#define P2048o(a) (TF(a & NAND_Ecc_P2048o) << 1)
#define P1e(a) (TF(a & NAND_Ecc_P1e) << 2)
#define P1o(a) (TF(a & NAND_Ecc_P1o) << 3)
#define P2e(a) (TF(a & NAND_Ecc_P2e) << 4)
#define P2o(a) (TF(a & NAND_Ecc_P2o) << 5)
#define P4e(a) (TF(a & NAND_Ecc_P4e) << 6)
#define P4o(a) (TF(a & NAND_Ecc_P4o) << 7)
#define P8e(a) (TF(a & NAND_Ecc_P8e) << 0)
#define P8o(a) (TF(a & NAND_Ecc_P8o) << 1)
#define P16e(a) (TF(a & NAND_Ecc_P16e) << 2)
#define P16o(a) (TF(a & NAND_Ecc_P16o) << 3)
#define P32e(a) (TF(a & NAND_Ecc_P32e) << 4)
#define P32o(a) (TF(a & NAND_Ecc_P32o) << 5)
#define P64e(a) (TF(a & NAND_Ecc_P64e) << 6)
#define P64o(a) (TF(a & NAND_Ecc_P64o) << 7)
#define P128e(a) (TF(a & NAND_Ecc_P128e) << 0)
#define P128o(a) (TF(a & NAND_Ecc_P128o) << 1)
#define P256e(a) (TF(a & NAND_Ecc_P256e) << 2)
#define P256o(a) (TF(a & NAND_Ecc_P256o) << 3)
#define P512e(a) (TF(a & NAND_Ecc_P512e) << 4)
#define P512o(a) (TF(a & NAND_Ecc_P512o) << 5)
#define P1024e(a) (TF(a & NAND_Ecc_P1024e) << 6)
#define P1024o(a) (TF(a & NAND_Ecc_P1024o) << 7)
#define P8e_s(a) (TF(a & NAND_Ecc_P8e) << 0)
#define P8o_s(a) (TF(a & NAND_Ecc_P8o) << 1)
#define P16e_s(a) (TF(a & NAND_Ecc_P16e) << 2)
#define P16o_s(a) (TF(a & NAND_Ecc_P16o) << 3)
#define P1e_s(a) (TF(a & NAND_Ecc_P1e) << 4)
#define P1o_s(a) (TF(a & NAND_Ecc_P1o) << 5)
#define P2e_s(a) (TF(a & NAND_Ecc_P2e) << 6)
#define P2o_s(a) (TF(a & NAND_Ecc_P2o) << 7)
#define P4e_s(a) (TF(a & NAND_Ecc_P4e) << 0)
#define P4o_s(a) (TF(a & NAND_Ecc_P4o) << 1)
static const char *part_probes[] = { "cmdlinepart", NULL };
/* 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
* while scanning a device for factory marked good / bad blocks
*/
static uint8_t scan_ff_pattern[] = { 0xff };
static struct nand_bbt_descr bb_descrip_flashbased = {
.options = NAND_BBT_SCANEMPTY | NAND_BBT_SCANALLPAGES,
.offs = 0,
.len = 1,
.pattern = scan_ff_pattern,
};
struct omap_nand_info {
struct nand_hw_control controller;
struct omap_nand_platform_data *pdata;
struct mtd_info mtd;
struct mtd_partition *parts;
struct nand_chip nand;
struct platform_device *pdev;
int gpmc_cs;
unsigned long phys_base;
struct completion comp;
int dma_ch;
int gpmc_irq;
enum {
OMAP_NAND_IO_READ = 0, /* read */
OMAP_NAND_IO_WRITE, /* write */
} iomode;
u_char *buf;
int buf_len;
};
/**
* omap_hwcontrol - hardware specific access to control-lines
* @mtd: MTD device structure
* @cmd: command to device
* @ctrl:
* NAND_NCE: bit 0 -> don't care
* NAND_CLE: bit 1 -> Command Latch
* NAND_ALE: bit 2 -> Address Latch
*
* NOTE: boards may use different bits for these!!
*/
static void omap_hwcontrol(struct mtd_info *mtd, int cmd, unsigned int ctrl)
{
struct omap_nand_info *info = container_of(mtd,
struct omap_nand_info, mtd);
if (cmd != NAND_CMD_NONE) {
if (ctrl & NAND_CLE)
gpmc_nand_write(info->gpmc_cs, GPMC_NAND_COMMAND, cmd);
else if (ctrl & NAND_ALE)
gpmc_nand_write(info->gpmc_cs, GPMC_NAND_ADDRESS, cmd);
else /* NAND_NCE */
gpmc_nand_write(info->gpmc_cs, GPMC_NAND_DATA, cmd);
}
}
/**
* omap_read_buf8 - read data from NAND controller into buffer
* @mtd: MTD device structure
* @buf: buffer to store date
* @len: number of bytes to read
*/
static