Commit 1e2da4ad authored by Brian Norris's avatar Brian Norris

Merge tag 'for-4.9' of github.com:linux-nand/linux

"
Notable core changes:
- add the infrastructure to automate NAND timings configuration
- provide a generic DT property to maximize ECC strength

The rest is just a bunch of minor drivers and core fixes/cleanup
patches.
"

Also not noted: some refactoring in the core bad block table handling,
to help with improving some of the logic in error cases.
Signed-off-by: default avatarBrian Norris <computersforpeace@gmail.com>
parents 5e149073 d44154f9
......@@ -35,6 +35,15 @@ Optional NAND chip properties:
- nand-ecc-step-size: integer representing the number of data bytes
that are covered by a single ECC step.
- nand-ecc-maximize: boolean used to specify that you want to maximize ECC
strength. The maximum ECC strength is both controller and
chip dependent. The controller side has to select the ECC
config providing the best strength and taking the OOB area
size constraint into account.
This is particularly useful when only the in-band area is
used by the upper layers, and you want to make your NAND
as reliable as possible.
The ECC strength and ECC step size properties define the correction capability
of a controller. Together, they say a controller can correct "{strength} bit
errors per {size} bytes".
......
......@@ -5976,6 +5976,12 @@ M: Zubair Lutfullah Kakakhel <Zubair.Kakakhel@imgtec.com>
S: Maintained
F: drivers/dma/dma-jz4780.c
INGENIC JZ4780 NAND DRIVER
M: Harvey Hunt <harveyhuntnexus@gmail.com>
L: linux-mtd@lists.infradead.org
S: Maintained
F: drivers/mtd/nand/jz4780_*
INTEGRITY MEASUREMENT ARCHITECTURE (IMA)
M: Mimi Zohar <zohar@linux.vnet.ibm.com>
M: Dmitry Kasatkin <dmitry.kasatkin@gmail.com>
......
......@@ -88,11 +88,11 @@ config MTD_NAND_AMS_DELTA
Support for NAND flash on Amstrad E3 (Delta).
config MTD_NAND_OMAP2
tristate "NAND Flash device on OMAP2, OMAP3 and OMAP4"
depends on ARCH_OMAP2PLUS
tristate "NAND Flash device on OMAP2, OMAP3, OMAP4 and Keystone"
depends on (ARCH_OMAP2PLUS || ARCH_KEYSTONE)
help
Support for NAND flash on Texas Instruments OMAP2, OMAP3 and OMAP4
platforms.
Support for NAND flash on Texas Instruments OMAP2, OMAP3, OMAP4
and Keystone platforms.
config MTD_NAND_OMAP_BCH
depends on MTD_NAND_OMAP2
......@@ -428,7 +428,7 @@ config MTD_NAND_ORION
config MTD_NAND_FSL_ELBC
tristate "NAND support for Freescale eLBC controllers"
depends on PPC
depends on FSL_SOC
select FSL_LBC
help
Various Freescale chips, including the 8313, include a NAND Flash
......@@ -438,7 +438,7 @@ config MTD_NAND_FSL_ELBC
config MTD_NAND_FSL_IFC
tristate "NAND support for Freescale IFC controller"
depends on MTD_NAND && (FSL_SOC || ARCH_LAYERSCAPE)
depends on FSL_SOC || ARCH_LAYERSCAPE
select FSL_IFC
select MEMORY
help
......
......@@ -761,8 +761,7 @@ static int bf5xx_nand_probe(struct platform_device *pdev)
platform_set_drvdata(pdev, info);
spin_lock_init(&info->controller.lock);
init_waitqueue_head(&info->controller.wq);
nand_hw_control_init(&info->controller);
info->device = &pdev->dev;
info->platform = plat;
......
......@@ -1336,7 +1336,7 @@ static void brcmnand_cmdfunc(struct mtd_info *mtd, unsigned command,
u32 *flash_cache = (u32 *)ctrl->flash_cache;
int i;
brcmnand_soc_data_bus_prepare(ctrl->soc);
brcmnand_soc_data_bus_prepare(ctrl->soc, true);
/*
* Must cache the FLASH_CACHE now, since changes in
......@@ -1349,7 +1349,7 @@ static void brcmnand_cmdfunc(struct mtd_info *mtd, unsigned command,
*/
flash_cache[i] = be32_to_cpu(brcmnand_read_fc(ctrl, i));
brcmnand_soc_data_bus_unprepare(ctrl->soc);
brcmnand_soc_data_bus_unprepare(ctrl->soc, true);
/* Cleanup from HW quirk: restore SECTOR_SIZE_1K */
if (host->hwcfg.sector_size_1k)
......@@ -1565,12 +1565,12 @@ static int brcmnand_read_by_pio(struct mtd_info *mtd, struct nand_chip *chip,
brcmnand_waitfunc(mtd, chip);
if (likely(buf)) {
brcmnand_soc_data_bus_prepare(ctrl->soc);
brcmnand_soc_data_bus_prepare(ctrl->soc, false);
for (j = 0; j < FC_WORDS; j++, buf++)
*buf = brcmnand_read_fc(ctrl, j);
brcmnand_soc_data_bus_unprepare(ctrl->soc);
brcmnand_soc_data_bus_unprepare(ctrl->soc, false);
}
if (oob)
......@@ -1815,12 +1815,12 @@ static int brcmnand_write(struct mtd_info *mtd, struct nand_chip *chip,
(void)brcmnand_read_reg(ctrl, BRCMNAND_CMD_ADDRESS);
if (buf) {
brcmnand_soc_data_bus_prepare(ctrl->soc);
brcmnand_soc_data_bus_prepare(ctrl->soc, false);
for (j = 0; j < FC_WORDS; j++, buf++)
brcmnand_write_fc(ctrl, j, *buf);
brcmnand_soc_data_bus_unprepare(ctrl->soc);
brcmnand_soc_data_bus_unprepare(ctrl->soc, false);
} else if (oob) {
for (j = 0; j < FC_WORDS; j++)
brcmnand_write_fc(ctrl, j, 0xffffffff);
......@@ -2370,8 +2370,7 @@ int brcmnand_probe(struct platform_device *pdev, struct brcmnand_soc *soc)
init_completion(&ctrl->done);
init_completion(&ctrl->dma_done);
spin_lock_init(&ctrl->controller.lock);
init_waitqueue_head(&ctrl->controller.wq);
nand_hw_control_init(&ctrl->controller);
INIT_LIST_HEAD(&ctrl->host_list);
/* NAND register range */
......
......@@ -23,19 +23,22 @@ struct dev_pm_ops;
struct brcmnand_soc {
bool (*ctlrdy_ack)(struct brcmnand_soc *soc);
void (*ctlrdy_set_enabled)(struct brcmnand_soc *soc, bool en);
void (*prepare_data_bus)(struct brcmnand_soc *soc, bool prepare);
void (*prepare_data_bus)(struct brcmnand_soc *soc, bool prepare,
bool is_param);
};
static inline void brcmnand_soc_data_bus_prepare(struct brcmnand_soc *soc)
static inline void brcmnand_soc_data_bus_prepare(struct brcmnand_soc *soc,
bool is_param)
{
if (soc && soc->prepare_data_bus)
soc->prepare_data_bus(soc, true);
soc->prepare_data_bus(soc, true, is_param);
}
static inline void brcmnand_soc_data_bus_unprepare(struct brcmnand_soc *soc)
static inline void brcmnand_soc_data_bus_unprepare(struct brcmnand_soc *soc,
bool is_param)
{
if (soc && soc->prepare_data_bus)
soc->prepare_data_bus(soc, false);
soc->prepare_data_bus(soc, false, is_param);
}
static inline u32 brcmnand_readl(void __iomem *addr)
......
......@@ -74,7 +74,8 @@ static void iproc_nand_intc_set(struct brcmnand_soc *soc, bool en)
spin_unlock_irqrestore(&priv->idm_lock, flags);
}
static void iproc_nand_apb_access(struct brcmnand_soc *soc, bool prepare)
static void iproc_nand_apb_access(struct brcmnand_soc *soc, bool prepare,
bool is_param)
{
struct iproc_nand_soc *priv =
container_of(soc, struct iproc_nand_soc, soc);
......@@ -86,10 +87,19 @@ static void iproc_nand_apb_access(struct brcmnand_soc *soc, bool prepare)
val = brcmnand_readl(mmio);
if (prepare)
val |= IPROC_NAND_APB_LE_MODE;
else
/*
* In the case of BE or when dealing with NAND data, alway configure
* the APB bus to LE mode before accessing the FIFO and back to BE mode
* after the access is done
*/
if (IS_ENABLED(CONFIG_CPU_BIG_ENDIAN) || !is_param) {
if (prepare)
val |= IPROC_NAND_APB_LE_MODE;
else
val &= ~IPROC_NAND_APB_LE_MODE;
} else { /* when in LE accessing the parameter page, keep APB in BE */
val &= ~IPROC_NAND_APB_LE_MODE;
}
brcmnand_writel(val, mmio);
......
......@@ -1249,8 +1249,7 @@ static void __init init_mtd_structs(struct mtd_info *mtd)
nand->options = NAND_BUSWIDTH_16 | NAND_NO_SUBPAGE_WRITE;
nand->IO_ADDR_R = nand->IO_ADDR_W = doc->virtadr + DOC_IOSPACE_DATA;
nand->controller = &nand->hwcontrol;
spin_lock_init(&nand->controller->lock);
init_waitqueue_head(&nand->controller->wq);
nand_hw_control_init(nand->controller);
/* methods */
nand->cmdfunc = docg4_command;
......
......@@ -879,8 +879,7 @@ static int fsl_elbc_nand_probe(struct platform_device *pdev)
}
elbc_fcm_ctrl->counter++;
spin_lock_init(&elbc_fcm_ctrl->controller.lock);
init_waitqueue_head(&elbc_fcm_ctrl->controller.wq);
nand_hw_control_init(&elbc_fcm_ctrl->controller);
fsl_lbc_ctrl_dev->nand = elbc_fcm_ctrl;
} else {
elbc_fcm_ctrl = fsl_lbc_ctrl_dev->nand;
......
......@@ -987,8 +987,7 @@ static int fsl_ifc_nand_probe(struct platform_device *dev)
ifc_nand_ctrl->addr = NULL;
fsl_ifc_ctrl_dev->nand = ifc_nand_ctrl;
spin_lock_init(&ifc_nand_ctrl->controller.lock);
init_waitqueue_head(&ifc_nand_ctrl->controller.wq);
nand_hw_control_init(&ifc_nand_ctrl->controller);
} else {
ifc_nand_ctrl = fsl_ifc_ctrl_dev->nand;
}
......
......@@ -318,7 +318,8 @@ static int legacy_set_geometry(struct gpmi_nand_data *this)
return -EINVAL;
}
geo->page_size = mtd->writesize + mtd->oobsize;
geo->page_size = mtd->writesize + geo->metadata_size +
(geo->gf_len * geo->ecc_strength * geo->ecc_chunk_count) / 8;
geo->payload_size = mtd->writesize;
/*
......
......@@ -368,9 +368,8 @@ static int jz4780_nand_probe(struct platform_device *pdev)
nfc->dev = dev;
nfc->num_banks = num_banks;
spin_lock_init(&nfc->controller.lock);
nand_hw_control_init(&nfc->controller);
INIT_LIST_HEAD(&nfc->chips);
init_waitqueue_head(&nfc->controller.wq);
ret = jz4780_nand_init_chips(nfc, pdev);
if (ret) {
......
......@@ -152,6 +152,9 @@ struct mxc_nand_devtype_data {
void (*select_chip)(struct mtd_info *mtd, int chip);
int (*correct_data)(struct mtd_info *mtd, u_char *dat,
u_char *read_ecc, u_char *calc_ecc);
int (*setup_data_interface)(struct mtd_info *mtd,
const struct nand_data_interface *conf,
bool check_only);
/*
* On i.MX21 the CONFIG2:INT bit cannot be read if interrupts are masked
......@@ -1012,6 +1015,82 @@ static void preset_v1(struct mtd_info *mtd)
writew(0x4, NFC_V1_V2_WRPROT);
}
static int mxc_nand_v2_setup_data_interface(struct mtd_info *mtd,
const struct nand_data_interface *conf,
bool check_only)
{
struct nand_chip *nand_chip = mtd_to_nand(mtd);
struct mxc_nand_host *host = nand_get_controller_data(nand_chip);
int tRC_min_ns, tRC_ps, ret;
unsigned long rate, rate_round;
const struct nand_sdr_timings *timings;
u16 config1;
timings = nand_get_sdr_timings(conf);
if (IS_ERR(timings))
return -ENOTSUPP;
config1 = readw(NFC_V1_V2_CONFIG1);
tRC_min_ns = timings->tRC_min / 1000;
rate = 1000000000 / tRC_min_ns;
/*
* For tRC < 30ns we have to use EDO mode. In this case the controller
* does one access per clock cycle. Otherwise the controller does one
* access in two clock cycles, thus we have to double the rate to the
* controller.
*/
if (tRC_min_ns < 30) {
rate_round = clk_round_rate(host->clk, rate);
config1 |= NFC_V2_CONFIG1_ONE_CYCLE;
tRC_ps = 1000000000 / (rate_round / 1000);
} else {
rate *= 2;
rate_round = clk_round_rate(host->clk, rate);
config1 &= ~NFC_V2_CONFIG1_ONE_CYCLE;
tRC_ps = 1000000000 / (rate_round / 1000 / 2);
}
/*
* The timing values compared against are from the i.MX25 Automotive
* datasheet, Table 50. NFC Timing Parameters
*/
if (timings->tCLS_min > tRC_ps - 1000 ||
timings->tCLH_min > tRC_ps - 2000 ||
timings->tCS_min > tRC_ps - 1000 ||
timings->tCH_min > tRC_ps - 2000 ||
timings->tWP_min > tRC_ps - 1500 ||
timings->tALS_min > tRC_ps ||
timings->tALH_min > tRC_ps - 3000 ||
timings->tDS_min > tRC_ps ||
timings->tDH_min > tRC_ps - 5000 ||
timings->tWC_min > 2 * tRC_ps ||
timings->tWH_min > tRC_ps - 2500 ||
timings->tRR_min > 6 * tRC_ps ||
timings->tRP_min > 3 * tRC_ps / 2 ||
timings->tRC_min > 2 * tRC_ps ||
timings->tREH_min > (tRC_ps / 2) - 2500) {
dev_dbg(host->dev, "Timing out of bounds\n");
return -EINVAL;
}
if (check_only)
return 0;
ret = clk_set_rate(host->clk, rate);
if (ret)
return ret;
writew(config1, NFC_V1_V2_CONFIG1);
dev_dbg(host->dev, "Setting rate to %ldHz, %s mode\n", rate_round,
config1 & NFC_V2_CONFIG1_ONE_CYCLE ? "One cycle (EDO)" :
"normal");
return 0;
}
static void preset_v2(struct mtd_info *mtd)
{
struct nand_chip *nand_chip = mtd_to_nand(mtd);
......@@ -1239,6 +1318,57 @@ static void mxc_nand_command(struct mtd_info *mtd, unsigned command,
}
}
static int mxc_nand_onfi_set_features(struct mtd_info *mtd,
struct nand_chip *chip, int addr,
u8 *subfeature_param)
{
struct nand_chip *nand_chip = mtd_to_nand(mtd);
struct mxc_nand_host *host = nand_get_controller_data(nand_chip);
int i;
if (!chip->onfi_version ||
!(le16_to_cpu(chip->onfi_params.opt_cmd)
& ONFI_OPT_CMD_SET_GET_FEATURES))
return -EINVAL;
host->buf_start = 0;
for (i = 0; i < ONFI_SUBFEATURE_PARAM_LEN; ++i)
chip->write_byte(mtd, subfeature_param[i]);
memcpy32_toio(host->main_area0, host->data_buf, mtd->writesize);
host->devtype_data->send_cmd(host, NAND_CMD_SET_FEATURES, false);
mxc_do_addr_cycle(mtd, addr, -1);
host->devtype_data->send_page(mtd, NFC_INPUT);
return 0;
}
static int mxc_nand_onfi_get_features(struct mtd_info *mtd,
struct nand_chip *chip, int addr,
u8 *subfeature_param)
{
struct nand_chip *nand_chip = mtd_to_nand(mtd);
struct mxc_nand_host *host = nand_get_controller_data(nand_chip);
int i;
if (!chip->onfi_version ||
!(le16_to_cpu(chip->onfi_params.opt_cmd)
& ONFI_OPT_CMD_SET_GET_FEATURES))
return -EINVAL;
host->devtype_data->send_cmd(host, NAND_CMD_GET_FEATURES, false);
mxc_do_addr_cycle(mtd, addr, -1);
host->devtype_data->send_page(mtd, NFC_OUTPUT);
memcpy32_fromio(host->data_buf, host->main_area0, 512);
host->buf_start = 0;
for (i = 0; i < ONFI_SUBFEATURE_PARAM_LEN; ++i)
*subfeature_param++ = chip->read_byte(mtd);
return 0;
}
/*
* The generic flash bbt decriptors overlap with our ecc
* hardware, so define some i.MX specific ones.
......@@ -1327,6 +1457,7 @@ static const struct mxc_nand_devtype_data imx25_nand_devtype_data = {
.ooblayout = &mxc_v2_ooblayout_ops,
.select_chip = mxc_nand_select_chip_v2,
.correct_data = mxc_nand_correct_data_v2_v3,
.setup_data_interface = mxc_nand_v2_setup_data_interface,
.irqpending_quirk = 0,
.needs_ip = 0,
.regs_offset = 0x1e00,
......@@ -1434,7 +1565,7 @@ static const struct platform_device_id mxcnd_devtype[] = {
};
MODULE_DEVICE_TABLE(platform, mxcnd_devtype);
#ifdef CONFIG_OF_MTD
#ifdef CONFIG_OF
static const struct of_device_id mxcnd_dt_ids[] = {
{
.compatible = "fsl,imx21-nand",
......@@ -1513,6 +1644,8 @@ static int mxcnd_probe(struct platform_device *pdev)
this->read_word = mxc_nand_read_word;
this->write_buf = mxc_nand_write_buf;
this->read_buf = mxc_nand_read_buf;
this->onfi_set_features = mxc_nand_onfi_set_features;
this->onfi_get_features = mxc_nand_onfi_get_features;
host->clk = devm_clk_get(&pdev->dev, NULL);
if (IS_ERR(host->clk))
......@@ -1533,6 +1666,8 @@ static int mxcnd_probe(struct platform_device *pdev)
if (err < 0)
return err;
this->setup_data_interface = host->devtype_data->setup_data_interface;
if (host->devtype_data->needs_ip) {
res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
host->regs_ip = devm_ioremap_resource(&pdev->dev, res);
......
This diff is collapsed.
......@@ -604,6 +604,100 @@ static void search_read_bbts(struct mtd_info *mtd, uint8_t *buf,
search_bbt(mtd, buf, md);
}
/**
* get_bbt_block - Get the first valid eraseblock suitable to store a BBT
* @this: the NAND device
* @td: the BBT description
* @md: the mirror BBT descriptor
* @chip: the CHIP selector
*
* This functions returns a positive block number pointing a valid eraseblock
* suitable to store a BBT (i.e. in the range reserved for BBT), or -ENOSPC if
* all blocks are already used of marked bad. If td->pages[chip] was already
* pointing to a valid block we re-use it, otherwise we search for the next
* valid one.
*/
static int get_bbt_block(struct nand_chip *this, struct nand_bbt_descr *td,
struct nand_bbt_descr *md, int chip)
{
int startblock, dir, page, numblocks, i;
/*
* There was already a version of the table, reuse the page. This
* applies for absolute placement too, as we have the page number in
* td->pages.
*/
if (td->pages[chip] != -1)
return td->pages[chip] >>
(this->bbt_erase_shift - this->page_shift);
numblocks = (int)(this->chipsize >> this->bbt_erase_shift);
if (!(td->options & NAND_BBT_PERCHIP))
numblocks *= this->numchips;
/*
* Automatic placement of the bad block table. Search direction
* top -> down?
*/
if (td->options & NAND_BBT_LASTBLOCK) {
startblock = numblocks * (chip + 1) - 1;
dir = -1;
} else {
startblock = chip * numblocks;
dir = 1;
}
for (i = 0; i < td->maxblocks; i++) {
int block = startblock + dir * i;
/* Check, if the block is bad */
switch (bbt_get_entry(this, block)) {
case BBT_BLOCK_WORN:
case BBT_BLOCK_FACTORY_BAD:
continue;
}
page = block << (this->bbt_erase_shift - this->page_shift);
/* Check, if the block is used by the mirror table */
if (!md || md->pages[chip] != page)
return block;
}
return -ENOSPC;
}
/**
* mark_bbt_block_bad - Mark one of the block reserved for BBT bad
* @this: the NAND device
* @td: the BBT description
* @chip: the CHIP selector
* @block: the BBT block to mark
*
* Blocks reserved for BBT can become bad. This functions is an helper to mark
* such blocks as bad. It takes care of updating the in-memory BBT, marking the
* block as bad using a bad block marker and invalidating the associated
* td->pages[] entry.
*/
static void mark_bbt_block_bad(struct nand_chip *this,
struct nand_bbt_descr *td,
int chip, int block)
{
struct mtd_info *mtd = nand_to_mtd(this);
loff_t to;
int res;
bbt_mark_entry(this, block, BBT_BLOCK_WORN);
to = (loff_t)block << this->bbt_erase_shift;
res = this->block_markbad(mtd, to);
if (res)
pr_warn("nand_bbt: error %d while marking block %d bad\n",
res, block);
td->pages[chip] = -1;
}
/**
* write_bbt - [GENERIC] (Re)write the bad block table
* @mtd: MTD device structure
......@@ -621,7 +715,7 @@ static int write_bbt(struct mtd_info *mtd, uint8_t *buf,
struct nand_chip *this = mtd_to_nand(mtd);
struct erase_info einfo;
int i, res, chip = 0;
int bits, startblock, dir, page, offs, numblocks, sft, sftmsk;
int bits, page, offs, numblocks, sft, sftmsk;
int nrchips, pageoffs, ooboffs;
uint8_t msk[4];
uint8_t rcode = td->reserved_block_code;
......@@ -652,46 +746,21 @@ static int write_bbt(struct mtd_info *mtd, uint8_t *buf,
}
/* Loop through the chips */
for (; chip < nrchips; chip++) {
/*
* There was already a version of the table, reuse the page
* This applies for absolute placement too, as we have the
* page nr. in td->pages.
*/
if (td->pages[chip] != -1) {
page = td->pages[chip];
goto write;
while (chip < nrchips) {
int block;
block = get_bbt_block(this, td, md, chip);
if (block < 0) {
pr_err("No space left to write bad block table\n");
res = block;
goto outerr;
}
/*
* Automatic placement of the bad block table. Search direction
* top -> down?
* get_bbt_block() returns a block number, shift the value to
* get a page number.
*/
if (td->options & NAND_BBT_LASTBLOCK) {
startblock = numblocks * (chip + 1) - 1;
dir = -1;
} else {
startblock = chip * numblocks;
dir = 1;
}
for (i = 0; i < td->maxblocks; i++) {
int block = startblock + dir * i;
/* Check, if the block is bad */
switch (bbt_get_entry(this, block)) {
case BBT_BLOCK_WORN:
case BBT_BLOCK_FACTORY_BAD:
continue;
}
page = block <<
(this->bbt_erase_shift - this->page_shift);
/* Check, if the block is used by the mirror table */
if (!md || md->pages[chip] != page)
goto write;
}
pr_err("No space left to write bad block table\n");
return -ENOSPC;
write:
page = block << (this->bbt_erase_shift - this->page_shift);
/* Set up shift count and masks for the flash table */
bits = td->options & NAND_BBT_NRBITS_MSK;
......@@ -787,20 +856,28 @@ static int write_bbt(struct mtd_info *mtd, uint8_t *buf,
einfo.addr = to;
einfo.len = 1 << this->bbt_erase_shift;
res = nand_erase_nand(mtd, &einfo, 1);
if (res < 0)
goto outerr;
if (res < 0) {
pr_warn("nand_bbt: error while erasing BBT block %d\n",
res);
mark_bbt_block_bad(this, td, chip, block);
continue;
}
res = scan_write_bbt(mtd, to, len, buf,
td->options & NAND_BBT_NO_OOB ? NULL :
&buf[len]);
if (res < 0)
goto outerr;
if (res < 0) {
pr_warn("nand_bbt: error while writing BBT block %d\n",
res);
mark_bbt_block_bad(this, td, chip, block);
continue;
}
pr_info("Bad block table written to 0x%012llx, version 0x%02X\n",
(unsigned long long)to, td->version[chip]);
/* Mark it as used */
td->pages[chip] = page;
td->pages[chip++] = page;
}
return 0;
......
This diff is collapsed.
......@@ -218,8 +218,7 @@ static int ndfc_probe(struct platform_device *ofdev)
ndfc = &ndfc_ctrl[cs];
ndfc->chip_select = cs;
spin_lock_init(&ndfc->ndfc_control.lock);
init_waitqueue_head(&ndfc->ndfc_control.wq);
nand_hw_control_init(&ndfc->ndfc_control);
ndfc->ofdev = ofdev;
dev_set_drvdata(&ofdev->dev, ndfc);
......
......@@ -1810,8 +1810,7 @@ static int alloc_nand_resource(struct platform_device *pdev)
chip->cmdfunc = nand_cmdfunc;
}
spin_lock_init(&chip->controller->lock);
init_waitqueue_head(&chip->controller->wq);
nand_hw_control_init(chip->controller);
info->clk = devm_clk_get(&pdev->dev, NULL);
if (IS_ERR(info->clk)) {
dev_err(&pdev->dev, "failed to get nand clock\n");
......
......@@ -1957,8 +1957,7 @@ static int qcom_nandc_alloc(struct qcom_nand_controller *nandc)
INIT_LIST_HEAD(&nandc->desc_list);
INIT_LIST_HEAD(&nandc->host_list);
spin_lock_init(&nandc->controller.lock);
init_waitqueue_head(&nandc->controller.wq);
nand_hw_control_init(&nandc->controller);
return 0;
}
......
......@@ -180,7 +180,7 @@ struct s3c2410_nand_info {
enum s3c_cpu_type cpu_type;
#ifdef CONFIG_CPU_FREQ
#ifdef CONFIG_ARM_S3C24XX_CPUFREQ
struct notifier_block freq_transition;
#endif
};
......@@ -701,7 +701,7 @@ static void s3c2440_nand_write_buf(struct mtd_info *mtd, const u_char *buf,
/* cpufreq driver support */
#ifdef CONFIG_CPU_FREQ
#ifdef CONFIG_ARM_S3C24XX_CPUFREQ
static int s3c2410_nand_cpufreq_transition(struct notifier_block *nb,
unsigned long val, void *data)
......@@ -977,8 +977,7 @@ static int s3c24xx_nand_probe(struct platform_device *pdev)
platform_set_drvdata(pdev, info);
spin_lock_init(&info->controller.lock);
init_waitqueue_head(&info->controller.wq);
nand_hw_control_init(&info->controller);
/* get the clock source and enable it */
......
......@@ -397,7 +397,7 @@ static int flctl_dma_fifo0_transfer(struct sh_flctl *flctl, unsigned long *buf,
struct dma_chan *chan;
enum dma_transfer_direction tr_dir;
dma_addr_t dma_addr;
dma_cookie_t cookie = -EINVAL;
dma_cookie_t cookie;
uint32_t reg;
int ret;
......@@ -423,6 +423,12 @@ static int flctl_dma_fifo0_transfer(struct sh_flctl *flctl, unsigned long *buf,
desc->callback = flctl_dma_complete;
desc->callback_param = flctl;
cookie = dmaengine_submit(desc);
if (dma_submit_error(cookie)) {
ret = dma_submit_error(cookie);
dev_warn(&flctl->pdev->dev,
"DMA submit failed, falling back to PIO\n");
goto out;
}
dma_async_issue_pending(chan);
} else {
......
......@@ -1572,14 +1572,22 @@ static int _sunxi_nand_lookup_timing(const s32 *lut, int lut_size, u32 duration,
#define sunxi_nand_lookup_timing(l, p, c) \
_sunxi_nand_lookup_timing(l, ARRAY_SIZE(l), p, c)
static int sunxi_nand_chip_set_timings(struct sunxi_nand_chip *chip,
const struct nand_sdr_timings *timings)
static int sunxi_nfc_setup_data_interface(struct mtd_info *mtd,
const struct nand_data_interface *conf,
bool check_only)
{
struct nand_chip *nand = mtd_to_nand(mtd);
struct sunxi_nand_chip *chip = to_sunxi_nand(nand);
struct sunxi_nfc *nfc = to_sunxi_nfc(chip->nand.controller);
const struct nand_sdr_timings *timings;
u32 min_clk_period = 0;
s32 tWB, tADL, tWHR, tRHW, tCAD;
long real_clk_rate;
timings = nand_get_sdr_timings(conf);
if (IS_ERR(timings))
return -ENOTSUPP;
/* T1 <=> tCLS */
if (timings->tCLS_min > min_clk_period)
min_clk_period = timings->tCLS_min;
......@@ -1679,6 +1687,9 @@ static int sunxi_nand_chip_set_timings(struct sunxi_nand_chip *chip,
return tRHW;
}
if (check_only)
return 0;
/*
* TODO: according to ONFI specs this value only applies for DDR NAND,
* but Allwinner seems to set this to 0x7. Mimic them for now.
......@@ -1712,44 +1723,6 @@ static int sunxi_nand_chip_set_timings(struct sunxi_nand_chip *chip,
return 0;
}
static int sunxi_nand_chip_init_timings(struct sunxi_nand_chip *chip,
struct device_node *np)
{
struct mtd_info *mtd = nand_to_mtd(&chip->nand);
const struct nand_sdr_timings *timings;
int ret;
int mode;
mode = onfi_get_async_timing_mode(&chip->nand);
if (mode == ONFI_TIMING_MODE_UNKNOWN) {
mode = chip->nand.onfi_timing_mode_default;
} else {
uint8_t feature[ONFI_SUBFEATURE_PARAM_LEN] = {};
int i;
mode = fls(mode) - 1;
if (mode < 0)
mode = 0;
feature[0] = mode;
for (i = 0; i < chip->nsels; i++) {
chip->nand.select_chip(mtd, i);
ret = chip->nand.onfi_set_features(mtd, &chip->nand,
ONFI_FEATURE_ADDR_TIMING_MODE,
feature);
chip->nand.select_chip(mtd, -1);
if (ret)
return ret;
}
}
timings = onfi_async_timing_mode_to_sdr_timings(mode);
if (IS_ERR(timings))
return PTR_ERR(timings);
return sunxi_nand_chip_set_timings(chip, timings);
}
static int sunxi_nand_ooblayout_ecc(struct mtd_info *mtd, int section,
struct mtd_oob_region *oobregion)
{
......@@ -1814,6 +1787,35 @@ static int sunxi_nand_hw_common_ecc_ctrl_init(struct mtd_info *mtd,
int ret;
int i;
if (ecc->options & NAND_ECC_MAXIMIZE) {
int bytes;
ecc->size = 1024;
nsectors = mtd->writesize / ecc->size;
/* Reserve 2 bytes for the BBM */
bytes = (mtd->oobsize - 2) / nsectors;
/* 4 non-ECC bytes are added before each ECC bytes section */
bytes -= 4;
/* and bytes has to be even. */
if (bytes % 2)
bytes--;
ecc->strength = bytes * 8 / fls(8 * ecc->size);
for (i = 0; i < ARRAY_SIZE(strengths); i++) {
if (strengths[i] > ecc->strength)
break;
}
if (!i)
ecc->strength = 0;
else
ecc->strength = strengths[i - 1];
}
if (ecc->size != 512 && ecc->size != 1024)
return -EINVAL;
......@@ -1975,7 +1977,6 @@ static int sunxi_nand_ecc_init(struct mtd_info *mtd, struct nand_ecc_ctrl *ecc,
static int sunxi_nand_chip_init(struct device *dev, struct sunxi_nfc *nfc,
struct device_node *np)
{
const struct nand_sdr_timings *timings;
struct sunxi_nand_chip *chip;
struct mtd_info *mtd;
struct nand_chip *nand;
......@@ -2065,25 +2066,11 @@ static int sunxi_nand_chip_init(struct device *dev, struct sunxi_nfc *nfc,
nand->read_buf = sunxi_nfc_read_buf;
nand->write_buf = sunxi_nfc_write_buf;
nand->read_byte = sunxi_nfc_read_byte;
nand->setup_data_interface = sunxi_nfc_setup_data_interface;
mtd = nand_to_mtd(nand);
mtd->dev.parent = dev;
timings = onfi_async_timing_mode_to_sdr_timings(0);
if (IS_ERR(timings)) {
ret = PTR_ERR(timings);
dev_err(dev,
"could not retrieve timings for ONFI mode 0: %d\n",
ret);
return ret;
}
ret = sunxi_nand_chip_set_timings(chip, timings);
if (ret) {
dev_err(dev, "could not configure chip timings: %d\n", ret);
return ret;
}
ret = nand_scan_ident(mtd, nsels, NULL);
if (ret)
return ret;
......@@ -2096,12 +2083,6 @@ static int sunxi_nand_chip_init(struct device *dev, struct sunxi_nfc *nfc,
nand->options |= NAND_SUBPAGE_READ;
ret = sunxi_nand_chip_init_timings(chip, np);
if (ret) {
dev_err(dev, "could not configure chip timings: %d\n", ret);
return ret;
}
ret = sunxi_nand_ecc_init(mtd, &nand->ecc, np);
if (ret) {
dev_err(dev, "ECC init failed: %d\n", ret);
......@@ -2175,8 +2156,7 @@ static int sunxi_nfc_probe(struct platform_device *pdev)
return -ENOMEM;
nfc->dev = dev;
spin_lock_init(&nfc->controller.lock);
init_waitqueue_head(&nfc->controller.wq);
nand_hw_control_init(&nfc->controller);
INIT_LIST_HEAD(&nfc->chips);
r = platform_get_resource(pdev, IORESOURCE_MEM, 0);
......
......@@ -303,8 +303,7 @@ static int __init txx9ndfmc_probe(struct platform_device *dev)
dev_info(&dev->dev, "CLK:%ldMHz HOLD:%d SPW:%d\n",
(gbusclk + 500000) / 1000000, hold, spw);
spin_lock_init(&drvdata->hw_control.lock);
init_waitqueue_head(&drvdata->hw_control.wq);
nand_hw_control_init(&drvdata->hw_control);
platform_set_drvdata(dev, drvdata);
txx9ndfmc_initialize(dev);
......
......@@ -90,10 +90,6 @@ config OF_PCI_IRQ
help
OpenFirmware PCI IRQ routing helpers
config OF_MTD
depends on MTD
def_bool y
config OF_RESERVED_MEM
depends on OF_EARLY_FLATTREE
bool
......
This diff is collapsed.
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment