1
0
Fork 0

{MTD] add support for Intel's "Sibley" flash

This updates the Primary Vendor-Specific Extended Query parsing to
version 1.4 in order to get the information about the Configurable
Programming Mode regions implemented in the Sibley flash, as well as
selecting the appropriate write command code.

This flash does not behave like traditional NOR flash when writing data.
While mtdblock should just work, further changes are needed for JFFS2 use.

Signed-off-by: Nicolas Pitre <nico@cam.org>
Signed-off-by: Thomas Gleixner <tglx@linutronix.de>
wifi-calibration
Nicolas Pitre 2005-08-06 05:40:46 +01:00 committed by Thomas Gleixner
parent 4843653cab
commit 638d983840
5 changed files with 92 additions and 29 deletions

View File

@ -4,7 +4,7 @@
* *
* (C) 2000 Red Hat. GPL'd * (C) 2000 Red Hat. GPL'd
* *
* $Id: cfi_cmdset_0001.c,v 1.181 2005/08/06 04:16:48 nico Exp $ * $Id: cfi_cmdset_0001.c,v 1.182 2005/08/06 04:40:41 nico Exp $
* *
* *
* 10/10/2000 Nicolas Pitre <nico@cam.org> * 10/10/2000 Nicolas Pitre <nico@cam.org>
@ -105,6 +105,7 @@ static struct mtd_chip_driver cfi_intelext_chipdrv = {
static void cfi_tell_features(struct cfi_pri_intelext *extp) static void cfi_tell_features(struct cfi_pri_intelext *extp)
{ {
int i; int i;
printk(" Extended Query version %c.%c\n", extp->MajorVersion, extp->MinorVersion);
printk(" Feature/Command Support: %4.4X\n", extp->FeatureSupport); printk(" Feature/Command Support: %4.4X\n", extp->FeatureSupport);
printk(" - Chip Erase: %s\n", extp->FeatureSupport&1?"supported":"unsupported"); printk(" - Chip Erase: %s\n", extp->FeatureSupport&1?"supported":"unsupported");
printk(" - Suspend Erase: %s\n", extp->FeatureSupport&2?"supported":"unsupported"); printk(" - Suspend Erase: %s\n", extp->FeatureSupport&2?"supported":"unsupported");
@ -116,7 +117,8 @@ static void cfi_tell_features(struct cfi_pri_intelext *extp)
printk(" - Page-mode read: %s\n", extp->FeatureSupport&128?"supported":"unsupported"); printk(" - Page-mode read: %s\n", extp->FeatureSupport&128?"supported":"unsupported");
printk(" - Synchronous read: %s\n", extp->FeatureSupport&256?"supported":"unsupported"); printk(" - Synchronous read: %s\n", extp->FeatureSupport&256?"supported":"unsupported");
printk(" - Simultaneous operations: %s\n", extp->FeatureSupport&512?"supported":"unsupported"); printk(" - Simultaneous operations: %s\n", extp->FeatureSupport&512?"supported":"unsupported");
for (i=10; i<32; i++) { printk(" - Extended Flash Array: %s\n", extp->FeatureSupport&1024?"supported":"unsupported");
for (i=11; i<32; i++) {
if (extp->FeatureSupport & (1<<i)) if (extp->FeatureSupport & (1<<i))
printk(" - Unknown Bit %X: supported\n", i); printk(" - Unknown Bit %X: supported\n", i);
} }
@ -130,12 +132,18 @@ static void cfi_tell_features(struct cfi_pri_intelext *extp)
printk(" Block Status Register Mask: %4.4X\n", extp->BlkStatusRegMask); printk(" Block Status Register Mask: %4.4X\n", extp->BlkStatusRegMask);
printk(" - Lock Bit Active: %s\n", extp->BlkStatusRegMask&1?"yes":"no"); printk(" - Lock Bit Active: %s\n", extp->BlkStatusRegMask&1?"yes":"no");
printk(" - Valid Bit Active: %s\n", extp->BlkStatusRegMask&2?"yes":"no"); printk(" - Lock-Down Bit Active: %s\n", extp->BlkStatusRegMask&2?"yes":"no");
for (i=2; i<16; i++) { for (i=2; i<3; i++) {
if (extp->BlkStatusRegMask & (1<<i)) if (extp->BlkStatusRegMask & (1<<i))
printk(" - Unknown Bit %X Active: yes\n",i); printk(" - Unknown Bit %X Active: yes\n",i);
} }
printk(" - EFA Lock Bit: %s\n", extp->BlkStatusRegMask&16?"yes":"no");
printk(" - EFA Lock-Down Bit: %s\n", extp->BlkStatusRegMask&32?"yes":"no");
for (i=6; i<16; i++) {
if (extp->BlkStatusRegMask & (1<<i))
printk(" - Unknown Bit %X Active: yes\n",i);
}
printk(" Vcc Logic Supply Optimum Program/Erase Voltage: %d.%d V\n", printk(" Vcc Logic Supply Optimum Program/Erase Voltage: %d.%d V\n",
extp->VccOptimal >> 4, extp->VccOptimal & 0xf); extp->VccOptimal >> 4, extp->VccOptimal & 0xf);
if (extp->VppOptimal) if (extp->VppOptimal)
@ -253,7 +261,7 @@ read_pri_intelext(struct map_info *map, __u16 adr)
return NULL; return NULL;
if (extp->MajorVersion != '1' || if (extp->MajorVersion != '1' ||
(extp->MinorVersion < '0' || extp->MinorVersion > '3')) { (extp->MinorVersion < '0' || extp->MinorVersion > '4')) {
printk(KERN_ERR " Unknown Intel/Sharp Extended Query " printk(KERN_ERR " Unknown Intel/Sharp Extended Query "
"version %c.%c.\n", extp->MajorVersion, "version %c.%c.\n", extp->MajorVersion,
extp->MinorVersion); extp->MinorVersion);
@ -266,7 +274,7 @@ read_pri_intelext(struct map_info *map, __u16 adr)
extp->BlkStatusRegMask = le16_to_cpu(extp->BlkStatusRegMask); extp->BlkStatusRegMask = le16_to_cpu(extp->BlkStatusRegMask);
extp->ProtRegAddr = le16_to_cpu(extp->ProtRegAddr); extp->ProtRegAddr = le16_to_cpu(extp->ProtRegAddr);
if (extp->MajorVersion == '1' && extp->MinorVersion == '3') { if (extp->MajorVersion == '1' && extp->MinorVersion >= '3') {
unsigned int extra_size = 0; unsigned int extra_size = 0;
int nb_parts, i; int nb_parts, i;
@ -275,7 +283,7 @@ read_pri_intelext(struct map_info *map, __u16 adr)
sizeof(struct cfi_intelext_otpinfo); sizeof(struct cfi_intelext_otpinfo);
/* Burst Read info */ /* Burst Read info */
extra_size += 6; extra_size += (extp->MinorVersion < '4') ? 6 : 5;
/* Number of hardware-partitions */ /* Number of hardware-partitions */
extra_size += 1; extra_size += 1;
@ -283,6 +291,10 @@ read_pri_intelext(struct map_info *map, __u16 adr)
goto need_more; goto need_more;
nb_parts = extp->extra[extra_size - 1]; nb_parts = extp->extra[extra_size - 1];
/* skip the sizeof(partregion) field in CFI 1.4 */
if (extp->MinorVersion >= '4')
extra_size += 2;
for (i = 0; i < nb_parts; i++) { for (i = 0; i < nb_parts; i++) {
struct cfi_intelext_regioninfo *rinfo; struct cfi_intelext_regioninfo *rinfo;
rinfo = (struct cfi_intelext_regioninfo *)&extp->extra[extra_size]; rinfo = (struct cfi_intelext_regioninfo *)&extp->extra[extra_size];
@ -294,6 +306,9 @@ read_pri_intelext(struct map_info *map, __u16 adr)
* sizeof(struct cfi_intelext_blockinfo); * sizeof(struct cfi_intelext_blockinfo);
} }
if (extp->MinorVersion >= '4')
extra_size += sizeof(struct cfi_intelext_programming_regioninfo);
if (extp_size < sizeof(*extp) + extra_size) { if (extp_size < sizeof(*extp) + extra_size) {
need_more: need_more:
extp_size = sizeof(*extp) + extra_size; extp_size = sizeof(*extp) + extra_size;
@ -490,7 +505,7 @@ static int cfi_intelext_partition_fixup(struct mtd_info *mtd,
* arrangement at this point. This can be rearranged in the future * arrangement at this point. This can be rearranged in the future
* if someone feels motivated enough. --nico * if someone feels motivated enough. --nico
*/ */
if (extp && extp->MajorVersion == '1' && extp->MinorVersion == '3' if (extp && extp->MajorVersion == '1' && extp->MinorVersion >= '3'
&& extp->FeatureSupport & (1 << 9)) { && extp->FeatureSupport & (1 << 9)) {
struct cfi_private *newcfi; struct cfi_private *newcfi;
struct flchip *chip; struct flchip *chip;
@ -502,12 +517,16 @@ static int cfi_intelext_partition_fixup(struct mtd_info *mtd,
sizeof(struct cfi_intelext_otpinfo); sizeof(struct cfi_intelext_otpinfo);
/* Burst Read info */ /* Burst Read info */
offs += 6; offs += (extp->MinorVersion < '4') ? 6 : 5;
/* Number of partition regions */ /* Number of partition regions */
numregions = extp->extra[offs]; numregions = extp->extra[offs];
offs += 1; offs += 1;
/* skip the sizeof(partregion) field in CFI 1.4 */
if (extp->MinorVersion >= '4')
offs += 2;
/* Number of hardware partitions */ /* Number of hardware partitions */
numparts = 0; numparts = 0;
for (i = 0; i < numregions; i++) { for (i = 0; i < numregions; i++) {
@ -519,6 +538,20 @@ static int cfi_intelext_partition_fixup(struct mtd_info *mtd,
sizeof(struct cfi_intelext_blockinfo); sizeof(struct cfi_intelext_blockinfo);
} }
/* Programming Region info */
if (extp->MinorVersion >= '4') {
struct cfi_intelext_programming_regioninfo *prinfo;
prinfo = (struct cfi_intelext_programming_regioninfo *)&extp->extra[offs];
MTD_PROGREGION_SIZE(mtd) = cfi->interleave << prinfo->ProgRegShift;
MTD_PROGREGION_CTRLMODE_VALID(mtd) = cfi->interleave * prinfo->ControlValid;
MTD_PROGREGION_CTRLMODE_INVALID(mtd) = cfi->interleave * prinfo->ControlInvalid;
mtd->flags |= MTD_PROGRAM_REGIONS;
printk(KERN_DEBUG "%s: program region size/ctrl_valid/ctrl_inval = %d/%d/%d\n",
map->name, MTD_PROGREGION_SIZE(mtd),
MTD_PROGREGION_CTRLMODE_VALID(mtd),
MTD_PROGREGION_CTRLMODE_INVALID(mtd));
}
/* /*
* All functions below currently rely on all chips having * All functions below currently rely on all chips having
* the same geometry so we'll just assume that all hardware * the same geometry so we'll just assume that all hardware
@ -1222,12 +1255,17 @@ static int __xipram do_write_oneword(struct map_info *map, struct flchip *chip,
adr += chip->start; adr += chip->start;
/* Let's determine this according to the interleave only once */ /* Let's determine those according to the interleave only once */
status_OK = CMD(0x80); status_OK = CMD(0x80);
switch (mode) { switch (mode) {
case FL_WRITING: write_cmd = CMD(0x40); break; case FL_WRITING:
case FL_OTP_WRITE: write_cmd = CMD(0xc0); break; write_cmd = (cfi->cfiq->P_ID != 0x0200) ? CMD(0x40) : CMD(0x41);
default: return -EINVAL; break;
case FL_OTP_WRITE:
write_cmd = CMD(0xc0);
break;
default:
return -EINVAL;
} }
spin_lock(chip->mutex); spin_lock(chip->mutex);
@ -1410,16 +1448,17 @@ static int __xipram do_write_buffer(struct map_info *map, struct flchip *chip,
unsigned long adr, const u_char *buf, int len) unsigned long adr, const u_char *buf, int len)
{ {
struct cfi_private *cfi = map->fldrv_priv; struct cfi_private *cfi = map->fldrv_priv;
map_word status, status_OK; map_word status, status_OK, write_cmd;
unsigned long cmd_adr, timeo; unsigned long cmd_adr, timeo;
int wbufsize, z, ret=0, bytes, words; int wbufsize, z, ret=0, bytes, words;
wbufsize = cfi_interleave(cfi) << cfi->cfiq->MaxBufWriteSize; wbufsize = cfi_interleave(cfi) << cfi->cfiq->MaxBufWriteSize;
adr += chip->start; adr += chip->start;
cmd_adr = adr & ~(wbufsize-1); cmd_adr = adr & ~(wbufsize-1);
/* Let's determine this according to the interleave only once */ /* Let's determine this according to the interleave only once */
status_OK = CMD(0x80); status_OK = CMD(0x80);
write_cmd = (cfi->cfiq->P_ID != 0x0200) ? CMD(0xe8) : CMD(0xe9);
spin_lock(chip->mutex); spin_lock(chip->mutex);
ret = get_chip(map, chip, cmd_adr, FL_WRITING); ret = get_chip(map, chip, cmd_adr, FL_WRITING);
@ -1451,7 +1490,7 @@ static int __xipram do_write_buffer(struct map_info *map, struct flchip *chip,
z = 0; z = 0;
for (;;) { for (;;) {
map_write(map, CMD(0xe8), cmd_adr); map_write(map, write_cmd, cmd_adr);
status = map_read(map, cmd_adr); status = map_read(map, cmd_adr);
if (map_word_andequal(map, status, status_OK, status_OK)) if (map_word_andequal(map, status, status_OK, status_OK))
@ -2380,20 +2419,23 @@ static void cfi_intelext_destroy(struct mtd_info *mtd)
kfree(mtd->eraseregions); kfree(mtd->eraseregions);
} }
static char im_name_1[]="cfi_cmdset_0001"; static char im_name_0001[] = "cfi_cmdset_0001";
static char im_name_3[]="cfi_cmdset_0003"; static char im_name_0003[] = "cfi_cmdset_0003";
static char im_name_0200[] = "cfi_cmdset_0200";
static int __init cfi_intelext_init(void) static int __init cfi_intelext_init(void)
{ {
inter_module_register(im_name_1, THIS_MODULE, &cfi_cmdset_0001); inter_module_register(im_name_0001, THIS_MODULE, &cfi_cmdset_0001);
inter_module_register(im_name_3, THIS_MODULE, &cfi_cmdset_0001); inter_module_register(im_name_0003, THIS_MODULE, &cfi_cmdset_0001);
inter_module_register(im_name_0200, THIS_MODULE, &cfi_cmdset_0001);
return 0; return 0;
} }
static void __exit cfi_intelext_exit(void) static void __exit cfi_intelext_exit(void)
{ {
inter_module_unregister(im_name_1); inter_module_unregister(im_name_0001);
inter_module_unregister(im_name_3); inter_module_unregister(im_name_0003);
inter_module_unregister(im_name_0200);
} }
module_init(cfi_intelext_init); module_init(cfi_intelext_init);

View File

@ -2,7 +2,7 @@
* Routines common to all CFI-type probes. * Routines common to all CFI-type probes.
* (C) 2001-2003 Red Hat, Inc. * (C) 2001-2003 Red Hat, Inc.
* GPL'd * GPL'd
* $Id: gen_probe.c,v 1.22 2005/01/24 23:49:50 rmk Exp $ * $Id: gen_probe.c,v 1.23 2005/08/06 04:40:41 nico Exp $
*/ */
#include <linux/kernel.h> #include <linux/kernel.h>
@ -235,6 +235,7 @@ static struct mtd_info *check_cmd_set(struct map_info *map, int primary)
#ifdef CONFIG_MTD_CFI_INTELEXT #ifdef CONFIG_MTD_CFI_INTELEXT
case 0x0001: case 0x0001:
case 0x0003: case 0x0003:
case 0x0200:
return cfi_cmdset_0001(map, primary); return cfi_cmdset_0001(map, primary);
#endif #endif
#ifdef CONFIG_MTD_CFI_AMDSTD #ifdef CONFIG_MTD_CFI_AMDSTD

View File

@ -1,7 +1,7 @@
/* Common Flash Interface structures /* Common Flash Interface structures
* See http://support.intel.com/design/flash/technote/index.htm * See http://support.intel.com/design/flash/technote/index.htm
* $Id: cfi.h,v 1.54 2005/06/06 23:04:36 tpoynor Exp $ * $Id: cfi.h,v 1.55 2005/08/06 04:40:42 nico Exp $
*/ */
#ifndef __MTD_CFI_H__ #ifndef __MTD_CFI_H__
@ -173,6 +173,15 @@ struct cfi_intelext_regioninfo {
struct cfi_intelext_blockinfo BlockTypes[1]; struct cfi_intelext_blockinfo BlockTypes[1];
} __attribute__((packed)); } __attribute__((packed));
struct cfi_intelext_programming_regioninfo {
uint8_t ProgRegShift;
uint8_t Reserved1;
uint8_t ControlValid;
uint8_t Reserved2;
uint8_t ControlInvalid;
uint8_t Reserved3;
} __attribute__((packed));
/* Vendor-Specific PRI for AMD/Fujitsu Extended Command Set (0x0002) */ /* Vendor-Specific PRI for AMD/Fujitsu Extended Command Set (0x0002) */
struct cfi_pri_amdstd { struct cfi_pri_amdstd {
@ -316,7 +325,7 @@ static inline map_word cfi_build_cmd(u_long cmd, struct map_info *map, struct cf
#define CMD(x) cfi_build_cmd((x), map, cfi) #define CMD(x) cfi_build_cmd((x), map, cfi)
static inline unsigned char cfi_merge_status(map_word val, struct map_info *map, static inline unsigned long cfi_merge_status(map_word val, struct map_info *map,
struct cfi_private *cfi) struct cfi_private *cfi)
{ {
int wordwidth, words_per_bus, chip_mode, chips_per_word; int wordwidth, words_per_bus, chip_mode, chips_per_word;

View File

@ -1,5 +1,5 @@
/* /*
* $Id: mtd.h,v 1.59 2005/04/11 10:19:02 gleixner Exp $ * $Id: mtd.h,v 1.60 2005/08/06 04:40:42 nico Exp $
* *
* Copyright (C) 1999-2003 David Woodhouse <dwmw2@infradead.org> et al. * Copyright (C) 1999-2003 David Woodhouse <dwmw2@infradead.org> et al.
* *
@ -72,7 +72,17 @@ struct mtd_info {
u_int32_t oobsize; // Amount of OOB data per block (e.g. 16) u_int32_t oobsize; // Amount of OOB data per block (e.g. 16)
u_int32_t ecctype; u_int32_t ecctype;
u_int32_t eccsize; u_int32_t eccsize;
/*
* Reuse some of the above unused fields in the case of NOR flash
* with configurable programming regions to avoid modifying the
* user visible structure layout/size. Only valid when the
* MTD_PROGRAM_REGIONS flag is set.
* (Maybe we should have an union for those?)
*/
#define MTD_PROGREGION_SIZE(mtd) (mtd)->oobblock
#define MTD_PROGREGION_CTRLMODE_VALID(mtd) (mtd)->oobsize
#define MTD_PROGREGION_CTRLMODE_INVALID(mtd) (mtd)->ecctype
// Kernel-only stuff starts here. // Kernel-only stuff starts here.
char *name; char *name;

View File

@ -1,5 +1,5 @@
/* /*
* $Id: mtd-abi.h,v 1.11 2005/05/19 16:08:58 gleixner Exp $ * $Id: mtd-abi.h,v 1.12 2005/08/06 04:40:43 nico Exp $
* *
* Portions of MTD ABI definition which are shared by kernel and user space * Portions of MTD ABI definition which are shared by kernel and user space
*/ */
@ -42,6 +42,7 @@ struct mtd_oob_buf {
#define MTD_OOB 64 // Out-of-band data (NAND flash) #define MTD_OOB 64 // Out-of-band data (NAND flash)
#define MTD_ECC 128 // Device capable of automatic ECC #define MTD_ECC 128 // Device capable of automatic ECC
#define MTD_NO_VIRTBLOCKS 256 // Virtual blocks not allowed #define MTD_NO_VIRTBLOCKS 256 // Virtual blocks not allowed
#define MTD_PROGRAM_REGIONS 512 // Configurable Programming Regions
// Some common devices / combinations of capabilities // Some common devices / combinations of capabilities
#define MTD_CAP_ROM 0 #define MTD_CAP_ROM 0