mirror of
https://github.com/edk2-porting/linux-next.git
synced 2024-12-12 07:14:03 +08:00
MTD merge for 3.13
* Unify some compile-time differences so that we have fewer uses of #ifdef CONFIG_OF in atmel_nand * Other general cleanups (removing unused functions, options, variables, fields; use correct interfaces) * Fix BUG() for new odd-sized NAND, which report non-power-of-2 dimensions via ONFI * Miscellaneous driver fixes (SPI NOR flash; BCM47xx NAND flash; etc.) * Improve differentiation between SLC and MLC NAND -- this clarifies an ABI issue regarding the MTD "type" (in sysfs and in ioctl(MEMGETINFO)), where the MTD_MLCNANDFLASH type was present but inconsistently used * Extend GPMI NAND to support multi-chip-select NAND for some platforms * Many improvements to the OMAP2/3 NAND driver, including an expanded DT binding to bring us closer to mainline support for some OMAP systems * Fix a deadlock in the error path of the Atmel NAND driver probe * Correct the error codes from MTD mmap() to conform to POSIX and the Linux Programmer's Manual. This is an acknowledged change in the MTD ABI, but I can't imagine somebody relying on the non-standard -ENOSYS error code specifically. Am I just being unimaginative? :) * Fix a few important GPMI NAND bugs (one regression from 3.12 and one long-standing race condition) * More? Read the log! -----BEGIN PGP SIGNATURE----- Version: GnuPG v1.4.14 (GNU/Linux) iQIcBAABAgAGBQJSgzYRAAoJEFySrpd9RFgtv8EP/3ZIS1w4fHyWafVSdgVFGR0Y urlVDhg7iBauh9admN9xxBz6CYRwhjby8GnN87Q1qzu95Xp63RVx31nNfdBW3DGd 92vSyskijYJcUtanBxYqGp1i3EbQcpF4mumqxnre3C4KTLNije41t/wNVqnXAstU DWho2iymZdkweKJ0DqBA7WF4l/YscdFyNDanO9JWiwII05Rh3Acv7FPMFm3Clblw Nvfwzgp4XycYMeIQtkmQgQ3GgeWtxPgQwqMofn97MVH4zeTsmUP317ohIMukLGJD db33J2xBdrIbk9P4D3RvjOCYyAyonu9y6/p+B1Vmj+R4CAUvQOIljhklHFoT3UZW OzUHPxB6T0+NZyQ/5IRQIYH9As++vdb/bzsUXm/cXceI4o4I0QCPy/8adifakBOF IUX9/BCdUOfKXvdOXY5dXMR2sY1IBg/1WfI+qcAoITsS/EVrUTrOcfSLyGqF0ERU c7mAzXiyp4D51x66/QnfJ4aJjlioQSoa3mK1j4fXqH08YB5Zclpz938Bo1AO3lWy /n+NYSbeXJoi4rVkNawjrRVs+0OTby2XQ5OqBlUMH6f30fqjUefPm66ZBMhbxzYu 5QFDctUbnHCyAPpOtM/WR3/NOkIqVhQl1331A+dG2TzLK0vTHs+kbt/YmIITpjI+ yn70XJGhk1F4gy8zhD+V =z5qO -----END PGP SIGNATURE----- Merge tag 'for-linus-20131112' of git://git.infradead.org/linux-mtd Pull MTD changes from Brian Norris: - Unify some compile-time differences so that we have fewer uses of #ifdef CONFIG_OF in atmel_nand - Other general cleanups (removing unused functions, options, variables, fields; use correct interfaces) - Fix BUG() for new odd-sized NAND, which report non-power-of-2 dimensions via ONFI - Miscellaneous driver fixes (SPI NOR flash; BCM47xx NAND flash; etc.) - Improve differentiation between SLC and MLC NAND -- this clarifies an ABI issue regarding the MTD "type" (in sysfs and in the MEMGETINFO ioctl), where the MTD_MLCNANDFLASH type was present but inconsistently used - Extend GPMI NAND to support multi-chip-select NAND for some platforms - Many improvements to the OMAP2/3 NAND driver, including an expanded DT binding to bring us closer to mainline support for some OMAP systems - Fix a deadlock in the error path of the Atmel NAND driver probe - Correct the error codes from MTD mmap() to conform to POSIX and the Linux Programmer's Manual. This is an acknowledged change in the MTD ABI, but I can't imagine somebody relying on the non-standard -ENOSYS error code specifically. Am I just being unimaginative? :) - Fix a few important GPMI NAND bugs (one regression from 3.12 and one long-standing race condition) - More? Read the log! * tag 'for-linus-20131112' of git://git.infradead.org/linux-mtd: (98 commits) mtd: gpmi: fix the NULL pointer mtd: gpmi: fix kernel BUG due to racing DMA operations mtd: mtdchar: return expected errors on mmap() call mtd: gpmi: only scan two chips for imx6 mtd: gpmi: Use devm_kzalloc() mtd: atmel_nand: fix bug driver will in a dead lock if no nand detected mtd: nand: use a local variable to simplify the nand_scan_tail mtd: nand: remove deprecated IRQF_DISABLED mtd: dataflash: Say if we find a device we don't support mtd: nand: omap: fix error return code in omap_nand_probe() mtd: nand_bbt: kill NAND_BBT_SCANALLPAGES mtd: m25p80: fixup device removal failure path mtd: mxc_nand: Include linux/of.h header mtd: remove duplicated include from mtdcore.c mtd: m25p80: add support for Macronix mx25l3255e mtd: nand: omap: remove selection of BCH ecc-scheme via KConfig mtd: nand: omap: updated devm_xx for all resource allocation and free calls mtd: nand: omap: use drivers/mtd/nand/nand_bch.c wrapper for BCH ECC instead of lib/bch.c mtd: nand: omap: clean-up ecc layout for BCH ecc schemes mtd: nand: omap2: clean-up BCHx_HW and BCHx_SW ECC configurations in device_probe ...
This commit is contained in:
commit
82cb6acea4
@ -104,7 +104,7 @@ Description:
|
||||
One of the following ASCII strings, representing the device
|
||||
type:
|
||||
|
||||
absent, ram, rom, nor, nand, dataflash, ubi, unknown
|
||||
absent, ram, rom, nor, nand, mlc-nand, dataflash, ubi, unknown
|
||||
|
||||
What: /sys/class/mtd/mtdX/writesize
|
||||
Date: April 2009
|
||||
|
@ -1222,8 +1222,6 @@ in this page</entry>
|
||||
#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
|
||||
/* Write bbt if neccecary */
|
||||
#define NAND_BBT_WRITE 0x00001000
|
||||
/* Read and write back block contents when writing bbt */
|
||||
|
@ -22,10 +22,10 @@ Optional properties:
|
||||
width of 8 is assumed.
|
||||
|
||||
- ti,nand-ecc-opt: A string setting the ECC layout to use. One of:
|
||||
|
||||
"sw" Software method (default)
|
||||
"hw" Hardware method
|
||||
"hw-romcode" gpmc hamming mode method & romcode layout
|
||||
"sw" <deprecated> use "ham1" instead
|
||||
"hw" <deprecated> use "ham1" instead
|
||||
"hw-romcode" <deprecated> use "ham1" instead
|
||||
"ham1" 1-bit Hamming ecc code
|
||||
"bch4" 4-bit BCH ecc code
|
||||
"bch8" 8-bit BCH ecc code
|
||||
|
||||
@ -36,8 +36,12 @@ Optional properties:
|
||||
"prefetch-dma" Prefetch enabled sDMA mode
|
||||
"prefetch-irq" Prefetch enabled irq mode
|
||||
|
||||
- elm_id: Specifies elm device node. This is required to support BCH
|
||||
error correction using ELM module.
|
||||
- elm_id: <deprecated> use "ti,elm-id" instead
|
||||
- ti,elm-id: Specifies phandle of the ELM devicetree node.
|
||||
ELM is an on-chip hardware engine on TI SoC which is used for
|
||||
locating ECC errors for BCHx algorithms. SoC devices which have
|
||||
ELM hardware engines should specify this device node in .dtsi
|
||||
Using ELM for ECC error correction frees some CPU cycles.
|
||||
|
||||
For inline partiton table parsing (optional):
|
||||
|
||||
|
@ -142,7 +142,7 @@ __init board_nand_init(struct mtd_partition *nand_parts, u8 nr_parts, u8 cs,
|
||||
board_nand_data.nr_parts = nr_parts;
|
||||
board_nand_data.devsize = nand_type;
|
||||
|
||||
board_nand_data.ecc_opt = OMAP_ECC_HAMMING_CODE_DEFAULT;
|
||||
board_nand_data.ecc_opt = OMAP_ECC_BCH8_CODE_HW;
|
||||
gpmc_nand_init(&board_nand_data, gpmc_t);
|
||||
}
|
||||
#endif /* CONFIG_MTD_NAND_OMAP2 || CONFIG_MTD_NAND_OMAP2_MODULE */
|
||||
|
@ -1341,14 +1341,6 @@ static void __maybe_unused gpmc_read_timings_dt(struct device_node *np,
|
||||
|
||||
#ifdef CONFIG_MTD_NAND
|
||||
|
||||
static const char * const nand_ecc_opts[] = {
|
||||
[OMAP_ECC_HAMMING_CODE_DEFAULT] = "sw",
|
||||
[OMAP_ECC_HAMMING_CODE_HW] = "hw",
|
||||
[OMAP_ECC_HAMMING_CODE_HW_ROMCODE] = "hw-romcode",
|
||||
[OMAP_ECC_BCH4_CODE_HW] = "bch4",
|
||||
[OMAP_ECC_BCH8_CODE_HW] = "bch8",
|
||||
};
|
||||
|
||||
static const char * const nand_xfer_types[] = {
|
||||
[NAND_OMAP_PREFETCH_POLLED] = "prefetch-polled",
|
||||
[NAND_OMAP_POLLED] = "polled",
|
||||
@ -1378,13 +1370,41 @@ static int gpmc_probe_nand_child(struct platform_device *pdev,
|
||||
gpmc_nand_data->cs = val;
|
||||
gpmc_nand_data->of_node = child;
|
||||
|
||||
if (!of_property_read_string(child, "ti,nand-ecc-opt", &s))
|
||||
for (val = 0; val < ARRAY_SIZE(nand_ecc_opts); val++)
|
||||
if (!strcasecmp(s, nand_ecc_opts[val])) {
|
||||
gpmc_nand_data->ecc_opt = val;
|
||||
break;
|
||||
}
|
||||
/* Detect availability of ELM module */
|
||||
gpmc_nand_data->elm_of_node = of_parse_phandle(child, "ti,elm-id", 0);
|
||||
if (gpmc_nand_data->elm_of_node == NULL)
|
||||
gpmc_nand_data->elm_of_node =
|
||||
of_parse_phandle(child, "elm_id", 0);
|
||||
if (gpmc_nand_data->elm_of_node == NULL)
|
||||
pr_warn("%s: ti,elm-id property not found\n", __func__);
|
||||
|
||||
/* select ecc-scheme for NAND */
|
||||
if (of_property_read_string(child, "ti,nand-ecc-opt", &s)) {
|
||||
pr_err("%s: ti,nand-ecc-opt not found\n", __func__);
|
||||
return -ENODEV;
|
||||
}
|
||||
if (!strcmp(s, "ham1") || !strcmp(s, "sw") ||
|
||||
!strcmp(s, "hw") || !strcmp(s, "hw-romcode"))
|
||||
gpmc_nand_data->ecc_opt =
|
||||
OMAP_ECC_HAM1_CODE_HW;
|
||||
else if (!strcmp(s, "bch4"))
|
||||
if (gpmc_nand_data->elm_of_node)
|
||||
gpmc_nand_data->ecc_opt =
|
||||
OMAP_ECC_BCH4_CODE_HW;
|
||||
else
|
||||
gpmc_nand_data->ecc_opt =
|
||||
OMAP_ECC_BCH4_CODE_HW_DETECTION_SW;
|
||||
else if (!strcmp(s, "bch8"))
|
||||
if (gpmc_nand_data->elm_of_node)
|
||||
gpmc_nand_data->ecc_opt =
|
||||
OMAP_ECC_BCH8_CODE_HW;
|
||||
else
|
||||
gpmc_nand_data->ecc_opt =
|
||||
OMAP_ECC_BCH8_CODE_HW_DETECTION_SW;
|
||||
else
|
||||
pr_err("%s: ti,nand-ecc-opt invalid value\n", __func__);
|
||||
|
||||
/* select data transfer mode for NAND controller */
|
||||
if (!of_property_read_string(child, "ti,nand-xfer-type", &s))
|
||||
for (val = 0; val < ARRAY_SIZE(nand_xfer_types); val++)
|
||||
if (!strcasecmp(s, nand_xfer_types[val])) {
|
||||
|
@ -93,6 +93,7 @@
|
||||
#define CSOR_NAND_PGS_512 0x00000000
|
||||
#define CSOR_NAND_PGS_2K 0x00080000
|
||||
#define CSOR_NAND_PGS_4K 0x00100000
|
||||
#define CSOR_NAND_PGS_8K 0x00180000
|
||||
/* Spare region Size */
|
||||
#define CSOR_NAND_SPRZ_MASK 0x0000E000
|
||||
#define CSOR_NAND_SPRZ_SHIFT 13
|
||||
@ -102,6 +103,7 @@
|
||||
#define CSOR_NAND_SPRZ_210 0x00006000
|
||||
#define CSOR_NAND_SPRZ_218 0x00008000
|
||||
#define CSOR_NAND_SPRZ_224 0x0000A000
|
||||
#define CSOR_NAND_SPRZ_CSOR_EXT 0x0000C000
|
||||
/* Pages Per Block */
|
||||
#define CSOR_NAND_PB_MASK 0x00000700
|
||||
#define CSOR_NAND_PB_SHIFT 8
|
||||
|
@ -27,11 +27,13 @@
|
||||
|
||||
/* Magics */
|
||||
#define BOARD_DATA_MAGIC 0x5246504D /* MPFR */
|
||||
#define FACTORY_MAGIC 0x59544346 /* FCTY */
|
||||
#define POT_MAGIC1 0x54544f50 /* POTT */
|
||||
#define POT_MAGIC2 0x504f /* OP */
|
||||
#define ML_MAGIC1 0x39685a42
|
||||
#define ML_MAGIC2 0x26594131
|
||||
#define TRX_MAGIC 0x30524448
|
||||
#define SQSH_MAGIC 0x71736873 /* shsq */
|
||||
|
||||
struct trx_header {
|
||||
uint32_t magic;
|
||||
@ -71,7 +73,14 @@ static int bcm47xxpart_parse(struct mtd_info *master,
|
||||
/* Alloc */
|
||||
parts = kzalloc(sizeof(struct mtd_partition) * BCM47XXPART_MAX_PARTS,
|
||||
GFP_KERNEL);
|
||||
if (!parts)
|
||||
return -ENOMEM;
|
||||
|
||||
buf = kzalloc(BCM47XXPART_BYTES_TO_READ, GFP_KERNEL);
|
||||
if (!buf) {
|
||||
kfree(parts);
|
||||
return -ENOMEM;
|
||||
}
|
||||
|
||||
/* Parse block by block looking for magics */
|
||||
for (offset = 0; offset <= master->size - blocksize;
|
||||
@ -110,6 +119,13 @@ static int bcm47xxpart_parse(struct mtd_info *master,
|
||||
continue;
|
||||
}
|
||||
|
||||
/* Found on Huawei E970 */
|
||||
if (buf[0x000 / 4] == FACTORY_MAGIC) {
|
||||
bcm47xxpart_add_part(&parts[curr_part++], "factory",
|
||||
offset, MTD_WRITEABLE);
|
||||
continue;
|
||||
}
|
||||
|
||||
/* POT(TOP) */
|
||||
if (buf[0x000 / 4] == POT_MAGIC1 &&
|
||||
(buf[0x004 / 4] & 0xFFFF) == POT_MAGIC2) {
|
||||
@ -167,6 +183,13 @@ static int bcm47xxpart_parse(struct mtd_info *master,
|
||||
offset = rounddown(offset + trx->length, blocksize);
|
||||
continue;
|
||||
}
|
||||
|
||||
/* Squashfs on devices not using TRX */
|
||||
if (buf[0x000 / 4] == SQSH_MAGIC) {
|
||||
bcm47xxpart_add_part(&parts[curr_part++], "rootfs",
|
||||
offset, 0);
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
/* Look for NVRAM at the end of the last block. */
|
||||
|
@ -95,13 +95,6 @@ config MTD_M25P80
|
||||
if you want to specify device partitioning or to use a device which
|
||||
doesn't support the JEDEC ID instruction.
|
||||
|
||||
config M25PXX_USE_FAST_READ
|
||||
bool "Use FAST_READ OPCode allowing SPI CLK >= 50MHz"
|
||||
depends on MTD_M25P80
|
||||
default y
|
||||
help
|
||||
This option enables FAST_READ access supported by ST M25Pxx.
|
||||
|
||||
config MTD_SPEAR_SMI
|
||||
tristate "SPEAR MTD NOR Support through SMI controller"
|
||||
depends on PLAT_SPEAR
|
||||
|
@ -20,6 +20,7 @@
|
||||
#include <linux/mutex.h>
|
||||
#include <linux/mount.h>
|
||||
#include <linux/slab.h>
|
||||
#include <linux/major.h>
|
||||
|
||||
/* Info for the block device */
|
||||
struct block2mtd_dev {
|
||||
|
@ -2097,7 +2097,7 @@ notfound:
|
||||
ret = -ENODEV;
|
||||
dev_info(dev, "No supported DiskOnChip found\n");
|
||||
err_probe:
|
||||
kfree(cascade->bch);
|
||||
free_bch(cascade->bch);
|
||||
for (floor = 0; floor < DOC_MAX_NBFLOORS; floor++)
|
||||
if (cascade->floors[floor])
|
||||
doc_release_device(cascade->floors[floor]);
|
||||
|
@ -78,7 +78,7 @@
|
||||
|
||||
/* Define max times to check status register before we give up. */
|
||||
#define MAX_READY_WAIT_JIFFIES (40 * HZ) /* M25P16 specs 40s max chip erase */
|
||||
#define MAX_CMD_SIZE 5
|
||||
#define MAX_CMD_SIZE 6
|
||||
|
||||
#define JEDEC_MFR(_jedec_id) ((_jedec_id) >> 16)
|
||||
|
||||
@ -367,10 +367,6 @@ static int m25p80_read(struct mtd_info *mtd, loff_t from, size_t len,
|
||||
spi_message_init(&m);
|
||||
memset(t, 0, (sizeof t));
|
||||
|
||||
/* NOTE:
|
||||
* OPCODE_FAST_READ (if available) is faster.
|
||||
* Should add 1 byte DUMMY_BYTE.
|
||||
*/
|
||||
t[0].tx_buf = flash->command;
|
||||
t[0].len = m25p_cmdsz(flash) + (flash->fast_read ? 1 : 0);
|
||||
spi_message_add_tail(&t[0], &m);
|
||||
@ -388,11 +384,6 @@ static int m25p80_read(struct mtd_info *mtd, loff_t from, size_t len,
|
||||
return 1;
|
||||
}
|
||||
|
||||
/* FIXME switch to OPCODE_FAST_READ. It's required for higher
|
||||
* clocks; and at this writing, every chip this driver handles
|
||||
* supports that opcode.
|
||||
*/
|
||||
|
||||
/* Set up the write data buffer. */
|
||||
opcode = flash->read_opcode;
|
||||
flash->command[0] = opcode;
|
||||
@ -749,16 +740,19 @@ static const struct spi_device_id m25p_ids[] = {
|
||||
{ "at45db081d", INFO(0x1f2500, 0, 64 * 1024, 16, SECT_4K) },
|
||||
|
||||
/* EON -- en25xxx */
|
||||
{ "en25f32", INFO(0x1c3116, 0, 64 * 1024, 64, SECT_4K) },
|
||||
{ "en25p32", INFO(0x1c2016, 0, 64 * 1024, 64, 0) },
|
||||
{ "en25q32b", INFO(0x1c3016, 0, 64 * 1024, 64, 0) },
|
||||
{ "en25p64", INFO(0x1c2017, 0, 64 * 1024, 128, 0) },
|
||||
{ "en25q64", INFO(0x1c3017, 0, 64 * 1024, 128, SECT_4K) },
|
||||
{ "en25qh256", INFO(0x1c7019, 0, 64 * 1024, 512, 0) },
|
||||
{ "en25f32", INFO(0x1c3116, 0, 64 * 1024, 64, SECT_4K) },
|
||||
{ "en25p32", INFO(0x1c2016, 0, 64 * 1024, 64, 0) },
|
||||
{ "en25q32b", INFO(0x1c3016, 0, 64 * 1024, 64, 0) },
|
||||
{ "en25p64", INFO(0x1c2017, 0, 64 * 1024, 128, 0) },
|
||||
{ "en25q64", INFO(0x1c3017, 0, 64 * 1024, 128, SECT_4K) },
|
||||
{ "en25qh256", INFO(0x1c7019, 0, 64 * 1024, 512, 0) },
|
||||
|
||||
/* ESMT */
|
||||
{ "f25l32pa", INFO(0x8c2016, 0, 64 * 1024, 64, SECT_4K) },
|
||||
|
||||
/* Everspin */
|
||||
{ "mr25h256", CAT25_INFO( 32 * 1024, 1, 256, 2, M25P_NO_ERASE | M25P_NO_FR) },
|
||||
{ "mr25h10", CAT25_INFO(128 * 1024, 1, 256, 3, M25P_NO_ERASE | M25P_NO_FR) },
|
||||
{ "mr25h256", CAT25_INFO( 32 * 1024, 1, 256, 2, M25P_NO_ERASE | M25P_NO_FR) },
|
||||
{ "mr25h10", CAT25_INFO(128 * 1024, 1, 256, 3, M25P_NO_ERASE | M25P_NO_FR) },
|
||||
|
||||
/* GigaDevice */
|
||||
{ "gd25q32", INFO(0xc84016, 0, 64 * 1024, 64, SECT_4K) },
|
||||
@ -775,6 +769,7 @@ static const struct spi_device_id m25p_ids[] = {
|
||||
{ "mx25l8005", INFO(0xc22014, 0, 64 * 1024, 16, 0) },
|
||||
{ "mx25l1606e", INFO(0xc22015, 0, 64 * 1024, 32, SECT_4K) },
|
||||
{ "mx25l3205d", INFO(0xc22016, 0, 64 * 1024, 64, 0) },
|
||||
{ "mx25l3255e", INFO(0xc29e16, 0, 64 * 1024, 64, SECT_4K) },
|
||||
{ "mx25l6405d", INFO(0xc22017, 0, 64 * 1024, 128, 0) },
|
||||
{ "mx25l12805d", INFO(0xc22018, 0, 64 * 1024, 256, 0) },
|
||||
{ "mx25l12855e", INFO(0xc22618, 0, 64 * 1024, 256, 0) },
|
||||
@ -783,15 +778,16 @@ static const struct spi_device_id m25p_ids[] = {
|
||||
{ "mx66l51235l", INFO(0xc2201a, 0, 64 * 1024, 1024, 0) },
|
||||
|
||||
/* Micron */
|
||||
{ "n25q064", INFO(0x20ba17, 0, 64 * 1024, 128, 0) },
|
||||
{ "n25q128a11", INFO(0x20bb18, 0, 64 * 1024, 256, 0) },
|
||||
{ "n25q128a13", INFO(0x20ba18, 0, 64 * 1024, 256, 0) },
|
||||
{ "n25q256a", INFO(0x20ba19, 0, 64 * 1024, 512, SECT_4K) },
|
||||
{ "n25q064", INFO(0x20ba17, 0, 64 * 1024, 128, 0) },
|
||||
{ "n25q128a11", INFO(0x20bb18, 0, 64 * 1024, 256, 0) },
|
||||
{ "n25q128a13", INFO(0x20ba18, 0, 64 * 1024, 256, 0) },
|
||||
{ "n25q256a", INFO(0x20ba19, 0, 64 * 1024, 512, SECT_4K) },
|
||||
{ "n25q512a", INFO(0x20bb20, 0, 64 * 1024, 1024, SECT_4K) },
|
||||
|
||||
/* PMC */
|
||||
{ "pm25lv512", INFO(0, 0, 32 * 1024, 2, SECT_4K_PMC) },
|
||||
{ "pm25lv010", INFO(0, 0, 32 * 1024, 4, SECT_4K_PMC) },
|
||||
{ "pm25lq032", INFO(0x7f9d46, 0, 64 * 1024, 64, SECT_4K) },
|
||||
{ "pm25lv512", INFO(0, 0, 32 * 1024, 2, SECT_4K_PMC) },
|
||||
{ "pm25lv010", INFO(0, 0, 32 * 1024, 4, SECT_4K_PMC) },
|
||||
{ "pm25lq032", INFO(0x7f9d46, 0, 64 * 1024, 64, SECT_4K) },
|
||||
|
||||
/* Spansion -- single (large) sector size only, at least
|
||||
* for the chips listed here (without boot sectors).
|
||||
@ -940,12 +936,7 @@ static int m25p_probe(struct spi_device *spi)
|
||||
struct flash_info *info;
|
||||
unsigned i;
|
||||
struct mtd_part_parser_data ppdata;
|
||||
struct device_node __maybe_unused *np = spi->dev.of_node;
|
||||
|
||||
#ifdef CONFIG_MTD_OF_PARTS
|
||||
if (!of_device_is_available(np))
|
||||
return -ENODEV;
|
||||
#endif
|
||||
struct device_node *np = spi->dev.of_node;
|
||||
|
||||
/* Platform data helps sort out which chip type we have, as
|
||||
* well as how this board partitions it. If we don't have
|
||||
@ -992,15 +983,13 @@ static int m25p_probe(struct spi_device *spi)
|
||||
}
|
||||
}
|
||||
|
||||
flash = kzalloc(sizeof *flash, GFP_KERNEL);
|
||||
flash = devm_kzalloc(&spi->dev, sizeof(*flash), GFP_KERNEL);
|
||||
if (!flash)
|
||||
return -ENOMEM;
|
||||
flash->command = kmalloc(MAX_CMD_SIZE + (flash->fast_read ? 1 : 0),
|
||||
GFP_KERNEL);
|
||||
if (!flash->command) {
|
||||
kfree(flash);
|
||||
|
||||
flash->command = devm_kzalloc(&spi->dev, MAX_CMD_SIZE, GFP_KERNEL);
|
||||
if (!flash->command)
|
||||
return -ENOMEM;
|
||||
}
|
||||
|
||||
flash->spi = spi;
|
||||
mutex_init(&flash->lock);
|
||||
@ -1062,13 +1051,14 @@ static int m25p_probe(struct spi_device *spi)
|
||||
flash->page_size = info->page_size;
|
||||
flash->mtd.writebufsize = flash->page_size;
|
||||
|
||||
flash->fast_read = false;
|
||||
if (np && of_property_read_bool(np, "m25p,fast-read"))
|
||||
if (np)
|
||||
/* If we were instantiated by DT, use it */
|
||||
flash->fast_read = of_property_read_bool(np, "m25p,fast-read");
|
||||
else
|
||||
/* If we weren't instantiated by DT, default to fast-read */
|
||||
flash->fast_read = true;
|
||||
|
||||
#ifdef CONFIG_M25PXX_USE_FAST_READ
|
||||
flash->fast_read = true;
|
||||
#endif
|
||||
/* Some devices cannot do fast-read, no matter what DT tells us */
|
||||
if (info->flags & M25P_NO_FR)
|
||||
flash->fast_read = false;
|
||||
|
||||
@ -1133,15 +1123,9 @@ static int m25p_probe(struct spi_device *spi)
|
||||
static int m25p_remove(struct spi_device *spi)
|
||||
{
|
||||
struct m25p *flash = spi_get_drvdata(spi);
|
||||
int status;
|
||||
|
||||
/* Clean up MTD stuff. */
|
||||
status = mtd_device_unregister(&flash->mtd);
|
||||
if (status == 0) {
|
||||
kfree(flash->command);
|
||||
kfree(flash);
|
||||
}
|
||||
return 0;
|
||||
return mtd_device_unregister(&flash->mtd);
|
||||
}
|
||||
|
||||
|
||||
|
@ -88,8 +88,6 @@ struct dataflash {
|
||||
uint8_t command[4];
|
||||
char name[24];
|
||||
|
||||
unsigned partitioned:1;
|
||||
|
||||
unsigned short page_offset; /* offset in flash address */
|
||||
unsigned int page_size; /* of bytes per page */
|
||||
|
||||
@ -881,7 +879,7 @@ static int dataflash_probe(struct spi_device *spi)
|
||||
break;
|
||||
/* obsolete AT45DB1282 not (yet?) supported */
|
||||
default:
|
||||
pr_debug("%s: unsupported device (%x)\n", dev_name(&spi->dev),
|
||||
dev_info(&spi->dev, "unsupported device (%x)\n",
|
||||
status & 0x3c);
|
||||
status = -ENODEV;
|
||||
}
|
||||
|
@ -94,7 +94,7 @@ static void unregister_devices(void)
|
||||
}
|
||||
}
|
||||
|
||||
static int register_device(char *name, unsigned long start, unsigned long len)
|
||||
static int register_device(char *name, phys_addr_t start, size_t len)
|
||||
{
|
||||
struct phram_mtd_list *new;
|
||||
int ret = -ENOMEM;
|
||||
@ -141,35 +141,35 @@ out0:
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int ustrtoul(const char *cp, char **endp, unsigned int base)
|
||||
static int parse_num64(uint64_t *num64, char *token)
|
||||
{
|
||||
unsigned long result = simple_strtoul(cp, endp, base);
|
||||
size_t len;
|
||||
int shift = 0;
|
||||
int ret;
|
||||
|
||||
switch (**endp) {
|
||||
case 'G':
|
||||
result *= 1024;
|
||||
case 'M':
|
||||
result *= 1024;
|
||||
case 'k':
|
||||
result *= 1024;
|
||||
len = strlen(token);
|
||||
/* By dwmw2 editorial decree, "ki", "Mi" or "Gi" are to be used. */
|
||||
if ((*endp)[1] == 'i')
|
||||
(*endp) += 2;
|
||||
if (len > 2) {
|
||||
if (token[len - 1] == 'i') {
|
||||
switch (token[len - 2]) {
|
||||
case 'G':
|
||||
shift += 10;
|
||||
case 'M':
|
||||
shift += 10;
|
||||
case 'k':
|
||||
shift += 10;
|
||||
token[len - 2] = 0;
|
||||
break;
|
||||
default:
|
||||
return -EINVAL;
|
||||
}
|
||||
}
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
static int parse_num32(uint32_t *num32, const char *token)
|
||||
{
|
||||
char *endp;
|
||||
unsigned long n;
|
||||
ret = kstrtou64(token, 0, num64);
|
||||
*num64 <<= shift;
|
||||
|
||||
n = ustrtoul(token, &endp, 0);
|
||||
if (*endp)
|
||||
return -EINVAL;
|
||||
|
||||
*num32 = n;
|
||||
return 0;
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int parse_name(char **pname, const char *token)
|
||||
@ -209,19 +209,19 @@ static inline void kill_final_newline(char *str)
|
||||
* This shall contain the module parameter if any. It is of the form:
|
||||
* - phram=<device>,<address>,<size> for module case
|
||||
* - phram.phram=<device>,<address>,<size> for built-in case
|
||||
* We leave 64 bytes for the device name, 12 for the address and 12 for the
|
||||
* We leave 64 bytes for the device name, 20 for the address and 20 for the
|
||||
* size.
|
||||
* Example: phram.phram=rootfs,0xa0000000,512Mi
|
||||
*/
|
||||
static __initdata char phram_paramline[64+12+12];
|
||||
static __initdata char phram_paramline[64 + 20 + 20];
|
||||
|
||||
static int __init phram_setup(const char *val)
|
||||
{
|
||||
char buf[64+12+12], *str = buf;
|
||||
char buf[64 + 20 + 20], *str = buf;
|
||||
char *token[3];
|
||||
char *name;
|
||||
uint32_t start;
|
||||
uint32_t len;
|
||||
uint64_t start;
|
||||
uint64_t len;
|
||||
int i, ret;
|
||||
|
||||
if (strnlen(val, sizeof(buf)) >= sizeof(buf))
|
||||
@ -243,13 +243,13 @@ static int __init phram_setup(const char *val)
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
ret = parse_num32(&start, token[1]);
|
||||
ret = parse_num64(&start, token[1]);
|
||||
if (ret) {
|
||||
kfree(name);
|
||||
parse_err("illegal start address\n");
|
||||
}
|
||||
|
||||
ret = parse_num32(&len, token[2]);
|
||||
ret = parse_num64(&len, token[2]);
|
||||
if (ret) {
|
||||
kfree(name);
|
||||
parse_err("illegal device length\n");
|
||||
@ -257,7 +257,7 @@ static int __init phram_setup(const char *val)
|
||||
|
||||
ret = register_device(name, start, len);
|
||||
if (!ret)
|
||||
pr_info("%s device: %#x at %#x\n", name, len, start);
|
||||
pr_info("%s device: %#llx at %#llx\n", name, len, start);
|
||||
else
|
||||
kfree(name);
|
||||
|
||||
|
@ -364,7 +364,7 @@ static int sst25l_probe(struct spi_device *spi)
|
||||
if (!flash_info)
|
||||
return -ENODEV;
|
||||
|
||||
flash = kzalloc(sizeof(struct sst25l_flash), GFP_KERNEL);
|
||||
flash = devm_kzalloc(&spi->dev, sizeof(*flash), GFP_KERNEL);
|
||||
if (!flash)
|
||||
return -ENOMEM;
|
||||
|
||||
@ -402,11 +402,8 @@ static int sst25l_probe(struct spi_device *spi)
|
||||
ret = mtd_device_parse_register(&flash->mtd, NULL, NULL,
|
||||
data ? data->parts : NULL,
|
||||
data ? data->nr_parts : 0);
|
||||
if (ret) {
|
||||
kfree(flash);
|
||||
spi_set_drvdata(spi, NULL);
|
||||
if (ret)
|
||||
return -ENODEV;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
@ -414,12 +411,8 @@ static int sst25l_probe(struct spi_device *spi)
|
||||
static int sst25l_remove(struct spi_device *spi)
|
||||
{
|
||||
struct sst25l_flash *flash = spi_get_drvdata(spi);
|
||||
int ret;
|
||||
|
||||
ret = mtd_device_unregister(&flash->mtd);
|
||||
if (ret == 0)
|
||||
kfree(flash);
|
||||
return ret;
|
||||
return mtd_device_unregister(&flash->mtd);
|
||||
}
|
||||
|
||||
static struct spi_driver sst25l_driver = {
|
||||
|
@ -50,7 +50,7 @@ static void inftl_add_mtd(struct mtd_blktrans_ops *tr, struct mtd_info *mtd)
|
||||
struct INFTLrecord *inftl;
|
||||
unsigned long temp;
|
||||
|
||||
if (mtd->type != MTD_NANDFLASH || mtd->size > UINT_MAX)
|
||||
if (!mtd_type_is_nand(mtd) || mtd->size > UINT_MAX)
|
||||
return;
|
||||
/* OK, this is moderately ugly. But probably safe. Alternatives? */
|
||||
if (memcmp(mtd->name, "DiskOnChip", 10))
|
||||
|
@ -703,7 +703,7 @@ static int lpddr_erase(struct mtd_info *mtd, struct erase_info *instr)
|
||||
|
||||
#define DO_XXLOCK_LOCK 1
|
||||
#define DO_XXLOCK_UNLOCK 2
|
||||
int do_xxlock(struct mtd_info *mtd, loff_t adr, uint32_t len, int thunk)
|
||||
static int do_xxlock(struct mtd_info *mtd, loff_t adr, uint32_t len, int thunk)
|
||||
{
|
||||
int ret = 0;
|
||||
struct map_info *map = mtd->priv;
|
||||
|
@ -180,7 +180,6 @@ static void vr_nor_pci_remove(struct pci_dev *dev)
|
||||
{
|
||||
struct vr_nor_mtd *p = pci_get_drvdata(dev);
|
||||
|
||||
pci_set_drvdata(dev, NULL);
|
||||
vr_nor_destroy_partitions(p);
|
||||
vr_nor_destroy_mtd_setup(p);
|
||||
vr_nor_destroy_maps(p);
|
||||
|
@ -316,7 +316,6 @@ static void mtd_pci_remove(struct pci_dev *dev)
|
||||
map->exit(dev, map);
|
||||
kfree(map);
|
||||
|
||||
pci_set_drvdata(dev, NULL);
|
||||
pci_release_regions(dev);
|
||||
}
|
||||
|
||||
|
@ -55,7 +55,7 @@ struct platram_info {
|
||||
|
||||
static inline struct platram_info *to_platram_info(struct platform_device *dev)
|
||||
{
|
||||
return (struct platram_info *)platform_get_drvdata(dev);
|
||||
return platform_get_drvdata(dev);
|
||||
}
|
||||
|
||||
/* platram_setrw
|
||||
@ -257,21 +257,7 @@ static struct platform_driver platram_driver = {
|
||||
},
|
||||
};
|
||||
|
||||
/* module init/exit */
|
||||
|
||||
static int __init platram_init(void)
|
||||
{
|
||||
printk("Generic platform RAM MTD, (c) 2004 Simtec Electronics\n");
|
||||
return platform_driver_register(&platram_driver);
|
||||
}
|
||||
|
||||
static void __exit platram_exit(void)
|
||||
{
|
||||
platform_driver_unregister(&platram_driver);
|
||||
}
|
||||
|
||||
module_init(platram_init);
|
||||
module_exit(platram_exit);
|
||||
module_platform_driver(platram_driver);
|
||||
|
||||
MODULE_LICENSE("GPL");
|
||||
MODULE_AUTHOR("Ben Dooks <ben@simtec.co.uk>");
|
||||
|
@ -212,7 +212,6 @@ static void scb2_flash_remove(struct pci_dev *dev)
|
||||
|
||||
if (!region_fail)
|
||||
release_mem_region(SCB2_ADDR, SCB2_WINDOW);
|
||||
pci_set_drvdata(dev, NULL);
|
||||
}
|
||||
|
||||
static struct pci_device_id scb2_flash_pci_ids[] = {
|
||||
|
@ -32,6 +32,7 @@
|
||||
#include <linux/mtd/mtd.h>
|
||||
#include <linux/mtd/blktrans.h>
|
||||
#include <linux/mutex.h>
|
||||
#include <linux/major.h>
|
||||
|
||||
|
||||
struct mtdblk_dev {
|
||||
@ -373,7 +374,7 @@ static void mtdblock_remove_dev(struct mtd_blktrans_dev *dev)
|
||||
|
||||
static struct mtd_blktrans_ops mtdblock_tr = {
|
||||
.name = "mtdblock",
|
||||
.major = 31,
|
||||
.major = MTD_BLOCK_MAJOR,
|
||||
.part_bits = 0,
|
||||
.blksize = 512,
|
||||
.open = mtdblock_open,
|
||||
|
@ -24,6 +24,7 @@
|
||||
#include <linux/mtd/mtd.h>
|
||||
#include <linux/mtd/blktrans.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/major.h>
|
||||
|
||||
static int mtdblock_readsect(struct mtd_blktrans_dev *dev,
|
||||
unsigned long block, char *buf)
|
||||
@ -70,7 +71,7 @@ static void mtdblock_remove_dev(struct mtd_blktrans_dev *dev)
|
||||
|
||||
static struct mtd_blktrans_ops mtdblock_tr = {
|
||||
.name = "mtdblock",
|
||||
.major = 31,
|
||||
.major = MTD_BLOCK_MAJOR,
|
||||
.part_bits = 0,
|
||||
.blksize = 512,
|
||||
.readsect = mtdblock_readsect,
|
||||
|
@ -32,6 +32,7 @@
|
||||
#include <linux/mount.h>
|
||||
#include <linux/blkpg.h>
|
||||
#include <linux/magic.h>
|
||||
#include <linux/major.h>
|
||||
#include <linux/mtd/mtd.h>
|
||||
#include <linux/mtd/partitions.h>
|
||||
#include <linux/mtd/map.h>
|
||||
@ -1099,7 +1100,7 @@ static unsigned long mtdchar_get_unmapped_area(struct file *file,
|
||||
return (unsigned long) -EINVAL;
|
||||
|
||||
ret = mtd_get_unmapped_area(mtd, len, offset, flags);
|
||||
return ret == -EOPNOTSUPP ? -ENOSYS : ret;
|
||||
return ret == -EOPNOTSUPP ? -ENODEV : ret;
|
||||
}
|
||||
#endif
|
||||
|
||||
@ -1124,9 +1125,9 @@ static int mtdchar_mmap(struct file *file, struct vm_area_struct *vma)
|
||||
#endif
|
||||
return vm_iomap_memory(vma, map->phys, map->size);
|
||||
}
|
||||
return -ENOSYS;
|
||||
return -ENODEV;
|
||||
#else
|
||||
return vma->vm_flags & VM_SHARED ? 0 : -ENOSYS;
|
||||
return vma->vm_flags & VM_SHARED ? 0 : -EACCES;
|
||||
#endif
|
||||
}
|
||||
|
||||
|
@ -157,6 +157,9 @@ static ssize_t mtd_type_show(struct device *dev,
|
||||
case MTD_UBIVOLUME:
|
||||
type = "ubi";
|
||||
break;
|
||||
case MTD_MLCNANDFLASH:
|
||||
type = "mlc-nand";
|
||||
break;
|
||||
default:
|
||||
type = "unknown";
|
||||
}
|
||||
|
@ -17,6 +17,7 @@
|
||||
#include <linux/export.h>
|
||||
#include <linux/ctype.h>
|
||||
#include <linux/slab.h>
|
||||
#include <linux/major.h>
|
||||
|
||||
/*
|
||||
* compare superblocks to see if they're equivalent
|
||||
|
@ -96,43 +96,15 @@ config MTD_NAND_OMAP2
|
||||
|
||||
config MTD_NAND_OMAP_BCH
|
||||
depends on MTD_NAND && MTD_NAND_OMAP2 && ARCH_OMAP3
|
||||
tristate "Enable support for hardware BCH error correction"
|
||||
tristate "Support hardware based BCH error correction"
|
||||
default n
|
||||
select BCH
|
||||
select BCH_CONST_PARAMS
|
||||
help
|
||||
Support for hardware BCH error correction.
|
||||
|
||||
choice
|
||||
prompt "BCH error correction capability"
|
||||
depends on MTD_NAND_OMAP_BCH
|
||||
|
||||
config MTD_NAND_OMAP_BCH8
|
||||
bool "8 bits / 512 bytes (recommended)"
|
||||
help
|
||||
Support correcting up to 8 bitflips per 512-byte block.
|
||||
This will use 13 bytes of spare area per 512 bytes of page data.
|
||||
This is the recommended mode, as 4-bit mode does not work
|
||||
on some OMAP3 revisions, due to a hardware bug.
|
||||
|
||||
config MTD_NAND_OMAP_BCH4
|
||||
bool "4 bits / 512 bytes"
|
||||
help
|
||||
Support correcting up to 4 bitflips per 512-byte block.
|
||||
This will use 7 bytes of spare area per 512 bytes of page data.
|
||||
Note that this mode does not work on some OMAP3 revisions, due to a
|
||||
hardware bug. Please check your OMAP datasheet before selecting this
|
||||
mode.
|
||||
|
||||
endchoice
|
||||
|
||||
if MTD_NAND_OMAP_BCH
|
||||
config BCH_CONST_M
|
||||
default 13
|
||||
config BCH_CONST_T
|
||||
default 4 if MTD_NAND_OMAP_BCH4
|
||||
default 8 if MTD_NAND_OMAP_BCH8
|
||||
endif
|
||||
This config enables the ELM hardware engine, which can be used to
|
||||
locate and correct errors when using BCH ECC scheme. This offloads
|
||||
the cpu from doing ECC error searching and correction. However some
|
||||
legacy OMAP families like OMAP2xxx, OMAP3xxx do not have ELM engine
|
||||
so they should not enable this config symbol.
|
||||
|
||||
config MTD_NAND_IDS
|
||||
tristate
|
||||
|
@ -1062,56 +1062,28 @@ static void atmel_pmecc_core_init(struct mtd_info *mtd)
|
||||
}
|
||||
|
||||
/*
|
||||
* Get ECC requirement in ONFI parameters, returns -1 if ONFI
|
||||
* parameters is not supported.
|
||||
* return 0 if success to get the ECC requirement.
|
||||
*/
|
||||
static int get_onfi_ecc_param(struct nand_chip *chip,
|
||||
int *ecc_bits, int *sector_size)
|
||||
{
|
||||
*ecc_bits = *sector_size = 0;
|
||||
|
||||
if (chip->onfi_params.ecc_bits == 0xff)
|
||||
/* TODO: the sector_size and ecc_bits need to be find in
|
||||
* extended ecc parameter, currently we don't support it.
|
||||
*/
|
||||
return -1;
|
||||
|
||||
*ecc_bits = chip->onfi_params.ecc_bits;
|
||||
|
||||
/* The default sector size (ecc codeword size) is 512 */
|
||||
*sector_size = 512;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* Get ecc requirement from ONFI parameters ecc requirement.
|
||||
* Get minimum ecc requirements from NAND.
|
||||
* If pmecc-cap, pmecc-sector-size in DTS are not specified, this function
|
||||
* will set them according to ONFI ecc requirement. Otherwise, use the
|
||||
* will set them according to minimum ecc requirement. Otherwise, use the
|
||||
* value in DTS file.
|
||||
* return 0 if success. otherwise return error code.
|
||||
*/
|
||||
static int pmecc_choose_ecc(struct atmel_nand_host *host,
|
||||
int *cap, int *sector_size)
|
||||
{
|
||||
/* Get ECC requirement from ONFI parameters */
|
||||
*cap = *sector_size = 0;
|
||||
if (host->nand_chip.onfi_version) {
|
||||
if (!get_onfi_ecc_param(&host->nand_chip, cap, sector_size))
|
||||
dev_info(host->dev, "ONFI params, minimum required ECC: %d bits in %d bytes\n",
|
||||
/* Get minimum ECC requirements */
|
||||
if (host->nand_chip.ecc_strength_ds) {
|
||||
*cap = host->nand_chip.ecc_strength_ds;
|
||||
*sector_size = host->nand_chip.ecc_step_ds;
|
||||
dev_info(host->dev, "minimum ECC: %d bits in %d bytes\n",
|
||||
*cap, *sector_size);
|
||||
else
|
||||
dev_info(host->dev, "NAND chip ECC reqirement is in Extended ONFI parameter, we don't support yet.\n");
|
||||
} else {
|
||||
dev_info(host->dev, "NAND chip is not ONFI compliant, assume ecc_bits is 2 in 512 bytes");
|
||||
}
|
||||
if (*cap == 0 && *sector_size == 0) {
|
||||
*cap = 2;
|
||||
*sector_size = 512;
|
||||
dev_info(host->dev, "can't detect min. ECC, assume 2 bits in 512 bytes\n");
|
||||
}
|
||||
|
||||
/* If dts file doesn't specify then use the one in ONFI parameters */
|
||||
/* If device tree doesn't specify, use NAND's minimum ECC parameters */
|
||||
if (host->pmecc_corr_cap == 0) {
|
||||
/* use the most fitable ecc bits (the near bigger one ) */
|
||||
if (*cap <= 2)
|
||||
@ -1449,7 +1421,6 @@ static void atmel_nand_hwctl(struct mtd_info *mtd, int mode)
|
||||
ecc_writel(host->ecc, CR, ATMEL_ECC_RST);
|
||||
}
|
||||
|
||||
#if defined(CONFIG_OF)
|
||||
static int atmel_of_init_port(struct atmel_nand_host *host,
|
||||
struct device_node *np)
|
||||
{
|
||||
@ -1457,7 +1428,7 @@ static int atmel_of_init_port(struct atmel_nand_host *host,
|
||||
u32 offset[2];
|
||||
int ecc_mode;
|
||||
struct atmel_nand_data *board = &host->board;
|
||||
enum of_gpio_flags flags;
|
||||
enum of_gpio_flags flags = 0;
|
||||
|
||||
if (of_property_read_u32(np, "atmel,nand-addr-offset", &val) == 0) {
|
||||
if (val >= 32) {
|
||||
@ -1540,13 +1511,6 @@ static int atmel_of_init_port(struct atmel_nand_host *host,
|
||||
|
||||
return 0;
|
||||
}
|
||||
#else
|
||||
static int atmel_of_init_port(struct atmel_nand_host *host,
|
||||
struct device_node *np)
|
||||
{
|
||||
return -EINVAL;
|
||||
}
|
||||
#endif
|
||||
|
||||
static int atmel_hw_nand_init_params(struct platform_device *pdev,
|
||||
struct atmel_nand_host *host)
|
||||
@ -2019,7 +1983,8 @@ static int atmel_nand_probe(struct platform_device *pdev)
|
||||
mtd = &host->mtd;
|
||||
nand_chip = &host->nand_chip;
|
||||
host->dev = &pdev->dev;
|
||||
if (pdev->dev.of_node) {
|
||||
if (IS_ENABLED(CONFIG_OF) && pdev->dev.of_node) {
|
||||
/* Only when CONFIG_OF is enabled of_node can be parsed */
|
||||
res = atmel_of_init_port(host, pdev->dev.of_node);
|
||||
if (res)
|
||||
goto err_nand_ioremap;
|
||||
@ -2177,7 +2142,6 @@ err_no_card:
|
||||
if (host->dma_chan)
|
||||
dma_release_channel(host->dma_chan);
|
||||
err_nand_ioremap:
|
||||
platform_driver_unregister(&atmel_nand_nfc_driver);
|
||||
return res;
|
||||
}
|
||||
|
||||
@ -2207,14 +2171,12 @@ static int atmel_nand_remove(struct platform_device *pdev)
|
||||
return 0;
|
||||
}
|
||||
|
||||
#if defined(CONFIG_OF)
|
||||
static const struct of_device_id atmel_nand_dt_ids[] = {
|
||||
{ .compatible = "atmel,at91rm9200-nand" },
|
||||
{ /* sentinel */ }
|
||||
};
|
||||
|
||||
MODULE_DEVICE_TABLE(of, atmel_nand_dt_ids);
|
||||
#endif
|
||||
|
||||
static int atmel_nand_nfc_probe(struct platform_device *pdev)
|
||||
{
|
||||
@ -2253,12 +2215,11 @@ static int atmel_nand_nfc_probe(struct platform_device *pdev)
|
||||
return 0;
|
||||
}
|
||||
|
||||
#if defined(CONFIG_OF)
|
||||
static struct of_device_id atmel_nand_nfc_match[] = {
|
||||
static const struct of_device_id atmel_nand_nfc_match[] = {
|
||||
{ .compatible = "atmel,sama5d3-nfc" },
|
||||
{ /* sentinel */ }
|
||||
};
|
||||
#endif
|
||||
MODULE_DEVICE_TABLE(of, atmel_nand_nfc_match);
|
||||
|
||||
static struct platform_driver atmel_nand_nfc_driver = {
|
||||
.driver = {
|
||||
|
@ -29,11 +29,9 @@ static int bcm47xxnflash_probe(struct platform_device *pdev)
|
||||
struct bcm47xxnflash *b47n;
|
||||
int err = 0;
|
||||
|
||||
b47n = kzalloc(sizeof(*b47n), GFP_KERNEL);
|
||||
if (!b47n) {
|
||||
err = -ENOMEM;
|
||||
goto out;
|
||||
}
|
||||
b47n = devm_kzalloc(&pdev->dev, sizeof(*b47n), GFP_KERNEL);
|
||||
if (!b47n)
|
||||
return -ENOMEM;
|
||||
|
||||
b47n->nand_chip.priv = b47n;
|
||||
b47n->mtd.owner = THIS_MODULE;
|
||||
@ -48,22 +46,16 @@ static int bcm47xxnflash_probe(struct platform_device *pdev)
|
||||
}
|
||||
if (err) {
|
||||
pr_err("Initialization failed: %d\n", err);
|
||||
goto err_init;
|
||||
return err;
|
||||
}
|
||||
|
||||
err = mtd_device_parse_register(&b47n->mtd, probes, NULL, NULL, 0);
|
||||
if (err) {
|
||||
pr_err("Failed to register MTD device: %d\n", err);
|
||||
goto err_dev_reg;
|
||||
return err;
|
||||
}
|
||||
|
||||
return 0;
|
||||
|
||||
err_dev_reg:
|
||||
err_init:
|
||||
kfree(b47n);
|
||||
out:
|
||||
return err;
|
||||
}
|
||||
|
||||
static int bcm47xxnflash_remove(struct platform_device *pdev)
|
||||
@ -85,22 +77,4 @@ static struct platform_driver bcm47xxnflash_driver = {
|
||||
},
|
||||
};
|
||||
|
||||
static int __init bcm47xxnflash_init(void)
|
||||
{
|
||||
int err;
|
||||
|
||||
err = platform_driver_register(&bcm47xxnflash_driver);
|
||||
if (err)
|
||||
pr_err("Failed to register bcm47xx nand flash driver: %d\n",
|
||||
err);
|
||||
|
||||
return err;
|
||||
}
|
||||
|
||||
static void __exit bcm47xxnflash_exit(void)
|
||||
{
|
||||
platform_driver_unregister(&bcm47xxnflash_driver);
|
||||
}
|
||||
|
||||
module_init(bcm47xxnflash_init);
|
||||
module_exit(bcm47xxnflash_exit);
|
||||
module_platform_driver(bcm47xxnflash_driver);
|
||||
|
@ -1394,7 +1394,7 @@ static struct nand_bbt_descr bbt_mirror_descr = {
|
||||
};
|
||||
|
||||
/* initialize driver data structures */
|
||||
void denali_drv_init(struct denali_nand_info *denali)
|
||||
static void denali_drv_init(struct denali_nand_info *denali)
|
||||
{
|
||||
denali->idx = 0;
|
||||
|
||||
@ -1520,7 +1520,7 @@ int denali_init(struct denali_nand_info *denali)
|
||||
* so just let controller do 15bit ECC for MLC and 8bit ECC for
|
||||
* SLC if possible.
|
||||
* */
|
||||
if (denali->nand.cellinfo & NAND_CI_CELLTYPE_MSK &&
|
||||
if (!nand_is_slc(&denali->nand) &&
|
||||
(denali->mtd.oobsize > (denali->bbtskipbytes +
|
||||
ECC_15BITS * (denali->mtd.writesize /
|
||||
ECC_SECTOR_SIZE)))) {
|
||||
|
@ -119,7 +119,6 @@ static void denali_pci_remove(struct pci_dev *dev)
|
||||
iounmap(denali->flash_mem);
|
||||
pci_release_regions(dev);
|
||||
pci_disable_device(dev);
|
||||
pci_set_drvdata(dev, NULL);
|
||||
kfree(denali);
|
||||
}
|
||||
|
||||
|
@ -38,7 +38,7 @@
|
||||
#define CONFIG_MTD_NAND_DISKONCHIP_PROBE_ADDRESS 0
|
||||
#endif
|
||||
|
||||
static unsigned long __initdata doc_locations[] = {
|
||||
static unsigned long doc_locations[] __initdata = {
|
||||
#if defined (__alpha__) || defined(__i386__) || defined(__x86_64__)
|
||||
#ifdef CONFIG_MTD_NAND_DISKONCHIP_PROBE_HIGH
|
||||
0xfffc8000, 0xfffca000, 0xfffcc000, 0xfffce000,
|
||||
|
@ -44,6 +44,7 @@
|
||||
#include <linux/mtd/nand.h>
|
||||
#include <linux/bch.h>
|
||||
#include <linux/bitrev.h>
|
||||
#include <linux/jiffies.h>
|
||||
|
||||
/*
|
||||
* In "reliable mode" consecutive 2k pages are used in parallel (in some
|
||||
@ -269,7 +270,7 @@ static int poll_status(struct docg4_priv *doc)
|
||||
*/
|
||||
|
||||
uint16_t flash_status;
|
||||
unsigned int timeo;
|
||||
unsigned long timeo;
|
||||
void __iomem *docptr = doc->virtadr;
|
||||
|
||||
dev_dbg(doc->dev, "%s...\n", __func__);
|
||||
@ -277,22 +278,18 @@ static int poll_status(struct docg4_priv *doc)
|
||||
/* hardware quirk requires reading twice initially */
|
||||
flash_status = readw(docptr + DOC_FLASHCONTROL);
|
||||
|
||||
timeo = 1000;
|
||||
timeo = jiffies + msecs_to_jiffies(200); /* generous timeout */
|
||||
do {
|
||||
cpu_relax();
|
||||
flash_status = readb(docptr + DOC_FLASHCONTROL);
|
||||
} while (!(flash_status & DOC_CTRL_FLASHREADY) && --timeo);
|
||||
} while (!(flash_status & DOC_CTRL_FLASHREADY) &&
|
||||
time_before(jiffies, timeo));
|
||||
|
||||
|
||||
if (!timeo) {
|
||||
if (unlikely(!(flash_status & DOC_CTRL_FLASHREADY))) {
|
||||
dev_err(doc->dev, "%s: timed out!\n", __func__);
|
||||
return NAND_STATUS_FAIL;
|
||||
}
|
||||
|
||||
if (unlikely(timeo < 50))
|
||||
dev_warn(doc->dev, "%s: nearly timed out; %d remaining\n",
|
||||
__func__, timeo);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
@ -1239,7 +1236,6 @@ static void __init init_mtd_structs(struct mtd_info *mtd)
|
||||
nand->block_markbad = docg4_block_markbad;
|
||||
nand->read_buf = docg4_read_buf;
|
||||
nand->write_buf = docg4_write_buf16;
|
||||
nand->scan_bbt = nand_default_bbt;
|
||||
nand->erase_cmd = docg4_erase_block;
|
||||
nand->ecc.read_page = docg4_read_page;
|
||||
nand->ecc.write_page = docg4_write_page;
|
||||
|
@ -651,8 +651,6 @@ static int fsl_elbc_chip_init_tail(struct mtd_info *mtd)
|
||||
chip->page_shift);
|
||||
dev_dbg(priv->dev, "fsl_elbc_init: nand->phys_erase_shift = %d\n",
|
||||
chip->phys_erase_shift);
|
||||
dev_dbg(priv->dev, "fsl_elbc_init: nand->ecclayout = %p\n",
|
||||
chip->ecclayout);
|
||||
dev_dbg(priv->dev, "fsl_elbc_init: nand->ecc.mode = %d\n",
|
||||
chip->ecc.mode);
|
||||
dev_dbg(priv->dev, "fsl_elbc_init: nand->ecc.steps = %d\n",
|
||||
|
@ -136,6 +136,69 @@ static struct nand_ecclayout oob_4096_ecc8 = {
|
||||
.oobfree = { {2, 6}, {136, 82} },
|
||||
};
|
||||
|
||||
/* 8192-byte page size with 4-bit ECC */
|
||||
static struct nand_ecclayout oob_8192_ecc4 = {
|
||||
.eccbytes = 128,
|
||||
.eccpos = {
|
||||
8, 9, 10, 11, 12, 13, 14, 15,
|
||||
16, 17, 18, 19, 20, 21, 22, 23,
|
||||
24, 25, 26, 27, 28, 29, 30, 31,
|
||||
32, 33, 34, 35, 36, 37, 38, 39,
|
||||
40, 41, 42, 43, 44, 45, 46, 47,
|
||||
48, 49, 50, 51, 52, 53, 54, 55,
|
||||
56, 57, 58, 59, 60, 61, 62, 63,
|
||||
64, 65, 66, 67, 68, 69, 70, 71,
|
||||
72, 73, 74, 75, 76, 77, 78, 79,
|
||||
80, 81, 82, 83, 84, 85, 86, 87,
|
||||
88, 89, 90, 91, 92, 93, 94, 95,
|
||||
96, 97, 98, 99, 100, 101, 102, 103,
|
||||
104, 105, 106, 107, 108, 109, 110, 111,
|
||||
112, 113, 114, 115, 116, 117, 118, 119,
|
||||
120, 121, 122, 123, 124, 125, 126, 127,
|
||||
128, 129, 130, 131, 132, 133, 134, 135,
|
||||
},
|
||||
.oobfree = { {2, 6}, {136, 208} },
|
||||
};
|
||||
|
||||
/* 8192-byte page size with 8-bit ECC -- requires 218-byte OOB */
|
||||
static struct nand_ecclayout oob_8192_ecc8 = {
|
||||
.eccbytes = 256,
|
||||
.eccpos = {
|
||||
8, 9, 10, 11, 12, 13, 14, 15,
|
||||
16, 17, 18, 19, 20, 21, 22, 23,
|
||||
24, 25, 26, 27, 28, 29, 30, 31,
|
||||
32, 33, 34, 35, 36, 37, 38, 39,
|
||||
40, 41, 42, 43, 44, 45, 46, 47,
|
||||
48, 49, 50, 51, 52, 53, 54, 55,
|
||||
56, 57, 58, 59, 60, 61, 62, 63,
|
||||
64, 65, 66, 67, 68, 69, 70, 71,
|
||||
72, 73, 74, 75, 76, 77, 78, 79,
|
||||
80, 81, 82, 83, 84, 85, 86, 87,
|
||||
88, 89, 90, 91, 92, 93, 94, 95,
|
||||
96, 97, 98, 99, 100, 101, 102, 103,
|
||||
104, 105, 106, 107, 108, 109, 110, 111,
|
||||
112, 113, 114, 115, 116, 117, 118, 119,
|
||||
120, 121, 122, 123, 124, 125, 126, 127,
|
||||
128, 129, 130, 131, 132, 133, 134, 135,
|
||||
136, 137, 138, 139, 140, 141, 142, 143,
|
||||
144, 145, 146, 147, 148, 149, 150, 151,
|
||||
152, 153, 154, 155, 156, 157, 158, 159,
|
||||
160, 161, 162, 163, 164, 165, 166, 167,
|
||||
168, 169, 170, 171, 172, 173, 174, 175,
|
||||
176, 177, 178, 179, 180, 181, 182, 183,
|
||||
184, 185, 186, 187, 188, 189, 190, 191,
|
||||
192, 193, 194, 195, 196, 197, 198, 199,
|
||||
200, 201, 202, 203, 204, 205, 206, 207,
|
||||
208, 209, 210, 211, 212, 213, 214, 215,
|
||||
216, 217, 218, 219, 220, 221, 222, 223,
|
||||
224, 225, 226, 227, 228, 229, 230, 231,
|
||||
232, 233, 234, 235, 236, 237, 238, 239,
|
||||
240, 241, 242, 243, 244, 245, 246, 247,
|
||||
248, 249, 250, 251, 252, 253, 254, 255,
|
||||
256, 257, 258, 259, 260, 261, 262, 263,
|
||||
},
|
||||
.oobfree = { {2, 6}, {264, 80} },
|
||||
};
|
||||
|
||||
/*
|
||||
* Generic flash bbt descriptors
|
||||
@ -442,20 +505,29 @@ static void fsl_ifc_cmdfunc(struct mtd_info *mtd, unsigned int command,
|
||||
if (mtd->writesize > 512) {
|
||||
nand_fcr0 =
|
||||
(NAND_CMD_SEQIN << IFC_NAND_FCR0_CMD0_SHIFT) |
|
||||
(NAND_CMD_PAGEPROG << IFC_NAND_FCR0_CMD1_SHIFT);
|
||||
(NAND_CMD_STATUS << IFC_NAND_FCR0_CMD1_SHIFT) |
|
||||
(NAND_CMD_PAGEPROG << IFC_NAND_FCR0_CMD2_SHIFT);
|
||||
|
||||
iowrite32be(
|
||||
(IFC_FIR_OP_CW0 << IFC_NAND_FIR0_OP0_SHIFT) |
|
||||
(IFC_FIR_OP_CA0 << IFC_NAND_FIR0_OP1_SHIFT) |
|
||||
(IFC_FIR_OP_RA0 << IFC_NAND_FIR0_OP2_SHIFT) |
|
||||
(IFC_FIR_OP_WBCD << IFC_NAND_FIR0_OP3_SHIFT) |
|
||||
(IFC_FIR_OP_CW1 << IFC_NAND_FIR0_OP4_SHIFT),
|
||||
&ifc->ifc_nand.nand_fir0);
|
||||
(IFC_FIR_OP_CW0 << IFC_NAND_FIR0_OP0_SHIFT) |
|
||||
(IFC_FIR_OP_CA0 << IFC_NAND_FIR0_OP1_SHIFT) |
|
||||
(IFC_FIR_OP_RA0 << IFC_NAND_FIR0_OP2_SHIFT) |
|
||||
(IFC_FIR_OP_WBCD << IFC_NAND_FIR0_OP3_SHIFT) |
|
||||
(IFC_FIR_OP_CMD2 << IFC_NAND_FIR0_OP4_SHIFT),
|
||||
&ifc->ifc_nand.nand_fir0);
|
||||
iowrite32be(
|
||||
(IFC_FIR_OP_CW1 << IFC_NAND_FIR1_OP5_SHIFT) |
|
||||
(IFC_FIR_OP_RDSTAT <<
|
||||
IFC_NAND_FIR1_OP6_SHIFT) |
|
||||
(IFC_FIR_OP_NOP << IFC_NAND_FIR1_OP7_SHIFT),
|
||||
&ifc->ifc_nand.nand_fir1);
|
||||
} else {
|
||||
nand_fcr0 = ((NAND_CMD_PAGEPROG <<
|
||||
IFC_NAND_FCR0_CMD1_SHIFT) |
|
||||
(NAND_CMD_SEQIN <<
|
||||
IFC_NAND_FCR0_CMD2_SHIFT));
|
||||
IFC_NAND_FCR0_CMD2_SHIFT) |
|
||||
(NAND_CMD_STATUS <<
|
||||
IFC_NAND_FCR0_CMD3_SHIFT));
|
||||
|
||||
iowrite32be(
|
||||
(IFC_FIR_OP_CW0 << IFC_NAND_FIR0_OP0_SHIFT) |
|
||||
@ -464,8 +536,13 @@ static void fsl_ifc_cmdfunc(struct mtd_info *mtd, unsigned int command,
|
||||
(IFC_FIR_OP_RA0 << IFC_NAND_FIR0_OP3_SHIFT) |
|
||||
(IFC_FIR_OP_WBCD << IFC_NAND_FIR0_OP4_SHIFT),
|
||||
&ifc->ifc_nand.nand_fir0);
|
||||
iowrite32be(IFC_FIR_OP_CW1 << IFC_NAND_FIR1_OP5_SHIFT,
|
||||
&ifc->ifc_nand.nand_fir1);
|
||||
iowrite32be(
|
||||
(IFC_FIR_OP_CMD1 << IFC_NAND_FIR1_OP5_SHIFT) |
|
||||
(IFC_FIR_OP_CW3 << IFC_NAND_FIR1_OP6_SHIFT) |
|
||||
(IFC_FIR_OP_RDSTAT <<
|
||||
IFC_NAND_FIR1_OP7_SHIFT) |
|
||||
(IFC_FIR_OP_NOP << IFC_NAND_FIR1_OP8_SHIFT),
|
||||
&ifc->ifc_nand.nand_fir1);
|
||||
|
||||
if (column >= mtd->writesize)
|
||||
nand_fcr0 |=
|
||||
@ -719,8 +796,6 @@ static int fsl_ifc_chip_init_tail(struct mtd_info *mtd)
|
||||
chip->page_shift);
|
||||
dev_dbg(priv->dev, "%s: nand->phys_erase_shift = %d\n", __func__,
|
||||
chip->phys_erase_shift);
|
||||
dev_dbg(priv->dev, "%s: nand->ecclayout = %p\n", __func__,
|
||||
chip->ecclayout);
|
||||
dev_dbg(priv->dev, "%s: nand->ecc.mode = %d\n", __func__,
|
||||
chip->ecc.mode);
|
||||
dev_dbg(priv->dev, "%s: nand->ecc.steps = %d\n", __func__,
|
||||
@ -873,11 +948,25 @@ static int fsl_ifc_chip_init(struct fsl_ifc_mtd *priv)
|
||||
} else {
|
||||
layout = &oob_4096_ecc8;
|
||||
chip->ecc.bytes = 16;
|
||||
chip->ecc.strength = 8;
|
||||
}
|
||||
|
||||
priv->bufnum_mask = 1;
|
||||
break;
|
||||
|
||||
case CSOR_NAND_PGS_8K:
|
||||
if ((csor & CSOR_NAND_ECC_MODE_MASK) ==
|
||||
CSOR_NAND_ECC_MODE_4) {
|
||||
layout = &oob_8192_ecc4;
|
||||
} else {
|
||||
layout = &oob_8192_ecc8;
|
||||
chip->ecc.bytes = 16;
|
||||
chip->ecc.strength = 8;
|
||||
}
|
||||
|
||||
priv->bufnum_mask = 0;
|
||||
break;
|
||||
|
||||
default:
|
||||
dev_err(priv->dev, "bad csor %#x: bad page size\n", csor);
|
||||
return -ENODEV;
|
||||
@ -908,7 +997,6 @@ static int fsl_ifc_chip_remove(struct fsl_ifc_mtd *priv)
|
||||
iounmap(priv->vbase);
|
||||
|
||||
ifc_nand_ctrl->chips[priv->bank] = NULL;
|
||||
dev_set_drvdata(priv->dev, NULL);
|
||||
|
||||
return 0;
|
||||
}
|
||||
@ -1083,25 +1171,7 @@ static struct platform_driver fsl_ifc_nand_driver = {
|
||||
.remove = fsl_ifc_nand_remove,
|
||||
};
|
||||
|
||||
static int __init fsl_ifc_nand_init(void)
|
||||
{
|
||||
int ret;
|
||||
|
||||
ret = platform_driver_register(&fsl_ifc_nand_driver);
|
||||
if (ret)
|
||||
printk(KERN_ERR "fsl-ifc: Failed to register platform"
|
||||
"driver\n");
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static void __exit fsl_ifc_nand_exit(void)
|
||||
{
|
||||
platform_driver_unregister(&fsl_ifc_nand_driver);
|
||||
}
|
||||
|
||||
module_init(fsl_ifc_nand_init);
|
||||
module_exit(fsl_ifc_nand_exit);
|
||||
module_platform_driver(fsl_ifc_nand_driver);
|
||||
|
||||
MODULE_LICENSE("GPL");
|
||||
MODULE_AUTHOR("Freescale");
|
||||
|
@ -187,6 +187,12 @@ int gpmi_init(struct gpmi_nand_data *this)
|
||||
/* Select BCH ECC. */
|
||||
writel(BM_GPMI_CTRL1_BCH_MODE, r->gpmi_regs + HW_GPMI_CTRL1_SET);
|
||||
|
||||
/*
|
||||
* Decouple the chip select from dma channel. We use dma0 for all
|
||||
* the chips.
|
||||
*/
|
||||
writel(BM_GPMI_CTRL1_DECOUPLE_CS, r->gpmi_regs + HW_GPMI_CTRL1_SET);
|
||||
|
||||
gpmi_disable_clk(this);
|
||||
return 0;
|
||||
err_out:
|
||||
@ -1073,6 +1079,13 @@ int gpmi_is_ready(struct gpmi_nand_data *this, unsigned chip)
|
||||
mask = MX23_BM_GPMI_DEBUG_READY0 << chip;
|
||||
reg = readl(r->gpmi_regs + HW_GPMI_DEBUG);
|
||||
} else if (GPMI_IS_MX28(this) || GPMI_IS_MX6Q(this)) {
|
||||
/*
|
||||
* In the imx6, all the ready/busy pins are bound
|
||||
* together. So we only need to check chip 0.
|
||||
*/
|
||||
if (GPMI_IS_MX6Q(this))
|
||||
chip = 0;
|
||||
|
||||
/* MX28 shares the same R/B register as MX6Q. */
|
||||
mask = MX28_BF_GPMI_STAT_READY_BUSY(1 << chip);
|
||||
reg = readl(r->gpmi_regs + HW_GPMI_STAT);
|
||||
|
@ -45,7 +45,10 @@ static struct nand_bbt_descr gpmi_bbt_descr = {
|
||||
.pattern = scan_ff_pattern
|
||||
};
|
||||
|
||||
/* We will use all the (page + OOB). */
|
||||
/*
|
||||
* We may change the layout if we can get the ECC info from the datasheet,
|
||||
* else we will use all the (page + OOB).
|
||||
*/
|
||||
static struct nand_ecclayout gpmi_hw_ecclayout = {
|
||||
.eccbytes = 0,
|
||||
.eccpos = { 0, },
|
||||
@ -354,9 +357,8 @@ int common_nfc_set_geometry(struct gpmi_nand_data *this)
|
||||
|
||||
struct dma_chan *get_dma_chan(struct gpmi_nand_data *this)
|
||||
{
|
||||
int chipnr = this->current_chip;
|
||||
|
||||
return this->dma_chans[chipnr];
|
||||
/* We use the DMA channel 0 to access all the nand chips. */
|
||||
return this->dma_chans[0];
|
||||
}
|
||||
|
||||
/* Can we use the upper's buffer directly for DMA? */
|
||||
@ -392,8 +394,6 @@ static void dma_irq_callback(void *param)
|
||||
struct gpmi_nand_data *this = param;
|
||||
struct completion *dma_c = &this->dma_done;
|
||||
|
||||
complete(dma_c);
|
||||
|
||||
switch (this->dma_type) {
|
||||
case DMA_FOR_COMMAND:
|
||||
dma_unmap_sg(this->dev, &this->cmd_sgl, 1, DMA_TO_DEVICE);
|
||||
@ -418,6 +418,8 @@ static void dma_irq_callback(void *param)
|
||||
default:
|
||||
pr_err("in wrong DMA operation.\n");
|
||||
}
|
||||
|
||||
complete(dma_c);
|
||||
}
|
||||
|
||||
int start_dma_without_bch_irq(struct gpmi_nand_data *this,
|
||||
@ -1263,14 +1265,22 @@ static int gpmi_ecc_read_oob(struct mtd_info *mtd, struct nand_chip *chip,
|
||||
static int
|
||||
gpmi_ecc_write_oob(struct mtd_info *mtd, struct nand_chip *chip, int page)
|
||||
{
|
||||
/*
|
||||
* The BCH will use all the (page + oob).
|
||||
* Our gpmi_hw_ecclayout can only prohibit the JFFS2 to write the oob.
|
||||
* But it can not stop some ioctls such MEMWRITEOOB which uses
|
||||
* MTD_OPS_PLACE_OOB. So We have to implement this function to prohibit
|
||||
* these ioctls too.
|
||||
*/
|
||||
return -EPERM;
|
||||
struct nand_oobfree *of = mtd->ecclayout->oobfree;
|
||||
int status = 0;
|
||||
|
||||
/* Do we have available oob area? */
|
||||
if (!of->length)
|
||||
return -EPERM;
|
||||
|
||||
if (!nand_is_slc(chip))
|
||||
return -EPERM;
|
||||
|
||||
chip->cmdfunc(mtd, NAND_CMD_SEQIN, mtd->writesize + of->offset, page);
|
||||
chip->write_buf(mtd, chip->oob_poi + of->offset, of->length);
|
||||
chip->cmdfunc(mtd, NAND_CMD_PAGEPROG, -1, -1);
|
||||
|
||||
status = chip->waitfunc(mtd, chip);
|
||||
return status & NAND_STATUS_FAIL ? -EIO : 0;
|
||||
}
|
||||
|
||||
static int gpmi_block_markbad(struct mtd_info *mtd, loff_t ofs)
|
||||
@ -1568,8 +1578,6 @@ static int gpmi_set_geometry(struct gpmi_nand_data *this)
|
||||
|
||||
static int gpmi_pre_bbt_scan(struct gpmi_nand_data *this)
|
||||
{
|
||||
int ret;
|
||||
|
||||
/* Set up swap_block_mark, must be set before the gpmi_set_geometry() */
|
||||
if (GPMI_IS_MX23(this))
|
||||
this->swap_block_mark = false;
|
||||
@ -1577,12 +1585,8 @@ static int gpmi_pre_bbt_scan(struct gpmi_nand_data *this)
|
||||
this->swap_block_mark = true;
|
||||
|
||||
/* Set up the medium geometry */
|
||||
ret = gpmi_set_geometry(this);
|
||||
if (ret)
|
||||
return ret;
|
||||
return gpmi_set_geometry(this);
|
||||
|
||||
/* NAND boot init, depends on the gpmi_set_geometry(). */
|
||||
return nand_boot_init(this);
|
||||
}
|
||||
|
||||
static void gpmi_nfc_exit(struct gpmi_nand_data *this)
|
||||
@ -1664,7 +1668,7 @@ static int gpmi_nfc_init(struct gpmi_nand_data *this)
|
||||
if (ret)
|
||||
goto err_out;
|
||||
|
||||
ret = nand_scan_ident(mtd, 1, NULL);
|
||||
ret = nand_scan_ident(mtd, GPMI_IS_MX6Q(this) ? 2 : 1, NULL);
|
||||
if (ret)
|
||||
goto err_out;
|
||||
|
||||
@ -1672,10 +1676,16 @@ static int gpmi_nfc_init(struct gpmi_nand_data *this)
|
||||
if (ret)
|
||||
goto err_out;
|
||||
|
||||
chip->options |= NAND_SKIP_BBTSCAN;
|
||||
ret = nand_scan_tail(mtd);
|
||||
if (ret)
|
||||
goto err_out;
|
||||
|
||||
ret = nand_boot_init(this);
|
||||
if (ret)
|
||||
goto err_out;
|
||||
chip->scan_bbt(mtd);
|
||||
|
||||
ppdata.of_node = this->pdev->dev.of_node;
|
||||
ret = mtd_device_parse_register(mtd, NULL, &ppdata, NULL, 0);
|
||||
if (ret)
|
||||
@ -1691,19 +1701,19 @@ static const struct platform_device_id gpmi_ids[] = {
|
||||
{ .name = "imx23-gpmi-nand", .driver_data = IS_MX23, },
|
||||
{ .name = "imx28-gpmi-nand", .driver_data = IS_MX28, },
|
||||
{ .name = "imx6q-gpmi-nand", .driver_data = IS_MX6Q, },
|
||||
{},
|
||||
{}
|
||||
};
|
||||
|
||||
static const struct of_device_id gpmi_nand_id_table[] = {
|
||||
{
|
||||
.compatible = "fsl,imx23-gpmi-nand",
|
||||
.data = (void *)&gpmi_ids[IS_MX23]
|
||||
.data = (void *)&gpmi_ids[IS_MX23],
|
||||
}, {
|
||||
.compatible = "fsl,imx28-gpmi-nand",
|
||||
.data = (void *)&gpmi_ids[IS_MX28]
|
||||
.data = (void *)&gpmi_ids[IS_MX28],
|
||||
}, {
|
||||
.compatible = "fsl,imx6q-gpmi-nand",
|
||||
.data = (void *)&gpmi_ids[IS_MX6Q]
|
||||
.data = (void *)&gpmi_ids[IS_MX6Q],
|
||||
}, {}
|
||||
};
|
||||
MODULE_DEVICE_TABLE(of, gpmi_nand_id_table);
|
||||
@ -1722,7 +1732,7 @@ static int gpmi_nand_probe(struct platform_device *pdev)
|
||||
return -ENODEV;
|
||||
}
|
||||
|
||||
this = kzalloc(sizeof(*this), GFP_KERNEL);
|
||||
this = devm_kzalloc(&pdev->dev, sizeof(*this), GFP_KERNEL);
|
||||
if (!this) {
|
||||
pr_err("Failed to allocate per-device memory\n");
|
||||
return -ENOMEM;
|
||||
@ -1752,7 +1762,6 @@ exit_nfc_init:
|
||||
release_resources(this);
|
||||
exit_acquire_resources:
|
||||
dev_err(this->dev, "driver registration failed: %d\n", ret);
|
||||
kfree(this);
|
||||
|
||||
return ret;
|
||||
}
|
||||
@ -1763,7 +1772,6 @@ static int gpmi_nand_remove(struct platform_device *pdev)
|
||||
|
||||
gpmi_nfc_exit(this);
|
||||
release_resources(this);
|
||||
kfree(this);
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
@ -108,6 +108,9 @@
|
||||
#define HW_GPMI_CTRL1_CLR 0x00000068
|
||||
#define HW_GPMI_CTRL1_TOG 0x0000006c
|
||||
|
||||
#define BP_GPMI_CTRL1_DECOUPLE_CS 24
|
||||
#define BM_GPMI_CTRL1_DECOUPLE_CS (1 << BP_GPMI_CTRL1_DECOUPLE_CS)
|
||||
|
||||
#define BP_GPMI_CTRL1_WRN_DLY_SEL 22
|
||||
#define BM_GPMI_CTRL1_WRN_DLY_SEL (0x3 << BP_GPMI_CTRL1_WRN_DLY_SEL)
|
||||
#define BF_GPMI_CTRL1_WRN_DLY_SEL(v) \
|
||||
|
@ -905,7 +905,7 @@ static struct platform_driver lpc32xx_nand_driver = {
|
||||
.driver = {
|
||||
.name = DRV_NAME,
|
||||
.owner = THIS_MODULE,
|
||||
.of_match_table = of_match_ptr(lpc32xx_nand_match),
|
||||
.of_match_table = lpc32xx_nand_match,
|
||||
},
|
||||
};
|
||||
|
||||
|
@ -893,7 +893,6 @@ static int lpc32xx_nand_probe(struct platform_device *pdev)
|
||||
|
||||
/* Avoid extra scan if using BBT, setup BBT support */
|
||||
if (host->ncfg->use_bbt) {
|
||||
chip->options |= NAND_SKIP_BBTSCAN;
|
||||
chip->bbt_options |= NAND_BBT_USE_FLASH;
|
||||
|
||||
/*
|
||||
@ -915,13 +914,6 @@ static int lpc32xx_nand_probe(struct platform_device *pdev)
|
||||
goto err_exit3;
|
||||
}
|
||||
|
||||
/* Standard layout in FLASH for bad block tables */
|
||||
if (host->ncfg->use_bbt) {
|
||||
if (nand_default_bbt(mtd) < 0)
|
||||
dev_err(&pdev->dev,
|
||||
"Error initializing default bad block tables\n");
|
||||
}
|
||||
|
||||
mtd->name = "nxp_lpc3220_slc";
|
||||
ppdata.of_node = pdev->dev.of_node;
|
||||
res = mtd_device_parse_register(mtd, NULL, &ppdata, host->ncfg->parts,
|
||||
@ -1023,7 +1015,7 @@ static struct platform_driver lpc32xx_nand_driver = {
|
||||
.driver = {
|
||||
.name = LPC32XX_MODNAME,
|
||||
.owner = THIS_MODULE,
|
||||
.of_match_table = of_match_ptr(lpc32xx_nand_match),
|
||||
.of_match_table = lpc32xx_nand_match,
|
||||
},
|
||||
};
|
||||
|
||||
|
@ -32,6 +32,7 @@
|
||||
#include <linux/io.h>
|
||||
#include <linux/irq.h>
|
||||
#include <linux/completion.h>
|
||||
#include <linux/of.h>
|
||||
#include <linux/of_device.h>
|
||||
#include <linux/of_mtd.h>
|
||||
|
||||
@ -1507,7 +1508,7 @@ static int mxcnd_probe(struct platform_device *pdev)
|
||||
host->devtype_data->irq_control(host, 0);
|
||||
|
||||
err = devm_request_irq(&pdev->dev, host->irq, mxc_nfc_irq,
|
||||
IRQF_DISABLED, DRIVER_NAME, host);
|
||||
0, DRIVER_NAME, host);
|
||||
if (err)
|
||||
return err;
|
||||
|
||||
|
@ -2912,12 +2912,13 @@ static int nand_flash_detect_ext_param_page(struct mtd_info *mtd,
|
||||
/* get the info we want. */
|
||||
ecc = (struct onfi_ext_ecc_info *)cursor;
|
||||
|
||||
if (ecc->codeword_size) {
|
||||
chip->ecc_strength_ds = ecc->ecc_bits;
|
||||
chip->ecc_step_ds = 1 << ecc->codeword_size;
|
||||
if (!ecc->codeword_size) {
|
||||
pr_debug("Invalid codeword size\n");
|
||||
goto ext_out;
|
||||
}
|
||||
|
||||
pr_info("ONFI extended param page detected.\n");
|
||||
chip->ecc_strength_ds = ecc->ecc_bits;
|
||||
chip->ecc_step_ds = 1 << ecc->codeword_size;
|
||||
ret = 0;
|
||||
|
||||
ext_out:
|
||||
@ -2935,29 +2936,34 @@ static int nand_flash_detect_onfi(struct mtd_info *mtd, struct nand_chip *chip,
|
||||
int i;
|
||||
int val;
|
||||
|
||||
/* ONFI need to be probed in 8 bits mode, and 16 bits should be selected with NAND_BUSWIDTH_AUTO */
|
||||
if (chip->options & NAND_BUSWIDTH_16) {
|
||||
pr_err("Trying ONFI probe in 16 bits mode, aborting !\n");
|
||||
return 0;
|
||||
}
|
||||
/* Try ONFI for unknown chip or LP */
|
||||
chip->cmdfunc(mtd, NAND_CMD_READID, 0x20, -1);
|
||||
if (chip->read_byte(mtd) != 'O' || chip->read_byte(mtd) != 'N' ||
|
||||
chip->read_byte(mtd) != 'F' || chip->read_byte(mtd) != 'I')
|
||||
return 0;
|
||||
|
||||
/*
|
||||
* ONFI must be probed in 8-bit mode or with NAND_BUSWIDTH_AUTO, not
|
||||
* with NAND_BUSWIDTH_16
|
||||
*/
|
||||
if (chip->options & NAND_BUSWIDTH_16) {
|
||||
pr_err("ONFI cannot be probed in 16-bit mode; aborting\n");
|
||||
return 0;
|
||||
}
|
||||
|
||||
chip->cmdfunc(mtd, NAND_CMD_PARAM, 0, -1);
|
||||
for (i = 0; i < 3; i++) {
|
||||
chip->read_buf(mtd, (uint8_t *)p, sizeof(*p));
|
||||
if (onfi_crc16(ONFI_CRC_BASE, (uint8_t *)p, 254) ==
|
||||
le16_to_cpu(p->crc)) {
|
||||
pr_info("ONFI param page %d valid\n", i);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (i == 3)
|
||||
if (i == 3) {
|
||||
pr_err("Could not find valid ONFI parameter page; aborting\n");
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Check version */
|
||||
val = le16_to_cpu(p->revision);
|
||||
@ -2981,11 +2987,23 @@ static int nand_flash_detect_onfi(struct mtd_info *mtd, struct nand_chip *chip,
|
||||
sanitize_string(p->model, sizeof(p->model));
|
||||
if (!mtd->name)
|
||||
mtd->name = p->model;
|
||||
|
||||
mtd->writesize = le32_to_cpu(p->byte_per_page);
|
||||
mtd->erasesize = le32_to_cpu(p->pages_per_block) * mtd->writesize;
|
||||
|
||||
/*
|
||||
* pages_per_block and blocks_per_lun may not be a power-of-2 size
|
||||
* (don't ask me who thought of this...). MTD assumes that these
|
||||
* dimensions will be power-of-2, so just truncate the remaining area.
|
||||
*/
|
||||
mtd->erasesize = 1 << (fls(le32_to_cpu(p->pages_per_block)) - 1);
|
||||
mtd->erasesize *= mtd->writesize;
|
||||
|
||||
mtd->oobsize = le16_to_cpu(p->spare_bytes_per_page);
|
||||
chip->chipsize = le32_to_cpu(p->blocks_per_lun);
|
||||
|
||||
/* See erasesize comment */
|
||||
chip->chipsize = 1 << (fls(le32_to_cpu(p->blocks_per_lun)) - 1);
|
||||
chip->chipsize *= (uint64_t)mtd->erasesize * p->lun_count;
|
||||
chip->bits_per_cell = p->bits_per_cell;
|
||||
|
||||
if (onfi_feature(chip) & ONFI_FEATURE_16_BIT_BUS)
|
||||
*busw = NAND_BUSWIDTH_16;
|
||||
@ -3009,10 +3027,11 @@ static int nand_flash_detect_onfi(struct mtd_info *mtd, struct nand_chip *chip,
|
||||
|
||||
/* The Extended Parameter Page is supported since ONFI 2.1. */
|
||||
if (nand_flash_detect_ext_param_page(mtd, chip, p))
|
||||
pr_info("Failed to detect the extended param page.\n");
|
||||
pr_warn("Failed to detect ONFI extended param page\n");
|
||||
} else {
|
||||
pr_warn("Could not retrieve ONFI ECC requirements\n");
|
||||
}
|
||||
|
||||
pr_info("ONFI flash detected\n");
|
||||
return 1;
|
||||
}
|
||||
|
||||
@ -3075,6 +3094,16 @@ static int nand_id_len(u8 *id_data, int arrlen)
|
||||
return arrlen;
|
||||
}
|
||||
|
||||
/* Extract the bits of per cell from the 3rd byte of the extended ID */
|
||||
static int nand_get_bits_per_cell(u8 cellinfo)
|
||||
{
|
||||
int bits;
|
||||
|
||||
bits = cellinfo & NAND_CI_CELLTYPE_MSK;
|
||||
bits >>= NAND_CI_CELLTYPE_SHIFT;
|
||||
return bits + 1;
|
||||
}
|
||||
|
||||
/*
|
||||
* Many new NAND share similar device ID codes, which represent the size of the
|
||||
* chip. The rest of the parameters must be decoded according to generic or
|
||||
@ -3085,7 +3114,7 @@ static void nand_decode_ext_id(struct mtd_info *mtd, struct nand_chip *chip,
|
||||
{
|
||||
int extid, id_len;
|
||||
/* The 3rd id byte holds MLC / multichip data */
|
||||
chip->cellinfo = id_data[2];
|
||||
chip->bits_per_cell = nand_get_bits_per_cell(id_data[2]);
|
||||
/* The 4th id byte is the important one */
|
||||
extid = id_data[3];
|
||||
|
||||
@ -3101,8 +3130,7 @@ static void nand_decode_ext_id(struct mtd_info *mtd, struct nand_chip *chip,
|
||||
* ID to decide what to do.
|
||||
*/
|
||||
if (id_len == 6 && id_data[0] == NAND_MFR_SAMSUNG &&
|
||||
(chip->cellinfo & NAND_CI_CELLTYPE_MSK) &&
|
||||
id_data[5] != 0x00) {
|
||||
!nand_is_slc(chip) && id_data[5] != 0x00) {
|
||||
/* Calc pagesize */
|
||||
mtd->writesize = 2048 << (extid & 0x03);
|
||||
extid >>= 2;
|
||||
@ -3134,7 +3162,7 @@ static void nand_decode_ext_id(struct mtd_info *mtd, struct nand_chip *chip,
|
||||
(((extid >> 1) & 0x04) | (extid & 0x03));
|
||||
*busw = 0;
|
||||
} else if (id_len == 6 && id_data[0] == NAND_MFR_HYNIX &&
|
||||
(chip->cellinfo & NAND_CI_CELLTYPE_MSK)) {
|
||||
!nand_is_slc(chip)) {
|
||||
unsigned int tmp;
|
||||
|
||||
/* Calc pagesize */
|
||||
@ -3197,7 +3225,7 @@ static void nand_decode_ext_id(struct mtd_info *mtd, struct nand_chip *chip,
|
||||
* - ID byte 5, bit[7]: 1 -> BENAND, 0 -> raw SLC
|
||||
*/
|
||||
if (id_len >= 6 && id_data[0] == NAND_MFR_TOSHIBA &&
|
||||
!(chip->cellinfo & NAND_CI_CELLTYPE_MSK) &&
|
||||
nand_is_slc(chip) &&
|
||||
(id_data[5] & 0x7) == 0x6 /* 24nm */ &&
|
||||
!(id_data[4] & 0x80) /* !BENAND */) {
|
||||
mtd->oobsize = 32 * mtd->writesize >> 9;
|
||||
@ -3222,6 +3250,9 @@ static void nand_decode_id(struct mtd_info *mtd, struct nand_chip *chip,
|
||||
mtd->oobsize = mtd->writesize / 32;
|
||||
*busw = type->options & NAND_BUSWIDTH_16;
|
||||
|
||||
/* All legacy ID NAND are small-page, SLC */
|
||||
chip->bits_per_cell = 1;
|
||||
|
||||
/*
|
||||
* Check for Spansion/AMD ID + repeating 5th, 6th byte since
|
||||
* some Spansion chips have erasesize that conflicts with size
|
||||
@ -3258,11 +3289,11 @@ static void nand_decode_bbm_options(struct mtd_info *mtd,
|
||||
* Micron devices with 2KiB pages and on SLC Samsung, Hynix, Toshiba,
|
||||
* AMD/Spansion, and Macronix. All others scan only the first page.
|
||||
*/
|
||||
if ((chip->cellinfo & NAND_CI_CELLTYPE_MSK) &&
|
||||
if (!nand_is_slc(chip) &&
|
||||
(maf_id == NAND_MFR_SAMSUNG ||
|
||||
maf_id == NAND_MFR_HYNIX))
|
||||
chip->bbt_options |= NAND_BBT_SCANLASTPAGE;
|
||||
else if ((!(chip->cellinfo & NAND_CI_CELLTYPE_MSK) &&
|
||||
else if ((nand_is_slc(chip) &&
|
||||
(maf_id == NAND_MFR_SAMSUNG ||
|
||||
maf_id == NAND_MFR_HYNIX ||
|
||||
maf_id == NAND_MFR_TOSHIBA ||
|
||||
@ -3286,7 +3317,7 @@ static bool find_full_id_nand(struct mtd_info *mtd, struct nand_chip *chip,
|
||||
mtd->erasesize = type->erasesize;
|
||||
mtd->oobsize = type->oobsize;
|
||||
|
||||
chip->cellinfo = id_data[2];
|
||||
chip->bits_per_cell = nand_get_bits_per_cell(id_data[2]);
|
||||
chip->chipsize = (uint64_t)type->chipsize << 20;
|
||||
chip->options |= type->options;
|
||||
chip->ecc_strength_ds = NAND_ECC_STRENGTH(type);
|
||||
@ -3441,11 +3472,13 @@ ident_done:
|
||||
if (mtd->writesize > 512 && chip->cmdfunc == nand_command)
|
||||
chip->cmdfunc = nand_command_lp;
|
||||
|
||||
pr_info("NAND device: Manufacturer ID: 0x%02x, Chip ID: 0x%02x (%s %s),"
|
||||
" %dMiB, page size: %d, OOB size: %d\n",
|
||||
pr_info("NAND device: Manufacturer ID: 0x%02x, Chip ID: 0x%02x (%s %s)\n",
|
||||
*maf_id, *dev_id, nand_manuf_ids[maf_idx].name,
|
||||
chip->onfi_version ? chip->onfi_params.model : type->name,
|
||||
(int)(chip->chipsize >> 20), mtd->writesize, mtd->oobsize);
|
||||
chip->onfi_version ? chip->onfi_params.model : type->name);
|
||||
|
||||
pr_info("NAND device: %dMiB, %s, page size: %d, OOB size: %d\n",
|
||||
(int)(chip->chipsize >> 20), nand_is_slc(chip) ? "SLC" : "MLC",
|
||||
mtd->writesize, mtd->oobsize);
|
||||
|
||||
return type;
|
||||
}
|
||||
@ -3525,6 +3558,7 @@ int nand_scan_tail(struct mtd_info *mtd)
|
||||
{
|
||||
int i;
|
||||
struct nand_chip *chip = mtd->priv;
|
||||
struct nand_ecc_ctrl *ecc = &chip->ecc;
|
||||
|
||||
/* New bad blocks should be marked in OOB, flash-based BBT, or both */
|
||||
BUG_ON((chip->bbt_options & NAND_BBT_NO_OOB_BBM) &&
|
||||
@ -3541,19 +3575,19 @@ int nand_scan_tail(struct mtd_info *mtd)
|
||||
/*
|
||||
* If no default placement scheme is given, select an appropriate one.
|
||||
*/
|
||||
if (!chip->ecc.layout && (chip->ecc.mode != NAND_ECC_SOFT_BCH)) {
|
||||
if (!ecc->layout && (ecc->mode != NAND_ECC_SOFT_BCH)) {
|
||||
switch (mtd->oobsize) {
|
||||
case 8:
|
||||
chip->ecc.layout = &nand_oob_8;
|
||||
ecc->layout = &nand_oob_8;
|
||||
break;
|
||||
case 16:
|
||||
chip->ecc.layout = &nand_oob_16;
|
||||
ecc->layout = &nand_oob_16;
|
||||
break;
|
||||
case 64:
|
||||
chip->ecc.layout = &nand_oob_64;
|
||||
ecc->layout = &nand_oob_64;
|
||||
break;
|
||||
case 128:
|
||||
chip->ecc.layout = &nand_oob_128;
|
||||
ecc->layout = &nand_oob_128;
|
||||
break;
|
||||
default:
|
||||
pr_warn("No oob scheme defined for oobsize %d\n",
|
||||
@ -3570,64 +3604,62 @@ int nand_scan_tail(struct mtd_info *mtd)
|
||||
* selected and we have 256 byte pagesize fallback to software ECC
|
||||
*/
|
||||
|
||||
switch (chip->ecc.mode) {
|
||||
switch (ecc->mode) {
|
||||
case NAND_ECC_HW_OOB_FIRST:
|
||||
/* Similar to NAND_ECC_HW, but a separate read_page handle */
|
||||
if (!chip->ecc.calculate || !chip->ecc.correct ||
|
||||
!chip->ecc.hwctl) {
|
||||
if (!ecc->calculate || !ecc->correct || !ecc->hwctl) {
|
||||
pr_warn("No ECC functions supplied; "
|
||||
"hardware ECC not possible\n");
|
||||
BUG();
|
||||
}
|
||||
if (!chip->ecc.read_page)
|
||||
chip->ecc.read_page = nand_read_page_hwecc_oob_first;
|
||||
if (!ecc->read_page)
|
||||
ecc->read_page = nand_read_page_hwecc_oob_first;
|
||||
|
||||
case NAND_ECC_HW:
|
||||
/* Use standard hwecc read page function? */
|
||||
if (!chip->ecc.read_page)
|
||||
chip->ecc.read_page = nand_read_page_hwecc;
|
||||
if (!chip->ecc.write_page)
|
||||
chip->ecc.write_page = nand_write_page_hwecc;
|
||||
if (!chip->ecc.read_page_raw)
|
||||
chip->ecc.read_page_raw = nand_read_page_raw;
|
||||
if (!chip->ecc.write_page_raw)
|
||||
chip->ecc.write_page_raw = nand_write_page_raw;
|
||||
if (!chip->ecc.read_oob)
|
||||
chip->ecc.read_oob = nand_read_oob_std;
|
||||
if (!chip->ecc.write_oob)
|
||||
chip->ecc.write_oob = nand_write_oob_std;
|
||||
if (!chip->ecc.read_subpage)
|
||||
chip->ecc.read_subpage = nand_read_subpage;
|
||||
if (!chip->ecc.write_subpage)
|
||||
chip->ecc.write_subpage = nand_write_subpage_hwecc;
|
||||
if (!ecc->read_page)
|
||||
ecc->read_page = nand_read_page_hwecc;
|
||||
if (!ecc->write_page)
|
||||
ecc->write_page = nand_write_page_hwecc;
|
||||
if (!ecc->read_page_raw)
|
||||
ecc->read_page_raw = nand_read_page_raw;
|
||||
if (!ecc->write_page_raw)
|
||||
ecc->write_page_raw = nand_write_page_raw;
|
||||
if (!ecc->read_oob)
|
||||
ecc->read_oob = nand_read_oob_std;
|
||||
if (!ecc->write_oob)
|
||||
ecc->write_oob = nand_write_oob_std;
|
||||
if (!ecc->read_subpage)
|
||||
ecc->read_subpage = nand_read_subpage;
|
||||
if (!ecc->write_subpage)
|
||||
ecc->write_subpage = nand_write_subpage_hwecc;
|
||||
|
||||
case NAND_ECC_HW_SYNDROME:
|
||||
if ((!chip->ecc.calculate || !chip->ecc.correct ||
|
||||
!chip->ecc.hwctl) &&
|
||||
(!chip->ecc.read_page ||
|
||||
chip->ecc.read_page == nand_read_page_hwecc ||
|
||||
!chip->ecc.write_page ||
|
||||
chip->ecc.write_page == nand_write_page_hwecc)) {
|
||||
if ((!ecc->calculate || !ecc->correct || !ecc->hwctl) &&
|
||||
(!ecc->read_page ||
|
||||
ecc->read_page == nand_read_page_hwecc ||
|
||||
!ecc->write_page ||
|
||||
ecc->write_page == nand_write_page_hwecc)) {
|
||||
pr_warn("No ECC functions supplied; "
|
||||
"hardware ECC not possible\n");
|
||||
BUG();
|
||||
}
|
||||
/* Use standard syndrome read/write page function? */
|
||||
if (!chip->ecc.read_page)
|
||||
chip->ecc.read_page = nand_read_page_syndrome;
|
||||
if (!chip->ecc.write_page)
|
||||
chip->ecc.write_page = nand_write_page_syndrome;
|
||||
if (!chip->ecc.read_page_raw)
|
||||
chip->ecc.read_page_raw = nand_read_page_raw_syndrome;
|
||||
if (!chip->ecc.write_page_raw)
|
||||
chip->ecc.write_page_raw = nand_write_page_raw_syndrome;
|
||||
if (!chip->ecc.read_oob)
|
||||
chip->ecc.read_oob = nand_read_oob_syndrome;
|
||||
if (!chip->ecc.write_oob)
|
||||
chip->ecc.write_oob = nand_write_oob_syndrome;
|
||||
if (!ecc->read_page)
|
||||
ecc->read_page = nand_read_page_syndrome;
|
||||
if (!ecc->write_page)
|
||||
ecc->write_page = nand_write_page_syndrome;
|
||||
if (!ecc->read_page_raw)
|
||||
ecc->read_page_raw = nand_read_page_raw_syndrome;
|
||||
if (!ecc->write_page_raw)
|
||||
ecc->write_page_raw = nand_write_page_raw_syndrome;
|
||||
if (!ecc->read_oob)
|
||||
ecc->read_oob = nand_read_oob_syndrome;
|
||||
if (!ecc->write_oob)
|
||||
ecc->write_oob = nand_write_oob_syndrome;
|
||||
|
||||
if (mtd->writesize >= chip->ecc.size) {
|
||||
if (!chip->ecc.strength) {
|
||||
if (mtd->writesize >= ecc->size) {
|
||||
if (!ecc->strength) {
|
||||
pr_warn("Driver must set ecc.strength when using hardware ECC\n");
|
||||
BUG();
|
||||
}
|
||||
@ -3635,23 +3667,23 @@ int nand_scan_tail(struct mtd_info *mtd)
|
||||
}
|
||||
pr_warn("%d byte HW ECC not possible on "
|
||||
"%d byte page size, fallback to SW ECC\n",
|
||||
chip->ecc.size, mtd->writesize);
|
||||
chip->ecc.mode = NAND_ECC_SOFT;
|
||||
ecc->size, mtd->writesize);
|
||||
ecc->mode = NAND_ECC_SOFT;
|
||||
|
||||
case NAND_ECC_SOFT:
|
||||
chip->ecc.calculate = nand_calculate_ecc;
|
||||
chip->ecc.correct = nand_correct_data;
|
||||
chip->ecc.read_page = nand_read_page_swecc;
|
||||
chip->ecc.read_subpage = nand_read_subpage;
|
||||
chip->ecc.write_page = nand_write_page_swecc;
|
||||
chip->ecc.read_page_raw = nand_read_page_raw;
|
||||
chip->ecc.write_page_raw = nand_write_page_raw;
|
||||
chip->ecc.read_oob = nand_read_oob_std;
|
||||
chip->ecc.write_oob = nand_write_oob_std;
|
||||
if (!chip->ecc.size)
|
||||
chip->ecc.size = 256;
|
||||
chip->ecc.bytes = 3;
|
||||
chip->ecc.strength = 1;
|
||||
ecc->calculate = nand_calculate_ecc;
|
||||
ecc->correct = nand_correct_data;
|
||||
ecc->read_page = nand_read_page_swecc;
|
||||
ecc->read_subpage = nand_read_subpage;
|
||||
ecc->write_page = nand_write_page_swecc;
|
||||
ecc->read_page_raw = nand_read_page_raw;
|
||||
ecc->write_page_raw = nand_write_page_raw;
|
||||
ecc->read_oob = nand_read_oob_std;
|
||||
ecc->write_oob = nand_write_oob_std;
|
||||
if (!ecc->size)
|
||||
ecc->size = 256;
|
||||
ecc->bytes = 3;
|
||||
ecc->strength = 1;
|
||||
break;
|
||||
|
||||
case NAND_ECC_SOFT_BCH:
|
||||
@ -3659,88 +3691,83 @@ int nand_scan_tail(struct mtd_info *mtd)
|
||||
pr_warn("CONFIG_MTD_ECC_BCH not enabled\n");
|
||||
BUG();
|
||||
}
|
||||
chip->ecc.calculate = nand_bch_calculate_ecc;
|
||||
chip->ecc.correct = nand_bch_correct_data;
|
||||
chip->ecc.read_page = nand_read_page_swecc;
|
||||
chip->ecc.read_subpage = nand_read_subpage;
|
||||
chip->ecc.write_page = nand_write_page_swecc;
|
||||
chip->ecc.read_page_raw = nand_read_page_raw;
|
||||
chip->ecc.write_page_raw = nand_write_page_raw;
|
||||
chip->ecc.read_oob = nand_read_oob_std;
|
||||
chip->ecc.write_oob = nand_write_oob_std;
|
||||
ecc->calculate = nand_bch_calculate_ecc;
|
||||
ecc->correct = nand_bch_correct_data;
|
||||
ecc->read_page = nand_read_page_swecc;
|
||||
ecc->read_subpage = nand_read_subpage;
|
||||
ecc->write_page = nand_write_page_swecc;
|
||||
ecc->read_page_raw = nand_read_page_raw;
|
||||
ecc->write_page_raw = nand_write_page_raw;
|
||||
ecc->read_oob = nand_read_oob_std;
|
||||
ecc->write_oob = nand_write_oob_std;
|
||||
/*
|
||||
* Board driver should supply ecc.size and ecc.bytes values to
|
||||
* select how many bits are correctable; see nand_bch_init()
|
||||
* for details. Otherwise, default to 4 bits for large page
|
||||
* devices.
|
||||
*/
|
||||
if (!chip->ecc.size && (mtd->oobsize >= 64)) {
|
||||
chip->ecc.size = 512;
|
||||
chip->ecc.bytes = 7;
|
||||
if (!ecc->size && (mtd->oobsize >= 64)) {
|
||||
ecc->size = 512;
|
||||
ecc->bytes = 7;
|
||||
}
|
||||
chip->ecc.priv = nand_bch_init(mtd,
|
||||
chip->ecc.size,
|
||||
chip->ecc.bytes,
|
||||
&chip->ecc.layout);
|
||||
if (!chip->ecc.priv) {
|
||||
ecc->priv = nand_bch_init(mtd, ecc->size, ecc->bytes,
|
||||
&ecc->layout);
|
||||
if (!ecc->priv) {
|
||||
pr_warn("BCH ECC initialization failed!\n");
|
||||
BUG();
|
||||
}
|
||||
chip->ecc.strength =
|
||||
chip->ecc.bytes * 8 / fls(8 * chip->ecc.size);
|
||||
ecc->strength = ecc->bytes * 8 / fls(8 * ecc->size);
|
||||
break;
|
||||
|
||||
case NAND_ECC_NONE:
|
||||
pr_warn("NAND_ECC_NONE selected by board driver. "
|
||||
"This is not recommended!\n");
|
||||
chip->ecc.read_page = nand_read_page_raw;
|
||||
chip->ecc.write_page = nand_write_page_raw;
|
||||
chip->ecc.read_oob = nand_read_oob_std;
|
||||
chip->ecc.read_page_raw = nand_read_page_raw;
|
||||
chip->ecc.write_page_raw = nand_write_page_raw;
|
||||
chip->ecc.write_oob = nand_write_oob_std;
|
||||
chip->ecc.size = mtd->writesize;
|
||||
chip->ecc.bytes = 0;
|
||||
chip->ecc.strength = 0;
|
||||
ecc->read_page = nand_read_page_raw;
|
||||
ecc->write_page = nand_write_page_raw;
|
||||
ecc->read_oob = nand_read_oob_std;
|
||||
ecc->read_page_raw = nand_read_page_raw;
|
||||
ecc->write_page_raw = nand_write_page_raw;
|
||||
ecc->write_oob = nand_write_oob_std;
|
||||
ecc->size = mtd->writesize;
|
||||
ecc->bytes = 0;
|
||||
ecc->strength = 0;
|
||||
break;
|
||||
|
||||
default:
|
||||
pr_warn("Invalid NAND_ECC_MODE %d\n", chip->ecc.mode);
|
||||
pr_warn("Invalid NAND_ECC_MODE %d\n", ecc->mode);
|
||||
BUG();
|
||||
}
|
||||
|
||||
/* For many systems, the standard OOB write also works for raw */
|
||||
if (!chip->ecc.read_oob_raw)
|
||||
chip->ecc.read_oob_raw = chip->ecc.read_oob;
|
||||
if (!chip->ecc.write_oob_raw)
|
||||
chip->ecc.write_oob_raw = chip->ecc.write_oob;
|
||||
if (!ecc->read_oob_raw)
|
||||
ecc->read_oob_raw = ecc->read_oob;
|
||||
if (!ecc->write_oob_raw)
|
||||
ecc->write_oob_raw = ecc->write_oob;
|
||||
|
||||
/*
|
||||
* The number of bytes available for a client to place data into
|
||||
* the out of band area.
|
||||
*/
|
||||
chip->ecc.layout->oobavail = 0;
|
||||
for (i = 0; chip->ecc.layout->oobfree[i].length
|
||||
&& i < ARRAY_SIZE(chip->ecc.layout->oobfree); i++)
|
||||
chip->ecc.layout->oobavail +=
|
||||
chip->ecc.layout->oobfree[i].length;
|
||||
mtd->oobavail = chip->ecc.layout->oobavail;
|
||||
ecc->layout->oobavail = 0;
|
||||
for (i = 0; ecc->layout->oobfree[i].length
|
||||
&& i < ARRAY_SIZE(ecc->layout->oobfree); i++)
|
||||
ecc->layout->oobavail += ecc->layout->oobfree[i].length;
|
||||
mtd->oobavail = ecc->layout->oobavail;
|
||||
|
||||
/*
|
||||
* Set the number of read / write steps for one page depending on ECC
|
||||
* mode.
|
||||
*/
|
||||
chip->ecc.steps = mtd->writesize / chip->ecc.size;
|
||||
if (chip->ecc.steps * chip->ecc.size != mtd->writesize) {
|
||||
ecc->steps = mtd->writesize / ecc->size;
|
||||
if (ecc->steps * ecc->size != mtd->writesize) {
|
||||
pr_warn("Invalid ECC parameters\n");
|
||||
BUG();
|
||||
}
|
||||
chip->ecc.total = chip->ecc.steps * chip->ecc.bytes;
|
||||
ecc->total = ecc->steps * ecc->bytes;
|
||||
|
||||
/* Allow subpage writes up to ecc.steps. Not possible for MLC flash */
|
||||
if (!(chip->options & NAND_NO_SUBPAGE_WRITE) &&
|
||||
!(chip->cellinfo & NAND_CI_CELLTYPE_MSK)) {
|
||||
switch (chip->ecc.steps) {
|
||||
if (!(chip->options & NAND_NO_SUBPAGE_WRITE) && nand_is_slc(chip)) {
|
||||
switch (ecc->steps) {
|
||||
case 2:
|
||||
mtd->subpage_sft = 1;
|
||||
break;
|
||||
@ -3760,11 +3787,11 @@ int nand_scan_tail(struct mtd_info *mtd)
|
||||
chip->pagebuf = -1;
|
||||
|
||||
/* Large page NAND with SOFT_ECC should support subpage reads */
|
||||
if ((chip->ecc.mode == NAND_ECC_SOFT) && (chip->page_shift > 9))
|
||||
if ((ecc->mode == NAND_ECC_SOFT) && (chip->page_shift > 9))
|
||||
chip->options |= NAND_SUBPAGE_READ;
|
||||
|
||||
/* Fill in remaining MTD driver data */
|
||||
mtd->type = MTD_NANDFLASH;
|
||||
mtd->type = nand_is_slc(chip) ? MTD_NANDFLASH : MTD_MLCNANDFLASH;
|
||||
mtd->flags = (chip->options & NAND_ROM) ? MTD_CAP_ROM :
|
||||
MTD_CAP_NANDFLASH;
|
||||
mtd->_erase = nand_erase;
|
||||
@ -3785,9 +3812,9 @@ int nand_scan_tail(struct mtd_info *mtd)
|
||||
mtd->writebufsize = mtd->writesize;
|
||||
|
||||
/* propagate ecc info to mtd_info */
|
||||
mtd->ecclayout = chip->ecc.layout;
|
||||
mtd->ecc_strength = chip->ecc.strength;
|
||||
mtd->ecc_step_size = chip->ecc.size;
|
||||
mtd->ecclayout = ecc->layout;
|
||||
mtd->ecc_strength = ecc->strength;
|
||||
mtd->ecc_step_size = ecc->size;
|
||||
/*
|
||||
* Initialize bitflip_threshold to its default prior scan_bbt() call.
|
||||
* scan_bbt() might invoke mtd_read(), thus bitflip_threshold must be
|
||||
|
@ -412,25 +412,6 @@ static void read_abs_bbts(struct mtd_info *mtd, uint8_t *buf,
|
||||
}
|
||||
}
|
||||
|
||||
/* Scan a given block full */
|
||||
static int scan_block_full(struct mtd_info *mtd, struct nand_bbt_descr *bd,
|
||||
loff_t offs, uint8_t *buf, size_t readlen,
|
||||
int scanlen, int numpages)
|
||||
{
|
||||
int ret, j;
|
||||
|
||||
ret = scan_read_oob(mtd, buf, offs, readlen);
|
||||
/* Ignore ECC errors when checking for BBM */
|
||||
if (ret && !mtd_is_bitflip_or_eccerr(ret))
|
||||
return ret;
|
||||
|
||||
for (j = 0; j < numpages; j++, buf += scanlen) {
|
||||
if (check_pattern(buf, scanlen, mtd->writesize, bd))
|
||||
return 1;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Scan a given block partially */
|
||||
static int scan_block_fast(struct mtd_info *mtd, struct nand_bbt_descr *bd,
|
||||
loff_t offs, uint8_t *buf, int numpages)
|
||||
@ -477,24 +458,17 @@ static int create_bbt(struct mtd_info *mtd, uint8_t *buf,
|
||||
struct nand_bbt_descr *bd, int chip)
|
||||
{
|
||||
struct nand_chip *this = mtd->priv;
|
||||
int i, numblocks, numpages, scanlen;
|
||||
int i, numblocks, numpages;
|
||||
int startblock;
|
||||
loff_t from;
|
||||
size_t readlen;
|
||||
|
||||
pr_info("Scanning device for bad blocks\n");
|
||||
|
||||
if (bd->options & NAND_BBT_SCANALLPAGES)
|
||||
numpages = 1 << (this->bbt_erase_shift - this->page_shift);
|
||||
else if (bd->options & NAND_BBT_SCAN2NDPAGE)
|
||||
if (bd->options & NAND_BBT_SCAN2NDPAGE)
|
||||
numpages = 2;
|
||||
else
|
||||
numpages = 1;
|
||||
|
||||
/* We need only read few bytes from the OOB area */
|
||||
scanlen = 0;
|
||||
readlen = bd->len;
|
||||
|
||||
if (chip == -1) {
|
||||
numblocks = mtd->size >> this->bbt_erase_shift;
|
||||
startblock = 0;
|
||||
@ -519,12 +493,7 @@ static int create_bbt(struct mtd_info *mtd, uint8_t *buf,
|
||||
|
||||
BUG_ON(bd->options & NAND_BBT_NO_OOB);
|
||||
|
||||
if (bd->options & NAND_BBT_SCANALLPAGES)
|
||||
ret = scan_block_full(mtd, bd, from, buf, readlen,
|
||||
scanlen, numpages);
|
||||
else
|
||||
ret = scan_block_fast(mtd, bd, from, buf, numpages);
|
||||
|
||||
ret = scan_block_fast(mtd, bd, from, buf, numpages);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
@ -1392,4 +1361,3 @@ int nand_markbad_bbt(struct mtd_info *mtd, loff_t offs)
|
||||
}
|
||||
|
||||
EXPORT_SYMBOL(nand_scan_bbt);
|
||||
EXPORT_SYMBOL(nand_default_bbt);
|
||||
|
@ -2372,7 +2372,7 @@ static int __init ns_init_module(void)
|
||||
if ((retval = init_nandsim(nsmtd)) != 0)
|
||||
goto err_exit;
|
||||
|
||||
if ((retval = nand_default_bbt(nsmtd)) != 0)
|
||||
if ((retval = chip->scan_bbt(nsmtd)) != 0)
|
||||
goto err_exit;
|
||||
|
||||
if ((retval = parse_badblocks(nand, nsmtd)) != 0)
|
||||
|
@ -25,10 +25,8 @@
|
||||
#include <linux/of.h>
|
||||
#include <linux/of_device.h>
|
||||
|
||||
#ifdef CONFIG_MTD_NAND_OMAP_BCH
|
||||
#include <linux/bch.h>
|
||||
#include <linux/mtd/nand_bch.h>
|
||||
#include <linux/platform_data/elm.h>
|
||||
#endif
|
||||
|
||||
#include <linux/platform_data/mtd-nand-omap2.h>
|
||||
|
||||
@ -141,6 +139,8 @@
|
||||
#define BCH_ECC_SIZE0 0x0 /* ecc_size0 = 0, no oob protection */
|
||||
#define BCH_ECC_SIZE1 0x20 /* ecc_size1 = 32 */
|
||||
|
||||
#define BADBLOCK_MARKER_LENGTH 2
|
||||
|
||||
#ifdef CONFIG_MTD_NAND_OMAP_BCH
|
||||
static u_char bch8_vector[] = {0xf3, 0xdb, 0x14, 0x16, 0x8b, 0xd2, 0xbe, 0xcc,
|
||||
0xac, 0x6b, 0xff, 0x99, 0x7b};
|
||||
@ -149,17 +149,6 @@ static u_char bch4_vector[] = {0x00, 0x6b, 0x31, 0xdd, 0x41, 0xbc, 0x10};
|
||||
|
||||
/* oob info generated runtime depending on ecc algorithm and layout selected */
|
||||
static struct nand_ecclayout omap_oobinfo;
|
||||
/* Define some generic bad / good block scan pattern which are used
|
||||
* while scanning a device for factory marked good / bad blocks
|
||||
*/
|
||||
static uint8_t scan_ff_pattern[] = { 0xff };
|
||||
static struct nand_bbt_descr bb_descrip_flashbased = {
|
||||
.options = NAND_BBT_SCANALLPAGES,
|
||||
.offs = 0,
|
||||
.len = 1,
|
||||
.pattern = scan_ff_pattern,
|
||||
};
|
||||
|
||||
|
||||
struct omap_nand_info {
|
||||
struct nand_hw_control controller;
|
||||
@ -182,14 +171,10 @@ struct omap_nand_info {
|
||||
u_char *buf;
|
||||
int buf_len;
|
||||
struct gpmc_nand_regs reg;
|
||||
|
||||
#ifdef CONFIG_MTD_NAND_OMAP_BCH
|
||||
struct bch_control *bch;
|
||||
struct nand_ecclayout ecclayout;
|
||||
/* fields specific for BCHx_HW ECC scheme */
|
||||
bool is_elm_used;
|
||||
struct device *elm_dev;
|
||||
struct device_node *of_node;
|
||||
#endif
|
||||
};
|
||||
|
||||
/**
|
||||
@ -1058,8 +1043,7 @@ static int omap_dev_ready(struct mtd_info *mtd)
|
||||
}
|
||||
}
|
||||
|
||||
#ifdef CONFIG_MTD_NAND_OMAP_BCH
|
||||
|
||||
#if defined(CONFIG_MTD_NAND_ECC_BCH) || defined(CONFIG_MTD_NAND_OMAP_BCH)
|
||||
/**
|
||||
* omap3_enable_hwecc_bch - Program OMAP3 GPMC to perform BCH ECC correction
|
||||
* @mtd: MTD device structure
|
||||
@ -1140,7 +1124,9 @@ static void omap3_enable_hwecc_bch(struct mtd_info *mtd, int mode)
|
||||
/* Clear ecc and enable bits */
|
||||
writel(ECCCLEAR | ECC1, info->reg.gpmc_ecc_control);
|
||||
}
|
||||
#endif
|
||||
|
||||
#ifdef CONFIG_MTD_NAND_ECC_BCH
|
||||
/**
|
||||
* omap3_calculate_ecc_bch4 - Generate 7 bytes of ECC bytes
|
||||
* @mtd: MTD device structure
|
||||
@ -1225,7 +1211,9 @@ static int omap3_calculate_ecc_bch8(struct mtd_info *mtd, const u_char *dat,
|
||||
|
||||
return 0;
|
||||
}
|
||||
#endif /* CONFIG_MTD_NAND_ECC_BCH */
|
||||
|
||||
#ifdef CONFIG_MTD_NAND_OMAP_BCH
|
||||
/**
|
||||
* omap3_calculate_ecc_bch - Generate bytes of ECC bytes
|
||||
* @mtd: MTD device structure
|
||||
@ -1518,38 +1506,6 @@ static int omap_elm_correct_data(struct mtd_info *mtd, u_char *data,
|
||||
return stat;
|
||||
}
|
||||
|
||||
/**
|
||||
* omap3_correct_data_bch - Decode received data and correct errors
|
||||
* @mtd: MTD device structure
|
||||
* @data: page data
|
||||
* @read_ecc: ecc read from nand flash
|
||||
* @calc_ecc: ecc read from HW ECC registers
|
||||
*/
|
||||
static int omap3_correct_data_bch(struct mtd_info *mtd, u_char *data,
|
||||
u_char *read_ecc, u_char *calc_ecc)
|
||||
{
|
||||
int i, count;
|
||||
/* cannot correct more than 8 errors */
|
||||
unsigned int errloc[8];
|
||||
struct omap_nand_info *info = container_of(mtd, struct omap_nand_info,
|
||||
mtd);
|
||||
|
||||
count = decode_bch(info->bch, NULL, 512, read_ecc, calc_ecc, NULL,
|
||||
errloc);
|
||||
if (count > 0) {
|
||||
/* correct errors */
|
||||
for (i = 0; i < count; i++) {
|
||||
/* correct data only, not ecc bytes */
|
||||
if (errloc[i] < 8*512)
|
||||
data[errloc[i]/8] ^= 1 << (errloc[i] & 7);
|
||||
pr_debug("corrected bitflip %u\n", errloc[i]);
|
||||
}
|
||||
} else if (count < 0) {
|
||||
pr_err("ecc unrecoverable error\n");
|
||||
}
|
||||
return count;
|
||||
}
|
||||
|
||||
/**
|
||||
* omap_write_page_bch - BCH ecc based write page function for entire page
|
||||
* @mtd: mtd info structure
|
||||
@ -1637,197 +1593,46 @@ static int omap_read_page_bch(struct mtd_info *mtd, struct nand_chip *chip,
|
||||
}
|
||||
|
||||
/**
|
||||
* omap3_free_bch - Release BCH ecc resources
|
||||
* @mtd: MTD device structure
|
||||
* is_elm_present - checks for presence of ELM module by scanning DT nodes
|
||||
* @omap_nand_info: NAND device structure containing platform data
|
||||
* @bch_type: 0x0=BCH4, 0x1=BCH8, 0x2=BCH16
|
||||
*/
|
||||
static void omap3_free_bch(struct mtd_info *mtd)
|
||||
static int is_elm_present(struct omap_nand_info *info,
|
||||
struct device_node *elm_node, enum bch_ecc bch_type)
|
||||
{
|
||||
struct omap_nand_info *info = container_of(mtd, struct omap_nand_info,
|
||||
mtd);
|
||||
if (info->bch) {
|
||||
free_bch(info->bch);
|
||||
info->bch = NULL;
|
||||
struct platform_device *pdev;
|
||||
info->is_elm_used = false;
|
||||
/* check whether elm-id is passed via DT */
|
||||
if (!elm_node) {
|
||||
pr_err("nand: error: ELM DT node not found\n");
|
||||
return -ENODEV;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* omap3_init_bch - Initialize BCH ECC
|
||||
* @mtd: MTD device structure
|
||||
* @ecc_opt: OMAP ECC mode (OMAP_ECC_BCH4_CODE_HW or OMAP_ECC_BCH8_CODE_HW)
|
||||
*/
|
||||
static int omap3_init_bch(struct mtd_info *mtd, int ecc_opt)
|
||||
{
|
||||
int max_errors;
|
||||
struct omap_nand_info *info = container_of(mtd, struct omap_nand_info,
|
||||
mtd);
|
||||
#ifdef CONFIG_MTD_NAND_OMAP_BCH8
|
||||
const int hw_errors = BCH8_MAX_ERROR;
|
||||
#else
|
||||
const int hw_errors = BCH4_MAX_ERROR;
|
||||
#endif
|
||||
enum bch_ecc bch_type;
|
||||
const __be32 *parp;
|
||||
int lenp;
|
||||
struct device_node *elm_node;
|
||||
|
||||
info->bch = NULL;
|
||||
|
||||
max_errors = (ecc_opt == OMAP_ECC_BCH8_CODE_HW) ?
|
||||
BCH8_MAX_ERROR : BCH4_MAX_ERROR;
|
||||
if (max_errors != hw_errors) {
|
||||
pr_err("cannot configure %d-bit BCH ecc, only %d-bit supported",
|
||||
max_errors, hw_errors);
|
||||
goto fail;
|
||||
pdev = of_find_device_by_node(elm_node);
|
||||
/* check whether ELM device is registered */
|
||||
if (!pdev) {
|
||||
pr_err("nand: error: ELM device not found\n");
|
||||
return -ENODEV;
|
||||
}
|
||||
|
||||
info->nand.ecc.size = 512;
|
||||
info->nand.ecc.hwctl = omap3_enable_hwecc_bch;
|
||||
info->nand.ecc.mode = NAND_ECC_HW;
|
||||
info->nand.ecc.strength = max_errors;
|
||||
|
||||
if (hw_errors == BCH8_MAX_ERROR)
|
||||
bch_type = BCH8_ECC;
|
||||
else
|
||||
bch_type = BCH4_ECC;
|
||||
|
||||
/* Detect availability of ELM module */
|
||||
parp = of_get_property(info->of_node, "elm_id", &lenp);
|
||||
if ((parp == NULL) && (lenp != (sizeof(void *) * 2))) {
|
||||
pr_err("Missing elm_id property, fall back to Software BCH\n");
|
||||
info->is_elm_used = false;
|
||||
} else {
|
||||
struct platform_device *pdev;
|
||||
|
||||
elm_node = of_find_node_by_phandle(be32_to_cpup(parp));
|
||||
pdev = of_find_device_by_node(elm_node);
|
||||
info->elm_dev = &pdev->dev;
|
||||
|
||||
if (elm_config(info->elm_dev, bch_type) == 0)
|
||||
info->is_elm_used = true;
|
||||
}
|
||||
|
||||
if (info->is_elm_used && (mtd->writesize <= 4096)) {
|
||||
|
||||
if (hw_errors == BCH8_MAX_ERROR)
|
||||
info->nand.ecc.bytes = BCH8_SIZE;
|
||||
else
|
||||
info->nand.ecc.bytes = BCH4_SIZE;
|
||||
|
||||
info->nand.ecc.correct = omap_elm_correct_data;
|
||||
info->nand.ecc.calculate = omap3_calculate_ecc_bch;
|
||||
info->nand.ecc.read_page = omap_read_page_bch;
|
||||
info->nand.ecc.write_page = omap_write_page_bch;
|
||||
} else {
|
||||
/*
|
||||
* software bch library is only used to detect and
|
||||
* locate errors
|
||||
*/
|
||||
info->bch = init_bch(13, max_errors,
|
||||
0x201b /* hw polynomial */);
|
||||
if (!info->bch)
|
||||
goto fail;
|
||||
|
||||
info->nand.ecc.correct = omap3_correct_data_bch;
|
||||
|
||||
/*
|
||||
* The number of corrected errors in an ecc block that will
|
||||
* trigger block scrubbing defaults to the ecc strength (4 or 8)
|
||||
* Set mtd->bitflip_threshold here to define a custom threshold.
|
||||
*/
|
||||
|
||||
if (max_errors == 8) {
|
||||
info->nand.ecc.bytes = 13;
|
||||
info->nand.ecc.calculate = omap3_calculate_ecc_bch8;
|
||||
} else {
|
||||
info->nand.ecc.bytes = 7;
|
||||
info->nand.ecc.calculate = omap3_calculate_ecc_bch4;
|
||||
}
|
||||
}
|
||||
|
||||
pr_info("enabling NAND BCH ecc with %d-bit correction\n", max_errors);
|
||||
/* ELM module available, now configure it */
|
||||
info->elm_dev = &pdev->dev;
|
||||
if (elm_config(info->elm_dev, bch_type))
|
||||
return -ENODEV;
|
||||
info->is_elm_used = true;
|
||||
return 0;
|
||||
fail:
|
||||
omap3_free_bch(mtd);
|
||||
return -1;
|
||||
}
|
||||
|
||||
/**
|
||||
* omap3_init_bch_tail - Build an oob layout for BCH ECC correction.
|
||||
* @mtd: MTD device structure
|
||||
*/
|
||||
static int omap3_init_bch_tail(struct mtd_info *mtd)
|
||||
{
|
||||
int i, steps, offset;
|
||||
struct omap_nand_info *info = container_of(mtd, struct omap_nand_info,
|
||||
mtd);
|
||||
struct nand_ecclayout *layout = &info->ecclayout;
|
||||
|
||||
/* build oob layout */
|
||||
steps = mtd->writesize/info->nand.ecc.size;
|
||||
layout->eccbytes = steps*info->nand.ecc.bytes;
|
||||
|
||||
/* do not bother creating special oob layouts for small page devices */
|
||||
if (mtd->oobsize < 64) {
|
||||
pr_err("BCH ecc is not supported on small page devices\n");
|
||||
goto fail;
|
||||
}
|
||||
|
||||
/* reserve 2 bytes for bad block marker */
|
||||
if (layout->eccbytes+2 > mtd->oobsize) {
|
||||
pr_err("no oob layout available for oobsize %d eccbytes %u\n",
|
||||
mtd->oobsize, layout->eccbytes);
|
||||
goto fail;
|
||||
}
|
||||
|
||||
/* ECC layout compatible with RBL for BCH8 */
|
||||
if (info->is_elm_used && (info->nand.ecc.bytes == BCH8_SIZE))
|
||||
offset = 2;
|
||||
else
|
||||
offset = mtd->oobsize - layout->eccbytes;
|
||||
|
||||
/* put ecc bytes at oob tail */
|
||||
for (i = 0; i < layout->eccbytes; i++)
|
||||
layout->eccpos[i] = offset + i;
|
||||
|
||||
if (info->is_elm_used && (info->nand.ecc.bytes == BCH8_SIZE))
|
||||
layout->oobfree[0].offset = 2 + layout->eccbytes * steps;
|
||||
else
|
||||
layout->oobfree[0].offset = 2;
|
||||
|
||||
layout->oobfree[0].length = mtd->oobsize-2-layout->eccbytes;
|
||||
info->nand.ecc.layout = layout;
|
||||
|
||||
if (!(info->nand.options & NAND_BUSWIDTH_16))
|
||||
info->nand.badblock_pattern = &bb_descrip_flashbased;
|
||||
return 0;
|
||||
fail:
|
||||
omap3_free_bch(mtd);
|
||||
return -1;
|
||||
}
|
||||
|
||||
#else
|
||||
static int omap3_init_bch(struct mtd_info *mtd, int ecc_opt)
|
||||
{
|
||||
pr_err("CONFIG_MTD_NAND_OMAP_BCH is not enabled\n");
|
||||
return -1;
|
||||
}
|
||||
static int omap3_init_bch_tail(struct mtd_info *mtd)
|
||||
{
|
||||
return -1;
|
||||
}
|
||||
static void omap3_free_bch(struct mtd_info *mtd)
|
||||
{
|
||||
}
|
||||
#endif /* CONFIG_MTD_NAND_OMAP_BCH */
|
||||
#endif /* CONFIG_MTD_NAND_ECC_BCH */
|
||||
|
||||
static int omap_nand_probe(struct platform_device *pdev)
|
||||
{
|
||||
struct omap_nand_info *info;
|
||||
struct omap_nand_platform_data *pdata;
|
||||
struct mtd_info *mtd;
|
||||
struct nand_chip *nand_chip;
|
||||
struct nand_ecclayout *ecclayout;
|
||||
int err;
|
||||
int i, offset;
|
||||
dma_cap_mask_t mask;
|
||||
unsigned sig;
|
||||
int i;
|
||||
dma_cap_mask_t mask;
|
||||
unsigned sig;
|
||||
struct resource *res;
|
||||
struct mtd_part_parser_data ppdata = {};
|
||||
|
||||
@ -1837,7 +1642,8 @@ static int omap_nand_probe(struct platform_device *pdev)
|
||||
return -ENODEV;
|
||||
}
|
||||
|
||||
info = kzalloc(sizeof(struct omap_nand_info), GFP_KERNEL);
|
||||
info = devm_kzalloc(&pdev->dev, sizeof(struct omap_nand_info),
|
||||
GFP_KERNEL);
|
||||
if (!info)
|
||||
return -ENOMEM;
|
||||
|
||||
@ -1846,47 +1652,45 @@ static int omap_nand_probe(struct platform_device *pdev)
|
||||
spin_lock_init(&info->controller.lock);
|
||||
init_waitqueue_head(&info->controller.wq);
|
||||
|
||||
info->pdev = pdev;
|
||||
|
||||
info->pdev = pdev;
|
||||
info->gpmc_cs = pdata->cs;
|
||||
info->reg = pdata->reg;
|
||||
|
||||
info->mtd.priv = &info->nand;
|
||||
info->mtd.name = dev_name(&pdev->dev);
|
||||
info->mtd.owner = THIS_MODULE;
|
||||
|
||||
info->nand.options = pdata->devsize;
|
||||
info->nand.options |= NAND_SKIP_BBTSCAN;
|
||||
#ifdef CONFIG_MTD_NAND_OMAP_BCH
|
||||
info->of_node = pdata->of_node;
|
||||
#endif
|
||||
mtd = &info->mtd;
|
||||
mtd->priv = &info->nand;
|
||||
mtd->name = dev_name(&pdev->dev);
|
||||
mtd->owner = THIS_MODULE;
|
||||
nand_chip = &info->nand;
|
||||
nand_chip->ecc.priv = NULL;
|
||||
nand_chip->options |= NAND_SKIP_BBTSCAN;
|
||||
|
||||
res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
|
||||
if (res == NULL) {
|
||||
err = -EINVAL;
|
||||
dev_err(&pdev->dev, "error getting memory resource\n");
|
||||
goto out_free_info;
|
||||
goto return_error;
|
||||
}
|
||||
|
||||
info->phys_base = res->start;
|
||||
info->mem_size = resource_size(res);
|
||||
|
||||
if (!request_mem_region(info->phys_base, info->mem_size,
|
||||
pdev->dev.driver->name)) {
|
||||
if (!devm_request_mem_region(&pdev->dev, info->phys_base,
|
||||
info->mem_size, pdev->dev.driver->name)) {
|
||||
err = -EBUSY;
|
||||
goto out_free_info;
|
||||
goto return_error;
|
||||
}
|
||||
|
||||
info->nand.IO_ADDR_R = ioremap(info->phys_base, info->mem_size);
|
||||
if (!info->nand.IO_ADDR_R) {
|
||||
nand_chip->IO_ADDR_R = devm_ioremap(&pdev->dev, info->phys_base,
|
||||
info->mem_size);
|
||||
if (!nand_chip->IO_ADDR_R) {
|
||||
err = -ENOMEM;
|
||||
goto out_release_mem_region;
|
||||
goto return_error;
|
||||
}
|
||||
|
||||
info->nand.controller = &info->controller;
|
||||
nand_chip->controller = &info->controller;
|
||||
|
||||
info->nand.IO_ADDR_W = info->nand.IO_ADDR_R;
|
||||
info->nand.cmd_ctrl = omap_hwcontrol;
|
||||
nand_chip->IO_ADDR_W = nand_chip->IO_ADDR_R;
|
||||
nand_chip->cmd_ctrl = omap_hwcontrol;
|
||||
|
||||
/*
|
||||
* If RDY/BSY line is connected to OMAP then use the omap ready
|
||||
@ -1896,26 +1700,42 @@ static int omap_nand_probe(struct platform_device *pdev)
|
||||
* device and read status register until you get a failure or success
|
||||
*/
|
||||
if (pdata->dev_ready) {
|
||||
info->nand.dev_ready = omap_dev_ready;
|
||||
info->nand.chip_delay = 0;
|
||||
nand_chip->dev_ready = omap_dev_ready;
|
||||
nand_chip->chip_delay = 0;
|
||||
} else {
|
||||
info->nand.waitfunc = omap_wait;
|
||||
info->nand.chip_delay = 50;
|
||||
nand_chip->waitfunc = omap_wait;
|
||||
nand_chip->chip_delay = 50;
|
||||
}
|
||||
|
||||
/* scan NAND device connected to chip controller */
|
||||
nand_chip->options |= pdata->devsize & NAND_BUSWIDTH_16;
|
||||
if (nand_scan_ident(mtd, 1, NULL)) {
|
||||
pr_err("nand device scan failed, may be bus-width mismatch\n");
|
||||
err = -ENXIO;
|
||||
goto return_error;
|
||||
}
|
||||
|
||||
/* check for small page devices */
|
||||
if ((mtd->oobsize < 64) && (pdata->ecc_opt != OMAP_ECC_HAM1_CODE_HW)) {
|
||||
pr_err("small page devices are not supported\n");
|
||||
err = -EINVAL;
|
||||
goto return_error;
|
||||
}
|
||||
|
||||
/* re-populate low-level callbacks based on xfer modes */
|
||||
switch (pdata->xfer_type) {
|
||||
case NAND_OMAP_PREFETCH_POLLED:
|
||||
info->nand.read_buf = omap_read_buf_pref;
|
||||
info->nand.write_buf = omap_write_buf_pref;
|
||||
nand_chip->read_buf = omap_read_buf_pref;
|
||||
nand_chip->write_buf = omap_write_buf_pref;
|
||||
break;
|
||||
|
||||
case NAND_OMAP_POLLED:
|
||||
if (info->nand.options & NAND_BUSWIDTH_16) {
|
||||
info->nand.read_buf = omap_read_buf16;
|
||||
info->nand.write_buf = omap_write_buf16;
|
||||
if (nand_chip->options & NAND_BUSWIDTH_16) {
|
||||
nand_chip->read_buf = omap_read_buf16;
|
||||
nand_chip->write_buf = omap_write_buf16;
|
||||
} else {
|
||||
info->nand.read_buf = omap_read_buf8;
|
||||
info->nand.write_buf = omap_write_buf8;
|
||||
nand_chip->read_buf = omap_read_buf8;
|
||||
nand_chip->write_buf = omap_write_buf8;
|
||||
}
|
||||
break;
|
||||
|
||||
@ -1927,7 +1747,7 @@ static int omap_nand_probe(struct platform_device *pdev)
|
||||
if (!info->dma) {
|
||||
dev_err(&pdev->dev, "DMA engine request failed\n");
|
||||
err = -ENXIO;
|
||||
goto out_release_mem_region;
|
||||
goto return_error;
|
||||
} else {
|
||||
struct dma_slave_config cfg;
|
||||
|
||||
@ -1942,10 +1762,10 @@ static int omap_nand_probe(struct platform_device *pdev)
|
||||
if (err) {
|
||||
dev_err(&pdev->dev, "DMA engine slave config failed: %d\n",
|
||||
err);
|
||||
goto out_release_mem_region;
|
||||
goto return_error;
|
||||
}
|
||||
info->nand.read_buf = omap_read_buf_dma_pref;
|
||||
info->nand.write_buf = omap_write_buf_dma_pref;
|
||||
nand_chip->read_buf = omap_read_buf_dma_pref;
|
||||
nand_chip->write_buf = omap_write_buf_dma_pref;
|
||||
}
|
||||
break;
|
||||
|
||||
@ -1954,34 +1774,36 @@ static int omap_nand_probe(struct platform_device *pdev)
|
||||
if (info->gpmc_irq_fifo <= 0) {
|
||||
dev_err(&pdev->dev, "error getting fifo irq\n");
|
||||
err = -ENODEV;
|
||||
goto out_release_mem_region;
|
||||
goto return_error;
|
||||
}
|
||||
err = request_irq(info->gpmc_irq_fifo, omap_nand_irq,
|
||||
IRQF_SHARED, "gpmc-nand-fifo", info);
|
||||
err = devm_request_irq(&pdev->dev, info->gpmc_irq_fifo,
|
||||
omap_nand_irq, IRQF_SHARED,
|
||||
"gpmc-nand-fifo", info);
|
||||
if (err) {
|
||||
dev_err(&pdev->dev, "requesting irq(%d) error:%d",
|
||||
info->gpmc_irq_fifo, err);
|
||||
info->gpmc_irq_fifo = 0;
|
||||
goto out_release_mem_region;
|
||||
goto return_error;
|
||||
}
|
||||
|
||||
info->gpmc_irq_count = platform_get_irq(pdev, 1);
|
||||
if (info->gpmc_irq_count <= 0) {
|
||||
dev_err(&pdev->dev, "error getting count irq\n");
|
||||
err = -ENODEV;
|
||||
goto out_release_mem_region;
|
||||
goto return_error;
|
||||
}
|
||||
err = request_irq(info->gpmc_irq_count, omap_nand_irq,
|
||||
IRQF_SHARED, "gpmc-nand-count", info);
|
||||
err = devm_request_irq(&pdev->dev, info->gpmc_irq_count,
|
||||
omap_nand_irq, IRQF_SHARED,
|
||||
"gpmc-nand-count", info);
|
||||
if (err) {
|
||||
dev_err(&pdev->dev, "requesting irq(%d) error:%d",
|
||||
info->gpmc_irq_count, err);
|
||||
info->gpmc_irq_count = 0;
|
||||
goto out_release_mem_region;
|
||||
goto return_error;
|
||||
}
|
||||
|
||||
info->nand.read_buf = omap_read_buf_irq_pref;
|
||||
info->nand.write_buf = omap_write_buf_irq_pref;
|
||||
nand_chip->read_buf = omap_read_buf_irq_pref;
|
||||
nand_chip->write_buf = omap_write_buf_irq_pref;
|
||||
|
||||
break;
|
||||
|
||||
@ -1989,117 +1811,223 @@ static int omap_nand_probe(struct platform_device *pdev)
|
||||
dev_err(&pdev->dev,
|
||||
"xfer_type(%d) not supported!\n", pdata->xfer_type);
|
||||
err = -EINVAL;
|
||||
goto out_release_mem_region;
|
||||
goto return_error;
|
||||
}
|
||||
|
||||
/* select the ecc type */
|
||||
if (pdata->ecc_opt == OMAP_ECC_HAMMING_CODE_DEFAULT)
|
||||
info->nand.ecc.mode = NAND_ECC_SOFT;
|
||||
else if ((pdata->ecc_opt == OMAP_ECC_HAMMING_CODE_HW) ||
|
||||
(pdata->ecc_opt == OMAP_ECC_HAMMING_CODE_HW_ROMCODE)) {
|
||||
info->nand.ecc.bytes = 3;
|
||||
info->nand.ecc.size = 512;
|
||||
info->nand.ecc.strength = 1;
|
||||
info->nand.ecc.calculate = omap_calculate_ecc;
|
||||
info->nand.ecc.hwctl = omap_enable_hwecc;
|
||||
info->nand.ecc.correct = omap_correct_data;
|
||||
info->nand.ecc.mode = NAND_ECC_HW;
|
||||
} else if ((pdata->ecc_opt == OMAP_ECC_BCH4_CODE_HW) ||
|
||||
(pdata->ecc_opt == OMAP_ECC_BCH8_CODE_HW)) {
|
||||
err = omap3_init_bch(&info->mtd, pdata->ecc_opt);
|
||||
if (err) {
|
||||
/* populate MTD interface based on ECC scheme */
|
||||
nand_chip->ecc.layout = &omap_oobinfo;
|
||||
ecclayout = &omap_oobinfo;
|
||||
switch (pdata->ecc_opt) {
|
||||
case OMAP_ECC_HAM1_CODE_HW:
|
||||
pr_info("nand: using OMAP_ECC_HAM1_CODE_HW\n");
|
||||
nand_chip->ecc.mode = NAND_ECC_HW;
|
||||
nand_chip->ecc.bytes = 3;
|
||||
nand_chip->ecc.size = 512;
|
||||
nand_chip->ecc.strength = 1;
|
||||
nand_chip->ecc.calculate = omap_calculate_ecc;
|
||||
nand_chip->ecc.hwctl = omap_enable_hwecc;
|
||||
nand_chip->ecc.correct = omap_correct_data;
|
||||
/* define ECC layout */
|
||||
ecclayout->eccbytes = nand_chip->ecc.bytes *
|
||||
(mtd->writesize /
|
||||
nand_chip->ecc.size);
|
||||
if (nand_chip->options & NAND_BUSWIDTH_16)
|
||||
ecclayout->eccpos[0] = BADBLOCK_MARKER_LENGTH;
|
||||
else
|
||||
ecclayout->eccpos[0] = 1;
|
||||
ecclayout->oobfree->offset = ecclayout->eccpos[0] +
|
||||
ecclayout->eccbytes;
|
||||
break;
|
||||
|
||||
case OMAP_ECC_BCH4_CODE_HW_DETECTION_SW:
|
||||
#ifdef CONFIG_MTD_NAND_ECC_BCH
|
||||
pr_info("nand: using OMAP_ECC_BCH4_CODE_HW_DETECTION_SW\n");
|
||||
nand_chip->ecc.mode = NAND_ECC_HW;
|
||||
nand_chip->ecc.size = 512;
|
||||
nand_chip->ecc.bytes = 7;
|
||||
nand_chip->ecc.strength = 4;
|
||||
nand_chip->ecc.hwctl = omap3_enable_hwecc_bch;
|
||||
nand_chip->ecc.correct = nand_bch_correct_data;
|
||||
nand_chip->ecc.calculate = omap3_calculate_ecc_bch4;
|
||||
/* define ECC layout */
|
||||
ecclayout->eccbytes = nand_chip->ecc.bytes *
|
||||
(mtd->writesize /
|
||||
nand_chip->ecc.size);
|
||||
ecclayout->eccpos[0] = BADBLOCK_MARKER_LENGTH;
|
||||
ecclayout->oobfree->offset = ecclayout->eccpos[0] +
|
||||
ecclayout->eccbytes;
|
||||
/* software bch library is used for locating errors */
|
||||
nand_chip->ecc.priv = nand_bch_init(mtd,
|
||||
nand_chip->ecc.size,
|
||||
nand_chip->ecc.bytes,
|
||||
&nand_chip->ecc.layout);
|
||||
if (!nand_chip->ecc.priv) {
|
||||
pr_err("nand: error: unable to use s/w BCH library\n");
|
||||
err = -EINVAL;
|
||||
goto out_release_mem_region;
|
||||
}
|
||||
}
|
||||
break;
|
||||
#else
|
||||
pr_err("nand: error: CONFIG_MTD_NAND_ECC_BCH not enabled\n");
|
||||
err = -EINVAL;
|
||||
goto return_error;
|
||||
#endif
|
||||
|
||||
/* DIP switches on some boards change between 8 and 16 bit
|
||||
* bus widths for flash. Try the other width if the first try fails.
|
||||
*/
|
||||
if (nand_scan_ident(&info->mtd, 1, NULL)) {
|
||||
info->nand.options ^= NAND_BUSWIDTH_16;
|
||||
if (nand_scan_ident(&info->mtd, 1, NULL)) {
|
||||
err = -ENXIO;
|
||||
goto out_release_mem_region;
|
||||
case OMAP_ECC_BCH4_CODE_HW:
|
||||
#ifdef CONFIG_MTD_NAND_OMAP_BCH
|
||||
pr_info("nand: using OMAP_ECC_BCH4_CODE_HW ECC scheme\n");
|
||||
nand_chip->ecc.mode = NAND_ECC_HW;
|
||||
nand_chip->ecc.size = 512;
|
||||
/* 14th bit is kept reserved for ROM-code compatibility */
|
||||
nand_chip->ecc.bytes = 7 + 1;
|
||||
nand_chip->ecc.strength = 4;
|
||||
nand_chip->ecc.hwctl = omap3_enable_hwecc_bch;
|
||||
nand_chip->ecc.correct = omap_elm_correct_data;
|
||||
nand_chip->ecc.calculate = omap3_calculate_ecc_bch;
|
||||
nand_chip->ecc.read_page = omap_read_page_bch;
|
||||
nand_chip->ecc.write_page = omap_write_page_bch;
|
||||
/* define ECC layout */
|
||||
ecclayout->eccbytes = nand_chip->ecc.bytes *
|
||||
(mtd->writesize /
|
||||
nand_chip->ecc.size);
|
||||
ecclayout->eccpos[0] = BADBLOCK_MARKER_LENGTH;
|
||||
ecclayout->oobfree->offset = ecclayout->eccpos[0] +
|
||||
ecclayout->eccbytes;
|
||||
/* This ECC scheme requires ELM H/W block */
|
||||
if (is_elm_present(info, pdata->elm_of_node, BCH4_ECC) < 0) {
|
||||
pr_err("nand: error: could not initialize ELM\n");
|
||||
err = -ENODEV;
|
||||
goto return_error;
|
||||
}
|
||||
}
|
||||
break;
|
||||
#else
|
||||
pr_err("nand: error: CONFIG_MTD_NAND_OMAP_BCH not enabled\n");
|
||||
err = -EINVAL;
|
||||
goto return_error;
|
||||
#endif
|
||||
|
||||
/* rom code layout */
|
||||
if (pdata->ecc_opt == OMAP_ECC_HAMMING_CODE_HW_ROMCODE) {
|
||||
|
||||
if (info->nand.options & NAND_BUSWIDTH_16)
|
||||
offset = 2;
|
||||
else {
|
||||
offset = 1;
|
||||
info->nand.badblock_pattern = &bb_descrip_flashbased;
|
||||
}
|
||||
omap_oobinfo.eccbytes = 3 * (info->mtd.oobsize/16);
|
||||
for (i = 0; i < omap_oobinfo.eccbytes; i++)
|
||||
omap_oobinfo.eccpos[i] = i+offset;
|
||||
|
||||
omap_oobinfo.oobfree->offset = offset + omap_oobinfo.eccbytes;
|
||||
omap_oobinfo.oobfree->length = info->mtd.oobsize -
|
||||
(offset + omap_oobinfo.eccbytes);
|
||||
|
||||
info->nand.ecc.layout = &omap_oobinfo;
|
||||
} else if ((pdata->ecc_opt == OMAP_ECC_BCH4_CODE_HW) ||
|
||||
(pdata->ecc_opt == OMAP_ECC_BCH8_CODE_HW)) {
|
||||
/* build OOB layout for BCH ECC correction */
|
||||
err = omap3_init_bch_tail(&info->mtd);
|
||||
if (err) {
|
||||
case OMAP_ECC_BCH8_CODE_HW_DETECTION_SW:
|
||||
#ifdef CONFIG_MTD_NAND_ECC_BCH
|
||||
pr_info("nand: using OMAP_ECC_BCH8_CODE_HW_DETECTION_SW\n");
|
||||
nand_chip->ecc.mode = NAND_ECC_HW;
|
||||
nand_chip->ecc.size = 512;
|
||||
nand_chip->ecc.bytes = 13;
|
||||
nand_chip->ecc.strength = 8;
|
||||
nand_chip->ecc.hwctl = omap3_enable_hwecc_bch;
|
||||
nand_chip->ecc.correct = nand_bch_correct_data;
|
||||
nand_chip->ecc.calculate = omap3_calculate_ecc_bch8;
|
||||
/* define ECC layout */
|
||||
ecclayout->eccbytes = nand_chip->ecc.bytes *
|
||||
(mtd->writesize /
|
||||
nand_chip->ecc.size);
|
||||
ecclayout->eccpos[0] = BADBLOCK_MARKER_LENGTH;
|
||||
ecclayout->oobfree->offset = ecclayout->eccpos[0] +
|
||||
ecclayout->eccbytes;
|
||||
/* software bch library is used for locating errors */
|
||||
nand_chip->ecc.priv = nand_bch_init(mtd,
|
||||
nand_chip->ecc.size,
|
||||
nand_chip->ecc.bytes,
|
||||
&nand_chip->ecc.layout);
|
||||
if (!nand_chip->ecc.priv) {
|
||||
pr_err("nand: error: unable to use s/w BCH library\n");
|
||||
err = -EINVAL;
|
||||
goto out_release_mem_region;
|
||||
goto return_error;
|
||||
}
|
||||
break;
|
||||
#else
|
||||
pr_err("nand: error: CONFIG_MTD_NAND_ECC_BCH not enabled\n");
|
||||
err = -EINVAL;
|
||||
goto return_error;
|
||||
#endif
|
||||
|
||||
case OMAP_ECC_BCH8_CODE_HW:
|
||||
#ifdef CONFIG_MTD_NAND_OMAP_BCH
|
||||
pr_info("nand: using OMAP_ECC_BCH8_CODE_HW ECC scheme\n");
|
||||
nand_chip->ecc.mode = NAND_ECC_HW;
|
||||
nand_chip->ecc.size = 512;
|
||||
/* 14th bit is kept reserved for ROM-code compatibility */
|
||||
nand_chip->ecc.bytes = 13 + 1;
|
||||
nand_chip->ecc.strength = 8;
|
||||
nand_chip->ecc.hwctl = omap3_enable_hwecc_bch;
|
||||
nand_chip->ecc.correct = omap_elm_correct_data;
|
||||
nand_chip->ecc.calculate = omap3_calculate_ecc_bch;
|
||||
nand_chip->ecc.read_page = omap_read_page_bch;
|
||||
nand_chip->ecc.write_page = omap_write_page_bch;
|
||||
/* This ECC scheme requires ELM H/W block */
|
||||
err = is_elm_present(info, pdata->elm_of_node, BCH8_ECC);
|
||||
if (err < 0) {
|
||||
pr_err("nand: error: could not initialize ELM\n");
|
||||
goto return_error;
|
||||
}
|
||||
/* define ECC layout */
|
||||
ecclayout->eccbytes = nand_chip->ecc.bytes *
|
||||
(mtd->writesize /
|
||||
nand_chip->ecc.size);
|
||||
ecclayout->eccpos[0] = BADBLOCK_MARKER_LENGTH;
|
||||
ecclayout->oobfree->offset = ecclayout->eccpos[0] +
|
||||
ecclayout->eccbytes;
|
||||
break;
|
||||
#else
|
||||
pr_err("nand: error: CONFIG_MTD_NAND_OMAP_BCH not enabled\n");
|
||||
err = -EINVAL;
|
||||
goto return_error;
|
||||
#endif
|
||||
|
||||
default:
|
||||
pr_err("nand: error: invalid or unsupported ECC scheme\n");
|
||||
err = -EINVAL;
|
||||
goto return_error;
|
||||
}
|
||||
|
||||
/* populate remaining ECC layout data */
|
||||
ecclayout->oobfree->length = mtd->oobsize - (BADBLOCK_MARKER_LENGTH +
|
||||
ecclayout->eccbytes);
|
||||
for (i = 1; i < ecclayout->eccbytes; i++)
|
||||
ecclayout->eccpos[i] = ecclayout->eccpos[0] + i;
|
||||
/* check if NAND device's OOB is enough to store ECC signatures */
|
||||
if (mtd->oobsize < (ecclayout->eccbytes + BADBLOCK_MARKER_LENGTH)) {
|
||||
pr_err("not enough OOB bytes required = %d, available=%d\n",
|
||||
ecclayout->eccbytes, mtd->oobsize);
|
||||
err = -EINVAL;
|
||||
goto return_error;
|
||||
}
|
||||
|
||||
/* second phase scan */
|
||||
if (nand_scan_tail(&info->mtd)) {
|
||||
if (nand_scan_tail(mtd)) {
|
||||
err = -ENXIO;
|
||||
goto out_release_mem_region;
|
||||
goto return_error;
|
||||
}
|
||||
|
||||
ppdata.of_node = pdata->of_node;
|
||||
mtd_device_parse_register(&info->mtd, NULL, &ppdata, pdata->parts,
|
||||
mtd_device_parse_register(mtd, NULL, &ppdata, pdata->parts,
|
||||
pdata->nr_parts);
|
||||
|
||||
platform_set_drvdata(pdev, &info->mtd);
|
||||
platform_set_drvdata(pdev, mtd);
|
||||
|
||||
return 0;
|
||||
|
||||
out_release_mem_region:
|
||||
return_error:
|
||||
if (info->dma)
|
||||
dma_release_channel(info->dma);
|
||||
if (info->gpmc_irq_count > 0)
|
||||
free_irq(info->gpmc_irq_count, info);
|
||||
if (info->gpmc_irq_fifo > 0)
|
||||
free_irq(info->gpmc_irq_fifo, info);
|
||||
release_mem_region(info->phys_base, info->mem_size);
|
||||
out_free_info:
|
||||
kfree(info);
|
||||
|
||||
if (nand_chip->ecc.priv) {
|
||||
nand_bch_free(nand_chip->ecc.priv);
|
||||
nand_chip->ecc.priv = NULL;
|
||||
}
|
||||
return err;
|
||||
}
|
||||
|
||||
static int omap_nand_remove(struct platform_device *pdev)
|
||||
{
|
||||
struct mtd_info *mtd = platform_get_drvdata(pdev);
|
||||
struct nand_chip *nand_chip = mtd->priv;
|
||||
struct omap_nand_info *info = container_of(mtd, struct omap_nand_info,
|
||||
mtd);
|
||||
omap3_free_bch(&info->mtd);
|
||||
|
||||
if (nand_chip->ecc.priv) {
|
||||
nand_bch_free(nand_chip->ecc.priv);
|
||||
nand_chip->ecc.priv = NULL;
|
||||
}
|
||||
if (info->dma)
|
||||
dma_release_channel(info->dma);
|
||||
|
||||
if (info->gpmc_irq_count > 0)
|
||||
free_irq(info->gpmc_irq_count, info);
|
||||
if (info->gpmc_irq_fifo > 0)
|
||||
free_irq(info->gpmc_irq_fifo, info);
|
||||
|
||||
/* Release NAND device, its internal structures and partitions */
|
||||
nand_release(&info->mtd);
|
||||
iounmap(info->nand.IO_ADDR_R);
|
||||
release_mem_region(info->phys_base, info->mem_size);
|
||||
kfree(info);
|
||||
nand_release(mtd);
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
@ -39,6 +39,13 @@
|
||||
#define NAND_STOP_DELAY (2 * HZ/50)
|
||||
#define PAGE_CHUNK_SIZE (2048)
|
||||
|
||||
/*
|
||||
* Define a buffer size for the initial command that detects the flash device:
|
||||
* STATUS, READID and PARAM. The largest of these is the PARAM command,
|
||||
* needing 256 bytes.
|
||||
*/
|
||||
#define INIT_BUFFER_SIZE 256
|
||||
|
||||
/* registers and bit definitions */
|
||||
#define NDCR (0x00) /* Control register */
|
||||
#define NDTR0CS0 (0x04) /* Timing Parameter 0 for CS0 */
|
||||
@ -164,6 +171,7 @@ struct pxa3xx_nand_info {
|
||||
|
||||
unsigned int buf_start;
|
||||
unsigned int buf_count;
|
||||
unsigned int buf_size;
|
||||
|
||||
/* DMA information */
|
||||
int drcmr_dat;
|
||||
@ -540,7 +548,6 @@ static int prepare_command_pool(struct pxa3xx_nand_info *info, int command,
|
||||
info->oob_size = 0;
|
||||
info->use_ecc = 0;
|
||||
info->use_spare = 1;
|
||||
info->use_dma = (use_dma) ? 1 : 0;
|
||||
info->is_ready = 0;
|
||||
info->retcode = ERR_NONE;
|
||||
if (info->cs != 0)
|
||||
@ -912,26 +919,20 @@ static int pxa3xx_nand_detect_config(struct pxa3xx_nand_info *info)
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* the maximum possible buffer size for large page with OOB data
|
||||
* is: 2048 + 64 = 2112 bytes, allocate a page here for both the
|
||||
* data buffer and the DMA descriptor
|
||||
*/
|
||||
#define MAX_BUFF_SIZE PAGE_SIZE
|
||||
|
||||
#ifdef ARCH_HAS_DMA
|
||||
static int pxa3xx_nand_init_buff(struct pxa3xx_nand_info *info)
|
||||
{
|
||||
struct platform_device *pdev = info->pdev;
|
||||
int data_desc_offset = MAX_BUFF_SIZE - sizeof(struct pxa_dma_desc);
|
||||
int data_desc_offset = info->buf_size - sizeof(struct pxa_dma_desc);
|
||||
|
||||
if (use_dma == 0) {
|
||||
info->data_buff = kmalloc(MAX_BUFF_SIZE, GFP_KERNEL);
|
||||
info->data_buff = kmalloc(info->buf_size, GFP_KERNEL);
|
||||
if (info->data_buff == NULL)
|
||||
return -ENOMEM;
|
||||
return 0;
|
||||
}
|
||||
|
||||
info->data_buff = dma_alloc_coherent(&pdev->dev, MAX_BUFF_SIZE,
|
||||
info->data_buff = dma_alloc_coherent(&pdev->dev, info->buf_size,
|
||||
&info->data_buff_phys, GFP_KERNEL);
|
||||
if (info->data_buff == NULL) {
|
||||
dev_err(&pdev->dev, "failed to allocate dma buffer\n");
|
||||
@ -945,11 +946,16 @@ static int pxa3xx_nand_init_buff(struct pxa3xx_nand_info *info)
|
||||
pxa3xx_nand_data_dma_irq, info);
|
||||
if (info->data_dma_ch < 0) {
|
||||
dev_err(&pdev->dev, "failed to request data dma\n");
|
||||
dma_free_coherent(&pdev->dev, MAX_BUFF_SIZE,
|
||||
dma_free_coherent(&pdev->dev, info->buf_size,
|
||||
info->data_buff, info->data_buff_phys);
|
||||
return info->data_dma_ch;
|
||||
}
|
||||
|
||||
/*
|
||||
* Now that DMA buffers are allocated we turn on
|
||||
* DMA proper for I/O operations.
|
||||
*/
|
||||
info->use_dma = 1;
|
||||
return 0;
|
||||
}
|
||||
|
||||
@ -958,7 +964,7 @@ static void pxa3xx_nand_free_buff(struct pxa3xx_nand_info *info)
|
||||
struct platform_device *pdev = info->pdev;
|
||||
if (use_dma) {
|
||||
pxa_free_dma(info->data_dma_ch);
|
||||
dma_free_coherent(&pdev->dev, MAX_BUFF_SIZE,
|
||||
dma_free_coherent(&pdev->dev, info->buf_size,
|
||||
info->data_buff, info->data_buff_phys);
|
||||
} else {
|
||||
kfree(info->data_buff);
|
||||
@ -967,7 +973,7 @@ static void pxa3xx_nand_free_buff(struct pxa3xx_nand_info *info)
|
||||
#else
|
||||
static int pxa3xx_nand_init_buff(struct pxa3xx_nand_info *info)
|
||||
{
|
||||
info->data_buff = kmalloc(MAX_BUFF_SIZE, GFP_KERNEL);
|
||||
info->data_buff = kmalloc(info->buf_size, GFP_KERNEL);
|
||||
if (info->data_buff == NULL)
|
||||
return -ENOMEM;
|
||||
return 0;
|
||||
@ -1081,7 +1087,16 @@ KEEP_CONFIG:
|
||||
else
|
||||
host->col_addr_cycles = 1;
|
||||
|
||||
/* release the initial buffer */
|
||||
kfree(info->data_buff);
|
||||
|
||||
/* allocate the real data + oob buffer */
|
||||
info->buf_size = mtd->writesize + mtd->oobsize;
|
||||
ret = pxa3xx_nand_init_buff(info);
|
||||
if (ret)
|
||||
return ret;
|
||||
info->oob_buff = info->data_buff + mtd->writesize;
|
||||
|
||||
if ((mtd->size >> chip->page_shift) > 65536)
|
||||
host->row_addr_cycles = 3;
|
||||
else
|
||||
@ -1187,15 +1202,18 @@ static int alloc_nand_resource(struct platform_device *pdev)
|
||||
}
|
||||
info->mmio_phys = r->start;
|
||||
|
||||
ret = pxa3xx_nand_init_buff(info);
|
||||
if (ret)
|
||||
/* Allocate a buffer to allow flash detection */
|
||||
info->buf_size = INIT_BUFFER_SIZE;
|
||||
info->data_buff = kmalloc(info->buf_size, GFP_KERNEL);
|
||||
if (info->data_buff == NULL) {
|
||||
ret = -ENOMEM;
|
||||
goto fail_disable_clk;
|
||||
}
|
||||
|
||||
/* initialize all interrupts to be disabled */
|
||||
disable_int(info, NDSR_MASK);
|
||||
|
||||
ret = request_irq(irq, pxa3xx_nand_irq, IRQF_DISABLED,
|
||||
pdev->name, info);
|
||||
ret = request_irq(irq, pxa3xx_nand_irq, 0, pdev->name, info);
|
||||
if (ret < 0) {
|
||||
dev_err(&pdev->dev, "failed to request IRQ\n");
|
||||
goto fail_free_buf;
|
||||
@ -1207,7 +1225,7 @@ static int alloc_nand_resource(struct platform_device *pdev)
|
||||
|
||||
fail_free_buf:
|
||||
free_irq(irq, info);
|
||||
pxa3xx_nand_free_buff(info);
|
||||
kfree(info->data_buff);
|
||||
fail_disable_clk:
|
||||
clk_disable_unprepare(info->clk);
|
||||
return ret;
|
||||
@ -1412,7 +1430,7 @@ static int pxa3xx_nand_resume(struct platform_device *pdev)
|
||||
static struct platform_driver pxa3xx_nand_driver = {
|
||||
.driver = {
|
||||
.name = "pxa3xx-nand",
|
||||
.of_match_table = of_match_ptr(pxa3xx_nand_dt_ids),
|
||||
.of_match_table = pxa3xx_nand_dt_ids,
|
||||
},
|
||||
.probe = pxa3xx_nand_probe,
|
||||
.remove = pxa3xx_nand_remove,
|
||||
|
@ -150,17 +150,13 @@ static int socrates_nand_probe(struct platform_device *ofdev)
|
||||
struct mtd_part_parser_data ppdata;
|
||||
|
||||
/* Allocate memory for the device structure (and zero it) */
|
||||
host = kzalloc(sizeof(struct socrates_nand_host), GFP_KERNEL);
|
||||
if (!host) {
|
||||
printk(KERN_ERR
|
||||
"socrates_nand: failed to allocate device structure.\n");
|
||||
host = devm_kzalloc(&ofdev->dev, sizeof(*host), GFP_KERNEL);
|
||||
if (!host)
|
||||
return -ENOMEM;
|
||||
}
|
||||
|
||||
host->io_base = of_iomap(ofdev->dev.of_node, 0);
|
||||
if (host->io_base == NULL) {
|
||||
printk(KERN_ERR "socrates_nand: ioremap failed\n");
|
||||
kfree(host);
|
||||
dev_err(&ofdev->dev, "ioremap failed\n");
|
||||
return -EIO;
|
||||
}
|
||||
|
||||
@ -212,9 +208,7 @@ static int socrates_nand_probe(struct platform_device *ofdev)
|
||||
nand_release(mtd);
|
||||
|
||||
out:
|
||||
dev_set_drvdata(&ofdev->dev, NULL);
|
||||
iounmap(host->io_base);
|
||||
kfree(host);
|
||||
return res;
|
||||
}
|
||||
|
||||
@ -228,9 +222,7 @@ static int socrates_nand_remove(struct platform_device *ofdev)
|
||||
|
||||
nand_release(mtd);
|
||||
|
||||
dev_set_drvdata(&ofdev->dev, NULL);
|
||||
iounmap(host->io_base);
|
||||
kfree(host);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
@ -428,8 +428,7 @@ static int tmio_probe(struct platform_device *dev)
|
||||
/* 15 us command delay time */
|
||||
nand_chip->chip_delay = 15;
|
||||
|
||||
retval = request_irq(irq, &tmio_irq,
|
||||
IRQF_DISABLED, dev_name(&dev->dev), tmio);
|
||||
retval = request_irq(irq, &tmio_irq, 0, dev_name(&dev->dev), tmio);
|
||||
if (retval) {
|
||||
dev_err(&dev->dev, "request_irq error %d\n", retval);
|
||||
goto err_irq;
|
||||
|
@ -50,7 +50,7 @@ static void nftl_add_mtd(struct mtd_blktrans_ops *tr, struct mtd_info *mtd)
|
||||
struct NFTLrecord *nftl;
|
||||
unsigned long temp;
|
||||
|
||||
if (mtd->type != MTD_NANDFLASH || mtd->size > UINT_MAX)
|
||||
if (!mtd_type_is_nand(mtd) || mtd->size > UINT_MAX)
|
||||
return;
|
||||
/* OK, this is moderately ugly. But probably safe. Alternatives? */
|
||||
if (memcmp(mtd->name, "DiskOnChip", 10))
|
||||
|
@ -573,28 +573,6 @@ static int omap2_onenand_write_bufferram(struct mtd_info *mtd, int area,
|
||||
|
||||
static struct platform_driver omap2_onenand_driver;
|
||||
|
||||
static int __adjust_timing(struct device *dev, void *data)
|
||||
{
|
||||
int ret = 0;
|
||||
struct omap2_onenand *c;
|
||||
|
||||
c = dev_get_drvdata(dev);
|
||||
|
||||
BUG_ON(c->setup == NULL);
|
||||
|
||||
/* DMA is not in use so this is all that is needed */
|
||||
/* Revisit for OMAP3! */
|
||||
ret = c->setup(c->onenand.base, &c->freq);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
int omap2_onenand_rephase(void)
|
||||
{
|
||||
return driver_for_each_device(&omap2_onenand_driver.driver, NULL,
|
||||
NULL, __adjust_timing);
|
||||
}
|
||||
|
||||
static void omap2_onenand_shutdown(struct platform_device *pdev)
|
||||
{
|
||||
struct omap2_onenand *c = dev_get_drvdata(&pdev->dev);
|
||||
|
@ -2556,10 +2556,6 @@ static int onenand_block_isbad(struct mtd_info *mtd, loff_t ofs)
|
||||
{
|
||||
int ret;
|
||||
|
||||
/* Check for invalid offset */
|
||||
if (ofs > mtd->size)
|
||||
return -EINVAL;
|
||||
|
||||
onenand_get_device(mtd, FL_READING);
|
||||
ret = onenand_block_isbad_nolock(mtd, ofs, 0);
|
||||
onenand_release_device(mtd);
|
||||
@ -3529,7 +3525,7 @@ static int flexonenand_get_boundary(struct mtd_info *mtd)
|
||||
{
|
||||
struct onenand_chip *this = mtd->priv;
|
||||
unsigned die, bdry;
|
||||
int ret, syscfg, locked;
|
||||
int syscfg, locked;
|
||||
|
||||
/* Disable ECC */
|
||||
syscfg = this->read_word(this->base + ONENAND_REG_SYS_CFG1);
|
||||
@ -3540,7 +3536,7 @@ static int flexonenand_get_boundary(struct mtd_info *mtd)
|
||||
this->wait(mtd, FL_SYNCING);
|
||||
|
||||
this->command(mtd, FLEXONENAND_CMD_READ_PI, die, 0);
|
||||
ret = this->wait(mtd, FL_READING);
|
||||
this->wait(mtd, FL_READING);
|
||||
|
||||
bdry = this->read_word(this->base + ONENAND_DATARAM);
|
||||
if ((bdry >> FLEXONENAND_PI_UNLOCK_SHIFT) == 3)
|
||||
@ -3550,7 +3546,7 @@ static int flexonenand_get_boundary(struct mtd_info *mtd)
|
||||
this->boundary[die] = bdry & FLEXONENAND_PI_MASK;
|
||||
|
||||
this->command(mtd, ONENAND_CMD_RESET, 0, 0);
|
||||
ret = this->wait(mtd, FL_RESETING);
|
||||
this->wait(mtd, FL_RESETING);
|
||||
|
||||
printk(KERN_INFO "Die %d boundary: %d%s\n", die,
|
||||
this->boundary[die], locked ? "(Locked)" : "(Unlocked)");
|
||||
@ -3734,7 +3730,7 @@ static int flexonenand_set_boundary(struct mtd_info *mtd, int die,
|
||||
|
||||
/* Check is boundary is locked */
|
||||
this->command(mtd, FLEXONENAND_CMD_READ_PI, die, 0);
|
||||
ret = this->wait(mtd, FL_READING);
|
||||
this->wait(mtd, FL_READING);
|
||||
|
||||
thisboundary = this->read_word(this->base + ONENAND_DATARAM);
|
||||
if ((thisboundary >> FLEXONENAND_PI_UNLOCK_SHIFT) != 3) {
|
||||
@ -3835,7 +3831,7 @@ static int onenand_chip_probe(struct mtd_info *mtd)
|
||||
static int onenand_probe(struct mtd_info *mtd)
|
||||
{
|
||||
struct onenand_chip *this = mtd->priv;
|
||||
int maf_id, dev_id, ver_id;
|
||||
int dev_id, ver_id;
|
||||
int density;
|
||||
int ret;
|
||||
|
||||
@ -3843,8 +3839,7 @@ static int onenand_probe(struct mtd_info *mtd)
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
/* Read manufacturer and device IDs from Register */
|
||||
maf_id = this->read_word(this->base + ONENAND_REG_MANUFACTURER_ID);
|
||||
/* Device and version IDs from Register */
|
||||
dev_id = this->read_word(this->base + ONENAND_REG_DEVICE_ID);
|
||||
ver_id = this->read_word(this->base + ONENAND_REG_VERSION_ID);
|
||||
this->technology = this->read_word(this->base + ONENAND_REG_TECHNOLOGY);
|
||||
|
@ -290,7 +290,7 @@ static void ssfdcr_add_mtd(struct mtd_blktrans_ops *tr, struct mtd_info *mtd)
|
||||
int cis_sector;
|
||||
|
||||
/* Check for small page NAND flash */
|
||||
if (mtd->type != MTD_NANDFLASH || mtd->oobsize != OOB_SIZE ||
|
||||
if (!mtd_type_is_nand(mtd) || mtd->oobsize != OOB_SIZE ||
|
||||
mtd->size > UINT_MAX)
|
||||
return;
|
||||
|
||||
|
@ -349,7 +349,7 @@ static int __init mtd_nandbiterrs_init(void)
|
||||
goto exit_mtddev;
|
||||
}
|
||||
|
||||
if (mtd->type != MTD_NANDFLASH) {
|
||||
if (!mtd_type_is_nand(mtd)) {
|
||||
pr_info("this test requires NAND flash\n");
|
||||
err = -ENODEV;
|
||||
goto exit_nand;
|
||||
|
@ -289,7 +289,7 @@ static int __init mtd_oobtest_init(void)
|
||||
return err;
|
||||
}
|
||||
|
||||
if (mtd->type != MTD_NANDFLASH) {
|
||||
if (!mtd_type_is_nand(mtd)) {
|
||||
pr_info("this test requires NAND flash\n");
|
||||
goto out;
|
||||
}
|
||||
|
@ -353,7 +353,7 @@ static int __init mtd_pagetest_init(void)
|
||||
return err;
|
||||
}
|
||||
|
||||
if (mtd->type != MTD_NANDFLASH) {
|
||||
if (!mtd_type_is_nand(mtd)) {
|
||||
pr_info("this test requires NAND flash\n");
|
||||
goto out;
|
||||
}
|
||||
|
@ -299,7 +299,7 @@ static int __init mtd_subpagetest_init(void)
|
||||
return err;
|
||||
}
|
||||
|
||||
if (mtd->type != MTD_NANDFLASH) {
|
||||
if (!mtd_type_is_nand(mtd)) {
|
||||
pr_info("this test requires NAND flash\n");
|
||||
goto out;
|
||||
}
|
||||
|
@ -41,6 +41,7 @@
|
||||
#include <linux/kthread.h>
|
||||
#include <linux/kernel.h>
|
||||
#include <linux/slab.h>
|
||||
#include <linux/major.h>
|
||||
#include "ubi.h"
|
||||
|
||||
/* Maximum length of the 'mtd=' parameter */
|
||||
|
@ -515,6 +515,10 @@ int jffs2_do_fill_super(struct super_block *sb, void *data, int silent)
|
||||
|
||||
c = JFFS2_SB_INFO(sb);
|
||||
|
||||
/* Do not support the MLC nand */
|
||||
if (c->mtd->type == MTD_MLCNANDFLASH)
|
||||
return -EINVAL;
|
||||
|
||||
#ifndef CONFIG_JFFS2_FS_WRITEBUFFER
|
||||
if (c->mtd->type == MTD_NANDFLASH) {
|
||||
pr_err("Cannot operate on NAND flash unless jffs2 NAND support is compiled in\n");
|
||||
|
@ -91,8 +91,6 @@ struct nand_bbt_descr {
|
||||
* with NAND_BBT_CREATE.
|
||||
*/
|
||||
#define NAND_BBT_CREATE_EMPTY 0x00000400
|
||||
/* Search good / bad pattern through all pages of a block */
|
||||
#define NAND_BBT_SCANALLPAGES 0x00000800
|
||||
/* Write bbt if neccecary */
|
||||
#define NAND_BBT_WRITE 0x00002000
|
||||
/* Read and write back block contents when writing bbt */
|
||||
|
@ -365,7 +365,7 @@ static inline map_word map_word_load_partial(struct map_info *map, map_word orig
|
||||
bitpos = (map_bankwidth(map)-1-i)*8;
|
||||
#endif
|
||||
orig.x[0] &= ~(0xff << bitpos);
|
||||
orig.x[0] |= buf[i-start] << bitpos;
|
||||
orig.x[0] |= (unsigned long)buf[i-start] << bitpos;
|
||||
}
|
||||
}
|
||||
return orig;
|
||||
@ -384,7 +384,7 @@ static inline map_word map_word_ff(struct map_info *map)
|
||||
|
||||
if (map_bankwidth(map) < MAP_FF_LIMIT) {
|
||||
int bw = 8 * map_bankwidth(map);
|
||||
r.x[0] = (1 << bw) - 1;
|
||||
r.x[0] = (1UL << bw) - 1;
|
||||
} else {
|
||||
for (i=0; i<map_words(map); i++)
|
||||
r.x[i] = ~0UL;
|
||||
|
@ -29,9 +29,6 @@
|
||||
|
||||
#include <asm/div64.h>
|
||||
|
||||
#define MTD_CHAR_MAJOR 90
|
||||
#define MTD_BLOCK_MAJOR 31
|
||||
|
||||
#define MTD_ERASE_PENDING 0x01
|
||||
#define MTD_ERASING 0x02
|
||||
#define MTD_ERASE_SUSPEND 0x04
|
||||
@ -354,6 +351,11 @@ static inline int mtd_has_oob(const struct mtd_info *mtd)
|
||||
return mtd->_read_oob && mtd->_write_oob;
|
||||
}
|
||||
|
||||
static inline int mtd_type_is_nand(const struct mtd_info *mtd)
|
||||
{
|
||||
return mtd->type == MTD_NANDFLASH || mtd->type == MTD_MLCNANDFLASH;
|
||||
}
|
||||
|
||||
static inline int mtd_can_have_bb(const struct mtd_info *mtd)
|
||||
{
|
||||
return !!mtd->_block_isbad;
|
||||
|
@ -198,6 +198,7 @@ typedef enum {
|
||||
/* Cell info constants */
|
||||
#define NAND_CI_CHIPNR_MSK 0x03
|
||||
#define NAND_CI_CELLTYPE_MSK 0x0C
|
||||
#define NAND_CI_CELLTYPE_SHIFT 2
|
||||
|
||||
/* Keep gcc happy */
|
||||
struct nand_chip;
|
||||
@ -477,7 +478,7 @@ struct nand_buffers {
|
||||
* @badblockbits: [INTERN] minimum number of set bits in a good block's
|
||||
* bad block marker position; i.e., BBM == 11110111b is
|
||||
* not bad when badblockbits == 7
|
||||
* @cellinfo: [INTERN] MLC/multichip data from chip ident
|
||||
* @bits_per_cell: [INTERN] number of bits per cell. i.e., 1 means SLC.
|
||||
* @ecc_strength_ds: [INTERN] ECC correctability from the datasheet.
|
||||
* Minimum amount of bit errors per @ecc_step_ds guaranteed
|
||||
* to be correctable. If unknown, set to zero.
|
||||
@ -498,7 +499,6 @@ struct nand_buffers {
|
||||
* supported, 0 otherwise.
|
||||
* @onfi_set_features: [REPLACEABLE] set the features for ONFI nand
|
||||
* @onfi_get_features: [REPLACEABLE] get the features for ONFI nand
|
||||
* @ecclayout: [REPLACEABLE] the default ECC placement scheme
|
||||
* @bbt: [INTERN] bad block table pointer
|
||||
* @bbt_td: [REPLACEABLE] bad block table descriptor for flash
|
||||
* lookup.
|
||||
@ -559,7 +559,7 @@ struct nand_chip {
|
||||
int pagebuf;
|
||||
unsigned int pagebuf_bitflips;
|
||||
int subpagesize;
|
||||
uint8_t cellinfo;
|
||||
uint8_t bits_per_cell;
|
||||
uint16_t ecc_strength_ds;
|
||||
uint16_t ecc_step_ds;
|
||||
int badblockpos;
|
||||
@ -572,7 +572,6 @@ struct nand_chip {
|
||||
|
||||
uint8_t *oob_poi;
|
||||
struct nand_hw_control *controller;
|
||||
struct nand_ecclayout *ecclayout;
|
||||
|
||||
struct nand_ecc_ctrl ecc;
|
||||
struct nand_buffers *buffers;
|
||||
@ -797,4 +796,13 @@ static inline int onfi_get_sync_timing_mode(struct nand_chip *chip)
|
||||
return le16_to_cpu(chip->onfi_params.src_sync_timing_mode);
|
||||
}
|
||||
|
||||
/*
|
||||
* Check if it is a SLC nand.
|
||||
* The !nand_is_slc() can be used to check the MLC/TLC nand chips.
|
||||
* We do not distinguish the MLC and TLC now.
|
||||
*/
|
||||
static inline bool nand_is_slc(struct nand_chip *chip)
|
||||
{
|
||||
return chip->bits_per_cell == 1;
|
||||
}
|
||||
#endif /* __LINUX_MTD_NAND_H */
|
||||
|
@ -10,10 +10,29 @@
|
||||
#define __LINUX_OF_NET_H
|
||||
|
||||
#ifdef CONFIG_OF_MTD
|
||||
|
||||
#include <linux/of.h>
|
||||
int of_get_nand_ecc_mode(struct device_node *np);
|
||||
int of_get_nand_bus_width(struct device_node *np);
|
||||
bool of_get_nand_on_flash_bbt(struct device_node *np);
|
||||
#endif
|
||||
|
||||
#else /* CONFIG_OF_MTD */
|
||||
|
||||
static inline int of_get_nand_ecc_mode(struct device_node *np)
|
||||
{
|
||||
return -ENOSYS;
|
||||
}
|
||||
|
||||
static inline int of_get_nand_bus_width(struct device_node *np)
|
||||
{
|
||||
return -ENOSYS;
|
||||
}
|
||||
|
||||
static inline bool of_get_nand_on_flash_bbt(struct device_node *np)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
#endif /* CONFIG_OF_MTD */
|
||||
|
||||
#endif /* __LINUX_OF_MTD_H */
|
||||
|
@ -23,13 +23,16 @@ enum nand_io {
|
||||
};
|
||||
|
||||
enum omap_ecc {
|
||||
/* 1-bit ecc: stored at end of spare area */
|
||||
OMAP_ECC_HAMMING_CODE_DEFAULT = 0, /* Default, s/w method */
|
||||
OMAP_ECC_HAMMING_CODE_HW, /* gpmc to detect the error */
|
||||
/* 1-bit ecc: stored at beginning of spare area as romcode */
|
||||
OMAP_ECC_HAMMING_CODE_HW_ROMCODE, /* gpmc method & romcode layout */
|
||||
OMAP_ECC_BCH4_CODE_HW, /* 4-bit BCH ecc code */
|
||||
OMAP_ECC_BCH8_CODE_HW, /* 8-bit BCH ecc code */
|
||||
/* 1-bit ECC calculation by GPMC, Error detection by Software */
|
||||
OMAP_ECC_HAM1_CODE_HW = 0,
|
||||
/* 4-bit ECC calculation by GPMC, Error detection by Software */
|
||||
OMAP_ECC_BCH4_CODE_HW_DETECTION_SW,
|
||||
/* 4-bit ECC calculation by GPMC, Error detection by ELM */
|
||||
OMAP_ECC_BCH4_CODE_HW,
|
||||
/* 8-bit ECC calculation by GPMC, Error detection by Software */
|
||||
OMAP_ECC_BCH8_CODE_HW_DETECTION_SW,
|
||||
/* 8-bit ECC calculation by GPMC, Error detection by ELM */
|
||||
OMAP_ECC_BCH8_CODE_HW,
|
||||
};
|
||||
|
||||
struct gpmc_nand_regs {
|
||||
@ -63,5 +66,6 @@ struct omap_nand_platform_data {
|
||||
|
||||
/* for passing the partitions */
|
||||
struct device_node *of_node;
|
||||
struct device_node *elm_of_node;
|
||||
};
|
||||
#endif
|
||||
|
@ -54,6 +54,7 @@
|
||||
#define ACSI_MAJOR 28
|
||||
#define AZTECH_CDROM_MAJOR 29
|
||||
#define FB_MAJOR 29 /* /dev/fb* framebuffers */
|
||||
#define MTD_BLOCK_MAJOR 31
|
||||
#define CM206_CDROM_MAJOR 32
|
||||
#define IDE2_MAJOR 33
|
||||
#define IDE3_MAJOR 34
|
||||
@ -105,6 +106,7 @@
|
||||
#define IDE6_MAJOR 88
|
||||
#define IDE7_MAJOR 89
|
||||
#define IDE8_MAJOR 90
|
||||
#define MTD_CHAR_MAJOR 90
|
||||
#define IDE9_MAJOR 91
|
||||
|
||||
#define DASD_MAJOR 94
|
||||
|
@ -94,10 +94,10 @@ struct mtd_write_req {
|
||||
#define MTD_RAM 1
|
||||
#define MTD_ROM 2
|
||||
#define MTD_NORFLASH 3
|
||||
#define MTD_NANDFLASH 4
|
||||
#define MTD_NANDFLASH 4 /* SLC NAND */
|
||||
#define MTD_DATAFLASH 6
|
||||
#define MTD_UBIVOLUME 7
|
||||
#define MTD_MLCNANDFLASH 8
|
||||
#define MTD_MLCNANDFLASH 8 /* MLC NAND (including TLC) */
|
||||
|
||||
#define MTD_WRITEABLE 0x400 /* Device is writeable */
|
||||
#define MTD_BIT_WRITEABLE 0x800 /* Single bits can be flipped */
|
||||
@ -275,4 +275,9 @@ enum mtd_file_modes {
|
||||
MTD_FILE_MODE_RAW,
|
||||
};
|
||||
|
||||
static inline int mtd_type_is_nand_user(const struct mtd_info_user *mtd)
|
||||
{
|
||||
return mtd->type == MTD_NANDFLASH || mtd->type == MTD_MLCNANDFLASH;
|
||||
}
|
||||
|
||||
#endif /* __MTD_ABI_H__ */
|
||||
|
Loading…
Reference in New Issue
Block a user