diff options
Diffstat (limited to 'linux-2.4.x/include/linux/mtd')
23 files changed, 2465 insertions, 815 deletions
diff --git a/linux-2.4.x/include/linux/mtd/bbm.h b/linux-2.4.x/include/linux/mtd/bbm.h new file mode 100644 index 0000000..7a7fbe8 --- /dev/null +++ b/linux-2.4.x/include/linux/mtd/bbm.h @@ -0,0 +1,122 @@ +/* + * linux/include/linux/mtd/bbm.h + * + * NAND family Bad Block Management (BBM) header file + * - Bad Block Table (BBT) implementation + * + * Copyright (c) 2005 Samsung Electronics + * Kyungmin Park <kyungmin.park@samsung.com> + * + * Copyright (c) 2000-2005 + * Thomas Gleixner <tglx@linuxtronix.de> + * + */ +#ifndef __LINUX_MTD_BBM_H +#define __LINUX_MTD_BBM_H + +/* The maximum number of NAND chips in an array */ +#define NAND_MAX_CHIPS 8 + +/** + * struct nand_bbt_descr - bad block table descriptor + * @param options options for this descriptor + * @param pages the page(s) where we find the bbt, used with + * option BBT_ABSPAGE when bbt is searched, + * then we store the found bbts pages here. + * Its an array and supports up to 8 chips now + * @param offs offset of the pattern in the oob area of the page + * @param veroffs offset of the bbt version counter in the oob are of the page + * @param version version read from the bbt page during scan + * @param len length of the pattern, if 0 no pattern check is performed + * @param maxblocks maximum number of blocks to search for a bbt. This number of + * blocks is reserved at the end of the device + * where the tables are written. + * @param reserved_block_code if non-0, this pattern denotes a reserved + * (rather than bad) block in the stored bbt + * @param pattern pattern to identify bad block table or factory marked + * good / bad blocks, can be NULL, if len = 0 + * + * Descriptor for the bad block table marker and the descriptor for the + * pattern which identifies good and bad blocks. The assumption is made + * that the pattern and the version count are always located in the oob area + * of the first block. + */ +struct nand_bbt_descr { + int options; + int pages[NAND_MAX_CHIPS]; + int offs; + int veroffs; + uint8_t version[NAND_MAX_CHIPS]; + int len; + int maxblocks; + int reserved_block_code; + uint8_t *pattern; +}; + +/* Options for the bad block table descriptors */ + +/* The number of bits used per block in the bbt on the device */ +#define NAND_BBT_NRBITS_MSK 0x0000000F +#define NAND_BBT_1BIT 0x00000001 +#define NAND_BBT_2BIT 0x00000002 +#define NAND_BBT_4BIT 0x00000004 +#define NAND_BBT_8BIT 0x00000008 +/* The bad block table is in the last good block of the device */ +#define NAND_BBT_LASTBLOCK 0x00000010 +/* The bbt is at the given page, else we must scan for the bbt */ +#define NAND_BBT_ABSPAGE 0x00000020 +/* The bbt is at the given page, else we must scan for the bbt */ +#define NAND_BBT_SEARCH 0x00000040 +/* bbt is stored per chip on multichip devices */ +#define NAND_BBT_PERCHIP 0x00000080 +/* bbt has a version counter at offset veroffs */ +#define NAND_BBT_VERSION 0x00000100 +/* Create a bbt if none axists */ +#define NAND_BBT_CREATE 0x00000200 +/* Search good / bad pattern through all pages of a block */ +#define NAND_BBT_SCANALLPAGES 0x00000400 +/* Scan block empty during good / bad block scan */ +#define NAND_BBT_SCANEMPTY 0x00000800 +/* Write bbt if neccecary */ +#define NAND_BBT_WRITE 0x00001000 +/* Read and write back block contents when writing bbt */ +#define NAND_BBT_SAVECONTENT 0x00002000 +/* Search good / bad pattern on the first and the second page */ +#define NAND_BBT_SCAN2NDPAGE 0x00004000 + +/* The maximum number of blocks to scan for a bbt */ +#define NAND_BBT_SCAN_MAXBLOCKS 4 + +/* + * Constants for oob configuration + */ +#define ONENAND_BADBLOCK_POS 0 + +/** + * struct bbt_info - [GENERIC] Bad Block Table data structure + * @param bbt_erase_shift [INTERN] number of address bits in a bbt entry + * @param badblockpos [INTERN] position of the bad block marker in the oob area + * @param bbt [INTERN] bad block table pointer + * @param badblock_pattern [REPLACEABLE] bad block scan pattern used for initial bad block scan + * @param priv [OPTIONAL] pointer to private bbm date + */ +struct bbm_info { + int bbt_erase_shift; + int badblockpos; + int options; + + uint8_t *bbt; + + int (*isbad_bbt)(struct mtd_info *mtd, loff_t ofs, int allowbbt); + + /* TODO Add more NAND specific fileds */ + struct nand_bbt_descr *badblock_pattern; + + void *priv; +}; + +/* OneNAND BBT interface */ +extern int onenand_scan_bbt(struct mtd_info *mtd, struct nand_bbt_descr *bd); +extern int onenand_default_bbt(struct mtd_info *mtd); + +#endif /* __LINUX_MTD_BBM_H */ diff --git a/linux-2.4.x/include/linux/mtd/blktrans.h b/linux-2.4.x/include/linux/mtd/blktrans.h new file mode 100644 index 0000000..23c00e4 --- /dev/null +++ b/linux-2.4.x/include/linux/mtd/blktrans.h @@ -0,0 +1,72 @@ +/* + * $Id: blktrans.h,v 1.7 2006/03/29 08:26:28 dwmw2 Exp $ + * + * (C) 2003 David Woodhouse <dwmw2@infradead.org> + * + * Interface to Linux block layer for MTD 'translation layers'. + * + */ + +#ifndef __MTD_TRANS_H__ +#define __MTD_TRANS_H__ + +#include <linux/mutex.h> + +struct hd_geometry; +struct mtd_info; +struct mtd_blktrans_ops; +struct file; +struct inode; + +struct mtd_blktrans_dev { + struct mtd_blktrans_ops *tr; + struct list_head list; + struct mtd_info *mtd; + struct mutex lock; + int devnum; + int blksize; + unsigned long size; + int readonly; + void *blkcore_priv; /* gendisk in 2.5, devfs_handle in 2.4 */ +}; + +struct blkcore_priv; /* Differs for 2.4 and 2.5 kernels; private */ + +struct mtd_blktrans_ops { + char *name; + int major; + int part_bits; + + /* Access functions */ + int (*readsect)(struct mtd_blktrans_dev *dev, + unsigned long block, char *buffer); + int (*writesect)(struct mtd_blktrans_dev *dev, + unsigned long block, char *buffer); + + /* Block layer ioctls */ + int (*getgeo)(struct mtd_blktrans_dev *dev, struct hd_geometry *geo); + int (*flush)(struct mtd_blktrans_dev *dev); + + /* Called with mtd_table_mutex held; no race with add/remove */ + int (*open)(struct mtd_blktrans_dev *dev); + int (*release)(struct mtd_blktrans_dev *dev); + + /* Called on {de,}registration and on subsequent addition/removal + of devices, with mtd_table_mutex held. */ + void (*add_mtd)(struct mtd_blktrans_ops *tr, struct mtd_info *mtd); + void (*remove_dev)(struct mtd_blktrans_dev *dev); + + struct list_head devs; + struct list_head list; + struct module *owner; + + struct mtd_blkcore_priv *blkcore_priv; +}; + +extern int register_mtd_blktrans(struct mtd_blktrans_ops *tr); +extern int deregister_mtd_blktrans(struct mtd_blktrans_ops *tr); +extern int add_mtd_blktrans_dev(struct mtd_blktrans_dev *dev); +extern int del_mtd_blktrans_dev(struct mtd_blktrans_dev *dev); + + +#endif /* __MTD_TRANS_H__ */ diff --git a/linux-2.4.x/include/linux/mtd/cfi.h b/linux-2.4.x/include/linux/mtd/cfi.h index 7d6b316..abf45ef 100644 --- a/linux-2.4.x/include/linux/mtd/cfi.h +++ b/linux-2.4.x/include/linux/mtd/cfi.h @@ -1,7 +1,7 @@ -/* Common Flash Interface structures +/* Common Flash Interface structures * See http://support.intel.com/design/flash/technote/index.htm - * $Id: cfi.h,v 1.25 2001/09/04 07:06:21 dwmw2 Exp $ + * $Id: cfi.h,v 1.58 2005/11/29 20:01:30 gleixner Exp $ */ #ifndef __MTD_CFI_H__ @@ -12,150 +12,83 @@ #include <linux/types.h> #include <linux/interrupt.h> #include <linux/mtd/flashchip.h> +#include <linux/mtd/map.h> #include <linux/mtd/cfi_endian.h> -/* - * You can optimize the code size and performance by defining only - * the geometry(ies) available on your hardware. - * CFIDEV_INTERLEAVE_n, where represents the interleave (number of chips to fill the bus width) - * CFIDEV_BUSWIDTH_n, where n is the bus width in bytes (1, 2 or 4 bytes) - * - * By default, all (known) geometries are supported. - */ - -#ifndef CONFIG_MTD_CFI_GEOMETRY - -#define CFIDEV_INTERLEAVE_1 (1) -#define CFIDEV_INTERLEAVE_2 (2) -#define CFIDEV_INTERLEAVE_4 (4) - -#define CFIDEV_BUSWIDTH_1 (1) -#define CFIDEV_BUSWIDTH_2 (2) -#define CFIDEV_BUSWIDTH_4 (4) - -#else - #ifdef CONFIG_MTD_CFI_I1 -#define CFIDEV_INTERLEAVE_1 (1) -#endif -#ifdef CONFIG_MTD_CFI_I2 -#define CFIDEV_INTERLEAVE_2 (2) -#endif -#ifdef CONFIG_MTD_CFI_I4 -#define CFIDEV_INTERLEAVE_4 (4) -#endif - -#ifdef CONFIG_MTD_CFI_B1 -#define CFIDEV_BUSWIDTH_1 (1) -#endif -#ifdef CONFIG_MTD_CFI_B2 -#define CFIDEV_BUSWIDTH_2 (2) -#endif -#ifdef CONFIG_MTD_CFI_B4 -#define CFIDEV_BUSWIDTH_4 (4) -#endif - +#define cfi_interleave(cfi) 1 +#define cfi_interleave_is_1(cfi) (cfi_interleave(cfi) == 1) +#else +#define cfi_interleave_is_1(cfi) (0) #endif -/* - * The following macros are used to select the code to execute: - * cfi_buswidth_is_*() - * cfi_interleave_is_*() - * [where * is either 1, 2 or 4] - * Those macros should be used with 'if' statements. If only one of few - * geometry arrangements are selected, they expand to constants thus allowing - * the compiler (most of them being 0) to optimize away all the unneeded code, - * while still validating the syntax (which is not possible with embedded - * #if ... #endif constructs). - */ - -#ifdef CFIDEV_INTERLEAVE_1 -# ifdef CFIDEV_INTERLEAVE -# undef CFIDEV_INTERLEAVE -# define CFIDEV_INTERLEAVE (cfi->interleave) +#ifdef CONFIG_MTD_CFI_I2 +# ifdef cfi_interleave +# undef cfi_interleave +# define cfi_interleave(cfi) ((cfi)->interleave) # else -# define CFIDEV_INTERLEAVE CFIDEV_INTERLEAVE_1 +# define cfi_interleave(cfi) 2 # endif -# define cfi_interleave_is_1() (CFIDEV_INTERLEAVE == CFIDEV_INTERLEAVE_1) +#define cfi_interleave_is_2(cfi) (cfi_interleave(cfi) == 2) #else -# define cfi_interleave_is_1() (0) +#define cfi_interleave_is_2(cfi) (0) #endif -#ifdef CFIDEV_INTERLEAVE_2 -# ifdef CFIDEV_INTERLEAVE -# undef CFIDEV_INTERLEAVE -# define CFIDEV_INTERLEAVE (cfi->interleave) +#ifdef CONFIG_MTD_CFI_I4 +# ifdef cfi_interleave +# undef cfi_interleave +# define cfi_interleave(cfi) ((cfi)->interleave) # else -# define CFIDEV_INTERLEAVE CFIDEV_INTERLEAVE_2 +# define cfi_interleave(cfi) 4 # endif -# define cfi_interleave_is_2() (CFIDEV_INTERLEAVE == CFIDEV_INTERLEAVE_2) +#define cfi_interleave_is_4(cfi) (cfi_interleave(cfi) == 4) #else -# define cfi_interleave_is_2() (0) +#define cfi_interleave_is_4(cfi) (0) #endif -#ifdef CFIDEV_INTERLEAVE_4 -# ifdef CFIDEV_INTERLEAVE -# undef CFIDEV_INTERLEAVE -# define CFIDEV_INTERLEAVE (cfi->interleave) +#ifdef CONFIG_MTD_CFI_I8 +# ifdef cfi_interleave +# undef cfi_interleave +# define cfi_interleave(cfi) ((cfi)->interleave) # else -# define CFIDEV_INTERLEAVE CFIDEV_INTERLEAVE_4 +# define cfi_interleave(cfi) 8 # endif -# define cfi_interleave_is_4() (CFIDEV_INTERLEAVE == CFIDEV_INTERLEAVE_4) +#define cfi_interleave_is_8(cfi) (cfi_interleave(cfi) == 8) #else -# define cfi_interleave_is_4() (0) +#define cfi_interleave_is_8(cfi) (0) #endif -#ifndef CFIDEV_INTERLEAVE -#error You must define at least one interleave to support! +static inline int cfi_interleave_supported(int i) +{ + switch (i) { +#ifdef CONFIG_MTD_CFI_I1 + case 1: #endif - -#ifdef CFIDEV_BUSWIDTH_1 -# ifdef CFIDEV_BUSWIDTH -# undef CFIDEV_BUSWIDTH -# define CFIDEV_BUSWIDTH (map->buswidth) -# else -# define CFIDEV_BUSWIDTH CFIDEV_BUSWIDTH_1 -# endif -# define cfi_buswidth_is_1() (CFIDEV_BUSWIDTH == CFIDEV_BUSWIDTH_1) -#else -# define cfi_buswidth_is_1() (0) +#ifdef CONFIG_MTD_CFI_I2 + case 2: #endif - -#ifdef CFIDEV_BUSWIDTH_2 -# ifdef CFIDEV_BUSWIDTH -# undef CFIDEV_BUSWIDTH -# define CFIDEV_BUSWIDTH (map->buswidth) -# else -# define CFIDEV_BUSWIDTH CFIDEV_BUSWIDTH_2 -# endif -# define cfi_buswidth_is_2() (CFIDEV_BUSWIDTH == CFIDEV_BUSWIDTH_2) -#else -# define cfi_buswidth_is_2() (0) +#ifdef CONFIG_MTD_CFI_I4 + case 4: #endif - -#ifdef CFIDEV_BUSWIDTH_4 -# ifdef CFIDEV_BUSWIDTH -# undef CFIDEV_BUSWIDTH -# define CFIDEV_BUSWIDTH (map->buswidth) -# else -# define CFIDEV_BUSWIDTH CFIDEV_BUSWIDTH_4 -# endif -# define cfi_buswidth_is_4() (CFIDEV_BUSWIDTH == CFIDEV_BUSWIDTH_4) -#else -# define cfi_buswidth_is_4() (0) +#ifdef CONFIG_MTD_CFI_I8 + case 8: #endif + return 1; + + default: + return 0; + } +} -#ifndef CFIDEV_BUSWIDTH -#error You must define at least one bus width to support! -#endif -/* NB: these values must represents the number of bytes needed to meet the - * device type (x8, x16, x32). Eg. a 32 bit device is 4 x 8 bytes. +/* NB: these values must represents the number of bytes needed to meet the + * device type (x8, x16, x32). Eg. a 32 bit device is 4 x 8 bytes. * These numbers are used in calculations. */ #define CFI_DEVICETYPE_X8 (8 / 8) #define CFI_DEVICETYPE_X16 (16 / 8) #define CFI_DEVICETYPE_X32 (32 / 8) +#define CFI_DEVICETYPE_X64 (64 / 8) /* NB: We keep these structures in memory in HOST byteorder, except * where individually noted. @@ -163,84 +96,147 @@ /* Basic Query Structure */ struct cfi_ident { - __u8 qry[3]; - __u16 P_ID; - __u16 P_ADR; - __u16 A_ID; - __u16 A_ADR; - __u8 VccMin; - __u8 VccMax; - __u8 VppMin; - __u8 VppMax; - __u8 WordWriteTimeoutTyp; - __u8 BufWriteTimeoutTyp; - __u8 BlockEraseTimeoutTyp; - __u8 ChipEraseTimeoutTyp; - __u8 WordWriteTimeoutMax; - __u8 BufWriteTimeoutMax; - __u8 BlockEraseTimeoutMax; - __u8 ChipEraseTimeoutMax; - __u8 DevSize; - __u16 InterfaceDesc; - __u16 MaxBufWriteSize; - __u8 NumEraseRegions; - __u32 EraseRegionInfo[0]; /* Not host ordered */ + uint8_t qry[3]; + uint16_t P_ID; + uint16_t P_ADR; + uint16_t A_ID; + uint16_t A_ADR; + uint8_t VccMin; + uint8_t VccMax; + uint8_t VppMin; + uint8_t VppMax; + uint8_t WordWriteTimeoutTyp; + uint8_t BufWriteTimeoutTyp; + uint8_t BlockEraseTimeoutTyp; + uint8_t ChipEraseTimeoutTyp; + uint8_t WordWriteTimeoutMax; + uint8_t BufWriteTimeoutMax; + uint8_t BlockEraseTimeoutMax; + uint8_t ChipEraseTimeoutMax; + uint8_t DevSize; + uint16_t InterfaceDesc; + uint16_t MaxBufWriteSize; + uint8_t NumEraseRegions; + uint32_t EraseRegionInfo[0]; /* Not host ordered */ } __attribute__((packed)); /* Extended Query Structure for both PRI and ALT */ struct cfi_extquery { - __u8 pri[3]; - __u8 MajorVersion; - __u8 MinorVersion; + uint8_t pri[3]; + uint8_t MajorVersion; + uint8_t MinorVersion; } __attribute__((packed)); /* Vendor-Specific PRI for Intel/Sharp Extended Command Set (0x0001) */ struct cfi_pri_intelext { - __u8 pri[3]; - __u8 MajorVersion; - __u8 MinorVersion; - __u32 FeatureSupport; - __u8 SuspendCmdSupport; - __u16 BlkStatusRegMask; - __u8 VccOptimal; - __u8 VppOptimal; + uint8_t pri[3]; + uint8_t MajorVersion; + uint8_t MinorVersion; + uint32_t FeatureSupport; /* if bit 31 is set then an additional uint32_t feature + block follows - FIXME - not currently supported */ + uint8_t SuspendCmdSupport; + uint16_t BlkStatusRegMask; + uint8_t VccOptimal; + uint8_t VppOptimal; + uint8_t NumProtectionFields; + uint16_t ProtRegAddr; + uint8_t FactProtRegSize; + uint8_t UserProtRegSize; + uint8_t extra[0]; +} __attribute__((packed)); + +struct cfi_intelext_otpinfo { + uint32_t ProtRegAddr; + uint16_t FactGroups; + uint8_t FactProtRegSize; + uint16_t UserGroups; + uint8_t UserProtRegSize; +} __attribute__((packed)); + +struct cfi_intelext_blockinfo { + uint16_t NumIdentBlocks; + uint16_t BlockSize; + uint16_t MinBlockEraseCycles; + uint8_t BitsPerCell; + uint8_t BlockCap; +} __attribute__((packed)); + +struct cfi_intelext_regioninfo { + uint16_t NumIdentPartitions; + uint8_t NumOpAllowed; + uint8_t NumOpAllowedSimProgMode; + uint8_t NumOpAllowedSimEraMode; + uint8_t NumBlockTypes; + struct cfi_intelext_blockinfo BlockTypes[1]; +} __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) */ + +struct cfi_pri_amdstd { + uint8_t pri[3]; + uint8_t MajorVersion; + uint8_t MinorVersion; + uint8_t SiliconRevision; /* bits 1-0: Address Sensitive Unlock */ + uint8_t EraseSuspend; + uint8_t BlkProt; + uint8_t TmpBlkUnprotect; + uint8_t BlkProtUnprot; + uint8_t SimultaneousOps; + uint8_t BurstMode; + uint8_t PageMode; + uint8_t VppMin; + uint8_t VppMax; + uint8_t TopBottom; } __attribute__((packed)); struct cfi_pri_query { - __u8 NumFields; - __u32 ProtField[1]; /* Not host ordered */ + uint8_t NumFields; + uint32_t ProtField[1]; /* Not host ordered */ } __attribute__((packed)); struct cfi_bri_query { - __u8 PageModeReadCap; - __u8 NumFields; - __u32 ConfField[1]; /* Not host ordered */ + uint8_t PageModeReadCap; + uint8_t NumFields; + uint32_t ConfField[1]; /* Not host ordered */ } __attribute__((packed)); -#define P_ID_NONE 0 -#define P_ID_INTEL_EXT 1 -#define P_ID_AMD_STD 2 -#define P_ID_INTEL_STD 3 -#define P_ID_AMD_EXT 4 -#define P_ID_MITSUBISHI_STD 256 -#define P_ID_MITSUBISHI_EXT 257 -#define P_ID_RESERVED 65535 +#define P_ID_NONE 0x0000 +#define P_ID_INTEL_EXT 0x0001 +#define P_ID_AMD_STD 0x0002 +#define P_ID_INTEL_STD 0x0003 +#define P_ID_AMD_EXT 0x0004 +#define P_ID_WINBOND 0x0006 +#define P_ID_ST_ADV 0x0020 +#define P_ID_MITSUBISHI_STD 0x0100 +#define P_ID_MITSUBISHI_EXT 0x0101 +#define P_ID_SST_PAGE 0x0102 +#define P_ID_INTEL_PERFORMANCE 0x0200 +#define P_ID_INTEL_DATA 0x0210 +#define P_ID_RESERVED 0xffff -#define CFI_MODE_CFI 0 -#define CFI_MODE_JEDEC 1 +#define CFI_MODE_CFI 1 +#define CFI_MODE_JEDEC 0 struct cfi_private { - __u16 cmdset; + uint16_t cmdset; void *cmdset_priv; int interleave; int device_type; int cfi_mode; /* Are we a JEDEC device pretending to be CFI? */ int addr_unlock1; int addr_unlock2; - int fast_prog; struct mtd_info *(*cmdset_setup)(struct map_info *); struct cfi_ident *cfiq; /* For now only one. We insist that all devs must be of the same type. */ @@ -251,83 +247,145 @@ struct cfi_private { struct flchip chips[0]; /* per-chip data structure for each chip */ }; -#define MAX_CFI_CHIPS 8 /* Entirely arbitrary to avoid realloc() */ - /* * Returns the command address according to the given geometry. */ -static inline __u32 cfi_build_cmd_addr(__u32 cmd_ofs, int interleave, int type) +static inline uint32_t cfi_build_cmd_addr(uint32_t cmd_ofs, int interleave, int type) { return (cmd_ofs * type) * interleave; } /* - * Transforms the CFI command for the given geometry (bus width & interleave. + * Transforms the CFI command for the given geometry (bus width & interleave). + * It looks too long to be inline, but in the common case it should almost all + * get optimised away. */ -static inline __u32 cfi_build_cmd(u_char cmd, struct map_info *map, struct cfi_private *cfi) +static inline map_word cfi_build_cmd(u_long cmd, struct map_info *map, struct cfi_private *cfi) { - __u32 val = 0; - - if (cfi_buswidth_is_1()) { - /* 1 x8 device */ - val = cmd; - } else if (cfi_buswidth_is_2()) { - if (cfi_interleave_is_1()) { - /* 1 x16 device in x16 mode */ - val = cpu_to_cfi16(cmd); - } else if (cfi_interleave_is_2()) { - /* 2 (x8, x16 or x32) devices in x8 mode */ - val = cpu_to_cfi16((cmd << 8) | cmd); - } - } else if (cfi_buswidth_is_4()) { - if (cfi_interleave_is_1()) { - /* 1 x32 device in x32 mode */ - val = cpu_to_cfi32(cmd); - } else if (cfi_interleave_is_2()) { - /* 2 x16 device in x16 mode */ - val = cpu_to_cfi32((cmd << 16) | cmd); - } else if (cfi_interleave_is_4()) { - /* 4 (x8, x16 or x32) devices in x8 mode */ - val = (cmd << 16) | cmd; - val = cpu_to_cfi32((val << 8) | val); - } + map_word val = { {0} }; + int wordwidth, words_per_bus, chip_mode, chips_per_word; + unsigned long onecmd; + int i; + + /* We do it this way to give the compiler a fighting chance + of optimising away all the crap for 'bankwidth' larger than + an unsigned long, in the common case where that support is + disabled */ + if (map_bankwidth_is_large(map)) { + wordwidth = sizeof(unsigned long); + words_per_bus = (map_bankwidth(map)) / wordwidth; // i.e. normally 1 + } else { + wordwidth = map_bankwidth(map); + words_per_bus = 1; + } + + chip_mode = map_bankwidth(map) / cfi_interleave(cfi); + chips_per_word = wordwidth * cfi_interleave(cfi) / map_bankwidth(map); + + /* First, determine what the bit-pattern should be for a single + device, according to chip mode and endianness... */ + switch (chip_mode) { + default: BUG(); + case 1: + onecmd = cmd; + break; + case 2: + onecmd = cpu_to_cfi16(cmd); + break; + case 4: + onecmd = cpu_to_cfi32(cmd); + break; + } + + /* Now replicate it across the size of an unsigned long, or + just to the bus width as appropriate */ + switch (chips_per_word) { + default: BUG(); +#if BITS_PER_LONG >= 64 + case 8: + onecmd |= (onecmd << (chip_mode * 32)); +#endif + case 4: + onecmd |= (onecmd << (chip_mode * 16)); + case 2: + onecmd |= (onecmd << (chip_mode * 8)); + case 1: + ; } + + /* And finally, for the multi-word case, replicate it + in all words in the structure */ + for (i=0; i < words_per_bus; i++) { + val.x[i] = onecmd; + } + return val; } #define CMD(x) cfi_build_cmd((x), map, cfi) -/* - * Read a value according to the bus width. - */ -static inline __u32 cfi_read(struct map_info *map, __u32 addr) +static inline unsigned long cfi_merge_status(map_word val, struct map_info *map, + struct cfi_private *cfi) { - if (cfi_buswidth_is_1()) { - return map->read8(map, addr); - } else if (cfi_buswidth_is_2()) { - return map->read16(map, addr); - } else if (cfi_buswidth_is_4()) { - return map->read32(map, addr); + int wordwidth, words_per_bus, chip_mode, chips_per_word; + unsigned long onestat, res = 0; + int i; + + /* We do it this way to give the compiler a fighting chance + of optimising away all the crap for 'bankwidth' larger than + an unsigned long, in the common case where that support is + disabled */ + if (map_bankwidth_is_large(map)) { + wordwidth = sizeof(unsigned long); + words_per_bus = (map_bankwidth(map)) / wordwidth; // i.e. normally 1 } else { - return 0; + wordwidth = map_bankwidth(map); + words_per_bus = 1; } -} -/* - * Write a value according to the bus width. - */ + chip_mode = map_bankwidth(map) / cfi_interleave(cfi); + chips_per_word = wordwidth * cfi_interleave(cfi) / map_bankwidth(map); -static inline void cfi_write(struct map_info *map, __u32 val, __u32 addr) -{ - if (cfi_buswidth_is_1()) { - map->write8(map, val, addr); - } else if (cfi_buswidth_is_2()) { - map->write16(map, val, addr); - } else if (cfi_buswidth_is_4()) { - map->write32(map, val, addr); + onestat = val.x[0]; + /* Or all status words together */ + for (i=1; i < words_per_bus; i++) { + onestat |= val.x[i]; + } + + res = onestat; + switch(chips_per_word) { + default: BUG(); +#if BITS_PER_LONG >= 64 + case 8: + res |= (onestat >> (chip_mode * 32)); +#endif + case 4: + res |= (onestat >> (chip_mode * 16)); + case 2: + res |= (onestat >> (chip_mode * 8)); + case 1: + ; + } + + /* Last, determine what the bit-pattern should be for a single + device, according to chip mode and endianness... */ + switch (chip_mode) { + case 1: + break; + case 2: + res = cfi16_to_cpu(res); + break; + case 4: + res = cfi32_to_cpu(res); + break; + default: BUG(); } + return res; } +#define MERGESTATUS(x) cfi_merge_status((x), map, cfi) + + /* * Sends a CFI command to a bank of flash for the given geometry. * @@ -335,59 +393,87 @@ static inline void cfi_write(struct map_info *map, __u32 val, __u32 addr) * If prev_val is non-null, it will be set to the value at the command address, * before the command was written. */ -static inline __u32 cfi_send_gen_cmd(u_char cmd, __u32 cmd_addr, __u32 base, +static inline uint32_t cfi_send_gen_cmd(u_char cmd, uint32_t cmd_addr, uint32_t base, struct map_info *map, struct cfi_private *cfi, - int type, __u32 *prev_val) + int type, map_word *prev_val) { - __u32 val; - __u32 addr = base + cfi_build_cmd_addr(cmd_addr, CFIDEV_INTERLEAVE, type); + map_word val; + uint32_t addr = base + cfi_build_cmd_addr(cmd_addr, cfi_interleave(cfi), type); val = cfi_build_cmd(cmd, map, cfi); if (prev_val) - *prev_val = cfi_read(map, addr); + *prev_val = map_read(map, addr); - cfi_write(map, val, addr); + map_write(map, val, addr); return addr - base; } -static inline __u8 cfi_read_query(struct map_info *map, __u32 addr) +static inline uint8_t cfi_read_query(struct map_info *map, uint32_t addr) { - if (cfi_buswidth_is_1()) { - return map->read8(map, addr); - } else if (cfi_buswidth_is_2()) { - return cfi16_to_cpu(map->read16(map, addr)); - } else if (cfi_buswidth_is_4()) { - return cfi32_to_cpu(map->read32(map, addr)); + map_word val = map_read(map, addr); + + if (map_bankwidth_is_1(map)) { + return val.x[0]; + } else if (map_bankwidth_is_2(map)) { + return cfi16_to_cpu(val.x[0]); } else { - return 0; + /* No point in a 64-bit byteswap since that would just be + swapping the responses from different chips, and we are + only interested in one chip (a representative sample) */ + return cfi32_to_cpu(val.x[0]); } } -static inline void cfi_udelay(int us) +static inline uint16_t cfi_read_query16(struct map_info *map, uint32_t addr) { -#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,2,0) - if (current->need_resched) { - unsigned long t = us * HZ / 1000000; - if (t < 1) - t = 1; - set_current_state(TASK_UNINTERRUPTIBLE); - schedule_timeout(t); + map_word val = map_read(map, addr); + + if (map_bankwidth_is_1(map)) { + return val.x[0] & 0xff; + } else if (map_bankwidth_is_2(map)) { + return cfi16_to_cpu(val.x[0]); + } else { + /* No point in a 64-bit byteswap since that would just be + swapping the responses from different chips, and we are + only interested in one chip (a representative sample) */ + return cfi32_to_cpu(val.x[0]); } - else -#endif - udelay(us); -} -static inline void cfi_spin_lock(spinlock_t *mutex) -{ - spin_lock_bh(mutex); } -static inline void cfi_spin_unlock(spinlock_t *mutex) +static inline void cfi_udelay(int us) { - spin_unlock_bh(mutex); + if (us >= 1000) { + msleep((us+999)/1000); + } else { + udelay(us); + cond_resched(); + } } +struct cfi_extquery *cfi_read_pri(struct map_info *map, uint16_t adr, uint16_t size, + const char* name); +struct cfi_fixup { + uint16_t mfr; + uint16_t id; + void (*fixup)(struct mtd_info *mtd, void* param); + void* param; +}; + +#define CFI_MFR_ANY 0xffff +#define CFI_ID_ANY 0xffff + +#define CFI_MFR_AMD 0x0001 +#define CFI_MFR_ST 0x0020 /* STMicroelectronics */ + +void cfi_fixup(struct mtd_info *mtd, struct cfi_fixup* fixups); + +typedef int (*varsize_frob_t)(struct map_info *map, struct flchip *chip, + unsigned long adr, int len, void *thunk); + +int cfi_varsize_frob(struct mtd_info *mtd, varsize_frob_t frob, + loff_t ofs, size_t len, void *thunk); + #endif /* __MTD_CFI_H__ */ diff --git a/linux-2.4.x/include/linux/mtd/cfi_endian.h b/linux-2.4.x/include/linux/mtd/cfi_endian.h index 9f3b041..25724f7 100644 --- a/linux-2.4.x/include/linux/mtd/cfi_endian.h +++ b/linux-2.4.x/include/linux/mtd/cfi_endian.h @@ -1,5 +1,5 @@ /* - * $Id: cfi_endian.h,v 1.10 2001/06/18 11:00:46 abz Exp $ + * $Id: cfi_endian.h,v 1.11 2002/01/30 23:20:48 awozniak Exp $ * */ @@ -30,22 +30,28 @@ #define cfi8_to_cpu(x) (x) #define cpu_to_cfi16(x) cpu_to_le16(x) #define cpu_to_cfi32(x) cpu_to_le32(x) +#define cpu_to_cfi64(x) cpu_to_le64(x) #define cfi16_to_cpu(x) le16_to_cpu(x) #define cfi32_to_cpu(x) le32_to_cpu(x) +#define cfi64_to_cpu(x) le64_to_cpu(x) #elif defined (CFI_BIG_ENDIAN) #define cpu_to_cfi8(x) (x) #define cfi8_to_cpu(x) (x) #define cpu_to_cfi16(x) cpu_to_be16(x) #define cpu_to_cfi32(x) cpu_to_be32(x) +#define cpu_to_cfi64(x) cpu_to_be64(x) #define cfi16_to_cpu(x) be16_to_cpu(x) #define cfi32_to_cpu(x) be32_to_cpu(x) +#define cfi64_to_cpu(x) be64_to_cpu(x) #elif defined (CFI_HOST_ENDIAN) #define cpu_to_cfi8(x) (x) #define cfi8_to_cpu(x) (x) #define cpu_to_cfi16(x) (x) #define cpu_to_cfi32(x) (x) +#define cpu_to_cfi64(x) (x) #define cfi16_to_cpu(x) (x) #define cfi32_to_cpu(x) (x) +#define cfi64_to_cpu(x) (x) #else #error No CFI endianness defined #endif diff --git a/linux-2.4.x/include/linux/mtd/compatmac.h b/linux-2.4.x/include/linux/mtd/compatmac.h index 9c9a227..5433d1f 100644 --- a/linux-2.4.x/include/linux/mtd/compatmac.h +++ b/linux-2.4.x/include/linux/mtd/compatmac.h @@ -1,202 +1,249 @@ - /* - * mtd/include/compatmac.h - * - * $Id: compatmac.h,v 1.4 2000/07/03 10:01:38 dwmw2 Exp $ + * $Id: compatmac.h,v 1.80 2005/11/07 11:14:54 gleixner Exp $ * * Extensions and omissions from the normal 'linux/compatmac.h' - * files. hopefully this will end up empty as the 'real' one + * files. hopefully this will end up empty as the 'real' one * becomes fully-featured. */ - -/* First, include the parts which the kernel is good enough to provide - * to us - */ - #ifndef __LINUX_MTD_COMPATMAC_H__ #define __LINUX_MTD_COMPATMAC_H__ -#include <linux/compatmac.h> -#include <linux/types.h> /* used later in this header */ -#include <linux/module.h> -#ifndef LINUX_VERSION_CODE #include <linux/version.h> + +#if LINUX_VERSION_CODE < KERNEL_VERSION(2,4,10) +#error "This kernel is too old: not supported by this file" #endif -#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,1,0) -#include <linux/vmalloc.h> + /* O(1) scheduler stuff. */ + +#if LINUX_VERSION_CODE < KERNEL_VERSION(2,5,5) && !defined(__rh_config_h__) +#include <linux/sched.h> +static inline void __recalc_sigpending(void) +{ + recalc_sigpending(current); +} +#undef recalc_sigpending +#define recalc_sigpending() __recalc_sigpending () + +#define set_user_nice(tsk, n) do { (tsk)->nice = n; } while(0) #endif -#if LINUX_VERSION_CODE < KERNEL_VERSION(2,0,0) -# error "This kernel is too old: not supported by this file" + + +#if LINUX_VERSION_CODE < KERNEL_VERSION(2,4,20) + +#ifndef yield +#define yield() do { set_current_state(TASK_RUNNING); schedule(); } while(0) #endif -/* Modularization issues */ -#if LINUX_VERSION_CODE < KERNEL_VERSION(2,1,18) -# define __USE_OLD_SYMTAB__ -# define EXPORT_NO_SYMBOLS register_symtab(NULL); -# define REGISTER_SYMTAB(tab) register_symtab(tab) -#else -# define REGISTER_SYMTAB(tab) /* nothing */ +#ifndef minor +#define major(d) (MAJOR(to_kdev_t(d))) +#define minor(d) (MINOR(to_kdev_t(d))) #endif -#ifdef __USE_OLD_SYMTAB__ -# define __MODULE_STRING(s) /* nothing */ -# define MODULE_PARM(v,t) /* nothing */ -# define MODULE_PARM_DESC(v,t) /* nothing */ -# define MODULE_AUTHOR(n) /* nothing */ -# define MODULE_DESCRIPTION(d) /* nothing */ -# define MODULE_SUPPORTED_DEVICE(n) /* nothing */ +#ifndef mk_kdev +#define mk_kdev(ma,mi) MKDEV(ma,mi) +#define kdev_t_to_nr(x) (x) #endif -/* - * "select" changed in 2.1.23. The implementation is twin, but this - * header is new - */ -#if LINUX_VERSION_CODE > KERNEL_VERSION(2,1,22) -# include <linux/poll.h> -#else -# define __USE_OLD_SELECT__ +#define need_resched() (current->need_resched) +#define cond_resched() do { if need_resched() { yield(); } } while(0) + +#endif /* < 2.4.20 */ +#if LINUX_VERSION_CODE < KERNEL_VERSION(2,5,73) +#define iminor(i) minor((i)->i_rdev) +#define imajor(i) major((i)->i_rdev) +#define old_encode_dev(d) ( (major(d)<<8) | minor(d) ) +#define old_decode_dev(rdev) (kdev_t_to_nr(mk_kdev((rdev)>>8, (rdev)&0xff))) +#define old_valid_dev(d) (1) #endif -/* Other change in the fops are solved using pseudo-types */ -#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,1,0) -# define lseek_t long long -# define lseek_off_t long long -#else -# define lseek_t int -# define lseek_off_t off_t +#if LINUX_VERSION_CODE < KERNEL_VERSION(2,5,61) + +#include <linux/sched.h> + +#ifdef __rh_config_h__ +#define sigmask_lock sighand->siglock +#define sig sighand #endif -/* changed the prototype of read/write */ +static inline void __daemonize_modvers(void) +{ + daemonize(); + + spin_lock_irq(¤t->sigmask_lock); + sigfillset(¤t->blocked); + recalc_sigpending(); + spin_unlock_irq(¤t->sigmask_lock); +} +#undef daemonize +#define daemonize(fmt, ...) do { \ + snprintf(current->comm, sizeof(current->comm), fmt ,##__VA_ARGS__); \ + __daemonize_modvers(); \ + } while(0) + +static inline int dequeue_signal_lock(struct task_struct *tsk, sigset_t *mask, siginfo_t *info) +{ + unsigned long flags; + unsigned long ret; + + spin_lock_irqsave(¤t->sigmask_lock, flags); + ret = dequeue_signal(mask, info); + spin_unlock_irqrestore(¤t->sigmask_lock, flags); + + return ret; +} + +static inline int allow_signal(int sig) +{ + if (sig < 1 || sig > _NSIG) + return -EINVAL; + + spin_lock_irq(¤t->sigmask_lock); + sigdelset(¤t->blocked, sig); + recalc_sigpending(); + /* Make sure the kernel neither eats it now converts to SIGKILL */ + current->sig->action[sig-1].sa.sa_handler = (void *)2; + spin_unlock_irq(¤t->sigmask_lock); + return 0; +} +static inline int disallow_signal(int sig) +{ + if (sig < 1 || sig > _NSIG) + return -EINVAL; -#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,1,0) || defined(__alpha__) -# define count_t unsigned long -# define read_write_t long -#else -# define count_t int -# define read_write_t int + spin_lock_irq(¤t->sigmask_lock); + sigaddset(¤t->blocked, sig); + recalc_sigpending(); + + current->sig->action[sig-1].sa.sa_handler = SIG_DFL; + spin_unlock_irq(¤t->sigmask_lock); + return 0; +} + +#define PF_FREEZE 0 +#define refrigerator(x) do { ; } while(0) #endif + /* Module bits */ + -#if LINUX_VERSION_CODE < KERNEL_VERSION(2,1,31) -# define release_t void -# define release_return(x) return -#else -# define release_t int -# define release_return(x) return (x) +#if LINUX_VERSION_CODE < KERNEL_VERSION(2,5,60) +#define try_module_get(m) try_inc_mod_count(m) +#define __module_get(m) do { if (!try_inc_mod_count(m)) BUG(); } while(0) +#define module_put(m) do { if (m) __MOD_DEC_USE_COUNT((struct module *)(m)); } while(0) +#define set_module_owner(x) do { x->owner = THIS_MODULE; } while(0) #endif -#if LINUX_VERSION_CODE < 0x20300 -#define __exit + + /* Random filesystem stuff, only for JFFS2 really */ + +#if LINUX_VERSION_CODE < KERNEL_VERSION(2,5,5) +#define parent_ino(d) ((d)->d_parent->d_inode->i_ino) #endif -#if LINUX_VERSION_CODE < 0x20200 -#define __init -#else -#include <linux/init.h> + +#if LINUX_VERSION_CODE < KERNEL_VERSION(2,5,12) +#define PageUptodate(x) Page_Uptodate(x) #endif -#if LINUX_VERSION_CODE < 0x20300 -#define init_MUTEX(x) do {*(x) = MUTEX;} while (0) -#define RQFUNC_ARG void -#define blkdev_dequeue_request(req) do {CURRENT = req->next;} while (0) -#else -#define RQFUNC_ARG request_queue_t *q +#if LINUX_VERSION_CODE < KERNEL_VERSION(2,5,48) +#define get_seconds() CURRENT_TIME #endif -#if LINUX_VERSION_CODE < KERNEL_VERSION(2,2,0) -#define __MOD_INC_USE_COUNT(mod) \ - (atomic_inc(&(mod)->uc.usecount), (mod)->flags |= MOD_VISITED|MOD_USED_ONCE) -#define __MOD_DEC_USE_COUNT(mod) \ - (atomic_dec(&(mod)->uc.usecount), (mod)->flags |= MOD_VISITED) +#if LINUX_VERSION_CODE < KERNEL_VERSION(2,5,53) +#define generic_file_readonly_mmap generic_file_mmap #endif +#if LINUX_VERSION_CODE < KERNEL_VERSION(2,5,70) + +#include <linux/kmod.h> +#include <linux/string.h> + +static inline char *strlcpy(char *dest, const char *src, int len) +{ + dest[len-1] = 0; + return strncpy(dest, src, len-1); +} + +static inline int do_old_request_module(const char *mod) +{ + return request_module(mod); +} +#undef request_module +#define request_module(fmt, ...) \ + ({ char modname[32]; snprintf(modname, 31, fmt ,##__VA_ARGS__); do_old_request_module(modname); }) + +#endif /* 2.5.70 */ +#ifndef container_of +#define container_of(ptr, type, member) ({ \ + const typeof( ((type *)0)->member ) *__mptr = (ptr); \ + (type *)( (char *)__mptr - offsetof(type,member) );}) +#endif -#if LINUX_VERSION_CODE < KERNEL_VERSION(2,3,0) +#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,7) +#define kvec iovec +#define __user +#endif -#define DECLARE_WAIT_QUEUE_HEAD(x) struct wait_queue *x = NULL -#define init_waitqueue_head init_waitqueue +#if LINUX_VERSION_CODE < KERNEL_VERSION(2,4,28) +#define msleep(x) \ + set_current_state(TASK_UNINTERRUPTIBLE); \ + schedule_timeout((x)*(HZ/1000)); +#endif -static inline int try_inc_mod_count(struct module *mod) +#ifndef __iomem +#define __iomem +#endif + +#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,11) +#define CURRENT_TIME_SEC ((struct timespec) { xtime.tv_sec, 0 }) +#include <linux/sched.h> +#include <linux/suspend.h> +static inline int try_to_freeze(unsigned long refrigerator_flags) { - if (mod) - __MOD_INC_USE_COUNT(mod); - return 1; + if (unlikely(current->flags & PF_FREEZE)) { + refrigerator(refrigerator_flags); + return 1; + } else + return 0; } #endif +#if LINUX_VERSION_CODE <= KERNEL_VERSION(2,6,12) +#define try_to_freeze() try_to_freeze(0) +#endif + +#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,13) +typedef struct class_simple class; +#define class_device_create(cs, dev, device, fmt, ...) class_simple_device_add((struct class_simple *)cs, dev, device, fmt, __VA_ARGS__) +#define class_device_destroy(cs, dev) class_simple_device_remove(dev) +#define class_create(owner, name) (struct class *)class_simple_create(owner, name) +#define class_destroy(cs) class_simple_destroy((struct class_simple *)cs) +#endif -/* Yes, I'm aware that it's a fairly ugly hack. - Until the __constant_* macros appear in Linus' own kernels, this is - the way it has to be done. - DW 19/1/00 +#ifndef list_for_each_entry_safe +/** + * list_for_each_entry_safe - iterate over list of given type safe against removal of list entry + * @pos: the type * to use as a loop counter. + * @n: another type * to use as temporary storage + * @head: the head for your list. + * @member: the name of the list_struct within the struct. */ +#define list_for_each_entry_safe(pos, n, head, member) \ + for (pos = list_entry((head)->next, typeof(*pos), member), \ + n = list_entry(pos->member.next, typeof(*pos), member); \ + &pos->member != (head); \ + pos = n, n = list_entry(n->member.next, typeof(*n), member)) -#include <asm/byteorder.h> - -#ifndef __constant_cpu_to_le16 - -#ifdef __BIG_ENDIAN -#define __constant_cpu_to_le64(x) ___swab64((x)) -#define __constant_le64_to_cpu(x) ___swab64((x)) -#define __constant_cpu_to_le32(x) ___swab32((x)) -#define __constant_le32_to_cpu(x) ___swab32((x)) -#define __constant_cpu_to_le16(x) ___swab16((x)) -#define __constant_le16_to_cpu(x) ___swab16((x)) -#define __constant_cpu_to_be64(x) ((__u64)(x)) -#define __constant_be64_to_cpu(x) ((__u64)(x)) -#define __constant_cpu_to_be32(x) ((__u32)(x)) -#define __constant_be32_to_cpu(x) ((__u32)(x)) -#define __constant_cpu_to_be16(x) ((__u16)(x)) -#define __constant_be16_to_cpu(x) ((__u16)(x)) -#else -#ifdef __LITTLE_ENDIAN -#define __constant_cpu_to_le64(x) ((__u64)(x)) -#define __constant_le64_to_cpu(x) ((__u64)(x)) -#define __constant_cpu_to_le32(x) ((__u32)(x)) -#define __constant_le32_to_cpu(x) ((__u32)(x)) -#define __constant_cpu_to_le16(x) ((__u16)(x)) -#define __constant_le16_to_cpu(x) ((__u16)(x)) -#define __constant_cpu_to_be64(x) ___swab64((x)) -#define __constant_be64_to_cpu(x) ___swab64((x)) -#define __constant_cpu_to_be32(x) ___swab32((x)) -#define __constant_be32_to_cpu(x) ___swab32((x)) -#define __constant_cpu_to_be16(x) ___swab16((x)) -#define __constant_be16_to_cpu(x) ___swab16((x)) -#else -#error No (recognised) endianness defined (unless it,s PDP) -#endif /* __LITTLE_ENDIAN */ -#endif /* __BIG_ENDIAN */ - -#endif /* ifndef __constant_cpu_to_le16 */ - -#if LINUX_VERSION_CODE < KERNEL_VERSION(2,3,0) - #define mod_init_t int __init - #define mod_exit_t void -#else - #define mod_init_t static int __init - #define mod_exit_t static void __exit -#endif - -#ifndef THIS_MODULE -#ifdef MODULE -#define THIS_MODULE (&__this_module) -#else -#define THIS_MODULE (NULL) -#endif -#endif - -#if LINUX_VERSION_CODE < 0x20300 -#include <linux/interrupt.h> -#define spin_lock_bh(lock) do {start_bh_atomic();spin_lock(lock);} while(0) -#define spin_unlock_bh(lock) do {spin_unlock(lock);end_bh_atomic();} while(0) -#else -#include <asm/softirq.h> -#include <linux/spinlock.h> #endif -#endif /* __LINUX_MTD_COMPATMAC_H__ */ - +#ifndef DEFINE_SPINLOCK +#define DEFINE_SPINLOCK(x) spinlock_t x = SPIN_LOCK_UNLOCKED +#endif +#ifndef DEFINE_RWLOCK +#define DEFINE_RWLOCK(x) rwlock_t x = RW_LOCK_UNLOCKED +#endif +#endif /* __LINUX_MTD_COMPATMAC_H__ */ diff --git a/linux-2.4.x/include/linux/mtd/doc2000.h b/linux-2.4.x/include/linux/mtd/doc2000.h index 6161f2c..244954e 100644 --- a/linux-2.4.x/include/linux/mtd/doc2000.h +++ b/linux-2.4.x/include/linux/mtd/doc2000.h @@ -1,13 +1,21 @@ - -/* Linux driver for Disk-On-Chip 2000 */ -/* (c) 1999 Machine Vision Holdings, Inc. */ -/* Author: David Woodhouse <dwmw2@mvhi.com> */ -/* $Id: doc2000.h,v 1.15 2001/09/19 00:22:15 dwmw2 Exp $ */ +/* + * Linux driver for Disk-On-Chip devices + * + * Copyright (C) 1999 Machine Vision Holdings, Inc. + * Copyright (C) 2001-2003 David Woodhouse <dwmw2@infradead.org> + * Copyright (C) 2002-2003 Greg Ungerer <gerg@snapgear.com> + * Copyright (C) 2002-2003 SnapGear Inc + * + * $Id: doc2000.h,v 1.26 2006/03/29 08:26:28 dwmw2 Exp $ + * + * Released under GPL + */ #ifndef __MTD_DOC2000_H__ #define __MTD_DOC2000_H__ #include <linux/mtd/mtd.h> +#include <linux/mutex.h> #define DoC_Sig1 0 #define DoC_Sig2 1 @@ -38,22 +46,51 @@ #define DoC_Mil_CDSN_IO 0x0800 #define DoC_2k_CDSN_IO 0x1800 -/* How to access the device? - * On ARM, it'll be mmap'd directly with 32-bit wide accesses. +#define DoC_Mplus_NOP 0x1002 +#define DoC_Mplus_AliasResolution 0x1004 +#define DoC_Mplus_DOCControl 0x1006 +#define DoC_Mplus_AccessStatus 0x1008 +#define DoC_Mplus_DeviceSelect 0x1008 +#define DoC_Mplus_Configuration 0x100a +#define DoC_Mplus_OutputControl 0x100c +#define DoC_Mplus_FlashControl 0x1020 +#define DoC_Mplus_FlashSelect 0x1022 +#define DoC_Mplus_FlashCmd 0x1024 +#define DoC_Mplus_FlashAddress 0x1026 +#define DoC_Mplus_FlashData0 0x1028 +#define DoC_Mplus_FlashData1 0x1029 +#define DoC_Mplus_ReadPipeInit 0x102a +#define DoC_Mplus_LastDataRead 0x102c +#define DoC_Mplus_LastDataRead1 0x102d +#define DoC_Mplus_WritePipeTerm 0x102e +#define DoC_Mplus_ECCSyndrome0 0x1040 +#define DoC_Mplus_ECCSyndrome1 0x1041 +#define DoC_Mplus_ECCSyndrome2 0x1042 +#define DoC_Mplus_ECCSyndrome3 0x1043 +#define DoC_Mplus_ECCSyndrome4 0x1044 +#define DoC_Mplus_ECCSyndrome5 0x1045 +#define DoC_Mplus_ECCConf 0x1046 +#define DoC_Mplus_Toggle 0x1046 +#define DoC_Mplus_DownloadStatus 0x1074 +#define DoC_Mplus_CtrlConfirm 0x1076 +#define DoC_Mplus_Power 0x1fff + +/* How to access the device? + * On ARM, it'll be mmap'd directly with 32-bit wide accesses. * On PPC, it's mmap'd and 16-bit wide. - * Others use readb/writeb + * Others use readb/writeb */ #if defined(__arm__) -#define ReadDOC_(adr, reg) ((unsigned char)(*(__u32 *)(((unsigned long)adr)+((reg)<<2)))) -#define WriteDOC_(d, adr, reg) do{ *(__u32 *)(((unsigned long)adr)+((reg)<<2)) = (__u32)d; wmb();} while(0) +#define ReadDOC_(adr, reg) ((unsigned char)(*(volatile __u32 *)(((unsigned long)adr)+((reg)<<2)))) +#define WriteDOC_(d, adr, reg) do{ *(volatile __u32 *)(((unsigned long)adr)+((reg)<<2)) = (__u32)d; wmb();} while(0) #define DOC_IOREMAP_LEN 0x8000 #elif defined(__ppc__) -#define ReadDOC_(adr, reg) ((unsigned char)(*(__u16 *)(((unsigned long)adr)+((reg)<<1)))) -#define WriteDOC_(d, adr, reg) do{ *(__u16 *)(((unsigned long)adr)+((reg)<<1)) = (__u16)d; wmb();} while(0) +#define ReadDOC_(adr, reg) ((unsigned char)(*(volatile __u16 *)(((unsigned long)adr)+((reg)<<1)))) +#define WriteDOC_(d, adr, reg) do{ *(volatile __u16 *)(((unsigned long)adr)+((reg)<<1)) = (__u16)d; wmb();} while(0) #define DOC_IOREMAP_LEN 0x4000 #else -#define ReadDOC_(adr, reg) readb(((unsigned long)adr) + (reg)) -#define WriteDOC_(d, adr, reg) writeb(d, ((unsigned long)adr) + (reg)) +#define ReadDOC_(adr, reg) readb((void __iomem *)(adr) + (reg)) +#define WriteDOC_(d, adr, reg) writeb(d, (void __iomem *)(adr) + (reg)) #define DOC_IOREMAP_LEN 0x2000 #endif @@ -71,13 +108,21 @@ #define DOC_MODE_RESERVED1 2 #define DOC_MODE_RESERVED2 3 -#define DOC_MODE_MDWREN 4 #define DOC_MODE_CLR_ERR 0x80 +#define DOC_MODE_RST_LAT 0x10 +#define DOC_MODE_BDECT 0x08 +#define DOC_MODE_MDWREN 0x04 #define DOC_ChipID_Doc2k 0x20 +#define DOC_ChipID_Doc2kTSOP 0x21 /* internal number for MTD */ #define DOC_ChipID_DocMil 0x30 +#define DOC_ChipID_DocMilPlus32 0x40 +#define DOC_ChipID_DocMilPlus16 0x41 #define CDSN_CTRL_FR_B 0x80 +#define CDSN_CTRL_FR_B0 0x40 +#define CDSN_CTRL_FR_B1 0x80 + #define CDSN_CTRL_ECC_IO 0x20 #define CDSN_CTRL_FLASH_IO 0x10 #define CDSN_CTRL_WP 0x08 @@ -93,6 +138,10 @@ #define DOC_ECC_RESV 0x02 #define DOC_ECC_IGNORE 0x01 +#define DOC_FLASH_CE 0x80 +#define DOC_FLASH_WP 0x40 +#define DOC_FLASH_BANK 0x02 + /* We have to also set the reserved bit 1 for enable */ #define DOC_ECC_EN (DOC_ECC__EN | DOC_ECC_RESV) #define DOC_ECC_DIS (DOC_ECC_RESV) @@ -107,34 +156,38 @@ struct Nand { #define MAX_FLOORS 4 #define MAX_CHIPS 4 -#define MAX_FLOORS_MIL 4 +#define MAX_FLOORS_MIL 1 #define MAX_CHIPS_MIL 1 +#define MAX_FLOORS_MPLUS 2 +#define MAX_CHIPS_MPLUS 1 + #define ADDR_COLUMN 1 #define ADDR_PAGE 2 #define ADDR_COLUMN_PAGE 3 struct DiskOnChip { unsigned long physadr; - unsigned long virtadr; + void __iomem *virtadr; unsigned long totlen; - char ChipID; /* Type of DiskOnChip */ + unsigned char ChipID; /* Type of DiskOnChip */ int ioreg; - + unsigned long mfr; /* Flash IDs - only one type of flash per device */ unsigned long id; int chipshift; char page256; char pageadrlen; + char interleave; /* Internal interleaving - Millennium Plus style */ unsigned long erasesize; - + int curfloor; int curchip; - + int numchips; struct Nand *chips; struct mtd_info *nextdoc; - struct semaphore lock; + struct mutex lock; }; int doc_decode_ecc(unsigned char sector[512], unsigned char ecc1[6]); diff --git a/linux-2.4.x/include/linux/mtd/flashchip.h b/linux-2.4.x/include/linux/mtd/flashchip.h index 4cdccad..a293a3b 100644 --- a/linux-2.4.x/include/linux/mtd/flashchip.h +++ b/linux-2.4.x/include/linux/mtd/flashchip.h @@ -1,12 +1,12 @@ -/* +/* * struct flchip definition - * - * Contains information about the location and state of a given flash device + * + * Contains information about the location and state of a given flash device * * (C) 2000 Red Hat. GPLd. * - * $Id: flashchip.h,v 1.7 2001/01/18 03:52:36 nico Exp $ + * $Id: flashchip.h,v 1.18 2005/11/07 11:14:54 gleixner Exp $ * */ @@ -15,11 +15,11 @@ /* For spinlocks. sched.h includes spinlock.h from whichever directory it * happens to be in - so we don't have to care whether we're on 2.2, which - * has asm/spinlock.h, or 2.4, which has linux/spinlock.h + * has asm/spinlock.h, or 2.4, which has linux/spinlock.h */ #include <linux/sched.h> -typedef enum { +typedef enum { FL_READY, FL_STATUS, FL_CFI_QUERY, @@ -29,6 +29,7 @@ typedef enum { FL_ERASE_SUSPENDED, FL_WRITING, FL_WRITING_TO_BUFFER, + FL_OTP_WRITE, FL_WRITE_SUSPENDING, FL_WRITE_SUSPENDED, FL_PM_SUSPENDED, @@ -36,13 +37,17 @@ typedef enum { FL_UNLOADING, FL_LOCKING, FL_UNLOCKING, + FL_POINT, + FL_XIP_WHILE_ERASING, + FL_XIP_WHILE_WRITING, FL_UNKNOWN } flstate_t; -/* NOTE: confusingly, this can be used to refer to more than one chip at a time, - if they're interleaved. */ +/* NOTE: confusingly, this can be used to refer to more than one chip at a time, + if they're interleaved. This can even refer to individual partitions on + the same physical chip when present. */ struct flchip { unsigned long start; /* Offset within the map */ @@ -54,8 +59,14 @@ struct flchip { a given offset, and we'll want to add the per-chip length field back in. */ + int ref_point_counter; flstate_t state; flstate_t oldstate; + + unsigned int write_suspended:1; + unsigned int erase_suspended:1; + unsigned long in_progress_block_addr; + spinlock_t *mutex; spinlock_t _spinlock; /* We do it like this because sometimes they'll be shared. */ wait_queue_head_t wq; /* Wait on here when we're waiting for the chip @@ -63,8 +74,17 @@ struct flchip { int word_write_time; int buffer_write_time; int erase_time; + + void *priv; }; +/* This is used to handle contention on write/erase operations + between partitions of the same physical chip. */ +struct flchip_shared { + spinlock_t lock; + struct flchip *writing; + struct flchip *erasing; +}; #endif /* __MTD_FLASHCHIP_H__ */ diff --git a/linux-2.4.x/include/linux/mtd/ftl.h b/linux-2.4.x/include/linux/mtd/ftl.h index ae017ef..d996091 100644 --- a/linux-2.4.x/include/linux/mtd/ftl.h +++ b/linux-2.4.x/include/linux/mtd/ftl.h @@ -1,6 +1,6 @@ /* - * $Id: ftl.h,v 1.5 2001/06/02 20:35:51 dwmw2 Exp $ - * + * $Id: ftl.h,v 1.7 2005/11/07 11:14:54 gleixner Exp $ + * * Derived from (and probably identical to): * ftl.h 1.7 1999/10/25 20:23:17 * @@ -12,7 +12,7 @@ * Software distributed under the License is distributed on an "AS IS" * basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See * the License for the specific language governing rights and - * limitations under the License. + * limitations under the License. * * The initial developer of the original code is David A. Hinds * <dahinds@users.sourceforge.net>. Portions created by David A. Hinds diff --git a/linux-2.4.x/include/linux/mtd/gen_probe.h b/linux-2.4.x/include/linux/mtd/gen_probe.h index 43c3a08..256e734 100644 --- a/linux-2.4.x/include/linux/mtd/gen_probe.h +++ b/linux-2.4.x/include/linux/mtd/gen_probe.h @@ -1,21 +1,21 @@ /* * (C) 2001, 2001 Red Hat, Inc. * GPL'd - * $Id: gen_probe.h,v 1.1 2001/09/02 18:50:13 dwmw2 Exp $ + * $Id: gen_probe.h,v 1.4 2005/11/07 11:14:54 gleixner Exp $ */ #ifndef __LINUX_MTD_GEN_PROBE_H__ #define __LINUX_MTD_GEN_PROBE_H__ #include <linux/mtd/flashchip.h> -#include <linux/mtd/map.h> +#include <linux/mtd/map.h> #include <linux/mtd/cfi.h> +#include <linux/bitops.h> struct chip_probe { char *name; int (*probe_chip)(struct map_info *map, __u32 base, - struct flchip *chips, struct cfi_private *cfi); - + unsigned long *chip_map, struct cfi_private *cfi); }; struct mtd_info *mtd_do_chip_probe(struct map_info *map, struct chip_probe *cp); diff --git a/linux-2.4.x/include/linux/mtd/inftl.h b/linux-2.4.x/include/linux/mtd/inftl.h new file mode 100644 index 0000000..9dbf209 --- /dev/null +++ b/linux-2.4.x/include/linux/mtd/inftl.h @@ -0,0 +1,62 @@ +/* + * inftl.h -- defines to support the Inverse NAND Flash Translation Layer + * + * (C) Copyright 2002, Greg Ungerer (gerg@snapgear.com) + * + * $Id: inftl.h,v 1.8 2006/03/29 08:27:08 dwmw2 Exp $ + */ + +#ifndef __MTD_INFTL_H__ +#define __MTD_INFTL_H__ + +#ifndef __KERNEL__ +#error This is a kernel header. Perhaps include nftl-user.h instead? +#endif + +#include <linux/mtd/blktrans.h> +#include <linux/mtd/mtd.h> +#include <linux/mtd/nftl.h> + +#include <mtd/inftl-user.h> + +#ifndef INFTL_MAJOR +#define INFTL_MAJOR 96 +#endif +#define INFTL_PARTN_BITS 4 + +#ifdef __KERNEL__ + +struct INFTLrecord { + struct mtd_blktrans_dev mbd; + __u16 MediaUnit; + __u32 EraseSize; + struct INFTLMediaHeader MediaHdr; + int usecount; + unsigned char heads; + unsigned char sectors; + unsigned short cylinders; + __u16 numvunits; + __u16 firstEUN; + __u16 lastEUN; + __u16 numfreeEUNs; + __u16 LastFreeEUN; /* To speed up finding a free EUN */ + int head,sect,cyl; + __u16 *PUtable; /* Physical Unit Table */ + __u16 *VUtable; /* Virtual Unit Table */ + unsigned int nb_blocks; /* number of physical blocks */ + unsigned int nb_boot_blocks; /* number of blocks used by the bios */ + struct erase_info instr; + struct nand_oobinfo oobinfo; +}; + +int INFTL_mount(struct INFTLrecord *s); +int INFTL_formatblock(struct INFTLrecord *s, int block); + +extern char inftlmountrev[]; + +void INFTL_dumptables(struct INFTLrecord *s); +void INFTL_dumpVUchains(struct INFTLrecord *s); + +#endif /* __KERNEL__ */ + +#endif /* __MTD_INFTL_H__ */ diff --git a/linux-2.4.x/include/linux/mtd/jedec.h b/linux-2.4.x/include/linux/mtd/jedec.h index 75271b8..9006feb 100644 --- a/linux-2.4.x/include/linux/mtd/jedec.h +++ b/linux-2.4.x/include/linux/mtd/jedec.h @@ -1,20 +1,19 @@ /* JEDEC Flash Interface. - * This is an older type of interface for self programming flash. It is + * This is an older type of interface for self programming flash. It is * commonly use in older AMD chips and is obsolete compared with CFI. * It is called JEDEC because the JEDEC association distributes the ID codes * for the chips. * * See the AMD flash databook for information on how to operate the interface. * - * $Id: jedec.h,v 1.2 2001/11/06 14:37:36 dwmw2 Exp $ + * $Id: jedec.h,v 1.4 2005/11/07 11:14:54 gleixner Exp $ */ #ifndef __LINUX_MTD_JEDEC_H__ #define __LINUX_MTD_JEDEC_H__ #include <linux/types.h> -#include <linux/mtd/map.h> #define MAX_JEDEC_CHIPS 16 @@ -34,16 +33,16 @@ struct jedec_flash_chip __u16 jedec; unsigned long size; unsigned long sectorsize; - + // *(__u8*)(base + (adder << addrshift)) = data << datashift // Address size = size << addrshift unsigned long base; // Byte 0 of the flash, will be unaligned unsigned int datashift; // Useful for 32bit/16bit accesses unsigned int addrshift; unsigned long offset; // linerized start. base==offset for unbanked, uninterleaved flash - + __u32 capabilities; - + // These markers are filled in by the flash_chip_scan function unsigned long start; unsigned long length; @@ -52,16 +51,16 @@ struct jedec_flash_chip struct jedec_private { unsigned long size; // Total size of all the devices - + /* Bank handling. If sum(bank_fill) == size then this is linear flash. Otherwise the mapping has holes in it. bank_fill may be used to - find the holes, but in the common symetric case - bank_fill[0] == bank_fill[*], thus addresses may be computed + find the holes, but in the common symetric case + bank_fill[0] == bank_fill[*], thus addresses may be computed mathmatically. bank_fill must be powers of two */ unsigned is_banked; unsigned long bank_fill[MAX_JEDEC_CHIPS]; - - struct jedec_flash_chip chips[MAX_JEDEC_CHIPS]; + + struct jedec_flash_chip chips[MAX_JEDEC_CHIPS]; }; #endif diff --git a/linux-2.4.x/include/linux/mtd/map.h b/linux-2.4.x/include/linux/mtd/map.h index 94ffed2..fedfbc8 100644 --- a/linux-2.4.x/include/linux/mtd/map.h +++ b/linux-2.4.x/include/linux/mtd/map.h @@ -1,27 +1,183 @@ /* Overhauled routines for dealing with different mmap regions of flash */ -/* $Id: map.h,v 1.25 2001/09/09 15:04:17 dwmw2 Exp $ */ +/* $Id: map.h,v 1.54 2005/11/07 11:14:54 gleixner Exp $ */ #ifndef __LINUX_MTD_MAP_H__ #define __LINUX_MTD_MAP_H__ #include <linux/config.h> #include <linux/types.h> -#include <linux/mtd/mtd.h> -#include <linux/slab.h> +#include <linux/list.h> +#include <linux/string.h> + +#include <linux/mtd/compatmac.h> + +#include <asm/unaligned.h> +#include <asm/system.h> +#include <asm/io.h> +#include <asm/bug.h> + +#ifdef CONFIG_MTD_MAP_BANK_WIDTH_1 +#define map_bankwidth(map) 1 +#define map_bankwidth_is_1(map) (map_bankwidth(map) == 1) +#define map_bankwidth_is_large(map) (0) +#define map_words(map) (1) +#define MAX_MAP_BANKWIDTH 1 +#else +#define map_bankwidth_is_1(map) (0) +#endif + +#ifdef CONFIG_MTD_MAP_BANK_WIDTH_2 +# ifdef map_bankwidth +# undef map_bankwidth +# define map_bankwidth(map) ((map)->bankwidth) +# else +# define map_bankwidth(map) 2 +# define map_bankwidth_is_large(map) (0) +# define map_words(map) (1) +# endif +#define map_bankwidth_is_2(map) (map_bankwidth(map) == 2) +#undef MAX_MAP_BANKWIDTH +#define MAX_MAP_BANKWIDTH 2 +#else +#define map_bankwidth_is_2(map) (0) +#endif + +#ifdef CONFIG_MTD_MAP_BANK_WIDTH_4 +# ifdef map_bankwidth +# undef map_bankwidth +# define map_bankwidth(map) ((map)->bankwidth) +# else +# define map_bankwidth(map) 4 +# define map_bankwidth_is_large(map) (0) +# define map_words(map) (1) +# endif +#define map_bankwidth_is_4(map) (map_bankwidth(map) == 4) +#undef MAX_MAP_BANKWIDTH +#define MAX_MAP_BANKWIDTH 4 +#else +#define map_bankwidth_is_4(map) (0) +#endif + +/* ensure we never evaluate anything shorted than an unsigned long + * to zero, and ensure we'll never miss the end of an comparison (bjd) */ + +#define map_calc_words(map) ((map_bankwidth(map) + (sizeof(unsigned long)-1))/ sizeof(unsigned long)) + +#ifdef CONFIG_MTD_MAP_BANK_WIDTH_8 +# ifdef map_bankwidth +# undef map_bankwidth +# define map_bankwidth(map) ((map)->bankwidth) +# if BITS_PER_LONG < 64 +# undef map_bankwidth_is_large +# define map_bankwidth_is_large(map) (map_bankwidth(map) > BITS_PER_LONG/8) +# undef map_words +# define map_words(map) map_calc_words(map) +# endif +# else +# define map_bankwidth(map) 8 +# define map_bankwidth_is_large(map) (BITS_PER_LONG < 64) +# define map_words(map) map_calc_words(map) +# endif +#define map_bankwidth_is_8(map) (map_bankwidth(map) == 8) +#undef MAX_MAP_BANKWIDTH +#define MAX_MAP_BANKWIDTH 8 +#else +#define map_bankwidth_is_8(map) (0) +#endif + +#ifdef CONFIG_MTD_MAP_BANK_WIDTH_16 +# ifdef map_bankwidth +# undef map_bankwidth +# define map_bankwidth(map) ((map)->bankwidth) +# undef map_bankwidth_is_large +# define map_bankwidth_is_large(map) (map_bankwidth(map) > BITS_PER_LONG/8) +# undef map_words +# define map_words(map) map_calc_words(map) +# else +# define map_bankwidth(map) 16 +# define map_bankwidth_is_large(map) (1) +# define map_words(map) map_calc_words(map) +# endif +#define map_bankwidth_is_16(map) (map_bankwidth(map) == 16) +#undef MAX_MAP_BANKWIDTH +#define MAX_MAP_BANKWIDTH 16 +#else +#define map_bankwidth_is_16(map) (0) +#endif + +#ifdef CONFIG_MTD_MAP_BANK_WIDTH_32 +# ifdef map_bankwidth +# undef map_bankwidth +# define map_bankwidth(map) ((map)->bankwidth) +# undef map_bankwidth_is_large +# define map_bankwidth_is_large(map) (map_bankwidth(map) > BITS_PER_LONG/8) +# undef map_words +# define map_words(map) map_calc_words(map) +# else +# define map_bankwidth(map) 32 +# define map_bankwidth_is_large(map) (1) +# define map_words(map) map_calc_words(map) +# endif +#define map_bankwidth_is_32(map) (map_bankwidth(map) == 32) +#undef MAX_MAP_BANKWIDTH +#define MAX_MAP_BANKWIDTH 32 +#else +#define map_bankwidth_is_32(map) (0) +#endif + +#ifndef map_bankwidth +#error "No bus width supported. What's the point?" +#endif + +static inline int map_bankwidth_supported(int w) +{ + switch (w) { +#ifdef CONFIG_MTD_MAP_BANK_WIDTH_1 + case 1: +#endif +#ifdef CONFIG_MTD_MAP_BANK_WIDTH_2 + case 2: +#endif +#ifdef CONFIG_MTD_MAP_BANK_WIDTH_4 + case 4: +#endif +#ifdef CONFIG_MTD_MAP_BANK_WIDTH_8 + case 8: +#endif +#ifdef CONFIG_MTD_MAP_BANK_WIDTH_16 + case 16: +#endif +#ifdef CONFIG_MTD_MAP_BANK_WIDTH_32 + case 32: +#endif + return 1; + + default: + return 0; + } +} + +#define MAX_MAP_LONGS ( ((MAX_MAP_BANKWIDTH*8) + BITS_PER_LONG - 1) / BITS_PER_LONG ) + +typedef union { + unsigned long x[MAX_MAP_LONGS]; +} map_word; /* The map stuff is very simple. You fill in your struct map_info with a handful of routines for accessing the device, making sure they handle paging etc. correctly if your device needs it. Then you pass it off - to a chip driver which deals with a mapped device - generally either - do_cfi_probe() or do_ram_probe(), either of which will return a - struct mtd_info if they liked what they saw. At which point, you - fill in the mtd->module with your own module address, and register - it. - + to a chip probe routine -- either JEDEC or CFI probe or both -- via + do_map_probe(). If a chip is recognised, the probe code will invoke the + appropriate chip driver (if present) and return a struct mtd_info. + At which point, you fill in the mtd->module with your own module + address, and register it with the MTD core code. Or you could partition + it and register the partitions instead, or keep it for your own private + use; whatever. + The mtd->priv field will point to the struct map_info, and any further - private data required by the chip driver is linked from the - mtd->priv->fldrv_priv field. This allows the map driver to get at + private data required by the chip driver is linked from the + mtd->priv->fldrv_priv field. This allows the map driver to get at the destructor function map->fldrv_destroy() when it's tired of living. */ @@ -29,34 +185,45 @@ struct map_info { char *name; unsigned long size; - int buswidth; /* in octets */ - __u8 (*read8)(struct map_info *, unsigned long); - __u16 (*read16)(struct map_info *, unsigned long); - __u32 (*read32)(struct map_info *, unsigned long); - /* If it returned a 'long' I'd call it readl. - * It doesn't. - * I won't. - * dwmw2 */ - + unsigned long phys; +#define NO_XIP (-1UL) + + void __iomem *virt; + void *cached; + + int bankwidth; /* in octets. This isn't necessarily the width + of actual bus cycles -- it's the repeat interval + in bytes, before you are talking to the first chip again. + */ + +#ifdef CONFIG_MTD_COMPLEX_MAPPINGS + map_word (*read)(struct map_info *, unsigned long); void (*copy_from)(struct map_info *, void *, unsigned long, ssize_t); - void (*write8)(struct map_info *, __u8, unsigned long); - void (*write16)(struct map_info *, __u16, unsigned long); - void (*write32)(struct map_info *, __u32, unsigned long); + + void (*write)(struct map_info *, const map_word, unsigned long); void (*copy_to)(struct map_info *, unsigned long, const void *, ssize_t); + /* We can perhaps put in 'point' and 'unpoint' methods, if we really + want to enable XIP for non-linear mappings. Not yet though. */ +#endif + /* It's possible for the map driver to use cached memory in its + copy_from implementation (and _only_ with copy_from). However, + when the chip driver knows some flash area has changed contents, + it will signal it to the map driver through this routine to let + the map driver invalidate the corresponding cache as needed. + If there is no cache to care about this can be set to NULL. */ + void (*inval_cache)(struct map_info *, unsigned long, ssize_t); + + /* set_vpp() must handle being reentered -- enable, enable, disable + must leave it enabled. */ void (*set_vpp)(struct map_info *, int); - /* We put these two here rather than a single void *map_priv, - because we want mappers to be able to have quickly-accessible - cache for the 'currently-mapped page' without the _extra_ - redirection that would be necessary. If you need more than - two longs, turn the second into a pointer. dwmw2 */ + unsigned long map_priv_1; unsigned long map_priv_2; void *fldrv_priv; struct mtd_chip_driver *fldrv; }; - struct mtd_chip_driver { struct mtd_info *(*probe)(struct map_info *map); void (*destroy)(struct mtd_info *); @@ -68,27 +235,204 @@ struct mtd_chip_driver { void register_mtd_chip_driver(struct mtd_chip_driver *); void unregister_mtd_chip_driver(struct mtd_chip_driver *); -struct mtd_info *do_map_probe(char *name, struct map_info *map); +struct mtd_info *do_map_probe(const char *name, struct map_info *map); +void map_destroy(struct mtd_info *mtd); + +#define ENABLE_VPP(map) do { if(map->set_vpp) map->set_vpp(map, 1); } while(0) +#define DISABLE_VPP(map) do { if(map->set_vpp) map->set_vpp(map, 0); } while(0) + +#define INVALIDATE_CACHED_RANGE(map, from, size) \ + do { if(map->inval_cache) map->inval_cache(map, from, size); } while(0) + + +static inline int map_word_equal(struct map_info *map, map_word val1, map_word val2) +{ + int i; + for (i=0; i<map_words(map); i++) { + if (val1.x[i] != val2.x[i]) + return 0; + } + return 1; +} + +static inline map_word map_word_and(struct map_info *map, map_word val1, map_word val2) +{ + map_word r; + int i; + + for (i=0; i<map_words(map); i++) { + r.x[i] = val1.x[i] & val2.x[i]; + } + return r; +} +static inline map_word map_word_clr(struct map_info *map, map_word val1, map_word val2) +{ + map_word r; + int i; -/* - * Destroy an MTD device which was created for a map device. - * Make sure the MTD device is already unregistered before calling this - */ -static inline void map_destroy(struct mtd_info *mtd) + for (i=0; i<map_words(map); i++) { + r.x[i] = val1.x[i] & ~val2.x[i]; + } + return r; +} + +static inline map_word map_word_or(struct map_info *map, map_word val1, map_word val2) { - struct map_info *map = mtd->priv; + map_word r; + int i; + + for (i=0; i<map_words(map); i++) { + r.x[i] = val1.x[i] | val2.x[i]; + } + return r; +} - if (map->fldrv->destroy) - map->fldrv->destroy(mtd); -#ifdef CONFIG_MODULES - if (map->fldrv->module) - __MOD_DEC_USE_COUNT(map->fldrv->module); +#define map_word_andequal(m, a, b, z) map_word_equal(m, z, map_word_and(m, a, b)) + +static inline int map_word_bitsset(struct map_info *map, map_word val1, map_word val2) +{ + int i; + + for (i=0; i<map_words(map); i++) { + if (val1.x[i] & val2.x[i]) + return 1; + } + return 0; +} + +static inline map_word map_word_load(struct map_info *map, const void *ptr) +{ + map_word r; + + if (map_bankwidth_is_1(map)) + r.x[0] = *(unsigned char *)ptr; + else if (map_bankwidth_is_2(map)) + r.x[0] = get_unaligned((uint16_t *)ptr); + else if (map_bankwidth_is_4(map)) + r.x[0] = get_unaligned((uint32_t *)ptr); +#if BITS_PER_LONG >= 64 + else if (map_bankwidth_is_8(map)) + r.x[0] = get_unaligned((uint64_t *)ptr); #endif - kfree(mtd); + else if (map_bankwidth_is_large(map)) + memcpy(r.x, ptr, map->bankwidth); + + return r; } -#define ENABLE_VPP(map) do { if(map->set_vpp) map->set_vpp(map, 1); } while(0) -#define DISABLE_VPP(map) do { if(map->set_vpp) map->set_vpp(map, 0); } while(0) +static inline map_word map_word_load_partial(struct map_info *map, map_word orig, const unsigned char *buf, int start, int len) +{ + int i; + + if (map_bankwidth_is_large(map)) { + char *dest = (char *)&orig; + memcpy(dest+start, buf, len); + } else { + for (i=start; i < start+len; i++) { + int bitpos; +#ifdef __LITTLE_ENDIAN + bitpos = i*8; +#else /* __BIG_ENDIAN */ + bitpos = (map_bankwidth(map)-1-i)*8; +#endif + orig.x[0] &= ~(0xff << bitpos); + orig.x[0] |= buf[i-start] << bitpos; + } + } + return orig; +} + +#if BITS_PER_LONG < 64 +#define MAP_FF_LIMIT 4 +#else +#define MAP_FF_LIMIT 8 +#endif + +static inline map_word map_word_ff(struct map_info *map) +{ + map_word r; + int i; + + if (map_bankwidth(map) < MAP_FF_LIMIT) { + int bw = 8 * map_bankwidth(map); + r.x[0] = (1 << bw) - 1; + } else { + for (i=0; i<map_words(map); i++) + r.x[i] = ~0UL; + } + return r; +} + +static inline map_word inline_map_read(struct map_info *map, unsigned long ofs) +{ + map_word r; + + if (map_bankwidth_is_1(map)) + r.x[0] = __raw_readb(map->virt + ofs); + else if (map_bankwidth_is_2(map)) + r.x[0] = __raw_readw(map->virt + ofs); + else if (map_bankwidth_is_4(map)) + r.x[0] = __raw_readl(map->virt + ofs); +#if BITS_PER_LONG >= 64 + else if (map_bankwidth_is_8(map)) + r.x[0] = __raw_readq(map->virt + ofs); +#endif + else if (map_bankwidth_is_large(map)) + memcpy_fromio(r.x, map->virt+ofs, map->bankwidth); + + return r; +} + +static inline void inline_map_write(struct map_info *map, const map_word datum, unsigned long ofs) +{ + if (map_bankwidth_is_1(map)) + __raw_writeb(datum.x[0], map->virt + ofs); + else if (map_bankwidth_is_2(map)) + __raw_writew(datum.x[0], map->virt + ofs); + else if (map_bankwidth_is_4(map)) + __raw_writel(datum.x[0], map->virt + ofs); +#if BITS_PER_LONG >= 64 + else if (map_bankwidth_is_8(map)) + __raw_writeq(datum.x[0], map->virt + ofs); +#endif + else if (map_bankwidth_is_large(map)) + memcpy_toio(map->virt+ofs, datum.x, map->bankwidth); + mb(); +} + +static inline void inline_map_copy_from(struct map_info *map, void *to, unsigned long from, ssize_t len) +{ + if (map->cached) + memcpy(to, (char *)map->cached + from, len); + else + memcpy_fromio(to, map->virt + from, len); +} + +static inline void inline_map_copy_to(struct map_info *map, unsigned long to, const void *from, ssize_t len) +{ + memcpy_toio(map->virt + to, from, len); +} + +#ifdef CONFIG_MTD_COMPLEX_MAPPINGS +#define map_read(map, ofs) (map)->read(map, ofs) +#define map_copy_from(map, to, from, len) (map)->copy_from(map, to, from, len) +#define map_write(map, datum, ofs) (map)->write(map, datum, ofs) +#define map_copy_to(map, to, from, len) (map)->copy_to(map, to, from, len) + +extern void simple_map_init(struct map_info *); +#define map_is_linear(map) (map->phys != NO_XIP) + +#else +#define map_read(map, ofs) inline_map_read(map, ofs) +#define map_copy_from(map, to, from, len) inline_map_copy_from(map, to, from, len) +#define map_write(map, datum, ofs) inline_map_write(map, datum, ofs) +#define map_copy_to(map, to, from, len) inline_map_copy_to(map, to, from, len) + + +#define simple_map_init(map) BUG_ON(!map_bankwidth_supported((map)->bankwidth)) +#define map_is_linear(map) ({ (void)(map); 1; }) + +#endif /* !CONFIG_MTD_COMPLEX_MAPPINGS */ #endif /* __LINUX_MTD_MAP_H__ */ diff --git a/linux-2.4.x/include/linux/mtd/mtd.h b/linux-2.4.x/include/linux/mtd/mtd.h index b186e6c..fbc075b 100644 --- a/linux-2.4.x/include/linux/mtd/mtd.h +++ b/linux-2.4.x/include/linux/mtd/mtd.h @@ -1,123 +1,45 @@ - -/* $Id: mtd.h,v 1.33 2001/06/09 00:08:59 dwmw2 Exp $ */ +/* + * $Id: mtd.h,v 1.62 2005/11/29 20:01:30 gleixner Exp $ + * + * Copyright (C) 1999-2003 David Woodhouse <dwmw2@infradead.org> et al. + * + * Released under GPL + */ #ifndef __MTD_MTD_H__ #define __MTD_MTD_H__ -#ifdef __KERNEL__ +#ifndef __KERNEL__ +#error This is a kernel header. Perhaps include mtd-user.h instead? +#endif #include <linux/config.h> -#include <linux/version.h> #include <linux/types.h> -#include <linux/mtd/compatmac.h> #include <linux/module.h> #include <linux/uio.h> +#include <linux/notifier.h> -#endif /* __KERNEL__ */ - -struct erase_info_user { - u_int32_t start; - u_int32_t length; -}; - -struct mtd_oob_buf { - u_int32_t start; - u_int32_t length; - unsigned char *ptr; -}; - +#include <linux/mtd/compatmac.h> +#include <mtd/mtd-abi.h> #define MTD_CHAR_MAJOR 90 #define MTD_BLOCK_MAJOR 31 #define MAX_MTD_DEVICES 16 - - -#define MTD_ABSENT 0 -#define MTD_RAM 1 -#define MTD_ROM 2 -#define MTD_NORFLASH 3 -#define MTD_NANDFLASH 4 -#define MTD_PEROM 5 -#define MTD_OTHER 14 -#define MTD_UNKNOWN 15 - - - -#define MTD_CLEAR_BITS 1 // Bits can be cleared (flash) -#define MTD_SET_BITS 2 // Bits can be set -#define MTD_ERASEABLE 4 // Has an erase function -#define MTD_WRITEB_WRITEABLE 8 // Direct IO is possible -#define MTD_VOLATILE 16 // Set for RAMs -#define MTD_XIP 32 // eXecute-In-Place possible -#define MTD_OOB 64 // Out-of-band data (NAND flash) -#define MTD_ECC 128 // Device capable of automatic ECC - -// Some common devices / combinations of capabilities -#define MTD_CAP_ROM 0 -#define MTD_CAP_RAM (MTD_CLEAR_BITS|MTD_SET_BITS|MTD_WRITEB_WRITEABLE) -#define MTD_CAP_NORFLASH (MTD_CLEAR_BITS|MTD_ERASEABLE) -#define MTD_CAP_NANDFLASH (MTD_CLEAR_BITS|MTD_ERASEABLE|MTD_OOB) -#define MTD_WRITEABLE (MTD_CLEAR_BITS|MTD_SET_BITS) - - -// Types of automatic ECC/Checksum available -#define MTD_ECC_NONE 0 // No automatic ECC available -#define MTD_ECC_RS_DiskOnChip 1 // Automatic ECC on DiskOnChip -#define MTD_ECC_SW 2 // SW ECC for Toshiba & Samsung devices - -struct mtd_info_user { - u_char type; - u_int32_t flags; - u_int32_t size; // Total size of the MTD - u_int32_t erasesize; - u_int32_t oobblock; // Size of OOB blocks (e.g. 512) - u_int32_t oobsize; // Amount of OOB data per block (e.g. 16) - u_int32_t ecctype; - u_int32_t eccsize; -}; - -struct region_info_user { - u_int32_t offset; /* At which this region starts, - * from the beginning of the MTD */ - u_int32_t erasesize; /* For this region */ - u_int32_t numblocks; /* Number of blocks in this region */ - u_int32_t regionindex; -}; - -#define MEMGETINFO _IOR('M', 1, struct mtd_info_user) -#define MEMERASE _IOW('M', 2, struct erase_info_user) -#define MEMWRITEOOB _IOWR('M', 3, struct mtd_oob_buf) -#define MEMREADOOB _IOWR('M', 4, struct mtd_oob_buf) -#define MEMLOCK _IOW('M', 5, struct erase_info_user) -#define MEMUNLOCK _IOW('M', 6, struct erase_info_user) -#define MEMGETREGIONCOUNT _IOR('M', 7, int) -#define MEMGETREGIONINFO _IOWR('M', 8, struct region_info_user) -#define MEMREADDATA _IOWR('M', 9, struct mtd_oob_buf) -#define MEMWRITEDATA _IOWR('M', 10, struct mtd_oob_buf) - -#ifndef __KERNEL__ - -typedef struct mtd_info_user mtd_info_t; -typedef struct erase_info_user erase_info_t; -typedef struct region_info_user region_info_t; - - /* User-space ioctl definitions */ - - -#else /* __KERNEL__ */ - - #define MTD_ERASE_PENDING 0x01 #define MTD_ERASING 0x02 #define MTD_ERASE_SUSPEND 0x04 #define MTD_ERASE_DONE 0x08 #define MTD_ERASE_FAILED 0x10 +/* If the erase fails, fail_addr might indicate exactly which block failed. If + fail_addr = 0xffffffff, the failure was not at the device level or was not + specific to any particular block. */ struct erase_info { struct mtd_info *mtd; u_int32_t addr; u_int32_t len; + u_int32_t fail_addr; u_long time; u_long retries; u_int dev; @@ -150,45 +72,75 @@ struct mtd_info { u_int32_t ecctype; 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. char *name; int index; + // oobinfo is a nand_oobinfo structure, which can be set by iotcl (MEMSETOOBINFO) + struct nand_oobinfo oobinfo; + u_int32_t oobavail; // Number of bytes in OOB area available for fs + /* Data for variable erase regions. If numeraseregions is zero, - * it means that the whole device has erasesize as given above. + * it means that the whole device has erasesize as given above. */ int numeraseregions; - struct mtd_erase_region_info *eraseregions; + struct mtd_erase_region_info *eraseregions; /* This really shouldn't be here. It can go away in 2.5 */ u_int32_t bank_size; - struct module *module; int (*erase) (struct mtd_info *mtd, struct erase_info *instr); /* This stuff for eXecute-In-Place */ int (*point) (struct mtd_info *mtd, loff_t from, size_t len, size_t *retlen, u_char **mtdbuf); /* We probably shouldn't allow XIP if the unpoint isn't a NULL */ - void (*unpoint) (struct mtd_info *mtd, u_char * addr); + void (*unpoint) (struct mtd_info *mtd, u_char * addr, loff_t from, size_t len); int (*read) (struct mtd_info *mtd, loff_t from, size_t len, size_t *retlen, u_char *buf); int (*write) (struct mtd_info *mtd, loff_t to, size_t len, size_t *retlen, const u_char *buf); - int (*read_ecc) (struct mtd_info *mtd, loff_t from, size_t len, size_t *retlen, u_char *buf, u_char *eccbuf); - int (*write_ecc) (struct mtd_info *mtd, loff_t to, size_t len, size_t *retlen, const u_char *buf, u_char *eccbuf); + int (*read_ecc) (struct mtd_info *mtd, loff_t from, size_t len, size_t *retlen, u_char *buf, u_char *eccbuf, struct nand_oobinfo *oobsel); + int (*write_ecc) (struct mtd_info *mtd, loff_t to, size_t len, size_t *retlen, const u_char *buf, u_char *eccbuf, struct nand_oobinfo *oobsel); int (*read_oob) (struct mtd_info *mtd, loff_t from, size_t len, size_t *retlen, u_char *buf); int (*write_oob) (struct mtd_info *mtd, loff_t to, size_t len, size_t *retlen, const u_char *buf); - /* iovec-based read/write methods. We need these especially for NAND flash, + /* + * Methods to access the protection register area, present in some + * flash devices. The user data is one time programmable but the + * factory data is read only. + */ + int (*get_fact_prot_info) (struct mtd_info *mtd, struct otp_info *buf, size_t len); + int (*read_fact_prot_reg) (struct mtd_info *mtd, loff_t from, size_t len, size_t *retlen, u_char *buf); + int (*get_user_prot_info) (struct mtd_info *mtd, struct otp_info *buf, size_t len); + int (*read_user_prot_reg) (struct mtd_info *mtd, loff_t from, size_t len, size_t *retlen, u_char *buf); + int (*write_user_prot_reg) (struct mtd_info *mtd, loff_t from, size_t len, size_t *retlen, u_char *buf); + int (*lock_user_prot_reg) (struct mtd_info *mtd, loff_t from, size_t len); + + /* kvec-based read/write methods. We need these especially for NAND flash, with its limited number of write cycles per erase. - NB: The 'count' parameter is the number of _vectors_, each of + NB: The 'count' parameter is the number of _vectors_, each of which contains an (ofs, len) tuple. */ - int (*readv) (struct mtd_info *mtd, struct iovec *vecs, unsigned long count, loff_t from, size_t *retlen); - int (*writev) (struct mtd_info *mtd, const struct iovec *vecs, unsigned long count, loff_t to, size_t *retlen); + int (*readv) (struct mtd_info *mtd, struct kvec *vecs, unsigned long count, loff_t from, size_t *retlen); + int (*readv_ecc) (struct mtd_info *mtd, struct kvec *vecs, unsigned long count, loff_t from, + size_t *retlen, u_char *eccbuf, struct nand_oobinfo *oobsel); + int (*writev) (struct mtd_info *mtd, const struct kvec *vecs, unsigned long count, loff_t to, size_t *retlen); + int (*writev_ecc) (struct mtd_info *mtd, const struct kvec *vecs, unsigned long count, loff_t to, + size_t *retlen, u_char *eccbuf, struct nand_oobinfo *oobsel); /* Sync */ void (*sync) (struct mtd_info *mtd); @@ -201,7 +153,16 @@ struct mtd_info { int (*suspend) (struct mtd_info *mtd); void (*resume) (struct mtd_info *mtd); + /* Bad block management functions */ + int (*block_isbad) (struct mtd_info *mtd, loff_t ofs); + int (*block_markbad) (struct mtd_info *mtd, loff_t ofs); + + struct notifier_block reboot_notifier; /* default mode before reboot */ + void *priv; + + struct module *owner; + int usecount; }; @@ -210,39 +171,27 @@ struct mtd_info { extern int add_mtd_device(struct mtd_info *mtd); extern int del_mtd_device (struct mtd_info *mtd); -extern struct mtd_info *__get_mtd_device(struct mtd_info *mtd, int num); - -static inline struct mtd_info *get_mtd_device(struct mtd_info *mtd, int num) -{ - struct mtd_info *ret; - - ret = __get_mtd_device(mtd, num); - - if (ret && ret->module && !try_inc_mod_count(ret->module)) - return NULL; +extern struct mtd_info *get_mtd_device(struct mtd_info *mtd, int num); - return ret; -} - -static inline void put_mtd_device(struct mtd_info *mtd) -{ - if (mtd->module) - __MOD_DEC_USE_COUNT(mtd->module); -} +extern void put_mtd_device(struct mtd_info *mtd); struct mtd_notifier { void (*add)(struct mtd_info *mtd); void (*remove)(struct mtd_info *mtd); - struct mtd_notifier *next; + struct list_head list; }; extern void register_mtd_user (struct mtd_notifier *new); extern int unregister_mtd_user (struct mtd_notifier *old); +int default_mtd_writev(struct mtd_info *mtd, const struct kvec *vecs, + unsigned long count, loff_t to, size_t *retlen); + +int default_mtd_readv(struct mtd_info *mtd, struct kvec *vecs, + unsigned long count, loff_t from, size_t *retlen); -#ifndef MTDC #define MTD_ERASE(mtd, args...) (*(mtd->erase))(mtd, args) #define MTD_POINT(mtd, a,b,c,d) (*(mtd->point))(mtd, a,b,c, (u_char **)(d)) #define MTD_UNPOINT(mtd, arg) (*(mtd->unpoint))(mtd, (u_char *)arg) @@ -254,8 +203,18 @@ extern int unregister_mtd_user (struct mtd_notifier *old); #define MTD_WRITEECC(mtd, args...) (*(mtd->write_ecc))(mtd, args) #define MTD_READOOB(mtd, args...) (*(mtd->read_oob))(mtd, args) #define MTD_WRITEOOB(mtd, args...) (*(mtd->write_oob))(mtd, args) -#define MTD_SYNC(mtd) do { if (mtd->sync) (*(mtd->sync))(mtd); } while (0) -#endif /* MTDC */ +#define MTD_SYNC(mtd) do { if (mtd->sync) (*(mtd->sync))(mtd); } while (0) + + +#ifdef CONFIG_MTD_PARTITIONS +void mtd_erase_callback(struct erase_info *instr); +#else +static inline void mtd_erase_callback(struct erase_info *instr) +{ + if (instr->callback) + instr->callback(instr); +} +#endif /* * Debugging macro and defines @@ -266,14 +225,14 @@ extern int unregister_mtd_user (struct mtd_notifier *old); #define MTD_DEBUG_LEVEL3 (3) /* Noisy */ #ifdef CONFIG_MTD_DEBUG -#define DEBUG(n, args...) \ - if (n <= CONFIG_MTD_DEBUG_VERBOSE) { \ - printk(KERN_INFO args); \ - } +#define DEBUG(n, args...) \ + do { \ + if (n <= CONFIG_MTD_DEBUG_VERBOSE) \ + printk(KERN_INFO args); \ + } while(0) #else /* CONFIG_MTD_DEBUG */ -#define DEBUG(n, args...) -#endif /* CONFIG_MTD_DEBUG */ +#define DEBUG(n, args...) do { } while(0) -#endif /* __KERNEL__ */ +#endif /* CONFIG_MTD_DEBUG */ #endif /* __MTD_MTD_H__ */ diff --git a/linux-2.4.x/include/linux/mtd/nand.h b/linux-2.4.x/include/linux/mtd/nand.h index 8c678ab..5127728 100644 --- a/linux-2.4.x/include/linux/mtd/nand.h +++ b/linux-2.4.x/include/linux/mtd/nand.h @@ -2,9 +2,10 @@ * linux/include/linux/mtd/nand.h * * Copyright (c) 2000 David Woodhouse <dwmw2@mvhi.com> - * Steven J. Hill <sjhill@cotw.com> + * Steven J. Hill <sjhill@realitydiluted.com> + * Thomas Gleixner <tglx@linutronix.de> * - * $Id: nand.h,v 1.8 2000/10/30 17:16:17 sjhill Exp $ + * $Id: nand.h,v 1.77 2005/12/16 15:41:33 vwool Exp $ * * 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 @@ -23,17 +24,83 @@ * bat later if I did something naughty. * 10-11-2000 SJH Added private NAND flash structure for driver * 10-24-2000 SJH Added prototype for 'nand_scan' function + * 10-29-2001 TG changed nand_chip structure to support + * hardwarespecific function for accessing control lines + * 02-21-2002 TG added support for different read/write adress and + * ready/busy line access function + * 02-26-2002 TG added chip_delay to nand_chip structure to optimize + * command delay times for different chips + * 04-28-2002 TG OOB config defines moved from nand.c to avoid duplicate + * defines in jffs2/wbuf.c + * 08-07-2002 TG forced bad block location to byte 5 of OOB, even if + * CONFIG_MTD_NAND_ECC_JFFS2 is not set + * 08-10-2002 TG extensions to nand_chip structure to support HW-ECC + * + * 08-29-2002 tglx nand_chip structure: data_poi for selecting + * internal / fs-driver buffer + * support for 6byte/512byte hardware ECC + * read_ecc, write_ecc extended for different oob-layout + * oob layout selections: NAND_NONE_OOB, NAND_JFFS2_OOB, + * NAND_YAFFS_OOB + * 11-25-2002 tglx Added Manufacturer code FUJITSU, NATIONAL + * Split manufacturer and device ID structures + * + * 02-08-2004 tglx added option field to nand structure for chip anomalities + * 05-25-2004 tglx added bad block table support, ST-MICRO manufacturer id + * update of nand_chip structure description + * 01-17-2005 dmarlin added extended commands for AG-AND device and added option + * for BBT_AUTO_REFRESH. + * 01-20-2005 dmarlin added optional pointer to hardware specific callback for + * extra error status checks. + * + * 11-01-2005 vwool NAND page layouts introduces for HW ECC handling */ #ifndef __LINUX_MTD_NAND_H #define __LINUX_MTD_NAND_H #include <linux/config.h> -#include <linux/sched.h> +#include <linux/wait.h> +#include <linux/spinlock.h> +#include <linux/mtd/mtd.h> -/* - * Searches for a NAND device +struct mtd_info; +/* Scan and identify a NAND device */ +extern int nand_scan (struct mtd_info *mtd, int max_chips); +/* Free resources held by the NAND device */ +extern void nand_release (struct mtd_info *mtd); + +/* Read raw data from the device without ECC */ +extern int nand_read_raw (struct mtd_info *mtd, uint8_t *buf, loff_t from, size_t len, size_t ooblen); + + +/* The maximum number of NAND chips in an array */ +#define NAND_MAX_CHIPS 8 + +/* This constant declares the max. oobsize / page, which + * is supported now. If you add a chip with bigger oobsize/page + * adjust this accordingly. */ -extern int nand_scan (struct mtd_info *mtd); +#define NAND_MAX_OOBSIZE 64 + +/* + * Constants for hardware specific CLE/ALE/NCE function +*/ +/* Select the chip by setting nCE to low */ +#define NAND_CTL_SETNCE 1 +/* Deselect the chip by setting nCE to high */ +#define NAND_CTL_CLRNCE 2 +/* Select the command latch by setting CLE to high */ +#define NAND_CTL_SETCLE 3 +/* Deselect the command latch by setting CLE to low */ +#define NAND_CTL_CLRCLE 4 +/* Select the address latch by setting ALE to high */ +#define NAND_CTL_SETALE 5 +/* Deselect the address latch by setting ALE to low */ +#define NAND_CTL_CLRALE 6 +/* Set write protection by setting WP to high. Not used! */ +#define NAND_CTL_SETWP 7 +/* Clear write protection by setting WP to low. Not used! */ +#define NAND_CTL_CLRWP 8 /* * Standard NAND flash commands @@ -44,12 +111,148 @@ extern int nand_scan (struct mtd_info *mtd); #define NAND_CMD_READOOB 0x50 #define NAND_CMD_ERASE1 0x60 #define NAND_CMD_STATUS 0x70 +#define NAND_CMD_STATUS_MULTI 0x71 #define NAND_CMD_SEQIN 0x80 #define NAND_CMD_READID 0x90 #define NAND_CMD_ERASE2 0xd0 #define NAND_CMD_RESET 0xff +/* Extended commands for large page devices */ +#define NAND_CMD_READSTART 0x30 +#define NAND_CMD_CACHEDPROG 0x15 + +/* Extended commands for AG-AND device */ +/* + * Note: the command for NAND_CMD_DEPLETE1 is really 0x00 but + * there is no way to distinguish that from NAND_CMD_READ0 + * until the remaining sequence of commands has been completed + * so add a high order bit and mask it off in the command. + */ +#define NAND_CMD_DEPLETE1 0x100 +#define NAND_CMD_DEPLETE2 0x38 +#define NAND_CMD_STATUS_MULTI 0x71 +#define NAND_CMD_STATUS_ERROR 0x72 +/* multi-bank error status (banks 0-3) */ +#define NAND_CMD_STATUS_ERROR0 0x73 +#define NAND_CMD_STATUS_ERROR1 0x74 +#define NAND_CMD_STATUS_ERROR2 0x75 +#define NAND_CMD_STATUS_ERROR3 0x76 +#define NAND_CMD_STATUS_RESET 0x7f +#define NAND_CMD_STATUS_CLEAR 0xff + +/* Status bits */ +#define NAND_STATUS_FAIL 0x01 +#define NAND_STATUS_FAIL_N1 0x02 +#define NAND_STATUS_TRUE_READY 0x20 +#define NAND_STATUS_READY 0x40 +#define NAND_STATUS_WP 0x80 + /* + * Constants for ECC_MODES + */ + +/* No ECC. Usage is not recommended ! */ +#define NAND_ECC_NONE 0 +/* Software ECC 3 byte ECC per 256 Byte data */ +#define NAND_ECC_SOFT 1 +/* Hardware ECC 3 byte ECC per 256 Byte data */ +#define NAND_ECC_HW3_256 2 +/* Hardware ECC 3 byte ECC per 512 Byte data */ +#define NAND_ECC_HW3_512 3 +/* Hardware ECC 6 byte ECC per 512 Byte data */ +#define NAND_ECC_HW6_512 4 +/* Hardware ECC 8 byte ECC per 512 Byte data */ +#define NAND_ECC_HW8_512 6 +/* Hardware ECC 12 byte ECC per 2048 Byte data */ +#define NAND_ECC_HW12_2048 7 + +struct page_layout_item { + int length; + enum { + ITEM_TYPE_DATA, + ITEM_TYPE_OOB, + ITEM_TYPE_ECC, + } type; +}; + +/* + * Constants for Hardware ECC + */ +/* Reset Hardware ECC for read */ +#define NAND_ECC_READ 0 +/* Reset Hardware ECC for write */ +#define NAND_ECC_WRITE 1 +/* Enable Hardware ECC before syndrom is read back from flash */ +#define NAND_ECC_READSYN 2 +#define NAND_ECC_WRITESYN 3 +#define NAND_ECC_READOOB 4 +#define NAND_ECC_WRITEOOB 5 + +/* Bit mask for flags passed to do_nand_read_ecc */ +#define NAND_GET_DEVICE 0x80 + + +/* Option constants for bizarre disfunctionality and real +* features +*/ +/* Chip can not auto increment pages */ +#define NAND_NO_AUTOINCR 0x00000001 +/* Buswitdh is 16 bit */ +#define NAND_BUSWIDTH_16 0x00000002 +/* Device supports partial programming without padding */ +#define NAND_NO_PADDING 0x00000004 +/* Chip has cache program function */ +#define NAND_CACHEPRG 0x00000008 +/* Chip has copy back function */ +#define NAND_COPYBACK 0x00000010 +/* AND Chip which has 4 banks and a confusing page / block + * assignment. See Renesas datasheet for further information */ +#define NAND_IS_AND 0x00000020 +/* Chip has a array of 4 pages which can be read without + * additional ready /busy waits */ +#define NAND_4PAGE_ARRAY 0x00000040 +/* Chip requires that BBT is periodically rewritten to prevent + * bits from adjacent blocks from 'leaking' in altering data. + * This happens with the Renesas AG-AND chips, possibly others. */ +#define BBT_AUTO_REFRESH 0x00000080 + +/* Options valid for Samsung large page devices */ +#define NAND_SAMSUNG_LP_OPTIONS \ + (NAND_NO_PADDING | NAND_CACHEPRG | NAND_COPYBACK) + +/* Macros to identify the above */ +#define NAND_CANAUTOINCR(chip) (!(chip->options & NAND_NO_AUTOINCR)) +#define NAND_MUST_PAD(chip) (!(chip->options & NAND_NO_PADDING)) +#define NAND_HAS_CACHEPROG(chip) ((chip->options & NAND_CACHEPRG)) +#define NAND_HAS_COPYBACK(chip) ((chip->options & NAND_COPYBACK)) + +/* Mask to zero out the chip options, which come from the id table */ +#define NAND_CHIPOPTIONS_MSK (0x0000ffff & ~NAND_NO_AUTOINCR) + +/* Non chip related options */ +/* Use a flash based bad block table. This option is passed to the + * default bad block table function. */ +#define NAND_USE_FLASH_BBT 0x00010000 +/* The hw ecc generator provides a syndrome instead a ecc value on read + * This can only work if we have the ecc bytes directly behind the + * data bytes. Applies for DOC and AG-AND Renesas HW Reed Solomon generators */ +#define NAND_HWECC_SYNDROME 0x00020000 +/* This option skips the bbt scan during initialization. */ +#define NAND_SKIP_BBTSCAN 0x00040000 +/* This option specifies that a whole NAND page is to be written in + * nand_write_oob. This is needed for some HW ECC generators that need a + * whole page to be written to generate ECC properly */ +#define NAND_COMPLEX_OOB_WRITE 0x00080000 + +/* Options set by nand scan */ +/* Nand scan has allocated oob_buf */ +#define NAND_OOBBUF_ALLOC 0x40000000 +/* Nand scan has allocated data_buf */ +#define NAND_DATABUF_ALLOC 0x80000000 + + +/* + * nand_state_t - chip states * Enumeration for NAND flash chip state */ typedef enum { @@ -57,55 +260,143 @@ typedef enum { FL_READING, FL_WRITING, FL_ERASING, - FL_SYNCING + FL_SYNCING, + FL_CACHEDPRG, + FL_PM_SUSPENDED, } nand_state_t; -/* - * NAND Private Flash Chip Data - * - * Structure overview: - * - * IO_ADDR - address to access the 8 I/O lines to the flash device - * - * CTRL_ADDR - address where ALE, CLE and CE control bits are accessed - * - * CLE - location in control word for Command Latch Enable bit - * - * ALE - location in control word for Address Latch Enable bit - * - * NCE - location in control word for nChip Enable bit - * - * chip_lock - spinlock used to protect access to this structure - * - * wq - wait queue to sleep on if a NAND operation is in progress - * - * state - give the current state of the NAND device - * - * page_shift - number of address bits in a page (column address bits) - * - * data_buf - data buffer passed to/from MTD user modules - * - * ecc_code_buf - used only for holding calculated or read ECCs for - * a page read or written when ECC is in use - * - * reserved - padding to make structure fall on word boundary if - * when ECC is in use +/* Keep gcc happy */ +struct nand_chip; + +/** + * struct nand_hw_control - Control structure for hardware controller (e.g ECC generator) shared among independend devices + * @lock: protection lock + * @active: the mtd device which holds the controller currently + * @wq: wait queue to sleep on if a NAND operation is in progress + * used instead of the per chip wait queue when a hw controller is available + */ +struct nand_hw_control { + spinlock_t lock; + struct nand_chip *active; + wait_queue_head_t wq; +}; + +/** + * struct nand_chip - NAND Private Flash Chip Data + * @IO_ADDR_R: [BOARDSPECIFIC] address to read the 8 I/O lines of the flash device + * @IO_ADDR_W: [BOARDSPECIFIC] address to write the 8 I/O lines of the flash device + * @read_byte: [REPLACEABLE] read one byte from the chip + * @write_byte: [REPLACEABLE] write one byte to the chip + * @read_word: [REPLACEABLE] read one word from the chip + * @write_word: [REPLACEABLE] write one word to the chip + * @write_buf: [REPLACEABLE] write data from the buffer to the chip + * @read_buf: [REPLACEABLE] read data from the chip into the buffer + * @verify_buf: [REPLACEABLE] verify buffer contents against the chip data + * @select_chip: [REPLACEABLE] select chip nr + * @block_bad: [REPLACEABLE] check, if the block is bad + * @block_markbad: [REPLACEABLE] mark the block bad + * @hwcontrol: [BOARDSPECIFIC] hardwarespecific function for accesing control-lines + * @dev_ready: [BOARDSPECIFIC] hardwarespecific function for accesing device ready/busy line + * If set to NULL no access to ready/busy is available and the ready/busy information + * is read from the chip status register + * @cmdfunc: [REPLACEABLE] hardwarespecific function for writing commands to the chip + * @waitfunc: [REPLACEABLE] hardwarespecific function for wait on ready + * @calculate_ecc: [REPLACEABLE] function for ecc calculation or readback from ecc hardware + * @correct_data: [REPLACEABLE] function for ecc correction, matching to ecc generator (sw/hw) + * @enable_hwecc: [BOARDSPECIFIC] function to enable (reset) hardware ecc generator. Must only + * be provided if a hardware ECC is available + * @erase_cmd: [INTERN] erase command write function, selectable due to AND support + * @scan_bbt: [REPLACEABLE] function to scan bad block table + * @eccmode: [BOARDSPECIFIC] mode of ecc, see defines + * @eccsize: [INTERN] databytes used per ecc-calculation + * @eccbytes: [INTERN] number of ecc bytes per ecc-calculation step + * @eccsteps: [INTERN] number of ecc calculation steps per page + * @chip_delay: [BOARDSPECIFIC] chip dependent delay for transfering data from array to read regs (tR) + * @chip_lock: [INTERN] spinlock used to protect access to this structure and the chip + * @wq: [INTERN] wait queue to sleep on if a NAND operation is in progress + * @state: [INTERN] the current state of the NAND device + * @page_shift: [INTERN] number of address bits in a page (column address bits) + * @phys_erase_shift: [INTERN] number of address bits in a physical eraseblock + * @bbt_erase_shift: [INTERN] number of address bits in a bbt entry + * @chip_shift: [INTERN] number of address bits in one chip + * @data_buf: [INTERN] internal buffer for one page + oob + * @oob_buf: [INTERN] oob buffer for one eraseblock + * @oobdirty: [INTERN] indicates that oob_buf must be reinitialized + * @data_poi: [INTERN] pointer to a data buffer + * @options: [BOARDSPECIFIC] various chip options. They can partly be set to inform nand_scan about + * special functionality. See the defines for further explanation + * @badblockpos: [INTERN] position of the bad block marker in the oob area + * @numchips: [INTERN] number of physical chips + * @chipsize: [INTERN] the size of one chip for multichip arrays + * @pagemask: [INTERN] page number mask = number of (pages / chip) - 1 + * @pagebuf: [INTERN] holds the pagenumber which is currently in data_buf + * @autooob: [REPLACEABLE] the default (auto)placement scheme + * @bbt: [INTERN] bad block table pointer + * @bbt_td: [REPLACEABLE] bad block table descriptor for flash lookup + * @bbt_md: [REPLACEABLE] bad block table mirror descriptor + * @badblock_pattern: [REPLACEABLE] bad block scan pattern used for initial bad block scan + * @controller: [OPTIONAL] a pointer to a hardware controller structure which is shared among multiple independend devices + * @priv: [OPTIONAL] pointer to private chip date + * @errstat: [OPTIONAL] hardware specific function to perform additional error status checks + * (determine if errors are correctable) */ + struct nand_chip { - unsigned long IO_ADDR; - unsigned long CTRL_ADDR; - unsigned int CLE; - unsigned int ALE; - unsigned int NCE; - spinlock_t chip_lock; + void __iomem *IO_ADDR_R; + void __iomem *IO_ADDR_W; + + u_char (*read_byte)(struct mtd_info *mtd); + void (*write_byte)(struct mtd_info *mtd, u_char byte); + u16 (*read_word)(struct mtd_info *mtd); + void (*write_word)(struct mtd_info *mtd, u16 word); + + void (*write_buf)(struct mtd_info *mtd, const u_char *buf, int len); + void (*read_buf)(struct mtd_info *mtd, u_char *buf, int len); + int (*verify_buf)(struct mtd_info *mtd, const u_char *buf, int len); + void (*select_chip)(struct mtd_info *mtd, int chip); + int (*block_bad)(struct mtd_info *mtd, loff_t ofs, int getchip); + int (*block_markbad)(struct mtd_info *mtd, loff_t ofs); + void (*hwcontrol)(struct mtd_info *mtd, int cmd); + int (*dev_ready)(struct mtd_info *mtd); + void (*cmdfunc)(struct mtd_info *mtd, unsigned command, int column, int page_addr); + int (*waitfunc)(struct mtd_info *mtd, struct nand_chip *this, int state); + int (*calculate_ecc)(struct mtd_info *mtd, const u_char *dat, u_char *ecc_code); + int (*correct_data)(struct mtd_info *mtd, u_char *dat, u_char *read_ecc, u_char *calc_ecc); + void (*enable_hwecc)(struct mtd_info *mtd, int mode); + void (*erase_cmd)(struct mtd_info *mtd, int page); + int (*scan_bbt)(struct mtd_info *mtd); + int eccmode; + int eccsize; + int eccbytes; + int eccsteps; + int chip_delay; + spinlock_t chip_lock; wait_queue_head_t wq; - nand_state_t state; - int page_shift; - u_char *data_buf; -#ifdef CONFIG_MTD_NAND_ECC - u_char ecc_code_buf[6]; - u_char reserved[2]; -#endif + nand_state_t state; + int page_shift; + int phys_erase_shift; + int bbt_erase_shift; + int chip_shift; + u_char *data_buf; + u_char *oob_buf; + int oobdirty; + u_char *data_poi; + unsigned int options; + int badblockpos; + int numchips; + unsigned long chipsize; + int pagemask; + int pagebuf; + struct nand_oobinfo *autooob; + struct page_layout_item *layout; + int layout_allocated; + uint8_t *bbt; + struct nand_bbt_descr *bbt_td; + struct nand_bbt_descr *bbt_md; + struct nand_bbt_descr *badblock_pattern; + struct nand_hw_control *controller; + void *priv; + int (*errstat)(struct mtd_info *mtd, struct nand_chip *this, int state, int status, int page); }; /* @@ -113,42 +404,129 @@ struct nand_chip { */ #define NAND_MFR_TOSHIBA 0x98 #define NAND_MFR_SAMSUNG 0xec +#define NAND_MFR_FUJITSU 0x04 +#define NAND_MFR_NATIONAL 0x8f +#define NAND_MFR_RENESAS 0x07 +#define NAND_MFR_STMICRO 0x20 +#define NAND_MFR_HYNIX 0xad -/* - * NAND Flash Device ID Structure - * - * Structure overview: - * - * name - Complete name of device - * - * manufacture_id - manufacturer ID code of device. +/** + * struct nand_flash_dev - NAND Flash Device ID Structure * - * model_id - model ID code of device. - * - * chipshift - total number of address bits for the device which - * is used to calculate address offsets and the total - * number of bytes the device is capable of. - * - * page256 - denotes if flash device has 256 byte pages or not. - * - * pageadrlen - number of bytes minus one needed to hold the - * complete address into the flash array. Keep in - * mind that when a read or write is done to a - * specific address, the address is input serially - * 8 bits at a time. This structure member is used - * by the read/write routines as a loop index for - * shifting the address out 8 bits at a time. - * - * erasesize - size of an erase block in the flash device. + * @name: Identify the device type + * @id: device ID code + * @pagesize: Pagesize in bytes. Either 256 or 512 or 0 + * If the pagesize is 0, then the real pagesize + * and the eraseize are determined from the + * extended id bytes in the chip + * @erasesize: Size of an erase block in the flash device. + * @chipsize: Total chipsize in Mega Bytes + * @options: Bitfield to store chip relevant options */ struct nand_flash_dev { - char * name; - int manufacture_id; - int model_id; - int chipshift; - char page256; - char pageadrlen; + char *name; + int id; + unsigned long pagesize; + unsigned long chipsize; unsigned long erasesize; + unsigned long options; }; +/** + * struct nand_manufacturers - NAND Flash Manufacturer ID Structure + * @name: Manufacturer name + * @id: manufacturer ID code of device. +*/ +struct nand_manufacturers { + int id; + char * name; +}; + +extern struct nand_flash_dev nand_flash_ids[]; +extern struct nand_manufacturers nand_manuf_ids[]; + +/** + * struct nand_bbt_descr - bad block table descriptor + * @options: options for this descriptor + * @pages: the page(s) where we find the bbt, used with option BBT_ABSPAGE + * when bbt is searched, then we store the found bbts pages here. + * Its an array and supports up to 8 chips now + * @offs: offset of the pattern in the oob area of the page + * @veroffs: offset of the bbt version counter in the oob are of the page + * @version: version read from the bbt page during scan + * @len: length of the pattern, if 0 no pattern check is performed + * @maxblocks: maximum number of blocks to search for a bbt. This number of + * blocks is reserved at the end of the device where the tables are + * written. + * @reserved_block_code: if non-0, this pattern denotes a reserved (rather than + * bad) block in the stored bbt + * @pattern: pattern to identify bad block table or factory marked good / + * bad blocks, can be NULL, if len = 0 + * + * Descriptor for the bad block table marker and the descriptor for the + * pattern which identifies good and bad blocks. The assumption is made + * that the pattern and the version count are always located in the oob area + * of the first block. + */ +struct nand_bbt_descr { + int options; + int pages[NAND_MAX_CHIPS]; + int offs; + int veroffs; + uint8_t version[NAND_MAX_CHIPS]; + int len; + int maxblocks; + int reserved_block_code; + uint8_t *pattern; +}; + +/* Options for the bad block table descriptors */ + +/* The number of bits used per block in the bbt on the device */ +#define NAND_BBT_NRBITS_MSK 0x0000000F +#define NAND_BBT_1BIT 0x00000001 +#define NAND_BBT_2BIT 0x00000002 +#define NAND_BBT_4BIT 0x00000004 +#define NAND_BBT_8BIT 0x00000008 +/* The bad block table is in the last good block of the device */ +#define NAND_BBT_LASTBLOCK 0x00000010 +/* The bbt is at the given page, else we must scan for the bbt */ +#define NAND_BBT_ABSPAGE 0x00000020 +/* The bbt is at the given page, else we must scan for the bbt */ +#define NAND_BBT_SEARCH 0x00000040 +/* bbt is stored per chip on multichip devices */ +#define NAND_BBT_PERCHIP 0x00000080 +/* bbt has a version counter at offset veroffs */ +#define NAND_BBT_VERSION 0x00000100 +/* Create a bbt if none axists */ +#define NAND_BBT_CREATE 0x00000200 +/* Search good / bad pattern through all pages of a block */ +#define NAND_BBT_SCANALLPAGES 0x00000400 +/* Scan block empty during good / bad block scan */ +#define NAND_BBT_SCANEMPTY 0x00000800 +/* Write bbt if neccecary */ +#define NAND_BBT_WRITE 0x00001000 +/* Read and write back block contents when writing bbt */ +#define NAND_BBT_SAVECONTENT 0x00002000 +/* Search good / bad pattern on the first and the second page */ +#define NAND_BBT_SCAN2NDPAGE 0x00004000 + +/* The maximum number of blocks to scan for a bbt */ +#define NAND_BBT_SCAN_MAXBLOCKS 4 + +extern int nand_scan_bbt (struct mtd_info *mtd, struct nand_bbt_descr *bd); +extern int nand_update_bbt (struct mtd_info *mtd, loff_t offs); +extern int nand_default_bbt (struct mtd_info *mtd); +extern int nand_isbad_bbt (struct mtd_info *mtd, loff_t offs, int allowbbt); +extern int nand_erase_nand (struct mtd_info *mtd, struct erase_info *instr, int allowbbt); +extern int nand_do_read_ecc (struct mtd_info *mtd, loff_t from, size_t len, + size_t * retlen, u_char * buf, u_char * oob_buf, + struct nand_oobinfo *oobsel, int flags); + +/* +* Constants for oob configuration +*/ +#define NAND_SMALL_BADBLOCK_POS 5 +#define NAND_LARGE_BADBLOCK_POS 0 + #endif /* __LINUX_MTD_NAND_H */ diff --git a/linux-2.4.x/include/linux/mtd/nand_ecc.h b/linux-2.4.x/include/linux/mtd/nand_ecc.h index f3f1d7e..12c5bc3 100644 --- a/linux-2.4.x/include/linux/mtd/nand_ecc.h +++ b/linux-2.4.x/include/linux/mtd/nand_ecc.h @@ -1,9 +1,9 @@ /* * drivers/mtd/nand_ecc.h * - * Copyright (C) 2000 Steven J. Hill (sjhill@cotw.com) + * Copyright (C) 2000 Steven J. Hill (sjhill@realitydiluted.com) * - * $Id: nand_ecc.h,v 1.1 2000/10/12 00:57:15 sjhill Exp $ + * $Id: nand_ecc.h,v 1.4 2004/06/17 02:35:02 dbrown Exp $ * * 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 @@ -12,17 +12,19 @@ * This file is the header for the ECC algorithm. */ -/* - * Creates non-inverted ECC code from line parity - */ -void nand_trans_result(u_char reg2, u_char reg3, u_char *ecc_code); +#ifndef __MTD_NAND_ECC_H__ +#define __MTD_NAND_ECC_H__ + +struct mtd_info; /* * Calculate 3 byte ECC code for 256 byte block */ -void nand_calculate_ecc (const u_char *dat, u_char *ecc_code); +int nand_calculate_ecc(struct mtd_info *mtd, const u_char *dat, u_char *ecc_code); /* * Detect and correct a 1 bit error for 256 byte block */ -int nand_correct_data (u_char *dat, u_char *read_ecc, u_char *calc_ecc); +int nand_correct_data(struct mtd_info *mtd, u_char *dat, u_char *read_ecc, u_char *calc_ecc); + +#endif /* __MTD_NAND_ECC_H__ */ diff --git a/linux-2.4.x/include/linux/mtd/nftl.h b/linux-2.4.x/include/linux/mtd/nftl.h index 3483a8c..d35d2c2 100644 --- a/linux-2.4.x/include/linux/mtd/nftl.h +++ b/linux-2.4.x/include/linux/mtd/nftl.h @@ -1,81 +1,16 @@ - -/* Defines for NAND Flash Translation Layer */ -/* (c) 1999 Machine Vision Holdings, Inc. */ -/* Author: David Woodhouse <dwmw2@mvhi.com> */ -/* $Id: nftl.h,v 1.10 2000/12/29 00:25:38 dwmw2 Exp $ */ +/* + * $Id: nftl.h,v 1.16 2004/06/30 14:49:00 dbrown Exp $ + * + * (C) 1999-2003 David Woodhouse <dwmw2@infradead.org> + */ #ifndef __MTD_NFTL_H__ #define __MTD_NFTL_H__ -#ifndef __BOOT__ #include <linux/mtd/mtd.h> -#endif - -/* Block Control Information */ - -struct nftl_bci { - unsigned char ECCSig[6]; - __u8 Status; - __u8 Status1; -}__attribute__((packed)); - -/* Unit Control Information */ +#include <linux/mtd/blktrans.h> -struct nftl_uci0 { - __u16 VirtUnitNum; - __u16 ReplUnitNum; - __u16 SpareVirtUnitNum; - __u16 SpareReplUnitNum; -} __attribute__((packed)); - -struct nftl_uci1 { - __u32 WearInfo; - __u16 EraseMark; - __u16 EraseMark1; -} __attribute__((packed)); - -struct nftl_uci2 { - __u16 FoldMark; - __u16 FoldMark1; - __u32 unused; -} __attribute__((packed)); - -union nftl_uci { - struct nftl_uci0 a; - struct nftl_uci1 b; - struct nftl_uci2 c; -}; - -struct nftl_oob { - struct nftl_bci b; - union nftl_uci u; -}; - -/* NFTL Media Header */ - -struct NFTLMediaHeader { - char DataOrgID[6]; - __u16 NumEraseUnits; - __u16 FirstPhysicalEUN; - __u32 FormattedSize; - unsigned char UnitSizeFactor; -} __attribute__((packed)); - -#define MAX_ERASE_ZONES (8192 - 512) - -#define ERASE_MARK 0x3c69 -#define SECTOR_FREE 0xff -#define SECTOR_USED 0x55 -#define SECTOR_IGNORE 0x11 -#define SECTOR_DELETED 0x00 - -#define FOLD_MARK_IN_PROGRESS 0x5555 - -#define ZONE_GOOD 0xff -#define ZONE_BAD_ORIGINAL 0 -#define ZONE_BAD_MARKED 7 - -#ifdef __KERNEL__ +#include <mtd/nftl-user.h> /* these info are used in ReplUnitTable */ #define BLOCK_NIL 0xffff /* last block of a chain */ @@ -84,8 +19,7 @@ struct NFTLMediaHeader { #define BLOCK_RESERVED 0xfffc /* bios block or bad block */ struct NFTLrecord { - struct mtd_info *mtd; - struct semaphore mutex; + struct mtd_blktrans_dev mbd; __u16 MediaUnit, SpareMediaUnit; __u32 EraseSize; struct NFTLMediaHeader MediaHdr; @@ -97,13 +31,13 @@ struct NFTLrecord { __u16 lastEUN; /* should be suppressed */ __u16 numfreeEUNs; __u16 LastFreeEUN; /* To speed up finding a free EUN */ - __u32 long nr_sects; int head,sect,cyl; __u16 *EUNtable; /* [numvunits]: First EUN for each virtual unit */ __u16 *ReplUnitTable; /* [numEUNs]: ReplUnitNumber for each */ unsigned int nb_blocks; /* number of physical blocks */ unsigned int nb_boot_blocks; /* number of blocks used by the bios */ struct erase_info instr; + struct nand_oobinfo oobinfo; }; int NFTL_mount(struct NFTLrecord *s); @@ -114,9 +48,7 @@ int NFTL_formatblock(struct NFTLrecord *s, int block); #endif #define MAX_NFTLS 16 -#define MAX_SECTORS_PER_UNIT 32 +#define MAX_SECTORS_PER_UNIT 64 #define NFTL_PARTN_BITS 4 -#endif /* __KERNEL__ */ - #endif /* __MTD_NFTL_H__ */ diff --git a/linux-2.4.x/include/linux/mtd/onenand.h b/linux-2.4.x/include/linux/mtd/onenand.h new file mode 100644 index 0000000..d259e0a --- /dev/null +++ b/linux-2.4.x/include/linux/mtd/onenand.h @@ -0,0 +1,161 @@ +/* + * linux/include/linux/mtd/onenand.h + * + * Copyright (C) 2005 Samsung Electronics + * Kyungmin Park <kyungmin.park@samsung.com> + * + * $Id: onenand.h,v 1.13 2006/02/22 00:26:38 kmpark Exp $ + * + * 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. + */ + +#ifndef __LINUX_MTD_ONENAND_H +#define __LINUX_MTD_ONENAND_H + +#include <linux/spinlock.h> +#include <linux/mtd/onenand_regs.h> +#include <linux/mtd/bbm.h> + +#define MAX_BUFFERRAM 2 + +/* Scan and identify a OneNAND device */ +extern int onenand_scan(struct mtd_info *mtd, int max_chips); +/* Free resources held by the OneNAND device */ +extern void onenand_release(struct mtd_info *mtd); + +/** + * onenand_state_t - chip states + * Enumeration for OneNAND flash chip state + */ +typedef enum { + FL_READY, + FL_READING, + FL_WRITING, + FL_ERASING, + FL_SYNCING, + FL_UNLOCKING, + FL_LOCKING, + FL_RESETING, + FL_OTPING, + FL_PM_SUSPENDED, +} onenand_state_t; + +/** + * struct onenand_bufferram - OneNAND BufferRAM Data + * @param block block address in BufferRAM + * @param page page address in BufferRAM + * @param valid valid flag + */ +struct onenand_bufferram { + int block; + int page; + int valid; +}; + +/** + * struct onenand_chip - OneNAND Private Flash Chip Data + * @param base [BOARDSPECIFIC] address to access OneNAND + * @param chipsize [INTERN] the size of one chip for multichip arrays + * @param device_id [INTERN] device ID + * @param verstion_id [INTERN] version ID + * @param options [BOARDSPECIFIC] various chip options. They can partly be set to inform onenand_scan about + * @param erase_shift [INTERN] number of address bits in a block + * @param page_shift [INTERN] number of address bits in a page + * @param ppb_shift [INTERN] number of address bits in a pages per block + * @param page_mask [INTERN] a page per block mask + * @param bufferam_index [INTERN] BufferRAM index + * @param bufferam [INTERN] BufferRAM info + * @param readw [REPLACEABLE] hardware specific function for read short + * @param writew [REPLACEABLE] hardware specific function for write short + * @param command [REPLACEABLE] hardware specific function for writing commands to the chip + * @param wait [REPLACEABLE] hardware specific function for wait on ready + * @param read_bufferram [REPLACEABLE] hardware specific function for BufferRAM Area + * @param write_bufferram [REPLACEABLE] hardware specific function for BufferRAM Area + * @param read_word [REPLACEABLE] hardware specific function for read register of OneNAND + * @param write_word [REPLACEABLE] hardware specific function for write register of OneNAND + * @param scan_bbt [REPLACEALBE] hardware specific function for scaning Bad block Table + * @param chip_lock [INTERN] spinlock used to protect access to this structure and the chip + * @param wq [INTERN] wait queue to sleep on if a OneNAND operation is in progress + * @param state [INTERN] the current state of the OneNAND device + * @param autooob [REPLACEABLE] the default (auto)placement scheme + * @param bbm [REPLACEABLE] pointer to Bad Block Management + * @param priv [OPTIONAL] pointer to private chip date + */ +struct onenand_chip { + void __iomem *base; + unsigned int chipsize; + unsigned int device_id; + unsigned int density_mask; + unsigned int options; + + unsigned int erase_shift; + unsigned int page_shift; + unsigned int ppb_shift; /* Pages per block shift */ + unsigned int page_mask; + + unsigned int bufferram_index; + struct onenand_bufferram bufferram[MAX_BUFFERRAM]; + + int (*command)(struct mtd_info *mtd, int cmd, loff_t address, size_t len); + int (*wait)(struct mtd_info *mtd, int state); + int (*read_bufferram)(struct mtd_info *mtd, int area, + unsigned char *buffer, int offset, size_t count); + int (*write_bufferram)(struct mtd_info *mtd, int area, + const unsigned char *buffer, int offset, size_t count); + unsigned short (*read_word)(void __iomem *addr); + void (*write_word)(unsigned short value, void __iomem *addr); + void (*mmcontrol)(struct mtd_info *mtd, int sync_read); + int (*block_markbad)(struct mtd_info *mtd, loff_t ofs); + int (*scan_bbt)(struct mtd_info *mtd); + + spinlock_t chip_lock; + wait_queue_head_t wq; + onenand_state_t state; + unsigned char *page_buf; + + struct nand_oobinfo *autooob; + + void *bbm; + + void *priv; +}; + +/* + * Helper macros + */ +#define ONENAND_CURRENT_BUFFERRAM(this) (this->bufferram_index) +#define ONENAND_NEXT_BUFFERRAM(this) (this->bufferram_index ^ 1) +#define ONENAND_SET_NEXT_BUFFERRAM(this) (this->bufferram_index ^= 1) + +#define ONENAND_GET_SYS_CFG1(this) \ + (this->read_word(this->base + ONENAND_REG_SYS_CFG1)) +#define ONENAND_SET_SYS_CFG1(v, this) \ + (this->write_word(v, this->base + ONENAND_REG_SYS_CFG1)) + +/* Check byte access in OneNAND */ +#define ONENAND_CHECK_BYTE_ACCESS(addr) (addr & 0x1) + +/* + * Options bits + */ +#define ONENAND_CONT_LOCK (0x0001) +#define ONENAND_PAGEBUF_ALLOC (0x1000) + +/* + * OneNAND Flash Manufacturer ID Codes + */ +#define ONENAND_MFR_SAMSUNG 0xec + +/** + * struct nand_manufacturers - NAND Flash Manufacturer ID Structure + * @param name: Manufacturer name + * @param id: manufacturer ID code of device. +*/ +struct onenand_manufacturers { + int id; + char *name; +}; + +#endif /* __LINUX_MTD_ONENAND_H */ diff --git a/linux-2.4.x/include/linux/mtd/onenand_regs.h b/linux-2.4.x/include/linux/mtd/onenand_regs.h new file mode 100644 index 0000000..32dacb4 --- /dev/null +++ b/linux-2.4.x/include/linux/mtd/onenand_regs.h @@ -0,0 +1,190 @@ +/* + * linux/include/linux/mtd/onenand_regs.h + * + * OneNAND Register header file + * + * Copyright (C) 2005 Samsung Electronics + * + * $Id: onenand_regs.h,v 1.4 2006/02/22 00:26:38 kmpark Exp $ + * + * 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. + */ + +#ifndef __ONENAND_REG_H +#define __ONENAND_REG_H + +/* Memory Address Map Translation (Word order) */ +#define ONENAND_MEMORY_MAP(x) ((x) << 1) + +/* + * External BufferRAM area + */ +#define ONENAND_BOOTRAM ONENAND_MEMORY_MAP(0x0000) +#define ONENAND_DATARAM ONENAND_MEMORY_MAP(0x0200) +#define ONENAND_SPARERAM ONENAND_MEMORY_MAP(0x8010) + +/* + * OneNAND Registers + */ +#define ONENAND_REG_MANUFACTURER_ID ONENAND_MEMORY_MAP(0xF000) +#define ONENAND_REG_DEVICE_ID ONENAND_MEMORY_MAP(0xF001) +#define ONENAND_REG_VERSION_ID ONENAND_MEMORY_MAP(0xF002) +#define ONENAND_REG_DATA_BUFFER_SIZE ONENAND_MEMORY_MAP(0xF003) +#define ONENAND_REG_BOOT_BUFFER_SIZE ONENAND_MEMORY_MAP(0xF004) +#define ONENAND_REG_NUM_BUFFERS ONENAND_MEMORY_MAP(0xF005) +#define ONENAND_REG_TECHNOLOGY ONENAND_MEMORY_MAP(0xF006) + +#define ONENAND_REG_START_ADDRESS1 ONENAND_MEMORY_MAP(0xF100) +#define ONENAND_REG_START_ADDRESS2 ONENAND_MEMORY_MAP(0xF101) +#define ONENAND_REG_START_ADDRESS3 ONENAND_MEMORY_MAP(0xF102) +#define ONENAND_REG_START_ADDRESS4 ONENAND_MEMORY_MAP(0xF103) +#define ONENAND_REG_START_ADDRESS5 ONENAND_MEMORY_MAP(0xF104) +#define ONENAND_REG_START_ADDRESS6 ONENAND_MEMORY_MAP(0xF105) +#define ONENAND_REG_START_ADDRESS7 ONENAND_MEMORY_MAP(0xF106) +#define ONENAND_REG_START_ADDRESS8 ONENAND_MEMORY_MAP(0xF107) + +#define ONENAND_REG_START_BUFFER ONENAND_MEMORY_MAP(0xF200) +#define ONENAND_REG_COMMAND ONENAND_MEMORY_MAP(0xF220) +#define ONENAND_REG_SYS_CFG1 ONENAND_MEMORY_MAP(0xF221) +#define ONENAND_REG_SYS_CFG2 ONENAND_MEMORY_MAP(0xF222) +#define ONENAND_REG_CTRL_STATUS ONENAND_MEMORY_MAP(0xF240) +#define ONENAND_REG_INTERRUPT ONENAND_MEMORY_MAP(0xF241) +#define ONENAND_REG_START_BLOCK_ADDRESS ONENAND_MEMORY_MAP(0xF24C) +#define ONENAND_REG_END_BLOCK_ADDRESS ONENAND_MEMORY_MAP(0xF24D) +#define ONENAND_REG_WP_STATUS ONENAND_MEMORY_MAP(0xF24E) + +#define ONENAND_REG_ECC_STATUS ONENAND_MEMORY_MAP(0xFF00) +#define ONENAND_REG_ECC_M0 ONENAND_MEMORY_MAP(0xFF01) +#define ONENAND_REG_ECC_S0 ONENAND_MEMORY_MAP(0xFF02) +#define ONENAND_REG_ECC_M1 ONENAND_MEMORY_MAP(0xFF03) +#define ONENAND_REG_ECC_S1 ONENAND_MEMORY_MAP(0xFF04) +#define ONENAND_REG_ECC_M2 ONENAND_MEMORY_MAP(0xFF05) +#define ONENAND_REG_ECC_S2 ONENAND_MEMORY_MAP(0xFF06) +#define ONENAND_REG_ECC_M3 ONENAND_MEMORY_MAP(0xFF07) +#define ONENAND_REG_ECC_S3 ONENAND_MEMORY_MAP(0xFF08) + +/* + * Device ID Register F001h (R) + */ +#define ONENAND_DEVICE_DENSITY_SHIFT (4) +#define ONENAND_DEVICE_IS_DDP (1 << 3) +#define ONENAND_DEVICE_IS_DEMUX (1 << 2) +#define ONENAND_DEVICE_VCC_MASK (0x3) + +#define ONENAND_DEVICE_DENSITY_512Mb (0x002) + +/* + * Version ID Register F002h (R) + */ +#define ONENAND_VERSION_PROCESS_SHIFT (8) + +/* + * Start Address 1 F100h (R/W) + */ +#define ONENAND_DDP_SHIFT (15) + +/* + * Start Address 8 F107h (R/W) + */ +#define ONENAND_FPA_MASK (0x3f) +#define ONENAND_FPA_SHIFT (2) +#define ONENAND_FSA_MASK (0x03) + +/* + * Start Buffer Register F200h (R/W) + */ +#define ONENAND_BSA_MASK (0x03) +#define ONENAND_BSA_SHIFT (8) +#define ONENAND_BSA_BOOTRAM (0 << 2) +#define ONENAND_BSA_DATARAM0 (2 << 2) +#define ONENAND_BSA_DATARAM1 (3 << 2) +#define ONENAND_BSC_MASK (0x03) + +/* + * Command Register F220h (R/W) + */ +#define ONENAND_CMD_READ (0x00) +#define ONENAND_CMD_READOOB (0x13) +#define ONENAND_CMD_PROG (0x80) +#define ONENAND_CMD_PROGOOB (0x1A) +#define ONENAND_CMD_UNLOCK (0x23) +#define ONENAND_CMD_LOCK (0x2A) +#define ONENAND_CMD_LOCK_TIGHT (0x2C) +#define ONENAND_CMD_ERASE (0x94) +#define ONENAND_CMD_RESET (0xF0) +#define ONENAND_CMD_OTP_ACCESS (0x65) +#define ONENAND_CMD_READID (0x90) + +/* NOTE: Those are not *REAL* commands */ +#define ONENAND_CMD_BUFFERRAM (0x1978) + +/* + * System Configuration 1 Register F221h (R, R/W) + */ +#define ONENAND_SYS_CFG1_SYNC_READ (1 << 15) +#define ONENAND_SYS_CFG1_BRL_7 (7 << 12) +#define ONENAND_SYS_CFG1_BRL_6 (6 << 12) +#define ONENAND_SYS_CFG1_BRL_5 (5 << 12) +#define ONENAND_SYS_CFG1_BRL_4 (4 << 12) +#define ONENAND_SYS_CFG1_BRL_3 (3 << 12) +#define ONENAND_SYS_CFG1_BRL_10 (2 << 12) +#define ONENAND_SYS_CFG1_BRL_9 (1 << 12) +#define ONENAND_SYS_CFG1_BRL_8 (0 << 12) +#define ONENAND_SYS_CFG1_BRL_SHIFT (12) +#define ONENAND_SYS_CFG1_BL_32 (4 << 9) +#define ONENAND_SYS_CFG1_BL_16 (3 << 9) +#define ONENAND_SYS_CFG1_BL_8 (2 << 9) +#define ONENAND_SYS_CFG1_BL_4 (1 << 9) +#define ONENAND_SYS_CFG1_BL_CONT (0 << 9) +#define ONENAND_SYS_CFG1_BL_SHIFT (9) +#define ONENAND_SYS_CFG1_NO_ECC (1 << 8) +#define ONENAND_SYS_CFG1_RDY (1 << 7) +#define ONENAND_SYS_CFG1_INT (1 << 6) +#define ONENAND_SYS_CFG1_IOBE (1 << 5) +#define ONENAND_SYS_CFG1_RDY_CONF (1 << 4) + +/* + * Controller Status Register F240h (R) + */ +#define ONENAND_CTRL_ONGO (1 << 15) +#define ONENAND_CTRL_LOCK (1 << 14) +#define ONENAND_CTRL_LOAD (1 << 13) +#define ONENAND_CTRL_PROGRAM (1 << 12) +#define ONENAND_CTRL_ERASE (1 << 11) +#define ONENAND_CTRL_ERROR (1 << 10) +#define ONENAND_CTRL_RSTB (1 << 7) +#define ONENAND_CTRL_OTP_L (1 << 6) +#define ONENAND_CTRL_OTP_BL (1 << 5) + +/* + * Interrupt Status Register F241h (R) + */ +#define ONENAND_INT_MASTER (1 << 15) +#define ONENAND_INT_READ (1 << 7) +#define ONENAND_INT_WRITE (1 << 6) +#define ONENAND_INT_ERASE (1 << 5) +#define ONENAND_INT_RESET (1 << 4) +#define ONENAND_INT_CLEAR (0 << 0) + +/* + * NAND Flash Write Protection Status Register F24Eh (R) + */ +#define ONENAND_WP_US (1 << 2) +#define ONENAND_WP_LS (1 << 1) +#define ONENAND_WP_LTS (1 << 0) + +/* + * ECC Status Reigser FF00h (R) + */ +#define ONENAND_ECC_1BIT (1 << 0) +#define ONENAND_ECC_2BIT (1 << 1) +#define ONENAND_ECC_2BIT_ALL (0xAAAA) + +/* + * One-Time Programmable (OTP) + */ +#define ONENAND_OTP_LOCK_OFFSET (14) + +#endif /* __ONENAND_REG_H */ diff --git a/linux-2.4.x/include/linux/mtd/partitions.h b/linux-2.4.x/include/linux/mtd/partitions.h index 7c55241..b03f512 100644 --- a/linux-2.4.x/include/linux/mtd/partitions.h +++ b/linux-2.4.x/include/linux/mtd/partitions.h @@ -5,7 +5,7 @@ * * This code is GPL * - * $Id: partitions.h,v 1.8 2002/03/08 16:34:36 rkaiser Exp $ + * $Id: partitions.h,v 1.17 2005/11/07 11:14:55 gleixner Exp $ */ #ifndef MTD_PARTITIONS_H @@ -16,32 +16,33 @@ /* * Partition definition structure: - * + * * An array of struct partition is passed along with a MTD object to * add_mtd_partitions() to create them. * * For each partition, these fields are available: * name: string that will be used to label the partition's MTD device. - * size: the partition size; if defined as MTDPART_SIZ_FULL, the partition + * size: the partition size; if defined as MTDPART_SIZ_FULL, the partition * will extend to the end of the master MTD device. - * offset: absolute starting position within the master MTD device; if - * defined as MTDPART_OFS_APPEND, the partition will start where the + * offset: absolute starting position within the master MTD device; if + * defined as MTDPART_OFS_APPEND, the partition will start where the * previous one ended; if MTDPART_OFS_NXTBLK, at the next erase block. - * mask_flags: contains flags that have to be masked (removed) from the + * mask_flags: contains flags that have to be masked (removed) from the * master MTD flag set for the corresponding MTD partition. - * For example, to force a read-only partition, simply adding + * For example, to force a read-only partition, simply adding * MTD_WRITEABLE to the mask_flags will do the trick. * - * Note: writeable partitions require their size and offset be + * Note: writeable partitions require their size and offset be * erasesize aligned (e.g. use MTDPART_OFS_NEXTBLK). - */ + */ struct mtd_partition { - char *name; /* identifier string */ - u_int32_t size; /* partition size */ + char *name; /* identifier string */ + u_int32_t size; /* partition size */ u_int32_t offset; /* offset within the master MTD space */ - u_int32_t mask_flags; /* master MTD flags to mask out for this partition */ - struct mtd_info **mtdp; /* pointer to store the MTD object */ + u_int32_t mask_flags; /* master MTD flags to mask out for this partition */ + struct nand_oobinfo *oobsel; /* out of band layout for this partition (NAND only)*/ + struct mtd_info **mtdp; /* pointer to store the MTD object */ }; #define MTDPART_OFS_NXTBLK (-2) @@ -49,8 +50,26 @@ struct mtd_partition { #define MTDPART_SIZ_FULL (0) -int add_mtd_partitions(struct mtd_info *, struct mtd_partition *, int); +int add_mtd_partitions(struct mtd_info *, const struct mtd_partition *, int); int del_mtd_partitions(struct mtd_info *); +/* + * Functions dealing with the various ways of partitioning the space + */ + +struct mtd_part_parser { + struct list_head list; + struct module *owner; + const char *name; + int (*parse_fn)(struct mtd_info *, struct mtd_partition **, unsigned long); +}; + +extern int register_mtd_parser(struct mtd_part_parser *parser); +extern int deregister_mtd_parser(struct mtd_part_parser *parser); +extern int parse_mtd_partitions(struct mtd_info *master, const char **types, + struct mtd_partition **pparts, unsigned long origin); + +#define put_partition_parser(p) do { module_put((p)->owner); } while(0) + #endif diff --git a/linux-2.4.x/include/linux/mtd/physmap.h b/linux-2.4.x/include/linux/mtd/physmap.h new file mode 100644 index 0000000..c7b8bcd --- /dev/null +++ b/linux-2.4.x/include/linux/mtd/physmap.h @@ -0,0 +1,61 @@ +/* + * For boards with physically mapped flash and using + * drivers/mtd/maps/physmap.c mapping driver. + * + * $Id: physmap.h,v 1.4 2005/11/07 11:14:55 gleixner Exp $ + * + * Copyright (C) 2003 MontaVista Software Inc. + * Author: Jun Sun, jsun@mvista.com or jsun@junsun.net + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2 of the License, or (at your + * option) any later version. + * + */ + +#ifndef __LINUX_MTD_PHYSMAP__ + +#include <linux/config.h> + +#if defined(CONFIG_MTD_PHYSMAP) + +#include <linux/mtd/mtd.h> +#include <linux/mtd/map.h> +#include <linux/mtd/partitions.h> + +/* + * The map_info for physmap. Board can override size, buswidth, phys, + * (*set_vpp)(), etc in their initial setup routine. + */ +extern struct map_info physmap_map; + +/* + * Board needs to specify the exact mapping during their setup time. + */ +static inline void physmap_configure(unsigned long addr, unsigned long size, int bankwidth, void (*set_vpp)(struct map_info *, int) ) +{ + physmap_map.phys = addr; + physmap_map.size = size; + physmap_map.bankwidth = bankwidth; + physmap_map.set_vpp = set_vpp; +} + +#if defined(CONFIG_MTD_PARTITIONS) + +/* + * Machines that wish to do flash partition may want to call this function in + * their setup routine. + * + * physmap_set_partitions(mypartitions, num_parts); + * + * Note that one can always override this hard-coded partition with + * command line partition (you need to enable CONFIG_MTD_CMDLINE_PARTS). + */ +void physmap_set_partitions(struct mtd_partition *parts, int num_parts); + +#endif /* defined(CONFIG_MTD_PARTITIONS) */ +#endif /* defined(CONFIG_MTD) */ + +#endif /* __LINUX_MTD_PHYSMAP__ */ + diff --git a/linux-2.4.x/include/linux/mtd/plat-ram.h b/linux-2.4.x/include/linux/mtd/plat-ram.h new file mode 100644 index 0000000..2332eda --- /dev/null +++ b/linux-2.4.x/include/linux/mtd/plat-ram.h @@ -0,0 +1,35 @@ +/* linux/include/mtd/plat-ram.h + * + * (c) 2004 Simtec Electronics + * http://www.simtec.co.uk/products/SWLINUX/ + * Ben Dooks <ben@simtec.co.uk> + * + * Generic platform device based RAM map + * + * $Id: plat-ram.h,v 1.2 2005/01/24 00:37:40 bjd Exp $ + * + * 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. + * + */ + +#ifndef __LINUX_MTD_PLATRAM_H +#define __LINUX_MTD_PLATRAM_H __FILE__ + +#define PLATRAM_RO (0) +#define PLATRAM_RW (1) + +struct platdata_mtd_ram { + char *mapname; + char **probes; + struct mtd_partition *partitions; + int nr_partitions; + int bankwidth; + + /* control callbacks */ + + void (*set_rw)(struct device *dev, int to); +}; + +#endif /* __LINUX_MTD_PLATRAM_H */ diff --git a/linux-2.4.x/include/linux/mtd/pmc551.h b/linux-2.4.x/include/linux/mtd/pmc551.h index 640d3eb..a7f6d20 100644 --- a/linux-2.4.x/include/linux/mtd/pmc551.h +++ b/linux-2.4.x/include/linux/mtd/pmc551.h @@ -1,5 +1,5 @@ /* - * $Id: pmc551.h,v 1.4 2001/06/12 16:19:38 major Exp $ + * $Id: pmc551.h,v 1.6 2005/11/07 11:14:55 gleixner Exp $ * * PMC551 PCI Mezzanine Ram Device * @@ -7,7 +7,7 @@ * Mark Ferrell * Copyright 1999,2000 Nortel Networks * - * License: + * License: * As part of this driver was derrived from the slram.c driver it falls * under the same license, which is GNU General Public License v2 */ @@ -17,7 +17,7 @@ #include <linux/mtd/mtd.h> -#define PMC551_VERSION "$Id: pmc551.h,v 1.4 2001/06/12 16:19:38 major Exp $\n"\ +#define PMC551_VERSION "$Id: pmc551.h,v 1.6 2005/11/07 11:14:55 gleixner Exp $\n"\ "Ramix PMC551 PCI Mezzanine Ram Driver. (C) 1999,2000 Nortel Networks.\n" /* @@ -30,16 +30,16 @@ struct mypriv { u32 curr_map0; u32 asize; struct mtd_info *nextpmc551; -}; +}; /* * Function Prototypes */ static int pmc551_erase(struct mtd_info *, struct erase_info *); -static void pmc551_unpoint(struct mtd_info *, u_char *); +static void pmc551_unpoint(struct mtd_info *, u_char *, loff_t, size_t); static int pmc551_point (struct mtd_info *mtd, loff_t from, size_t len, size_t *retlen, u_char **mtdbuf); static int pmc551_read(struct mtd_info *, loff_t, size_t, size_t *, u_char *); -static int pmc551_write(struct mtd_info *, loff_t, size_t, size_t *, const u_char *); +static int pmc551_write(struct mtd_info *, loff_t, size_t, size_t *, const u_char *); /* @@ -50,7 +50,7 @@ static int pmc551_write(struct mtd_info *, loff_t, size_t, size_t *, const u_cha #endif #ifndef PCI_DEVICE_ID_V3_SEMI_V370PDC -#define PCI_DEVICE_ID_V3_SEMI_V370PDC 0x0200 +#define PCI_DEVICE_ID_V3_SEMI_V370PDC 0x0200 #endif diff --git a/linux-2.4.x/include/linux/mtd/xip.h b/linux-2.4.x/include/linux/mtd/xip.h new file mode 100644 index 0000000..220d50b --- /dev/null +++ b/linux-2.4.x/include/linux/mtd/xip.h @@ -0,0 +1,102 @@ +/* + * MTD primitives for XIP support + * + * Author: Nicolas Pitre + * Created: Nov 2, 2004 + * Copyright: (C) 2004 MontaVista Software, Inc. + * + * This XIP support for MTD has been loosely inspired + * by an earlier patch authored by David Woodhouse. + * + * 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. + * + * $Id: xip.h,v 1.5 2005/11/07 11:14:55 gleixner Exp $ + */ + +#ifndef __LINUX_MTD_XIP_H__ +#define __LINUX_MTD_XIP_H__ + +#include <linux/config.h> + +#ifdef CONFIG_MTD_XIP + +/* + * We really don't want gcc to guess anything. + * We absolutely _need_ proper inlining. + */ +#include <linux/compiler.h> + +/* + * Function that are modifying the flash state away from array mode must + * obviously not be running from flash. The __xipram is therefore marking + * those functions so they get relocated to ram. + */ +#define __xipram noinline __attribute__ ((__section__ (".data"))) + +/* + * Each architecture has to provide the following macros. They must access + * the hardware directly and not rely on any other (XIP) functions since they + * won't be available when used (flash not in array mode). + * + * xip_irqpending() + * + * return non zero when any hardware interrupt is pending. + * + * xip_currtime() + * + * return a platform specific time reference to be used with + * xip_elapsed_since(). + * + * xip_elapsed_since(x) + * + * return in usecs the elapsed timebetween now and the reference x as + * returned by xip_currtime(). + * + * note 1: convertion to usec can be approximated, as long as the + * returned value is <= the real elapsed time. + * note 2: this should be able to cope with a few seconds without + * overflowing. + * + * xip_iprefetch() + * + * Macro to fill instruction prefetch + * e.g. a series of nops: asm volatile (".rep 8; nop; .endr"); + */ + +#include <asm/mtd-xip.h> + +#ifndef xip_irqpending + +#warning "missing IRQ and timer primitives for XIP MTD support" +#warning "some of the XIP MTD support code will be disabled" +#warning "your system will therefore be unresponsive when writing or erasing flash" + +#define xip_irqpending() (0) +#define xip_currtime() (0) +#define xip_elapsed_since(x) (0) + +#endif + +#ifndef xip_iprefetch +#define xip_iprefetch() do { } while (0) +#endif + +/* + * xip_cpu_idle() is used when waiting for a delay equal or larger than + * the system timer tick period. This should put the CPU into idle mode + * to save power and to be woken up only when some interrupts are pending. + * This should not rely upon standard kernel code. + */ +#ifndef xip_cpu_idle +#define xip_cpu_idle() do { } while (0) +#endif + +#else + +#define __xipram + +#endif /* CONFIG_MTD_XIP */ + +#endif /* __LINUX_MTD_XIP_H__ */ |