Merge v4.5-rc1 with MTD -next development
To start from a good base. Signed-off-by: Brian Norris <computersforpeace@gmail.com>
This commit is contained in:
commit
b33f7a437c
|
@ -66,11 +66,13 @@ static const char *bcm47xxpart_trx_data_part_name(struct mtd_info *master,
|
|||
{
|
||||
uint32_t buf;
|
||||
size_t bytes_read;
|
||||
int err;
|
||||
|
||||
if (mtd_read(master, offset, sizeof(buf), &bytes_read,
|
||||
(uint8_t *)&buf) < 0) {
|
||||
pr_err("mtd_read error while parsing (offset: 0x%X)!\n",
|
||||
offset);
|
||||
err = mtd_read(master, offset, sizeof(buf), &bytes_read,
|
||||
(uint8_t *)&buf);
|
||||
if (err && !mtd_is_bitflip(err)) {
|
||||
pr_err("mtd_read error while parsing (offset: 0x%X): %d\n",
|
||||
offset, err);
|
||||
goto out_default;
|
||||
}
|
||||
|
||||
|
@ -95,6 +97,7 @@ static int bcm47xxpart_parse(struct mtd_info *master,
|
|||
int trx_part = -1;
|
||||
int last_trx_part = -1;
|
||||
int possible_nvram_sizes[] = { 0x8000, 0xF000, 0x10000, };
|
||||
int err;
|
||||
|
||||
/*
|
||||
* Some really old flashes (like AT45DB*) had smaller erasesize-s, but
|
||||
|
@ -118,8 +121,8 @@ static int bcm47xxpart_parse(struct mtd_info *master,
|
|||
/* Parse block by block looking for magics */
|
||||
for (offset = 0; offset <= master->size - blocksize;
|
||||
offset += blocksize) {
|
||||
/* Nothing more in higher memory */
|
||||
if (offset >= 0x2000000)
|
||||
/* Nothing more in higher memory on BCM47XX (MIPS) */
|
||||
if (config_enabled(CONFIG_BCM47XX) && offset >= 0x2000000)
|
||||
break;
|
||||
|
||||
if (curr_part >= BCM47XXPART_MAX_PARTS) {
|
||||
|
@ -128,10 +131,11 @@ static int bcm47xxpart_parse(struct mtd_info *master,
|
|||
}
|
||||
|
||||
/* Read beginning of the block */
|
||||
if (mtd_read(master, offset, BCM47XXPART_BYTES_TO_READ,
|
||||
&bytes_read, (uint8_t *)buf) < 0) {
|
||||
pr_err("mtd_read error while parsing (offset: 0x%X)!\n",
|
||||
offset);
|
||||
err = mtd_read(master, offset, BCM47XXPART_BYTES_TO_READ,
|
||||
&bytes_read, (uint8_t *)buf);
|
||||
if (err && !mtd_is_bitflip(err)) {
|
||||
pr_err("mtd_read error while parsing (offset: 0x%X): %d\n",
|
||||
offset, err);
|
||||
continue;
|
||||
}
|
||||
|
||||
|
@ -254,10 +258,11 @@ static int bcm47xxpart_parse(struct mtd_info *master,
|
|||
}
|
||||
|
||||
/* Read middle of the block */
|
||||
if (mtd_read(master, offset + 0x8000, 0x4,
|
||||
&bytes_read, (uint8_t *)buf) < 0) {
|
||||
pr_err("mtd_read error while parsing (offset: 0x%X)!\n",
|
||||
offset);
|
||||
err = mtd_read(master, offset + 0x8000, 0x4, &bytes_read,
|
||||
(uint8_t *)buf);
|
||||
if (err && !mtd_is_bitflip(err)) {
|
||||
pr_err("mtd_read error while parsing (offset: 0x%X): %d\n",
|
||||
offset, err);
|
||||
continue;
|
||||
}
|
||||
|
||||
|
@ -277,10 +282,11 @@ static int bcm47xxpart_parse(struct mtd_info *master,
|
|||
}
|
||||
|
||||
offset = master->size - possible_nvram_sizes[i];
|
||||
if (mtd_read(master, offset, 0x4, &bytes_read,
|
||||
(uint8_t *)buf) < 0) {
|
||||
pr_err("mtd_read error while reading at offset 0x%X!\n",
|
||||
offset);
|
||||
err = mtd_read(master, offset, 0x4, &bytes_read,
|
||||
(uint8_t *)buf);
|
||||
if (err && !mtd_is_bitflip(err)) {
|
||||
pr_err("mtd_read error while reading (offset 0x%X): %d\n",
|
||||
offset, err);
|
||||
continue;
|
||||
}
|
||||
|
||||
|
|
|
@ -825,7 +825,7 @@ static void pmecc_correct_data(struct mtd_info *mtd, uint8_t *buf, uint8_t *ecc,
|
|||
*(buf + byte_pos) ^= (1 << bit_pos);
|
||||
|
||||
pos = sector_num * host->pmecc_sector_size + byte_pos;
|
||||
dev_info(host->dev, "Bit flip in data area, byte_pos: %d, bit_pos: %d, 0x%02x -> 0x%02x\n",
|
||||
dev_dbg(host->dev, "Bit flip in data area, byte_pos: %d, bit_pos: %d, 0x%02x -> 0x%02x\n",
|
||||
pos, bit_pos, err_byte, *(buf + byte_pos));
|
||||
} else {
|
||||
/* Bit flip in OOB area */
|
||||
|
@ -835,7 +835,7 @@ static void pmecc_correct_data(struct mtd_info *mtd, uint8_t *buf, uint8_t *ecc,
|
|||
ecc[tmp] ^= (1 << bit_pos);
|
||||
|
||||
pos = tmp + nand_chip->ecc.layout->eccpos[0];
|
||||
dev_info(host->dev, "Bit flip in OOB, oob_byte_pos: %d, bit_pos: %d, 0x%02x -> 0x%02x\n",
|
||||
dev_dbg(host->dev, "Bit flip in OOB, oob_byte_pos: %d, bit_pos: %d, 0x%02x -> 0x%02x\n",
|
||||
pos, bit_pos, err_byte, ecc[tmp]);
|
||||
}
|
||||
|
||||
|
@ -1486,8 +1486,6 @@ static void atmel_nand_hwctl(struct mtd_info *mtd, int mode)
|
|||
ecc_writel(host->ecc, CR, ATMEL_ECC_RST);
|
||||
}
|
||||
|
||||
static const struct of_device_id atmel_nand_dt_ids[];
|
||||
|
||||
static int atmel_of_init_port(struct atmel_nand_host *host,
|
||||
struct device_node *np)
|
||||
{
|
||||
|
@ -1498,7 +1496,7 @@ static int atmel_of_init_port(struct atmel_nand_host *host,
|
|||
enum of_gpio_flags flags = 0;
|
||||
|
||||
host->caps = (struct atmel_nand_caps *)
|
||||
of_match_device(atmel_nand_dt_ids, host->dev)->data;
|
||||
of_device_get_match_data(host->dev);
|
||||
|
||||
if (of_property_read_u32(np, "atmel,nand-addr-offset", &val) == 0) {
|
||||
if (val >= 32) {
|
||||
|
@ -1550,7 +1548,7 @@ static int atmel_of_init_port(struct atmel_nand_host *host,
|
|||
if ((val != 2) && (val != 4) && (val != 8) && (val != 12) &&
|
||||
(val != 24)) {
|
||||
dev_err(host->dev,
|
||||
"Unsupported PMECC correction capability: %d; should be 2, 4, 8, 12 or 24\n",
|
||||
"Required ECC strength not supported: %u\n",
|
||||
val);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
@ -1560,7 +1558,7 @@ static int atmel_of_init_port(struct atmel_nand_host *host,
|
|||
if (of_property_read_u32(np, "atmel,pmecc-sector-size", &val) == 0) {
|
||||
if ((val != 512) && (val != 1024)) {
|
||||
dev_err(host->dev,
|
||||
"Unsupported PMECC sector size: %d; should be 512 or 1024 bytes\n",
|
||||
"Required ECC sector size not supported: %u\n",
|
||||
val);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
/*
|
||||
* Freescale GPMI NAND Flash Driver
|
||||
*
|
||||
* Copyright (C) 2010-2011 Freescale Semiconductor, Inc.
|
||||
* Copyright (C) 2010-2015 Freescale Semiconductor, Inc.
|
||||
* Copyright (C) 2008 Embedded Alley Solutions, Inc.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
|
@ -136,7 +136,7 @@ static inline bool gpmi_check_ecc(struct gpmi_nand_data *this)
|
|||
*
|
||||
* We may have available oob space in this case.
|
||||
*/
|
||||
static bool set_geometry_by_ecc_info(struct gpmi_nand_data *this)
|
||||
static int set_geometry_by_ecc_info(struct gpmi_nand_data *this)
|
||||
{
|
||||
struct bch_geometry *geo = &this->bch_geometry;
|
||||
struct nand_chip *chip = &this->nand;
|
||||
|
@ -145,7 +145,7 @@ static bool set_geometry_by_ecc_info(struct gpmi_nand_data *this)
|
|||
unsigned int block_mark_bit_offset;
|
||||
|
||||
if (!(chip->ecc_strength_ds > 0 && chip->ecc_step_ds > 0))
|
||||
return false;
|
||||
return -EINVAL;
|
||||
|
||||
switch (chip->ecc_step_ds) {
|
||||
case SZ_512:
|
||||
|
@ -158,19 +158,19 @@ static bool set_geometry_by_ecc_info(struct gpmi_nand_data *this)
|
|||
dev_err(this->dev,
|
||||
"unsupported nand chip. ecc bits : %d, ecc size : %d\n",
|
||||
chip->ecc_strength_ds, chip->ecc_step_ds);
|
||||
return false;
|
||||
return -EINVAL;
|
||||
}
|
||||
geo->ecc_chunk_size = chip->ecc_step_ds;
|
||||
geo->ecc_strength = round_up(chip->ecc_strength_ds, 2);
|
||||
if (!gpmi_check_ecc(this))
|
||||
return false;
|
||||
return -EINVAL;
|
||||
|
||||
/* Keep the C >= O */
|
||||
if (geo->ecc_chunk_size < mtd->oobsize) {
|
||||
dev_err(this->dev,
|
||||
"unsupported nand chip. ecc size: %d, oob size : %d\n",
|
||||
chip->ecc_step_ds, mtd->oobsize);
|
||||
return false;
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
/* The default value, see comment in the legacy_set_geometry(). */
|
||||
|
@ -242,7 +242,7 @@ static bool set_geometry_by_ecc_info(struct gpmi_nand_data *this)
|
|||
+ ALIGN(geo->ecc_chunk_count, 4);
|
||||
|
||||
if (!this->swap_block_mark)
|
||||
return true;
|
||||
return 0;
|
||||
|
||||
/* For bit swap. */
|
||||
block_mark_bit_offset = mtd->writesize * 8 -
|
||||
|
@ -251,7 +251,7 @@ static bool set_geometry_by_ecc_info(struct gpmi_nand_data *this)
|
|||
|
||||
geo->block_mark_byte_offset = block_mark_bit_offset / 8;
|
||||
geo->block_mark_bit_offset = block_mark_bit_offset % 8;
|
||||
return true;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int legacy_set_geometry(struct gpmi_nand_data *this)
|
||||
|
@ -285,7 +285,8 @@ static int legacy_set_geometry(struct gpmi_nand_data *this)
|
|||
geo->ecc_strength = get_ecc_strength(this);
|
||||
if (!gpmi_check_ecc(this)) {
|
||||
dev_err(this->dev,
|
||||
"required ecc strength of the NAND chip: %d is not supported by the GPMI controller (%d)\n",
|
||||
"ecc strength: %d cannot be supported by the controller (%d)\n"
|
||||
"try to use minimum ecc strength that NAND chip required\n",
|
||||
geo->ecc_strength,
|
||||
this->devdata->bch_max_ecc_strength);
|
||||
return -EINVAL;
|
||||
|
@ -366,10 +367,11 @@ static int legacy_set_geometry(struct gpmi_nand_data *this)
|
|||
|
||||
int common_nfc_set_geometry(struct gpmi_nand_data *this)
|
||||
{
|
||||
if (of_property_read_bool(this->dev->of_node, "fsl,use-minimum-ecc")
|
||||
&& set_geometry_by_ecc_info(this))
|
||||
return 0;
|
||||
return legacy_set_geometry(this);
|
||||
if ((of_property_read_bool(this->dev->of_node, "fsl,use-minimum-ecc"))
|
||||
|| legacy_set_geometry(this))
|
||||
return set_geometry_by_ecc_info(this);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
struct dma_chan *get_dma_chan(struct gpmi_nand_data *this)
|
||||
|
@ -2033,9 +2035,54 @@ static int gpmi_nand_remove(struct platform_device *pdev)
|
|||
return 0;
|
||||
}
|
||||
|
||||
#ifdef CONFIG_PM_SLEEP
|
||||
static int gpmi_pm_suspend(struct device *dev)
|
||||
{
|
||||
struct gpmi_nand_data *this = dev_get_drvdata(dev);
|
||||
|
||||
release_dma_channels(this);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int gpmi_pm_resume(struct device *dev)
|
||||
{
|
||||
struct gpmi_nand_data *this = dev_get_drvdata(dev);
|
||||
int ret;
|
||||
|
||||
ret = acquire_dma_channels(this);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
/* re-init the GPMI registers */
|
||||
this->flags &= ~GPMI_TIMING_INIT_OK;
|
||||
ret = gpmi_init(this);
|
||||
if (ret) {
|
||||
dev_err(this->dev, "Error setting GPMI : %d\n", ret);
|
||||
return ret;
|
||||
}
|
||||
|
||||
/* re-init the BCH registers */
|
||||
ret = bch_set_geometry(this);
|
||||
if (ret) {
|
||||
dev_err(this->dev, "Error setting BCH : %d\n", ret);
|
||||
return ret;
|
||||
}
|
||||
|
||||
/* re-init others */
|
||||
gpmi_extra_init(this);
|
||||
|
||||
return 0;
|
||||
}
|
||||
#endif /* CONFIG_PM_SLEEP */
|
||||
|
||||
static const struct dev_pm_ops gpmi_pm_ops = {
|
||||
SET_SYSTEM_SLEEP_PM_OPS(gpmi_pm_suspend, gpmi_pm_resume)
|
||||
};
|
||||
|
||||
static struct platform_driver gpmi_nand_driver = {
|
||||
.driver = {
|
||||
.name = "gpmi-nand",
|
||||
.pm = &gpmi_pm_ops,
|
||||
.of_match_table = gpmi_nand_id_table,
|
||||
},
|
||||
.probe = gpmi_nand_probe,
|
||||
|
|
|
@ -626,7 +626,7 @@ static void mpc5121_nfc_free(struct device *dev, struct mtd_info *mtd)
|
|||
|
||||
static int mpc5121_nfc_probe(struct platform_device *op)
|
||||
{
|
||||
struct device_node *rootnode, *dn = op->dev.of_node;
|
||||
struct device_node *dn = op->dev.of_node;
|
||||
struct clk *clk;
|
||||
struct device *dev = &op->dev;
|
||||
struct mpc5121_nfc_prv *prv;
|
||||
|
@ -712,18 +712,15 @@ static int mpc5121_nfc_probe(struct platform_device *op)
|
|||
chip->ecc.mode = NAND_ECC_SOFT;
|
||||
|
||||
/* Support external chip-select logic on ADS5121 board */
|
||||
rootnode = of_find_node_by_path("/");
|
||||
if (of_device_is_compatible(rootnode, "fsl,mpc5121ads")) {
|
||||
if (of_machine_is_compatible("fsl,mpc5121ads")) {
|
||||
retval = ads5121_chipselect_init(mtd);
|
||||
if (retval) {
|
||||
dev_err(dev, "Chipselect init error!\n");
|
||||
of_node_put(rootnode);
|
||||
return retval;
|
||||
}
|
||||
|
||||
chip->select_chip = ads5121_select_chip;
|
||||
}
|
||||
of_node_put(rootnode);
|
||||
|
||||
/* Enable NFC clock */
|
||||
clk = devm_clk_get(dev, "ipg");
|
||||
|
|
|
@ -1373,5 +1373,3 @@ int nand_markbad_bbt(struct mtd_info *mtd, loff_t offs)
|
|||
|
||||
return ret;
|
||||
}
|
||||
|
||||
EXPORT_SYMBOL(nand_scan_bbt);
|
||||
|
|
|
@ -50,8 +50,8 @@ struct nand_flash_dev nand_flash_ids[] = {
|
|||
SZ_16K, SZ_8K, SZ_4M, 0, 6, 1280, NAND_ECC_INFO(40, SZ_1K) },
|
||||
{"H27UCG8T2ATR-BC 64G 3.3V 8-bit",
|
||||
{ .id = {0xad, 0xde, 0x94, 0xda, 0x74, 0xc4} },
|
||||
SZ_8K, SZ_8K, SZ_2M, 0, 6, 640, NAND_ECC_INFO(40, SZ_1K),
|
||||
4 },
|
||||
SZ_8K, SZ_8K, SZ_2M, NAND_NEED_SCRAMBLING, 6, 640,
|
||||
NAND_ECC_INFO(40, SZ_1K), 4 },
|
||||
|
||||
LEGACY_ID_NAND("NAND 4MiB 5V 8-bit", 0x6B, 4, SZ_8K, SP_OPTIONS),
|
||||
LEGACY_ID_NAND("NAND 4MiB 3,3V 8-bit", 0xE3, 4, SZ_8K, SP_OPTIONS),
|
||||
|
|
|
@ -113,7 +113,7 @@ static int nuc900_check_rb(struct nuc900_nand *nand)
|
|||
{
|
||||
unsigned int val;
|
||||
spin_lock(&nand->lock);
|
||||
val = __raw_readl(REG_SMISR);
|
||||
val = __raw_readl(nand->reg + REG_SMISR);
|
||||
val &= READYBUSY;
|
||||
spin_unlock(&nand->lock);
|
||||
|
||||
|
|
|
@ -60,6 +60,7 @@
|
|||
#define NFC_REG_ECC_ERR_CNT(x) ((0x0040 + (x)) & ~0x3)
|
||||
#define NFC_REG_USER_DATA(x) (0x0050 + ((x) * 4))
|
||||
#define NFC_REG_SPARE_AREA 0x00A0
|
||||
#define NFC_REG_PAT_ID 0x00A4
|
||||
#define NFC_RAM0_BASE 0x0400
|
||||
#define NFC_RAM1_BASE 0x0800
|
||||
|
||||
|
@ -538,6 +539,174 @@ static void sunxi_nfc_cmd_ctrl(struct mtd_info *mtd, int dat,
|
|||
sunxi_nfc_wait_int(nfc, NFC_CMD_INT_FLAG, 0);
|
||||
}
|
||||
|
||||
/* These seed values have been extracted from Allwinner's BSP */
|
||||
static const u16 sunxi_nfc_randomizer_page_seeds[] = {
|
||||
0x2b75, 0x0bd0, 0x5ca3, 0x62d1, 0x1c93, 0x07e9, 0x2162, 0x3a72,
|
||||
0x0d67, 0x67f9, 0x1be7, 0x077d, 0x032f, 0x0dac, 0x2716, 0x2436,
|
||||
0x7922, 0x1510, 0x3860, 0x5287, 0x480f, 0x4252, 0x1789, 0x5a2d,
|
||||
0x2a49, 0x5e10, 0x437f, 0x4b4e, 0x2f45, 0x216e, 0x5cb7, 0x7130,
|
||||
0x2a3f, 0x60e4, 0x4dc9, 0x0ef0, 0x0f52, 0x1bb9, 0x6211, 0x7a56,
|
||||
0x226d, 0x4ea7, 0x6f36, 0x3692, 0x38bf, 0x0c62, 0x05eb, 0x4c55,
|
||||
0x60f4, 0x728c, 0x3b6f, 0x2037, 0x7f69, 0x0936, 0x651a, 0x4ceb,
|
||||
0x6218, 0x79f3, 0x383f, 0x18d9, 0x4f05, 0x5c82, 0x2912, 0x6f17,
|
||||
0x6856, 0x5938, 0x1007, 0x61ab, 0x3e7f, 0x57c2, 0x542f, 0x4f62,
|
||||
0x7454, 0x2eac, 0x7739, 0x42d4, 0x2f90, 0x435a, 0x2e52, 0x2064,
|
||||
0x637c, 0x66ad, 0x2c90, 0x0bad, 0x759c, 0x0029, 0x0986, 0x7126,
|
||||
0x1ca7, 0x1605, 0x386a, 0x27f5, 0x1380, 0x6d75, 0x24c3, 0x0f8e,
|
||||
0x2b7a, 0x1418, 0x1fd1, 0x7dc1, 0x2d8e, 0x43af, 0x2267, 0x7da3,
|
||||
0x4e3d, 0x1338, 0x50db, 0x454d, 0x764d, 0x40a3, 0x42e6, 0x262b,
|
||||
0x2d2e, 0x1aea, 0x2e17, 0x173d, 0x3a6e, 0x71bf, 0x25f9, 0x0a5d,
|
||||
0x7c57, 0x0fbe, 0x46ce, 0x4939, 0x6b17, 0x37bb, 0x3e91, 0x76db,
|
||||
};
|
||||
|
||||
/*
|
||||
* sunxi_nfc_randomizer_ecc512_seeds and sunxi_nfc_randomizer_ecc1024_seeds
|
||||
* have been generated using
|
||||
* sunxi_nfc_randomizer_step(seed, (step_size * 8) + 15), which is what
|
||||
* the randomizer engine does internally before de/scrambling OOB data.
|
||||
*
|
||||
* Those tables are statically defined to avoid calculating randomizer state
|
||||
* at runtime.
|
||||
*/
|
||||
static const u16 sunxi_nfc_randomizer_ecc512_seeds[] = {
|
||||
0x3346, 0x367f, 0x1f18, 0x769a, 0x4f64, 0x068c, 0x2ef1, 0x6b64,
|
||||
0x28a9, 0x15d7, 0x30f8, 0x3659, 0x53db, 0x7c5f, 0x71d4, 0x4409,
|
||||
0x26eb, 0x03cc, 0x655d, 0x47d4, 0x4daa, 0x0877, 0x712d, 0x3617,
|
||||
0x3264, 0x49aa, 0x7f9e, 0x588e, 0x4fbc, 0x7176, 0x7f91, 0x6c6d,
|
||||
0x4b95, 0x5fb7, 0x3844, 0x4037, 0x0184, 0x081b, 0x0ee8, 0x5b91,
|
||||
0x293d, 0x1f71, 0x0e6f, 0x402b, 0x5122, 0x1e52, 0x22be, 0x3d2d,
|
||||
0x75bc, 0x7c60, 0x6291, 0x1a2f, 0x61d4, 0x74aa, 0x4140, 0x29ab,
|
||||
0x472d, 0x2852, 0x017e, 0x15e8, 0x5ec2, 0x17cf, 0x7d0f, 0x06b8,
|
||||
0x117a, 0x6b94, 0x789b, 0x3126, 0x6ac5, 0x5be7, 0x150f, 0x51f8,
|
||||
0x7889, 0x0aa5, 0x663d, 0x77e8, 0x0b87, 0x3dcb, 0x360d, 0x218b,
|
||||
0x512f, 0x7dc9, 0x6a4d, 0x630a, 0x3547, 0x1dd2, 0x5aea, 0x69a5,
|
||||
0x7bfa, 0x5e4f, 0x1519, 0x6430, 0x3a0e, 0x5eb3, 0x5425, 0x0c7a,
|
||||
0x5540, 0x3670, 0x63c1, 0x31e9, 0x5a39, 0x2de7, 0x5979, 0x2891,
|
||||
0x1562, 0x014b, 0x5b05, 0x2756, 0x5a34, 0x13aa, 0x6cb5, 0x2c36,
|
||||
0x5e72, 0x1306, 0x0861, 0x15ef, 0x1ee8, 0x5a37, 0x7ac4, 0x45dd,
|
||||
0x44c4, 0x7266, 0x2f41, 0x3ccc, 0x045e, 0x7d40, 0x7c66, 0x0fa0,
|
||||
};
|
||||
|
||||
static const u16 sunxi_nfc_randomizer_ecc1024_seeds[] = {
|
||||
0x2cf5, 0x35f1, 0x63a4, 0x5274, 0x2bd2, 0x778b, 0x7285, 0x32b6,
|
||||
0x6a5c, 0x70d6, 0x757d, 0x6769, 0x5375, 0x1e81, 0x0cf3, 0x3982,
|
||||
0x6787, 0x042a, 0x6c49, 0x1925, 0x56a8, 0x40a9, 0x063e, 0x7bd9,
|
||||
0x4dbf, 0x55ec, 0x672e, 0x7334, 0x5185, 0x4d00, 0x232a, 0x7e07,
|
||||
0x445d, 0x6b92, 0x528f, 0x4255, 0x53ba, 0x7d82, 0x2a2e, 0x3a4e,
|
||||
0x75eb, 0x450c, 0x6844, 0x1b5d, 0x581a, 0x4cc6, 0x0379, 0x37b2,
|
||||
0x419f, 0x0e92, 0x6b27, 0x5624, 0x01e3, 0x07c1, 0x44a5, 0x130c,
|
||||
0x13e8, 0x5910, 0x0876, 0x60c5, 0x54e3, 0x5b7f, 0x2269, 0x509f,
|
||||
0x7665, 0x36fd, 0x3e9a, 0x0579, 0x6295, 0x14ef, 0x0a81, 0x1bcc,
|
||||
0x4b16, 0x64db, 0x0514, 0x4f07, 0x0591, 0x3576, 0x6853, 0x0d9e,
|
||||
0x259f, 0x38b7, 0x64fb, 0x3094, 0x4693, 0x6ddd, 0x29bb, 0x0bc8,
|
||||
0x3f47, 0x490e, 0x0c0e, 0x7933, 0x3c9e, 0x5840, 0x398d, 0x3e68,
|
||||
0x4af1, 0x71f5, 0x57cf, 0x1121, 0x64eb, 0x3579, 0x15ac, 0x584d,
|
||||
0x5f2a, 0x47e2, 0x6528, 0x6eac, 0x196e, 0x6b96, 0x0450, 0x0179,
|
||||
0x609c, 0x06e1, 0x4626, 0x42c7, 0x273e, 0x486f, 0x0705, 0x1601,
|
||||
0x145b, 0x407e, 0x062b, 0x57a5, 0x53f9, 0x5659, 0x4410, 0x3ccd,
|
||||
};
|
||||
|
||||
static u16 sunxi_nfc_randomizer_step(u16 state, int count)
|
||||
{
|
||||
state &= 0x7fff;
|
||||
|
||||
/*
|
||||
* This loop is just a simple implementation of a Fibonacci LFSR using
|
||||
* the x16 + x15 + 1 polynomial.
|
||||
*/
|
||||
while (count--)
|
||||
state = ((state >> 1) |
|
||||
(((state ^ (state >> 1)) & 1) << 14)) & 0x7fff;
|
||||
|
||||
return state;
|
||||
}
|
||||
|
||||
static u16 sunxi_nfc_randomizer_state(struct mtd_info *mtd, int page, bool ecc)
|
||||
{
|
||||
const u16 *seeds = sunxi_nfc_randomizer_page_seeds;
|
||||
int mod = mtd_div_by_ws(mtd->erasesize, mtd);
|
||||
|
||||
if (mod > ARRAY_SIZE(sunxi_nfc_randomizer_page_seeds))
|
||||
mod = ARRAY_SIZE(sunxi_nfc_randomizer_page_seeds);
|
||||
|
||||
if (ecc) {
|
||||
if (mtd->ecc_step_size == 512)
|
||||
seeds = sunxi_nfc_randomizer_ecc512_seeds;
|
||||
else
|
||||
seeds = sunxi_nfc_randomizer_ecc1024_seeds;
|
||||
}
|
||||
|
||||
return seeds[page % mod];
|
||||
}
|
||||
|
||||
static void sunxi_nfc_randomizer_config(struct mtd_info *mtd,
|
||||
int page, bool ecc)
|
||||
{
|
||||
struct nand_chip *nand = mtd->priv;
|
||||
struct sunxi_nfc *nfc = to_sunxi_nfc(nand->controller);
|
||||
u32 ecc_ctl = readl(nfc->regs + NFC_REG_ECC_CTL);
|
||||
u16 state;
|
||||
|
||||
if (!(nand->options & NAND_NEED_SCRAMBLING))
|
||||
return;
|
||||
|
||||
ecc_ctl = readl(nfc->regs + NFC_REG_ECC_CTL);
|
||||
state = sunxi_nfc_randomizer_state(mtd, page, ecc);
|
||||
ecc_ctl = readl(nfc->regs + NFC_REG_ECC_CTL) & ~NFC_RANDOM_SEED_MSK;
|
||||
writel(ecc_ctl | NFC_RANDOM_SEED(state), nfc->regs + NFC_REG_ECC_CTL);
|
||||
}
|
||||
|
||||
static void sunxi_nfc_randomizer_enable(struct mtd_info *mtd)
|
||||
{
|
||||
struct nand_chip *nand = mtd->priv;
|
||||
struct sunxi_nfc *nfc = to_sunxi_nfc(nand->controller);
|
||||
|
||||
if (!(nand->options & NAND_NEED_SCRAMBLING))
|
||||
return;
|
||||
|
||||
writel(readl(nfc->regs + NFC_REG_ECC_CTL) | NFC_RANDOM_EN,
|
||||
nfc->regs + NFC_REG_ECC_CTL);
|
||||
}
|
||||
|
||||
static void sunxi_nfc_randomizer_disable(struct mtd_info *mtd)
|
||||
{
|
||||
struct nand_chip *nand = mtd->priv;
|
||||
struct sunxi_nfc *nfc = to_sunxi_nfc(nand->controller);
|
||||
|
||||
if (!(nand->options & NAND_NEED_SCRAMBLING))
|
||||
return;
|
||||
|
||||
writel(readl(nfc->regs + NFC_REG_ECC_CTL) & ~NFC_RANDOM_EN,
|
||||
nfc->regs + NFC_REG_ECC_CTL);
|
||||
}
|
||||
|
||||
static void sunxi_nfc_randomize_bbm(struct mtd_info *mtd, int page, u8 *bbm)
|
||||
{
|
||||
u16 state = sunxi_nfc_randomizer_state(mtd, page, true);
|
||||
|
||||
bbm[0] ^= state;
|
||||
bbm[1] ^= sunxi_nfc_randomizer_step(state, 8);
|
||||
}
|
||||
|
||||
static void sunxi_nfc_randomizer_write_buf(struct mtd_info *mtd,
|
||||
const uint8_t *buf, int len,
|
||||
bool ecc, int page)
|
||||
{
|
||||
sunxi_nfc_randomizer_config(mtd, page, ecc);
|
||||
sunxi_nfc_randomizer_enable(mtd);
|
||||
sunxi_nfc_write_buf(mtd, buf, len);
|
||||
sunxi_nfc_randomizer_disable(mtd);
|
||||
}
|
||||
|
||||
static void sunxi_nfc_randomizer_read_buf(struct mtd_info *mtd, uint8_t *buf,
|
||||
int len, bool ecc, int page)
|
||||
{
|
||||
sunxi_nfc_randomizer_config(mtd, page, ecc);
|
||||
sunxi_nfc_randomizer_enable(mtd);
|
||||
sunxi_nfc_read_buf(mtd, buf, len);
|
||||
sunxi_nfc_randomizer_disable(mtd);
|
||||
}
|
||||
|
||||
static void sunxi_nfc_hw_ecc_enable(struct mtd_info *mtd)
|
||||
{
|
||||
struct nand_chip *nand = mtd_to_nand(mtd);
|
||||
|
@ -574,18 +743,20 @@ static int sunxi_nfc_hw_ecc_read_chunk(struct mtd_info *mtd,
|
|||
u8 *data, int data_off,
|
||||
u8 *oob, int oob_off,
|
||||
int *cur_off,
|
||||
unsigned int *max_bitflips)
|
||||
unsigned int *max_bitflips,
|
||||
bool bbm, int page)
|
||||
{
|
||||
struct nand_chip *nand = mtd_to_nand(mtd);
|
||||
struct sunxi_nfc *nfc = to_sunxi_nfc(nand->controller);
|
||||
struct nand_ecc_ctrl *ecc = &nand->ecc;
|
||||
int raw_mode = 0;
|
||||
u32 status;
|
||||
int ret;
|
||||
|
||||
if (*cur_off != data_off)
|
||||
nand->cmdfunc(mtd, NAND_CMD_RNDOUT, data_off, -1);
|
||||
|
||||
sunxi_nfc_read_buf(mtd, NULL, ecc->size);
|
||||
sunxi_nfc_randomizer_read_buf(mtd, NULL, ecc->size, false, page);
|
||||
|
||||
if (data_off + ecc->size != oob_off)
|
||||
nand->cmdfunc(mtd, NAND_CMD_RNDOUT, oob_off, -1);
|
||||
|
@ -594,25 +765,54 @@ static int sunxi_nfc_hw_ecc_read_chunk(struct mtd_info *mtd,
|
|||
if (ret)
|
||||
return ret;
|
||||
|
||||
sunxi_nfc_randomizer_enable(mtd);
|
||||
writel(NFC_DATA_TRANS | NFC_DATA_SWAP_METHOD | NFC_ECC_OP,
|
||||
nfc->regs + NFC_REG_CMD);
|
||||
|
||||
ret = sunxi_nfc_wait_int(nfc, NFC_CMD_INT_FLAG, 0);
|
||||
sunxi_nfc_randomizer_disable(mtd);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
*cur_off = oob_off + ecc->bytes + 4;
|
||||
|
||||
status = readl(nfc->regs + NFC_REG_ECC_ST);
|
||||
if (status & NFC_ECC_PAT_FOUND(0)) {
|
||||
u8 pattern = 0xff;
|
||||
|
||||
if (unlikely(!(readl(nfc->regs + NFC_REG_PAT_ID) & 0x1)))
|
||||
pattern = 0x0;
|
||||
|
||||
memset(data, pattern, ecc->size);
|
||||
memset(oob, pattern, ecc->bytes + 4);
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
ret = NFC_ECC_ERR_CNT(0, readl(nfc->regs + NFC_REG_ECC_ERR_CNT(0)));
|
||||
|
||||
memcpy_fromio(data, nfc->regs + NFC_RAM0_BASE, ecc->size);
|
||||
|
||||
nand->cmdfunc(mtd, NAND_CMD_RNDOUT, oob_off, -1);
|
||||
sunxi_nfc_read_buf(mtd, oob, ecc->bytes + 4);
|
||||
sunxi_nfc_randomizer_read_buf(mtd, oob, ecc->bytes + 4, true, page);
|
||||
|
||||
if (status & NFC_ECC_ERR(0)) {
|
||||
/*
|
||||
* Re-read the data with the randomizer disabled to identify
|
||||
* bitflips in erased pages.
|
||||
*/
|
||||
if (nand->options & NAND_NEED_SCRAMBLING) {
|
||||
nand->cmdfunc(mtd, NAND_CMD_RNDOUT, data_off, -1);
|
||||
nand->read_buf(mtd, data, ecc->size);
|
||||
nand->cmdfunc(mtd, NAND_CMD_RNDOUT, oob_off, -1);
|
||||
nand->read_buf(mtd, oob, ecc->bytes + 4);
|
||||
}
|
||||
|
||||
ret = nand_check_erased_ecc_chunk(data, ecc->size,
|
||||
oob, ecc->bytes + 4,
|
||||
NULL, 0, ecc->strength);
|
||||
if (ret >= 0)
|
||||
raw_mode = 1;
|
||||
} else {
|
||||
/*
|
||||
* The engine protects 4 bytes of OOB data per chunk.
|
||||
|
@ -620,6 +820,10 @@ static int sunxi_nfc_hw_ecc_read_chunk(struct mtd_info *mtd,
|
|||
*/
|
||||
sunxi_nfc_user_data_to_buf(readl(nfc->regs + NFC_REG_USER_DATA(0)),
|
||||
oob);
|
||||
|
||||
/* De-randomize the Bad Block Marker. */
|
||||
if (bbm && nand->options & NAND_NEED_SCRAMBLING)
|
||||
sunxi_nfc_randomize_bbm(mtd, page, oob);
|
||||
}
|
||||
|
||||
if (ret < 0) {
|
||||
|
@ -629,13 +833,12 @@ static int sunxi_nfc_hw_ecc_read_chunk(struct mtd_info *mtd,
|
|||
*max_bitflips = max_t(unsigned int, *max_bitflips, ret);
|
||||
}
|
||||
|
||||
*cur_off = oob_off + ecc->bytes + 4;
|
||||
|
||||
return 0;
|
||||
return raw_mode;
|
||||
}
|
||||
|
||||
static void sunxi_nfc_hw_ecc_read_extra_oob(struct mtd_info *mtd,
|
||||
u8 *oob, int *cur_off)
|
||||
u8 *oob, int *cur_off,
|
||||
bool randomize, int page)
|
||||
{
|
||||
struct nand_chip *nand = mtd_to_nand(mtd);
|
||||
struct nand_ecc_ctrl *ecc = &nand->ecc;
|
||||
|
@ -649,7 +852,11 @@ static void sunxi_nfc_hw_ecc_read_extra_oob(struct mtd_info *mtd,
|
|||
nand->cmdfunc(mtd, NAND_CMD_RNDOUT,
|
||||
offset + mtd->writesize, -1);
|
||||
|
||||
sunxi_nfc_read_buf(mtd, oob + offset, len);
|
||||
if (!randomize)
|
||||
sunxi_nfc_read_buf(mtd, oob + offset, len);
|
||||
else
|
||||
sunxi_nfc_randomizer_read_buf(mtd, oob + offset, len,
|
||||
false, page);
|
||||
|
||||
*cur_off = mtd->oobsize + mtd->writesize;
|
||||
}
|
||||
|
@ -662,7 +869,8 @@ static inline u32 sunxi_nfc_buf_to_user_data(const u8 *buf)
|
|||
static int sunxi_nfc_hw_ecc_write_chunk(struct mtd_info *mtd,
|
||||
const u8 *data, int data_off,
|
||||
const u8 *oob, int oob_off,
|
||||
int *cur_off)
|
||||
int *cur_off, bool bbm,
|
||||
int page)
|
||||
{
|
||||
struct nand_chip *nand = mtd_to_nand(mtd);
|
||||
struct sunxi_nfc *nfc = to_sunxi_nfc(nand->controller);
|
||||
|
@ -672,11 +880,20 @@ static int sunxi_nfc_hw_ecc_write_chunk(struct mtd_info *mtd,
|
|||
if (data_off != *cur_off)
|
||||
nand->cmdfunc(mtd, NAND_CMD_RNDIN, data_off, -1);
|
||||
|
||||
sunxi_nfc_write_buf(mtd, data, ecc->size);
|
||||
sunxi_nfc_randomizer_write_buf(mtd, data, ecc->size, false, page);
|
||||
|
||||
/* Fill OOB data in */
|
||||
writel(sunxi_nfc_buf_to_user_data(oob),
|
||||
nfc->regs + NFC_REG_USER_DATA(0));
|
||||
if ((nand->options & NAND_NEED_SCRAMBLING) && bbm) {
|
||||
u8 user_data[4];
|
||||
|
||||
memcpy(user_data, oob, 4);
|
||||
sunxi_nfc_randomize_bbm(mtd, page, user_data);
|
||||
writel(sunxi_nfc_buf_to_user_data(user_data),
|
||||
nfc->regs + NFC_REG_USER_DATA(0));
|
||||
} else {
|
||||
writel(sunxi_nfc_buf_to_user_data(oob),
|
||||
nfc->regs + NFC_REG_USER_DATA(0));
|
||||
}
|
||||
|
||||
if (data_off + ecc->size != oob_off)
|
||||
nand->cmdfunc(mtd, NAND_CMD_RNDIN, oob_off, -1);
|
||||
|
@ -685,11 +902,13 @@ static int sunxi_nfc_hw_ecc_write_chunk(struct mtd_info *mtd,
|
|||
if (ret)
|
||||
return ret;
|
||||
|
||||
sunxi_nfc_randomizer_enable(mtd);
|
||||
writel(NFC_DATA_TRANS | NFC_DATA_SWAP_METHOD |
|
||||
NFC_ACCESS_DIR | NFC_ECC_OP,
|
||||
nfc->regs + NFC_REG_CMD);
|
||||
|
||||
ret = sunxi_nfc_wait_int(nfc, NFC_CMD_INT_FLAG, 0);
|
||||
sunxi_nfc_randomizer_disable(mtd);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
|
@ -699,7 +918,8 @@ static int sunxi_nfc_hw_ecc_write_chunk(struct mtd_info *mtd,
|
|||
}
|
||||
|
||||
static void sunxi_nfc_hw_ecc_write_extra_oob(struct mtd_info *mtd,
|
||||
u8 *oob, int *cur_off)
|
||||
u8 *oob, int *cur_off,
|
||||
int page)
|
||||
{
|
||||
struct nand_chip *nand = mtd_to_nand(mtd);
|
||||
struct nand_ecc_ctrl *ecc = &nand->ecc;
|
||||
|
@ -713,7 +933,7 @@ static void sunxi_nfc_hw_ecc_write_extra_oob(struct mtd_info *mtd,
|
|||
nand->cmdfunc(mtd, NAND_CMD_RNDIN,
|
||||
offset + mtd->writesize, -1);
|
||||
|
||||
sunxi_nfc_write_buf(mtd, oob + offset, len);
|
||||
sunxi_nfc_randomizer_write_buf(mtd, oob + offset, len, false, page);
|
||||
|
||||
*cur_off = mtd->oobsize + mtd->writesize;
|
||||
}
|
||||
|
@ -725,6 +945,7 @@ static int sunxi_nfc_hw_ecc_read_page(struct mtd_info *mtd,
|
|||
struct nand_ecc_ctrl *ecc = &chip->ecc;
|
||||
unsigned int max_bitflips = 0;
|
||||
int ret, i, cur_off = 0;
|
||||
bool raw_mode = false;
|
||||
|
||||
sunxi_nfc_hw_ecc_enable(mtd);
|
||||
|
||||
|
@ -736,13 +957,17 @@ static int sunxi_nfc_hw_ecc_read_page(struct mtd_info *mtd,
|
|||
|
||||
ret = sunxi_nfc_hw_ecc_read_chunk(mtd, data, data_off, oob,
|
||||
oob_off + mtd->writesize,
|
||||
&cur_off, &max_bitflips);
|
||||
if (ret)
|
||||
&cur_off, &max_bitflips,
|
||||
!i, page);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
else if (ret)
|
||||
raw_mode = true;
|
||||
}
|
||||
|
||||
if (oob_required)
|
||||
sunxi_nfc_hw_ecc_read_extra_oob(mtd, chip->oob_poi, &cur_off);
|
||||
sunxi_nfc_hw_ecc_read_extra_oob(mtd, chip->oob_poi, &cur_off,
|
||||
!raw_mode, page);
|
||||
|
||||
sunxi_nfc_hw_ecc_disable(mtd);
|
||||
|
||||
|
@ -767,13 +992,14 @@ static int sunxi_nfc_hw_ecc_write_page(struct mtd_info *mtd,
|
|||
|
||||
ret = sunxi_nfc_hw_ecc_write_chunk(mtd, data, data_off, oob,
|
||||
oob_off + mtd->writesize,
|
||||
&cur_off);
|
||||
&cur_off, !i, page);
|
||||
if (ret)
|
||||
return ret;
|
||||
}
|
||||
|
||||
if (oob_required)
|
||||
sunxi_nfc_hw_ecc_write_extra_oob(mtd, chip->oob_poi, &cur_off);
|
||||
if (oob_required || (chip->options & NAND_NEED_SCRAMBLING))
|
||||
sunxi_nfc_hw_ecc_write_extra_oob(mtd, chip->oob_poi,
|
||||
&cur_off, page);
|
||||
|
||||
sunxi_nfc_hw_ecc_disable(mtd);
|
||||
|
||||
|
@ -788,6 +1014,7 @@ static int sunxi_nfc_hw_syndrome_ecc_read_page(struct mtd_info *mtd,
|
|||
struct nand_ecc_ctrl *ecc = &chip->ecc;
|
||||
unsigned int max_bitflips = 0;
|
||||
int ret, i, cur_off = 0;
|
||||
bool raw_mode = false;
|
||||
|
||||
sunxi_nfc_hw_ecc_enable(mtd);
|
||||
|
||||
|
@ -799,13 +1026,16 @@ static int sunxi_nfc_hw_syndrome_ecc_read_page(struct mtd_info *mtd,
|
|||
|
||||
ret = sunxi_nfc_hw_ecc_read_chunk(mtd, data, data_off, oob,
|
||||
oob_off, &cur_off,
|
||||
&max_bitflips);
|
||||
if (ret)
|
||||
&max_bitflips, !i, page);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
else if (ret)
|
||||
raw_mode = true;
|
||||
}
|
||||
|
||||
if (oob_required)
|
||||
sunxi_nfc_hw_ecc_read_extra_oob(mtd, chip->oob_poi, &cur_off);
|
||||
sunxi_nfc_hw_ecc_read_extra_oob(mtd, chip->oob_poi, &cur_off,
|
||||
!raw_mode, page);
|
||||
|
||||
sunxi_nfc_hw_ecc_disable(mtd);
|
||||
|
||||
|
@ -829,13 +1059,15 @@ static int sunxi_nfc_hw_syndrome_ecc_write_page(struct mtd_info *mtd,
|
|||
const u8 *oob = chip->oob_poi + (i * (ecc->bytes + 4));
|
||||
|
||||
ret = sunxi_nfc_hw_ecc_write_chunk(mtd, data, data_off,
|
||||
oob, oob_off, &cur_off);
|
||||
oob, oob_off, &cur_off,
|
||||
false, page);
|
||||
if (ret)
|
||||
return ret;
|
||||
}
|
||||
|
||||
if (oob_required)
|
||||
sunxi_nfc_hw_ecc_write_extra_oob(mtd, chip->oob_poi, &cur_off);
|
||||
if (oob_required || (chip->options & NAND_NEED_SCRAMBLING))
|
||||
sunxi_nfc_hw_ecc_write_extra_oob(mtd, chip->oob_poi,
|
||||
&cur_off, page);
|
||||
|
||||
sunxi_nfc_hw_ecc_disable(mtd);
|
||||
|
||||
|
@ -1345,6 +1577,9 @@ static int sunxi_nand_chip_init(struct device *dev, struct sunxi_nfc *nfc,
|
|||
if (nand->bbt_options & NAND_BBT_USE_FLASH)
|
||||
nand->bbt_options |= NAND_BBT_NO_OOB;
|
||||
|
||||
if (nand->options & NAND_NEED_SCRAMBLING)
|
||||
nand->options |= NAND_NO_SUBPAGE_WRITE;
|
||||
|
||||
ret = sunxi_nand_chip_init_timings(chip, np);
|
||||
if (ret) {
|
||||
dev_err(dev, "could not configure chip timings: %d\n", ret);
|
||||
|
|
|
@ -179,7 +179,7 @@ static int onenand_isbad_bbt(struct mtd_info *mtd, loff_t offs, int allowbbt)
|
|||
* by the onenand_release function.
|
||||
*
|
||||
*/
|
||||
int onenand_scan_bbt(struct mtd_info *mtd, struct nand_bbt_descr *bd)
|
||||
static int onenand_scan_bbt(struct mtd_info *mtd, struct nand_bbt_descr *bd)
|
||||
{
|
||||
struct onenand_chip *this = mtd->priv;
|
||||
struct bbm_info *bbm = this->bbm;
|
||||
|
@ -247,6 +247,3 @@ int onenand_default_bbt(struct mtd_info *mtd)
|
|||
|
||||
return onenand_scan_bbt(mtd, bbm->badblock_pattern);
|
||||
}
|
||||
|
||||
EXPORT_SYMBOL(onenand_scan_bbt);
|
||||
EXPORT_SYMBOL(onenand_default_bbt);
|
||||
|
|
|
@ -371,8 +371,8 @@ static int mt8173_nor_write_reg(struct spi_nor *nor, u8 opcode, u8 *buf,
|
|||
return ret;
|
||||
}
|
||||
|
||||
static int __init mtk_nor_init(struct mt8173_nor *mt8173_nor,
|
||||
struct device_node *flash_node)
|
||||
static int mtk_nor_init(struct mt8173_nor *mt8173_nor,
|
||||
struct device_node *flash_node)
|
||||
{
|
||||
int ret;
|
||||
struct spi_nor *nor;
|
||||
|
|
|
@ -166,7 +166,6 @@ struct bbm_info {
|
|||
};
|
||||
|
||||
/* OneNAND BBT interface */
|
||||
extern int onenand_scan_bbt(struct mtd_info *mtd, struct nand_bbt_descr *bd);
|
||||
extern int onenand_default_bbt(struct mtd_info *mtd);
|
||||
|
||||
#endif /* __LINUX_MTD_BBM_H */
|
||||
|
|
|
@ -168,6 +168,12 @@ typedef enum {
|
|||
/* Device supports subpage reads */
|
||||
#define NAND_SUBPAGE_READ 0x00001000
|
||||
|
||||
/*
|
||||
* Some MLC NANDs need data scrambling to limit bitflips caused by repeated
|
||||
* patterns.
|
||||
*/
|
||||
#define NAND_NEED_SCRAMBLING 0x00002000
|
||||
|
||||
/* Options valid for Samsung large page devices */
|
||||
#define NAND_SAMSUNG_LP_OPTIONS NAND_CACHEPRG
|
||||
|
||||
|
|
Loading…
Reference in New Issue