summaryrefslogtreecommitdiff
path: root/drivers/mtd
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/mtd')
-rw-r--r--drivers/mtd/cfi_flash.c41
-rw-r--r--drivers/mtd/nand/fsl_upm.c128
-rw-r--r--drivers/mtd/nand/nand_base.c46
3 files changed, 113 insertions, 102 deletions
diff --git a/drivers/mtd/cfi_flash.c b/drivers/mtd/cfi_flash.c
index d84f0fc55e2..d505bc8e87b 100644
--- a/drivers/mtd/cfi_flash.c
+++ b/drivers/mtd/cfi_flash.c
@@ -76,7 +76,9 @@
#define FLASH_CMD_PROTECT_SET 0x01
#define FLASH_CMD_PROTECT_CLEAR 0xD0
#define FLASH_CMD_CLEAR_STATUS 0x50
+#define FLASH_CMD_READ_STATUS 0x70
#define FLASH_CMD_WRITE_TO_BUFFER 0xE8
+#define FLASH_CMD_WRITE_BUFFER_PROG 0xE9
#define FLASH_CMD_WRITE_BUFFER_CONFIRM 0xD0
#define FLASH_STATUS_DONE 0x80
@@ -136,6 +138,7 @@
#define CFI_CMDSET_MITSU_STANDARD 256
#define CFI_CMDSET_MITSU_EXTENDED 257
#define CFI_CMDSET_SST 258
+#define CFI_CMDSET_INTEL_PROG_REGIONS 512
#ifdef CFG_FLASH_CFI_AMD_RESET /* needed for STM_ID_29W320DB on UC100 */
# undef FLASH_CMD_RESET
@@ -298,17 +301,25 @@ static inline void flash_unmap(flash_info_t *info, flash_sect_t sect,
/*-----------------------------------------------------------------------
* make a proper sized command based on the port and chip widths
*/
-static void flash_make_cmd (flash_info_t * info, uchar cmd, void *cmdbuf)
+static void flash_make_cmd (flash_info_t * info, ulong cmd, void *cmdbuf)
{
int i;
+ int cword_offset;
+ int cp_offset;
+ uchar val;
uchar *cp = (uchar *) cmdbuf;
+ for (i = info->portwidth; i > 0; i--){
+ cword_offset = (info->portwidth-i)%info->chipwidth;
#if defined(__LITTLE_ENDIAN) || defined(CFG_WRITE_SWAPPED_DATA)
- for (i = info->portwidth; i > 0; i--)
+ cp_offset = info->portwidth - i;
+ val = *((uchar*)&cmd + cword_offset);
#else
- for (i = 1; i <= info->portwidth; i++)
+ cp_offset = i - 1;
+ val = *((uchar*)&cmd + sizeof(ulong) - cword_offset - 1);
#endif
- *cp++ = (i & (info->chipwidth - 1)) ? '\0' : cmd;
+ cp[cp_offset] = (cword_offset >= sizeof(ulong)) ? 0x00 : val;
+ }
}
#ifdef DEBUG
@@ -422,7 +433,7 @@ static ulong flash_read_long (flash_info_t * info, flash_sect_t sect,
* Write a proper sized command to the correct address
*/
static void flash_write_cmd (flash_info_t * info, flash_sect_t sect,
- uint offset, uchar cmd)
+ uint offset, ulong cmd)
{
void *addr;
@@ -605,6 +616,7 @@ static int flash_is_busy (flash_info_t * info, flash_sect_t sect)
int retval;
switch (info->vendor) {
+ case CFI_CMDSET_INTEL_PROG_REGIONS:
case CFI_CMDSET_INTEL_STANDARD:
case CFI_CMDSET_INTEL_EXTENDED:
retval = !flash_isset (info, sect, 0, FLASH_STATUS_DONE);
@@ -664,6 +676,7 @@ static int flash_full_status_check (flash_info_t * info, flash_sect_t sector,
retcode = flash_status_check (info, sector, tout, prompt);
switch (info->vendor) {
+ case CFI_CMDSET_INTEL_PROG_REGIONS:
case CFI_CMDSET_INTEL_EXTENDED:
case CFI_CMDSET_INTEL_STANDARD:
if ((retcode == ERR_OK)
@@ -792,6 +805,7 @@ static int flash_write_cfiword (flash_info_t * info, ulong dest,
flag = disable_interrupts ();
switch (info->vendor) {
+ case CFI_CMDSET_INTEL_PROG_REGIONS:
case CFI_CMDSET_INTEL_EXTENDED:
case CFI_CMDSET_INTEL_STANDARD:
flash_write_cmd (info, 0, 0, FLASH_CMD_CLEAR_STATUS);
@@ -846,6 +860,7 @@ static int flash_write_cfibuffer (flash_info_t * info, ulong dest, uchar * cp,
int flag = 0;
uint offset = 0;
unsigned int shift;
+ uchar write_cmd;
switch (info->portwidth) {
case FLASH_CFI_8BIT:
@@ -900,10 +915,14 @@ static int flash_write_cfibuffer (flash_info_t * info, ulong dest, uchar * cp,
sector = find_sector (info, dest);
switch (info->vendor) {
+ case CFI_CMDSET_INTEL_PROG_REGIONS:
case CFI_CMDSET_INTEL_STANDARD:
case CFI_CMDSET_INTEL_EXTENDED:
+ write_cmd = (info->vendor == CFI_CMDSET_INTEL_PROG_REGIONS) ?
+ FLASH_CMD_WRITE_BUFFER_PROG : FLASH_CMD_WRITE_TO_BUFFER;
flash_write_cmd (info, sector, 0, FLASH_CMD_CLEAR_STATUS);
- flash_write_cmd (info, sector, 0, FLASH_CMD_WRITE_TO_BUFFER);
+ flash_write_cmd (info, sector, 0, FLASH_CMD_READ_STATUS);
+ flash_write_cmd (info, sector, 0, write_cmd);
retcode = flash_status_check (info, sector,
info->buffer_write_tout,
"write to buffer");
@@ -911,7 +930,7 @@ static int flash_write_cfibuffer (flash_info_t * info, ulong dest, uchar * cp,
/* reduce the number of loops by the width of
* the port */
cnt = len >> shift;
- flash_write_cmd (info, sector, 0, (uchar) cnt - 1);
+ flash_write_cmd (info, sector, 0, cnt - 1);
while (cnt-- > 0) {
switch (info->portwidth) {
case FLASH_CFI_8BIT:
@@ -1038,6 +1057,7 @@ int flash_erase (flash_info_t * info, int s_first, int s_last)
for (sect = s_first; sect <= s_last; sect++) {
if (info->protect[sect] == 0) { /* not protected */
switch (info->vendor) {
+ case CFI_CMDSET_INTEL_PROG_REGIONS:
case CFI_CMDSET_INTEL_STANDARD:
case CFI_CMDSET_INTEL_EXTENDED:
flash_write_cmd (info, sect, 0,
@@ -1106,6 +1126,9 @@ void flash_print_info (flash_info_t * info)
info->size >> 20, info->sector_count);
printf (" ");
switch (info->vendor) {
+ case CFI_CMDSET_INTEL_PROG_REGIONS:
+ printf ("Intel Prog Regions");
+ break;
case CFI_CMDSET_INTEL_STANDARD:
printf ("Intel Standard");
break;
@@ -1496,6 +1519,7 @@ static void flash_read_jedec_ids (flash_info_t * info)
info->device_id2 = 0;
switch (info->vendor) {
+ case CFI_CMDSET_INTEL_PROG_REGIONS:
case CFI_CMDSET_INTEL_STANDARD:
case CFI_CMDSET_INTEL_EXTENDED:
cmdset_intel_read_jedec_ids(info);
@@ -1550,6 +1574,7 @@ static int flash_detect_legacy(ulong base, int banknum)
}
switch(info->vendor) {
+ case CFI_CMDSET_INTEL_PROG_REGIONS:
case CFI_CMDSET_INTEL_STANDARD:
case CFI_CMDSET_INTEL_EXTENDED:
info->cmd_reset = FLASH_CMD_RESET;
@@ -1747,6 +1772,7 @@ ulong flash_get_size (ulong base, int banknum)
#endif
switch (info->vendor) {
+ case CFI_CMDSET_INTEL_PROG_REGIONS:
case CFI_CMDSET_INTEL_STANDARD:
case CFI_CMDSET_INTEL_EXTENDED:
cmdset_intel_init(info, &qry);
@@ -1824,6 +1850,7 @@ ulong flash_get_size (ulong base, int banknum)
* supported devices (intel...)
*/
switch (info->vendor) {
+ case CFI_CMDSET_INTEL_PROG_REGIONS:
case CFI_CMDSET_INTEL_EXTENDED:
case CFI_CMDSET_INTEL_STANDARD:
info->protect[sect_cnt] =
diff --git a/drivers/mtd/nand/fsl_upm.c b/drivers/mtd/nand/fsl_upm.c
index 5cc410a5e2f..67ae9c8d5b1 100644
--- a/drivers/mtd/nand/fsl_upm.c
+++ b/drivers/mtd/nand/fsl_upm.c
@@ -20,112 +20,83 @@
#include <linux/mtd/fsl_upm.h>
#include <nand.h>
-#define FSL_UPM_MxMR_OP_NO (0 << 28) /* normal operation */
-#define FSL_UPM_MxMR_OP_WA (1 << 28) /* write array */
-#define FSL_UPM_MxMR_OP_RA (2 << 28) /* read array */
-#define FSL_UPM_MxMR_OP_RP (3 << 28) /* run pattern */
+static int fsl_upm_in_pattern;
static void fsl_upm_start_pattern(struct fsl_upm *upm, u32 pat_offset)
{
- out_be32(upm->mxmr, FSL_UPM_MxMR_OP_RP | pat_offset);
+ clrsetbits_be32(upm->mxmr, MxMR_MAD_MSK, MxMR_OP_RUNP | pat_offset);
}
static void fsl_upm_end_pattern(struct fsl_upm *upm)
{
- out_be32(upm->mxmr, FSL_UPM_MxMR_OP_NO);
- while (in_be32(upm->mxmr) != FSL_UPM_MxMR_OP_NO)
+ clrbits_be32(upm->mxmr, MxMR_OP_RUNP);
+
+ while (in_be32(upm->mxmr) & MxMR_OP_RUNP)
eieio();
}
static void fsl_upm_run_pattern(struct fsl_upm *upm, int width, u32 cmd)
{
- out_be32(upm->mar, cmd << (32 - width * 8));
- out_8(upm->io_addr, 0x0);
-}
-
-static void fsl_upm_setup(struct fsl_upm *upm)
-{
- int i;
-
- /* write upm array */
- out_be32(upm->mxmr, FSL_UPM_MxMR_OP_WA);
-
- for (i = 0; i < 64; i++) {
- out_be32(upm->mdr, upm->array[i]);
+ out_be32(upm->mar, cmd << (32 - width));
+ switch (width) {
+ case 8:
out_8(upm->io_addr, 0x0);
+ break;
+ case 16:
+ out_be16(upm->io_addr, 0x0);
+ break;
+ case 32:
+ out_be32(upm->io_addr, 0x0);
+ break;
}
-
- /* normal operation */
- out_be32(upm->mxmr, FSL_UPM_MxMR_OP_NO);
- while (in_be32(upm->mxmr) != FSL_UPM_MxMR_OP_NO)
- eieio();
}
-static void fun_cmdfunc(struct mtd_info *mtd, unsigned command, int column,
- int page_addr)
+static void nand_hwcontrol (struct mtd_info *mtd, int cmd)
{
struct nand_chip *chip = mtd->priv;
struct fsl_upm_nand *fun = chip->priv;
- fsl_upm_start_pattern(&fun->upm, fun->upm_cmd_offset);
-
- if (command == NAND_CMD_SEQIN) {
- int readcmd;
-
- if (column >= mtd->oobblock) {
- /* OOB area */
- column -= mtd->oobblock;
- readcmd = NAND_CMD_READOOB;
- } else if (column < 256) {
- /* First 256 bytes --> READ0 */
- readcmd = NAND_CMD_READ0;
- } else {
- column -= 256;
- readcmd = NAND_CMD_READ1;
- }
- fsl_upm_run_pattern(&fun->upm, fun->width, readcmd);
+ switch (cmd) {
+ case NAND_CTL_SETCLE:
+ fsl_upm_start_pattern(&fun->upm, fun->upm_cmd_offset);
+ fsl_upm_in_pattern++;
+ break;
+ case NAND_CTL_SETALE:
+ fsl_upm_start_pattern(&fun->upm, fun->upm_addr_offset);
+ fsl_upm_in_pattern++;
+ break;
+ case NAND_CTL_CLRCLE:
+ case NAND_CTL_CLRALE:
+ fsl_upm_end_pattern(&fun->upm);
+ fsl_upm_in_pattern--;
+ break;
}
+}
- fsl_upm_run_pattern(&fun->upm, fun->width, command);
-
- fsl_upm_end_pattern(&fun->upm);
-
- fsl_upm_start_pattern(&fun->upm, fun->upm_addr_offset);
-
- if (column != -1)
- fsl_upm_run_pattern(&fun->upm, fun->width, column);
+static void nand_write_byte(struct mtd_info *mtd, u_char byte)
+{
+ struct nand_chip *chip = mtd->priv;
- if (page_addr != -1) {
- fsl_upm_run_pattern(&fun->upm, fun->width, page_addr);
- fsl_upm_run_pattern(&fun->upm, fun->width,
- (page_addr >> 8) & 0xFF);
- if (chip->chipsize > (32 << 20)) {
- fsl_upm_run_pattern(&fun->upm, fun->width,
- (page_addr >> 16) & 0x0f);
- }
- }
+ if (fsl_upm_in_pattern) {
+ struct fsl_upm_nand *fun = chip->priv;
- fsl_upm_end_pattern(&fun->upm);
+ fsl_upm_run_pattern(&fun->upm, fun->width, byte);
- if (fun->wait_pattern) {
/*
* Some boards/chips needs this. At least on MPC8360E-RDK we
* need it. Probably weird chip, because I don't see any need
* for this on MPC8555E + Samsung K9F1G08U0A. Usually here are
* 0-2 unexpected busy states per block read.
*/
- while (!fun->dev_ready())
- debug("unexpected busy state\n");
+ if (fun->wait_pattern) {
+ while (!fun->dev_ready())
+ debug("unexpected busy state\n");
+ }
+ } else {
+ out_8(chip->IO_ADDR_W, byte);
}
}
-static void nand_write_byte(struct mtd_info *mtd, u_char byte)
-{
- struct nand_chip *chip = mtd->priv;
-
- out_8(chip->IO_ADDR_W, byte);
-}
-
static u8 nand_read_byte(struct mtd_info *mtd)
{
struct nand_chip *chip = mtd->priv;
@@ -164,10 +135,6 @@ static int nand_verify_buf(struct mtd_info *mtd, const u_char *buf, int len)
return 0;
}
-static void nand_hwcontrol(struct mtd_info *mtd, int cmd)
-{
-}
-
static int nand_dev_ready(struct mtd_info *mtd)
{
struct nand_chip *chip = mtd->priv;
@@ -178,23 +145,20 @@ static int nand_dev_ready(struct mtd_info *mtd)
int fsl_upm_nand_init(struct nand_chip *chip, struct fsl_upm_nand *fun)
{
- /* yet only 8 bit accessors implemented */
- if (fun->width != 1)
+ if (fun->width != 8 && fun->width != 16 && fun->width != 32)
return -ENOSYS;
- fsl_upm_setup(&fun->upm);
-
chip->priv = fun;
chip->chip_delay = fun->chip_delay;
chip->eccmode = NAND_ECC_SOFT;
- chip->cmdfunc = fun_cmdfunc;
chip->hwcontrol = nand_hwcontrol;
chip->read_byte = nand_read_byte;
chip->read_buf = nand_read_buf;
chip->write_byte = nand_write_byte;
chip->write_buf = nand_write_buf;
chip->verify_buf = nand_verify_buf;
- chip->dev_ready = nand_dev_ready;
+ if (fun->dev_ready)
+ chip->dev_ready = nand_dev_ready;
return 0;
}
diff --git a/drivers/mtd/nand/nand_base.c b/drivers/mtd/nand/nand_base.c
index 5aef31cd180..740d3fcc373 100644
--- a/drivers/mtd/nand/nand_base.c
+++ b/drivers/mtd/nand/nand_base.c
@@ -113,18 +113,22 @@ static struct nand_oobinfo nand_oob_64 = {
.oobfree = { {2, 38} }
};
-/* This is used for padding purposes in nand_write_oob */
-static u_char ffchars[] = {
- 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
- 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
- 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
- 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
- 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
- 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
- 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
- 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+static struct nand_oobinfo nand_oob_128 = {
+ .useecc = MTD_NANDECC_AUTOPLACE,
+ .eccbytes = 48,
+ .eccpos = {
+ 80, 81, 82, 83, 84, 85, 86, 87,
+ 88, 89, 90, 91, 92, 93, 94, 95,
+ 96, 97, 98, 99, 100, 101, 102, 103,
+ 104, 105, 106, 107, 108, 109, 110, 111,
+ 112, 113, 114, 115, 116, 117, 118, 119,
+ 120, 121, 122, 123, 124, 125, 126, 127},
+ .oobfree = { {2, 78} }
};
+/* This is used for padding purposes in nand_write_oob */
+static u_char *ffchars;
+
/*
* NAND low-level MTD interface functions
*/
@@ -193,6 +197,10 @@ static void nand_release_device (struct mtd_info *mtd)
{
struct nand_chip *this = mtd->priv;
this->select_chip(mtd, -1); /* De-select the NAND device */
+ if (ffchars) {
+ kfree(ffchars);
+ ffchars = NULL;
+ }
}
#endif
@@ -891,7 +899,7 @@ static int nand_write_page (struct mtd_info *mtd, struct nand_chip *this, int pa
u_char *oob_buf, struct nand_oobinfo *oobsel, int cached)
{
int i, status;
- u_char ecc_code[32];
+ u_char ecc_code[NAND_MAX_OOBSIZE];
int eccmode = oobsel->useecc ? this->eccmode : NAND_ECC_NONE;
uint *oob_config = oobsel->eccpos;
int datidx = 0, eccidx = 0, eccsteps = this->eccsteps;
@@ -1112,8 +1120,8 @@ static int nand_read_ecc (struct mtd_info *mtd, loff_t from, size_t len,
int read = 0, oob = 0, ecc_status = 0, ecc_failed = 0;
struct nand_chip *this = mtd->priv;
u_char *data_poi, *oob_data = oob_buf;
- u_char ecc_calc[32];
- u_char ecc_code[32];
+ u_char ecc_calc[NAND_MAX_OOBSIZE];
+ u_char ecc_code[NAND_MAX_OOBSIZE];
int eccmode, eccsteps;
unsigned *oob_config;
int datidx;
@@ -1811,6 +1819,15 @@ static int nand_write_oob (struct mtd_info *mtd, loff_t to, size_t len, size_t *
if (NAND_MUST_PAD(this)) {
/* Write out desired data */
this->cmdfunc (mtd, NAND_CMD_SEQIN, mtd->oobblock, page & this->pagemask);
+ if (!ffchars) {
+ if (!(ffchars = kmalloc (mtd->oobsize, GFP_KERNEL))) {
+ DEBUG (MTD_DEBUG_LEVEL0, "nand_write_oob: "
+ "No memory for padding array, need %d bytes", mtd->oobsize);
+ ret = -ENOMEM;
+ goto out;
+ }
+ memset(ffchars, 0xff, mtd->oobsize);
+ }
/* prepad 0xff for partial programming */
this->write_buf(mtd, ffchars, column);
/* write data */
@@ -2479,6 +2496,9 @@ int nand_scan (struct mtd_info *mtd, int maxchips)
case 64:
this->autooob = &nand_oob_64;
break;
+ case 128:
+ this->autooob = &nand_oob_128;
+ break;
default:
printk (KERN_WARNING "No oob scheme defined for oobsize %d\n",
mtd->oobsize);