diff options
author | RajithaY <rajithax.yerrumsetty@intel.com> | 2017-04-25 03:31:15 -0700 |
---|---|---|
committer | Rajitha Yerrumchetty <rajithax.yerrumsetty@intel.com> | 2017-05-22 06:48:08 +0000 |
commit | bb756eebdac6fd24e8919e2c43f7d2c8c4091f59 (patch) | |
tree | ca11e03542edf2d8f631efeca5e1626d211107e3 /qemu/roms/u-boot/drivers/mtd/nand | |
parent | a14b48d18a9ed03ec191cf16b162206998a895ce (diff) |
Adding qemu as a submodule of KVMFORNFV
This Patch includes the changes to add qemu as a submodule to
kvmfornfv repo and make use of the updated latest qemu for the
execution of all testcase
Change-Id: I1280af507a857675c7f81d30c95255635667bdd7
Signed-off-by:RajithaY<rajithax.yerrumsetty@intel.com>
Diffstat (limited to 'qemu/roms/u-boot/drivers/mtd/nand')
40 files changed, 0 insertions, 21180 deletions
diff --git a/qemu/roms/u-boot/drivers/mtd/nand/Makefile b/qemu/roms/u-boot/drivers/mtd/nand/Makefile deleted file mode 100644 index 4eb354da9..000000000 --- a/qemu/roms/u-boot/drivers/mtd/nand/Makefile +++ /dev/null @@ -1,72 +0,0 @@ -# -# (C) Copyright 2006 -# Wolfgang Denk, DENX Software Engineering, wd@denx.de. -# -# SPDX-License-Identifier: GPL-2.0+ -# - -ifdef CONFIG_SPL_BUILD - -ifdef CONFIG_SPL_NAND_DRIVERS -NORMAL_DRIVERS=y -endif - -obj-$(CONFIG_SPL_NAND_AM33XX_BCH) += am335x_spl_bch.o -obj-$(CONFIG_SPL_NAND_DOCG4) += docg4_spl.o -obj-$(CONFIG_SPL_NAND_SIMPLE) += nand_spl_simple.o -obj-$(CONFIG_SPL_NAND_LOAD) += nand_spl_load.o -obj-$(CONFIG_SPL_NAND_ECC) += nand_ecc.o -obj-$(CONFIG_SPL_NAND_BASE) += nand_base.o -obj-$(CONFIG_SPL_NAND_INIT) += nand.o -ifeq ($(CONFIG_SPL_ENV_SUPPORT),y) -obj-$(CONFIG_ENV_IS_IN_NAND) += nand_util.o -endif - -else # not spl - -NORMAL_DRIVERS=y - -obj-y += nand.o -obj-y += nand_bbt.o -obj-y += nand_ids.o -obj-y += nand_util.o -obj-y += nand_ecc.o -obj-y += nand_base.o - -endif # not spl - -ifdef NORMAL_DRIVERS - -obj-$(CONFIG_NAND_ECC_BCH) += nand_bch.o - -obj-$(CONFIG_NAND_ATMEL) += atmel_nand.o -obj-$(CONFIG_DRIVER_NAND_BFIN) += bfin_nand.o -obj-$(CONFIG_NAND_DAVINCI) += davinci_nand.o -obj-$(CONFIG_NAND_FSL_ELBC) += fsl_elbc_nand.o -obj-$(CONFIG_NAND_FSL_IFC) += fsl_ifc_nand.o -obj-$(CONFIG_NAND_FSL_UPM) += fsl_upm.o -obj-$(CONFIG_NAND_FSMC) += fsmc_nand.o -obj-$(CONFIG_NAND_JZ4740) += jz4740_nand.o -obj-$(CONFIG_NAND_KB9202) += kb9202_nand.o -obj-$(CONFIG_NAND_KIRKWOOD) += kirkwood_nand.o -obj-$(CONFIG_NAND_KMETER1) += kmeter1_nand.o -obj-$(CONFIG_NAND_MPC5121_NFC) += mpc5121_nfc.o -obj-$(CONFIG_NAND_MXC) += mxc_nand.o -obj-$(CONFIG_NAND_MXS) += mxs_nand.o -obj-$(CONFIG_NAND_NDFC) += ndfc.o -obj-$(CONFIG_NAND_NOMADIK) += nomadik.o -obj-$(CONFIG_NAND_S3C2410) += s3c2410_nand.o -obj-$(CONFIG_NAND_SPEAR) += spr_nand.o -obj-$(CONFIG_TEGRA_NAND) += tegra_nand.o -obj-$(CONFIG_NAND_OMAP_GPMC) += omap_gpmc.o -obj-$(CONFIG_NAND_OMAP_ELM) += omap_elm.o -obj-$(CONFIG_NAND_PLAT) += nand_plat.o -obj-$(CONFIG_NAND_DOCG4) += docg4.o - -else # minimal SPL drivers - -obj-$(CONFIG_NAND_FSL_ELBC) += fsl_elbc_spl.o -obj-$(CONFIG_NAND_FSL_IFC) += fsl_ifc_spl.o -obj-$(CONFIG_NAND_MXC) += mxc_nand_spl.o - -endif # drivers diff --git a/qemu/roms/u-boot/drivers/mtd/nand/am335x_spl_bch.c b/qemu/roms/u-boot/drivers/mtd/nand/am335x_spl_bch.c deleted file mode 100644 index bd89b067d..000000000 --- a/qemu/roms/u-boot/drivers/mtd/nand/am335x_spl_bch.c +++ /dev/null @@ -1,226 +0,0 @@ -/* - * (C) Copyright 2012 - * Konstantin Kozhevnikov, Cogent Embedded - * - * based on nand_spl_simple code - * - * (C) Copyright 2006-2008 - * Stefan Roese, DENX Software Engineering, sr@denx.de. - * - * SPDX-License-Identifier: GPL-2.0+ - */ - -#include <common.h> -#include <nand.h> -#include <asm/io.h> -#include <linux/mtd/nand_ecc.h> - -static int nand_ecc_pos[] = CONFIG_SYS_NAND_ECCPOS; -nand_info_t nand_info[1]; -static struct nand_chip nand_chip; - -#define ECCSTEPS (CONFIG_SYS_NAND_PAGE_SIZE / \ - CONFIG_SYS_NAND_ECCSIZE) -#define ECCTOTAL (ECCSTEPS * CONFIG_SYS_NAND_ECCBYTES) - - -/* - * NAND command for large page NAND devices (2k) - */ -static int nand_command(int block, int page, uint32_t offs, - u8 cmd) -{ - struct nand_chip *this = nand_info[0].priv; - int page_addr = page + block * CONFIG_SYS_NAND_PAGE_COUNT; - void (*hwctrl)(struct mtd_info *mtd, int cmd, - unsigned int ctrl) = this->cmd_ctrl; - - while (!this->dev_ready(&nand_info[0])) - ; - - /* Emulate NAND_CMD_READOOB */ - if (cmd == NAND_CMD_READOOB) { - offs += CONFIG_SYS_NAND_PAGE_SIZE; - cmd = NAND_CMD_READ0; - } - - /* Begin command latch cycle */ - hwctrl(&nand_info[0], cmd, NAND_CTRL_CLE | NAND_CTRL_CHANGE); - - if (cmd == NAND_CMD_RESET) { - hwctrl(&nand_info[0], NAND_CMD_NONE, NAND_NCE | NAND_CTRL_CHANGE); - while (!this->dev_ready(&nand_info[0])) - ; - return 0; - } - - /* Shift the offset from byte addressing to word addressing. */ - if (this->options & NAND_BUSWIDTH_16) - offs >>= 1; - - /* Set ALE and clear CLE to start address cycle */ - /* Column address */ - hwctrl(&nand_info[0], offs & 0xff, - NAND_CTRL_ALE | NAND_CTRL_CHANGE); /* A[7:0] */ - hwctrl(&nand_info[0], (offs >> 8) & 0xff, NAND_CTRL_ALE); /* A[11:9] */ - /* Row address */ - hwctrl(&nand_info[0], (page_addr & 0xff), NAND_CTRL_ALE); /* A[19:12] */ - hwctrl(&nand_info[0], ((page_addr >> 8) & 0xff), - NAND_CTRL_ALE); /* A[27:20] */ -#ifdef CONFIG_SYS_NAND_5_ADDR_CYCLE - /* One more address cycle for devices > 128MiB */ - hwctrl(&nand_info[0], (page_addr >> 16) & 0x0f, - NAND_CTRL_ALE); /* A[31:28] */ -#endif - hwctrl(&nand_info[0], NAND_CMD_NONE, NAND_NCE | NAND_CTRL_CHANGE); - - if (cmd == NAND_CMD_READ0) { - /* Latch in address */ - hwctrl(&nand_info[0], NAND_CMD_READSTART, - NAND_CTRL_CLE | NAND_CTRL_CHANGE); - hwctrl(&nand_info[0], NAND_CMD_NONE, NAND_NCE | NAND_CTRL_CHANGE); - - /* - * Wait a while for the data to be ready - */ - while (!this->dev_ready(&nand_info[0])) - ; - } else if (cmd == NAND_CMD_RNDOUT) { - hwctrl(&nand_info[0], NAND_CMD_RNDOUTSTART, NAND_CTRL_CLE | - NAND_CTRL_CHANGE); - hwctrl(&nand_info[0], NAND_CMD_NONE, NAND_NCE | NAND_CTRL_CHANGE); - } - - return 0; -} - -static int nand_is_bad_block(int block) -{ - struct nand_chip *this = nand_info[0].priv; - - nand_command(block, 0, CONFIG_SYS_NAND_BAD_BLOCK_POS, - NAND_CMD_READOOB); - - /* - * Read one byte (or two if it's a 16 bit chip). - */ - if (this->options & NAND_BUSWIDTH_16) { - if (readw(this->IO_ADDR_R) != 0xffff) - return 1; - } else { - if (readb(this->IO_ADDR_R) != 0xff) - return 1; - } - - return 0; -} - -static int nand_read_page(int block, int page, void *dst) -{ - struct nand_chip *this = nand_info[0].priv; - u_char ecc_calc[ECCTOTAL]; - u_char ecc_code[ECCTOTAL]; - u_char oob_data[CONFIG_SYS_NAND_OOBSIZE]; - int i; - int eccsize = CONFIG_SYS_NAND_ECCSIZE; - int eccbytes = CONFIG_SYS_NAND_ECCBYTES; - int eccsteps = ECCSTEPS; - uint8_t *p = dst; - uint32_t data_pos = 0; - uint8_t *oob = &oob_data[0] + nand_ecc_pos[0]; - uint32_t oob_pos = eccsize * eccsteps + nand_ecc_pos[0]; - - nand_command(block, page, 0, NAND_CMD_READ0); - - for (i = 0; eccsteps; eccsteps--, i += eccbytes, p += eccsize) { - this->ecc.hwctl(&nand_info[0], NAND_ECC_READ); - nand_command(block, page, data_pos, NAND_CMD_RNDOUT); - - this->read_buf(&nand_info[0], p, eccsize); - - nand_command(block, page, oob_pos, NAND_CMD_RNDOUT); - - this->read_buf(&nand_info[0], oob, eccbytes); - this->ecc.calculate(&nand_info[0], p, &ecc_calc[i]); - - data_pos += eccsize; - oob_pos += eccbytes; - oob += eccbytes; - } - - /* Pick the ECC bytes out of the oob data */ - for (i = 0; i < ECCTOTAL; i++) - ecc_code[i] = oob_data[nand_ecc_pos[i]]; - - eccsteps = ECCSTEPS; - p = dst; - - for (i = 0 ; eccsteps; eccsteps--, i += eccbytes, p += eccsize) { - /* No chance to do something with the possible error message - * from correct_data(). We just hope that all possible errors - * are corrected by this routine. - */ - this->ecc.correct(&nand_info[0], p, &ecc_code[i], &ecc_calc[i]); - } - - return 0; -} - -int nand_spl_load_image(uint32_t offs, unsigned int size, void *dst) -{ - unsigned int block, lastblock; - unsigned int page; - - /* - * offs has to be aligned to a page address! - */ - block = offs / CONFIG_SYS_NAND_BLOCK_SIZE; - lastblock = (offs + size - 1) / CONFIG_SYS_NAND_BLOCK_SIZE; - page = (offs % CONFIG_SYS_NAND_BLOCK_SIZE) / CONFIG_SYS_NAND_PAGE_SIZE; - - while (block <= lastblock) { - if (!nand_is_bad_block(block)) { - /* - * Skip bad blocks - */ - while (page < CONFIG_SYS_NAND_PAGE_COUNT) { - nand_read_page(block, page, dst); - dst += CONFIG_SYS_NAND_PAGE_SIZE; - page++; - } - - page = 0; - } else { - lastblock++; - } - - block++; - } - - return 0; -} - -/* nand_init() - initialize data to make nand usable by SPL */ -void nand_init(void) -{ - /* - * Init board specific nand support - */ - nand_info[0].priv = &nand_chip; - nand_chip.IO_ADDR_R = nand_chip.IO_ADDR_W = - (void __iomem *)CONFIG_SYS_NAND_BASE; - board_nand_init(&nand_chip); - - if (nand_chip.select_chip) - nand_chip.select_chip(&nand_info[0], 0); - - /* NAND chip may require reset after power-on */ - nand_command(0, 0, 0, NAND_CMD_RESET); -} - -/* Unselect after operation */ -void nand_deselect(void) -{ - if (nand_chip.select_chip) - nand_chip.select_chip(&nand_info[0], -1); -} diff --git a/qemu/roms/u-boot/drivers/mtd/nand/atmel_nand.c b/qemu/roms/u-boot/drivers/mtd/nand/atmel_nand.c deleted file mode 100644 index e1fc48fca..000000000 --- a/qemu/roms/u-boot/drivers/mtd/nand/atmel_nand.c +++ /dev/null @@ -1,1437 +0,0 @@ -/* - * (C) Copyright 2007-2008 - * Stelian Pop <stelian@popies.net> - * Lead Tech Design <www.leadtechdesign.com> - * - * (C) Copyright 2006 ATMEL Rousset, Lacressonniere Nicolas - * - * Add Programmable Multibit ECC support for various AT91 SoC - * (C) Copyright 2012 ATMEL, Hong Xu - * - * SPDX-License-Identifier: GPL-2.0+ - */ - -#include <common.h> -#include <asm/gpio.h> -#include <asm/arch/gpio.h> - -#include <malloc.h> -#include <nand.h> -#include <watchdog.h> - -#ifdef CONFIG_ATMEL_NAND_HWECC - -/* Register access macros */ -#define ecc_readl(add, reg) \ - readl(AT91_BASE_SYS + add + ATMEL_ECC_##reg) -#define ecc_writel(add, reg, value) \ - writel((value), AT91_BASE_SYS + add + ATMEL_ECC_##reg) - -#include "atmel_nand_ecc.h" /* Hardware ECC registers */ - -#ifdef CONFIG_ATMEL_NAND_HW_PMECC - -#ifdef CONFIG_SPL_BUILD -#undef CONFIG_SYS_NAND_ONFI_DETECTION -#endif - -struct atmel_nand_host { - struct pmecc_regs __iomem *pmecc; - struct pmecc_errloc_regs __iomem *pmerrloc; - void __iomem *pmecc_rom_base; - - u8 pmecc_corr_cap; - u16 pmecc_sector_size; - u32 pmecc_index_table_offset; - - int pmecc_bytes_per_sector; - int pmecc_sector_number; - int pmecc_degree; /* Degree of remainders */ - int pmecc_cw_len; /* Length of codeword */ - - /* lookup table for alpha_to and index_of */ - void __iomem *pmecc_alpha_to; - void __iomem *pmecc_index_of; - - /* data for pmecc computation */ - int16_t *pmecc_smu; - int16_t *pmecc_partial_syn; - int16_t *pmecc_si; - int16_t *pmecc_lmu; /* polynomal order */ - int *pmecc_mu; - int *pmecc_dmu; - int *pmecc_delta; -}; - -static struct atmel_nand_host pmecc_host; -static struct nand_ecclayout atmel_pmecc_oobinfo; - -/* - * Return number of ecc bytes per sector according to sector size and - * correction capability - * - * Following table shows what at91 PMECC supported: - * Correction Capability Sector_512_bytes Sector_1024_bytes - * ===================== ================ ================= - * 2-bits 4-bytes 4-bytes - * 4-bits 7-bytes 7-bytes - * 8-bits 13-bytes 14-bytes - * 12-bits 20-bytes 21-bytes - * 24-bits 39-bytes 42-bytes - */ -static int pmecc_get_ecc_bytes(int cap, int sector_size) -{ - int m = 12 + sector_size / 512; - return (m * cap + 7) / 8; -} - -static void pmecc_config_ecc_layout(struct nand_ecclayout *layout, - int oobsize, int ecc_len) -{ - int i; - - layout->eccbytes = ecc_len; - - /* ECC will occupy the last ecc_len bytes continuously */ - for (i = 0; i < ecc_len; i++) - layout->eccpos[i] = oobsize - ecc_len + i; - - layout->oobfree[0].offset = 2; - layout->oobfree[0].length = - oobsize - ecc_len - layout->oobfree[0].offset; -} - -static void __iomem *pmecc_get_alpha_to(struct atmel_nand_host *host) -{ - int table_size; - - table_size = host->pmecc_sector_size == 512 ? - PMECC_INDEX_TABLE_SIZE_512 : PMECC_INDEX_TABLE_SIZE_1024; - - /* the ALPHA lookup table is right behind the INDEX lookup table. */ - return host->pmecc_rom_base + host->pmecc_index_table_offset + - table_size * sizeof(int16_t); -} - -static void pmecc_data_free(struct atmel_nand_host *host) -{ - free(host->pmecc_partial_syn); - free(host->pmecc_si); - free(host->pmecc_lmu); - free(host->pmecc_smu); - free(host->pmecc_mu); - free(host->pmecc_dmu); - free(host->pmecc_delta); -} - -static int pmecc_data_alloc(struct atmel_nand_host *host) -{ - const int cap = host->pmecc_corr_cap; - int size; - - size = (2 * cap + 1) * sizeof(int16_t); - host->pmecc_partial_syn = malloc(size); - host->pmecc_si = malloc(size); - host->pmecc_lmu = malloc((cap + 1) * sizeof(int16_t)); - host->pmecc_smu = malloc((cap + 2) * size); - - size = (cap + 1) * sizeof(int); - host->pmecc_mu = malloc(size); - host->pmecc_dmu = malloc(size); - host->pmecc_delta = malloc(size); - - if (host->pmecc_partial_syn && - host->pmecc_si && - host->pmecc_lmu && - host->pmecc_smu && - host->pmecc_mu && - host->pmecc_dmu && - host->pmecc_delta) - return 0; - - /* error happened */ - pmecc_data_free(host); - return -ENOMEM; - -} - -static void pmecc_gen_syndrome(struct mtd_info *mtd, int sector) -{ - struct nand_chip *nand_chip = mtd->priv; - struct atmel_nand_host *host = nand_chip->priv; - int i; - uint32_t value; - - /* Fill odd syndromes */ - for (i = 0; i < host->pmecc_corr_cap; i++) { - value = readl(&host->pmecc->rem_port[sector].rem[i / 2]); - if (i & 1) - value >>= 16; - value &= 0xffff; - host->pmecc_partial_syn[(2 * i) + 1] = (int16_t)value; - } -} - -static void pmecc_substitute(struct mtd_info *mtd) -{ - struct nand_chip *nand_chip = mtd->priv; - struct atmel_nand_host *host = nand_chip->priv; - int16_t __iomem *alpha_to = host->pmecc_alpha_to; - int16_t __iomem *index_of = host->pmecc_index_of; - int16_t *partial_syn = host->pmecc_partial_syn; - const int cap = host->pmecc_corr_cap; - int16_t *si; - int i, j; - - /* si[] is a table that holds the current syndrome value, - * an element of that table belongs to the field - */ - si = host->pmecc_si; - - memset(&si[1], 0, sizeof(int16_t) * (2 * cap - 1)); - - /* Computation 2t syndromes based on S(x) */ - /* Odd syndromes */ - for (i = 1; i < 2 * cap; i += 2) { - for (j = 0; j < host->pmecc_degree; j++) { - if (partial_syn[i] & (0x1 << j)) - si[i] = readw(alpha_to + i * j) ^ si[i]; - } - } - /* Even syndrome = (Odd syndrome) ** 2 */ - for (i = 2, j = 1; j <= cap; i = ++j << 1) { - if (si[j] == 0) { - si[i] = 0; - } else { - int16_t tmp; - - tmp = readw(index_of + si[j]); - tmp = (tmp * 2) % host->pmecc_cw_len; - si[i] = readw(alpha_to + tmp); - } - } -} - -/* - * This function defines a Berlekamp iterative procedure for - * finding the value of the error location polynomial. - * The input is si[], initialize by pmecc_substitute(). - * The output is smu[][]. - * - * This function is written according to chip datasheet Chapter: - * Find the Error Location Polynomial Sigma(x) of Section: - * Programmable Multibit ECC Control (PMECC). - */ -static void pmecc_get_sigma(struct mtd_info *mtd) -{ - struct nand_chip *nand_chip = mtd->priv; - struct atmel_nand_host *host = nand_chip->priv; - - int16_t *lmu = host->pmecc_lmu; - int16_t *si = host->pmecc_si; - int *mu = host->pmecc_mu; - int *dmu = host->pmecc_dmu; /* Discrepancy */ - int *delta = host->pmecc_delta; /* Delta order */ - int cw_len = host->pmecc_cw_len; - const int16_t cap = host->pmecc_corr_cap; - const int num = 2 * cap + 1; - int16_t __iomem *index_of = host->pmecc_index_of; - int16_t __iomem *alpha_to = host->pmecc_alpha_to; - int i, j, k; - uint32_t dmu_0_count, tmp; - int16_t *smu = host->pmecc_smu; - - /* index of largest delta */ - int ro; - int largest; - int diff; - - /* Init the Sigma(x) */ - memset(smu, 0, sizeof(int16_t) * ARRAY_SIZE(smu)); - - dmu_0_count = 0; - - /* First Row */ - - /* Mu */ - mu[0] = -1; - - smu[0] = 1; - - /* discrepancy set to 1 */ - dmu[0] = 1; - /* polynom order set to 0 */ - lmu[0] = 0; - /* delta[0] = (mu[0] * 2 - lmu[0]) >> 1; */ - delta[0] = -1; - - /* Second Row */ - - /* Mu */ - mu[1] = 0; - /* Sigma(x) set to 1 */ - smu[num] = 1; - - /* discrepancy set to S1 */ - dmu[1] = si[1]; - - /* polynom order set to 0 */ - lmu[1] = 0; - - /* delta[1] = (mu[1] * 2 - lmu[1]) >> 1; */ - delta[1] = 0; - - for (i = 1; i <= cap; i++) { - mu[i + 1] = i << 1; - /* Begin Computing Sigma (Mu+1) and L(mu) */ - /* check if discrepancy is set to 0 */ - if (dmu[i] == 0) { - dmu_0_count++; - - tmp = ((cap - (lmu[i] >> 1) - 1) / 2); - if ((cap - (lmu[i] >> 1) - 1) & 0x1) - tmp += 2; - else - tmp += 1; - - if (dmu_0_count == tmp) { - for (j = 0; j <= (lmu[i] >> 1) + 1; j++) - smu[(cap + 1) * num + j] = - smu[i * num + j]; - - lmu[cap + 1] = lmu[i]; - return; - } - - /* copy polynom */ - for (j = 0; j <= lmu[i] >> 1; j++) - smu[(i + 1) * num + j] = smu[i * num + j]; - - /* copy previous polynom order to the next */ - lmu[i + 1] = lmu[i]; - } else { - ro = 0; - largest = -1; - /* find largest delta with dmu != 0 */ - for (j = 0; j < i; j++) { - if ((dmu[j]) && (delta[j] > largest)) { - largest = delta[j]; - ro = j; - } - } - - /* compute difference */ - diff = (mu[i] - mu[ro]); - - /* Compute degree of the new smu polynomial */ - if ((lmu[i] >> 1) > ((lmu[ro] >> 1) + diff)) - lmu[i + 1] = lmu[i]; - else - lmu[i + 1] = ((lmu[ro] >> 1) + diff) * 2; - - /* Init smu[i+1] with 0 */ - for (k = 0; k < num; k++) - smu[(i + 1) * num + k] = 0; - - /* Compute smu[i+1] */ - for (k = 0; k <= lmu[ro] >> 1; k++) { - int16_t a, b, c; - - if (!(smu[ro * num + k] && dmu[i])) - continue; - a = readw(index_of + dmu[i]); - b = readw(index_of + dmu[ro]); - c = readw(index_of + smu[ro * num + k]); - tmp = a + (cw_len - b) + c; - a = readw(alpha_to + tmp % cw_len); - smu[(i + 1) * num + (k + diff)] = a; - } - - for (k = 0; k <= lmu[i] >> 1; k++) - smu[(i + 1) * num + k] ^= smu[i * num + k]; - } - - /* End Computing Sigma (Mu+1) and L(mu) */ - /* In either case compute delta */ - delta[i + 1] = (mu[i + 1] * 2 - lmu[i + 1]) >> 1; - - /* Do not compute discrepancy for the last iteration */ - if (i >= cap) - continue; - - for (k = 0; k <= (lmu[i + 1] >> 1); k++) { - tmp = 2 * (i - 1); - if (k == 0) { - dmu[i + 1] = si[tmp + 3]; - } else if (smu[(i + 1) * num + k] && si[tmp + 3 - k]) { - int16_t a, b, c; - a = readw(index_of + - smu[(i + 1) * num + k]); - b = si[2 * (i - 1) + 3 - k]; - c = readw(index_of + b); - tmp = a + c; - tmp %= cw_len; - dmu[i + 1] = readw(alpha_to + tmp) ^ - dmu[i + 1]; - } - } - } -} - -static int pmecc_err_location(struct mtd_info *mtd) -{ - struct nand_chip *nand_chip = mtd->priv; - struct atmel_nand_host *host = nand_chip->priv; - const int cap = host->pmecc_corr_cap; - const int num = 2 * cap + 1; - int sector_size = host->pmecc_sector_size; - int err_nbr = 0; /* number of error */ - int roots_nbr; /* number of roots */ - int i; - uint32_t val; - int16_t *smu = host->pmecc_smu; - int timeout = PMECC_MAX_TIMEOUT_US; - - writel(PMERRLOC_DISABLE, &host->pmerrloc->eldis); - - for (i = 0; i <= host->pmecc_lmu[cap + 1] >> 1; i++) { - writel(smu[(cap + 1) * num + i], &host->pmerrloc->sigma[i]); - err_nbr++; - } - - val = PMERRLOC_ELCFG_NUM_ERRORS(err_nbr - 1); - if (sector_size == 1024) - val |= PMERRLOC_ELCFG_SECTOR_1024; - - writel(val, &host->pmerrloc->elcfg); - writel(sector_size * 8 + host->pmecc_degree * cap, - &host->pmerrloc->elen); - - while (--timeout) { - if (readl(&host->pmerrloc->elisr) & PMERRLOC_CALC_DONE) - break; - WATCHDOG_RESET(); - udelay(1); - } - - if (!timeout) { - dev_err(host->dev, "atmel_nand : Timeout to calculate PMECC error location\n"); - return -1; - } - - roots_nbr = (readl(&host->pmerrloc->elisr) & PMERRLOC_ERR_NUM_MASK) - >> 8; - /* Number of roots == degree of smu hence <= cap */ - if (roots_nbr == host->pmecc_lmu[cap + 1] >> 1) - return err_nbr - 1; - - /* Number of roots does not match the degree of smu - * unable to correct error */ - return -1; -} - -static void pmecc_correct_data(struct mtd_info *mtd, uint8_t *buf, uint8_t *ecc, - int sector_num, int extra_bytes, int err_nbr) -{ - struct nand_chip *nand_chip = mtd->priv; - struct atmel_nand_host *host = nand_chip->priv; - int i = 0; - int byte_pos, bit_pos, sector_size, pos; - uint32_t tmp; - uint8_t err_byte; - - sector_size = host->pmecc_sector_size; - - while (err_nbr) { - tmp = readl(&host->pmerrloc->el[i]) - 1; - byte_pos = tmp / 8; - bit_pos = tmp % 8; - - if (byte_pos >= (sector_size + extra_bytes)) - BUG(); /* should never happen */ - - if (byte_pos < sector_size) { - err_byte = *(buf + byte_pos); - *(buf + byte_pos) ^= (1 << bit_pos); - - pos = sector_num * host->pmecc_sector_size + byte_pos; - 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 */ - tmp = sector_num * host->pmecc_bytes_per_sector - + (byte_pos - sector_size); - err_byte = ecc[tmp]; - ecc[tmp] ^= (1 << bit_pos); - - pos = tmp + nand_chip->ecc.layout->eccpos[0]; - 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]); - } - - i++; - err_nbr--; - } - - return; -} - -static int pmecc_correction(struct mtd_info *mtd, u32 pmecc_stat, uint8_t *buf, - u8 *ecc) -{ - struct nand_chip *nand_chip = mtd->priv; - struct atmel_nand_host *host = nand_chip->priv; - int i, err_nbr, eccbytes; - uint8_t *buf_pos; - - eccbytes = nand_chip->ecc.bytes; - for (i = 0; i < eccbytes; i++) - if (ecc[i] != 0xff) - goto normal_check; - /* Erased page, return OK */ - return 0; - -normal_check: - for (i = 0; i < host->pmecc_sector_number; i++) { - err_nbr = 0; - if (pmecc_stat & 0x1) { - buf_pos = buf + i * host->pmecc_sector_size; - - pmecc_gen_syndrome(mtd, i); - pmecc_substitute(mtd); - pmecc_get_sigma(mtd); - - err_nbr = pmecc_err_location(mtd); - if (err_nbr == -1) { - dev_err(host->dev, "PMECC: Too many errors\n"); - mtd->ecc_stats.failed++; - return -EIO; - } else { - pmecc_correct_data(mtd, buf_pos, ecc, i, - host->pmecc_bytes_per_sector, err_nbr); - mtd->ecc_stats.corrected += err_nbr; - } - } - pmecc_stat >>= 1; - } - - return 0; -} - -static int atmel_nand_pmecc_read_page(struct mtd_info *mtd, - struct nand_chip *chip, uint8_t *buf, int oob_required, int page) -{ - struct atmel_nand_host *host = chip->priv; - int eccsize = chip->ecc.size; - uint8_t *oob = chip->oob_poi; - uint32_t *eccpos = chip->ecc.layout->eccpos; - uint32_t stat; - int timeout = PMECC_MAX_TIMEOUT_US; - - pmecc_writel(host->pmecc, ctrl, PMECC_CTRL_RST); - pmecc_writel(host->pmecc, ctrl, PMECC_CTRL_DISABLE); - pmecc_writel(host->pmecc, cfg, ((pmecc_readl(host->pmecc, cfg)) - & ~PMECC_CFG_WRITE_OP) | PMECC_CFG_AUTO_ENABLE); - - pmecc_writel(host->pmecc, ctrl, PMECC_CTRL_ENABLE); - pmecc_writel(host->pmecc, ctrl, PMECC_CTRL_DATA); - - chip->read_buf(mtd, buf, eccsize); - chip->read_buf(mtd, oob, mtd->oobsize); - - while (--timeout) { - if (!(pmecc_readl(host->pmecc, sr) & PMECC_SR_BUSY)) - break; - WATCHDOG_RESET(); - udelay(1); - } - - if (!timeout) { - dev_err(host->dev, "atmel_nand : Timeout to read PMECC page\n"); - return -1; - } - - stat = pmecc_readl(host->pmecc, isr); - if (stat != 0) - if (pmecc_correction(mtd, stat, buf, &oob[eccpos[0]]) != 0) - return -EIO; - - return 0; -} - -static int atmel_nand_pmecc_write_page(struct mtd_info *mtd, - struct nand_chip *chip, const uint8_t *buf, - int oob_required) -{ - struct atmel_nand_host *host = chip->priv; - uint32_t *eccpos = chip->ecc.layout->eccpos; - int i, j; - int timeout = PMECC_MAX_TIMEOUT_US; - - pmecc_writel(host->pmecc, ctrl, PMECC_CTRL_RST); - pmecc_writel(host->pmecc, ctrl, PMECC_CTRL_DISABLE); - - pmecc_writel(host->pmecc, cfg, (pmecc_readl(host->pmecc, cfg) | - PMECC_CFG_WRITE_OP) & ~PMECC_CFG_AUTO_ENABLE); - - pmecc_writel(host->pmecc, ctrl, PMECC_CTRL_ENABLE); - pmecc_writel(host->pmecc, ctrl, PMECC_CTRL_DATA); - - chip->write_buf(mtd, (u8 *)buf, mtd->writesize); - - while (--timeout) { - if (!(pmecc_readl(host->pmecc, sr) & PMECC_SR_BUSY)) - break; - WATCHDOG_RESET(); - udelay(1); - } - - if (!timeout) { - dev_err(host->dev, "atmel_nand : Timeout to read PMECC status, fail to write PMECC in oob\n"); - goto out; - } - - for (i = 0; i < host->pmecc_sector_number; i++) { - for (j = 0; j < host->pmecc_bytes_per_sector; j++) { - int pos; - - pos = i * host->pmecc_bytes_per_sector + j; - chip->oob_poi[eccpos[pos]] = - readb(&host->pmecc->ecc_port[i].ecc[j]); - } - } - chip->write_buf(mtd, chip->oob_poi, mtd->oobsize); -out: - return 0; -} - -static void atmel_pmecc_core_init(struct mtd_info *mtd) -{ - struct nand_chip *nand_chip = mtd->priv; - struct atmel_nand_host *host = nand_chip->priv; - uint32_t val = 0; - struct nand_ecclayout *ecc_layout; - - pmecc_writel(host->pmecc, ctrl, PMECC_CTRL_RST); - pmecc_writel(host->pmecc, ctrl, PMECC_CTRL_DISABLE); - - switch (host->pmecc_corr_cap) { - case 2: - val = PMECC_CFG_BCH_ERR2; - break; - case 4: - val = PMECC_CFG_BCH_ERR4; - break; - case 8: - val = PMECC_CFG_BCH_ERR8; - break; - case 12: - val = PMECC_CFG_BCH_ERR12; - break; - case 24: - val = PMECC_CFG_BCH_ERR24; - break; - } - - if (host->pmecc_sector_size == 512) - val |= PMECC_CFG_SECTOR512; - else if (host->pmecc_sector_size == 1024) - val |= PMECC_CFG_SECTOR1024; - - switch (host->pmecc_sector_number) { - case 1: - val |= PMECC_CFG_PAGE_1SECTOR; - break; - case 2: - val |= PMECC_CFG_PAGE_2SECTORS; - break; - case 4: - val |= PMECC_CFG_PAGE_4SECTORS; - break; - case 8: - val |= PMECC_CFG_PAGE_8SECTORS; - break; - } - - val |= (PMECC_CFG_READ_OP | PMECC_CFG_SPARE_DISABLE - | PMECC_CFG_AUTO_DISABLE); - pmecc_writel(host->pmecc, cfg, val); - - ecc_layout = nand_chip->ecc.layout; - pmecc_writel(host->pmecc, sarea, mtd->oobsize - 1); - pmecc_writel(host->pmecc, saddr, ecc_layout->eccpos[0]); - pmecc_writel(host->pmecc, eaddr, - ecc_layout->eccpos[ecc_layout->eccbytes - 1]); - /* See datasheet about PMECC Clock Control Register */ - pmecc_writel(host->pmecc, clk, PMECC_CLK_133MHZ); - pmecc_writel(host->pmecc, idr, 0xff); - pmecc_writel(host->pmecc, ctrl, PMECC_CTRL_ENABLE); -} - -#ifdef CONFIG_SYS_NAND_ONFI_DETECTION -/* - * get_onfi_ecc_param - Get ECC requirement from ONFI parameters - * @ecc_bits: store the ONFI ECC correct bits capbility - * @sector_size: in how many bytes that ONFI require to correct @ecc_bits - * - * Returns -1 if ONFI parameters is not supported. In this case @ecc_bits, - * @sector_size are initialize to 0. - * 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; -} - -/* - * pmecc_choose_ecc - Get ecc requirement from ONFI parameters. If - * pmecc_corr_cap or pmecc_sector_size is 0, then set it as - * ONFI ECC parameters. - * @host: point to an atmel_nand_host structure. - * if host->pmecc_corr_cap is 0 then set it as the ONFI ecc_bits. - * if host->pmecc_sector_size is 0 then set it as the ONFI sector_size. - * @chip: point to an nand_chip structure. - * @cap: store the ONFI ECC correct bits capbility - * @sector_size: in how many bytes that ONFI require to correct @ecc_bits - * - * Return 0 if success. otherwise return the error code. - */ -static int pmecc_choose_ecc(struct atmel_nand_host *host, - struct nand_chip *chip, - int *cap, int *sector_size) -{ - /* Get ECC requirement from ONFI parameters */ - *cap = *sector_size = 0; - if (chip->onfi_version) { - if (!get_onfi_ecc_param(chip, cap, sector_size)) { - MTDDEBUG(MTD_DEBUG_LEVEL1, "ONFI params, minimum required 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) { - /* Non-ONFI compliant or use extended ONFI parameters */ - *cap = 2; - *sector_size = 512; - } - - /* If head file doesn't specify then use the one in ONFI parameters */ - if (host->pmecc_corr_cap == 0) { - /* use the most fitable ecc bits (the near bigger one ) */ - if (*cap <= 2) - host->pmecc_corr_cap = 2; - else if (*cap <= 4) - host->pmecc_corr_cap = 4; - else if (*cap <= 8) - host->pmecc_corr_cap = 8; - else if (*cap <= 12) - host->pmecc_corr_cap = 12; - else if (*cap <= 24) - host->pmecc_corr_cap = 24; - else - return -EINVAL; - } - if (host->pmecc_sector_size == 0) { - /* use the most fitable sector size (the near smaller one ) */ - if (*sector_size >= 1024) - host->pmecc_sector_size = 1024; - else if (*sector_size >= 512) - host->pmecc_sector_size = 512; - else - return -EINVAL; - } - return 0; -} -#endif - -static int atmel_pmecc_nand_init_params(struct nand_chip *nand, - struct mtd_info *mtd) -{ - struct atmel_nand_host *host; - int cap, sector_size; - - host = nand->priv = &pmecc_host; - - nand->ecc.mode = NAND_ECC_HW; - nand->ecc.calculate = NULL; - nand->ecc.correct = NULL; - nand->ecc.hwctl = NULL; - -#ifdef CONFIG_SYS_NAND_ONFI_DETECTION - host->pmecc_corr_cap = host->pmecc_sector_size = 0; - -#ifdef CONFIG_PMECC_CAP - host->pmecc_corr_cap = CONFIG_PMECC_CAP; -#endif -#ifdef CONFIG_PMECC_SECTOR_SIZE - host->pmecc_sector_size = CONFIG_PMECC_SECTOR_SIZE; -#endif - /* Get ECC requirement of ONFI parameters. And if CONFIG_PMECC_CAP or - * CONFIG_PMECC_SECTOR_SIZE not defined, then use ecc_bits, sector_size - * from ONFI. - */ - if (pmecc_choose_ecc(host, nand, &cap, §or_size)) { - dev_err(host->dev, "The NAND flash's ECC requirement(ecc_bits: %d, sector_size: %d) are not support!", - cap, sector_size); - return -EINVAL; - } - - if (cap > host->pmecc_corr_cap) - dev_info(host->dev, "WARNING: Using different ecc correct bits(%d bit) from Nand ONFI ECC reqirement (%d bit).\n", - host->pmecc_corr_cap, cap); - if (sector_size < host->pmecc_sector_size) - dev_info(host->dev, "WARNING: Using different ecc correct sector size (%d bytes) from Nand ONFI ECC reqirement (%d bytes).\n", - host->pmecc_sector_size, sector_size); -#else /* CONFIG_SYS_NAND_ONFI_DETECTION */ - host->pmecc_corr_cap = CONFIG_PMECC_CAP; - host->pmecc_sector_size = CONFIG_PMECC_SECTOR_SIZE; -#endif - - cap = host->pmecc_corr_cap; - sector_size = host->pmecc_sector_size; - - /* TODO: need check whether cap & sector_size is validate */ - - if (host->pmecc_sector_size == 512) - host->pmecc_index_table_offset = ATMEL_PMECC_INDEX_OFFSET_512; - else - host->pmecc_index_table_offset = ATMEL_PMECC_INDEX_OFFSET_1024; - - MTDDEBUG(MTD_DEBUG_LEVEL1, - "Initialize PMECC params, cap: %d, sector: %d\n", - cap, sector_size); - - host->pmecc = (struct pmecc_regs __iomem *) ATMEL_BASE_PMECC; - host->pmerrloc = (struct pmecc_errloc_regs __iomem *) - ATMEL_BASE_PMERRLOC; - host->pmecc_rom_base = (void __iomem *) ATMEL_BASE_ROM; - - /* ECC is calculated for the whole page (1 step) */ - nand->ecc.size = mtd->writesize; - - /* set ECC page size and oob layout */ - switch (mtd->writesize) { - case 2048: - case 4096: - case 8192: - host->pmecc_degree = (sector_size == 512) ? - PMECC_GF_DIMENSION_13 : PMECC_GF_DIMENSION_14; - host->pmecc_cw_len = (1 << host->pmecc_degree) - 1; - host->pmecc_sector_number = mtd->writesize / sector_size; - host->pmecc_bytes_per_sector = pmecc_get_ecc_bytes( - cap, sector_size); - host->pmecc_alpha_to = pmecc_get_alpha_to(host); - host->pmecc_index_of = host->pmecc_rom_base + - host->pmecc_index_table_offset; - - nand->ecc.steps = 1; - nand->ecc.bytes = host->pmecc_bytes_per_sector * - host->pmecc_sector_number; - - if (nand->ecc.bytes > MTD_MAX_ECCPOS_ENTRIES_LARGE) { - dev_err(host->dev, "too large eccpos entries. max support ecc.bytes is %d\n", - MTD_MAX_ECCPOS_ENTRIES_LARGE); - return -EINVAL; - } - - if (nand->ecc.bytes > mtd->oobsize - 2) { - dev_err(host->dev, "No room for ECC bytes\n"); - return -EINVAL; - } - pmecc_config_ecc_layout(&atmel_pmecc_oobinfo, - mtd->oobsize, - nand->ecc.bytes); - nand->ecc.layout = &atmel_pmecc_oobinfo; - break; - case 512: - case 1024: - /* TODO */ - dev_err(host->dev, "Unsupported page size for PMECC, use Software ECC\n"); - default: - /* page size not handled by HW ECC */ - /* switching back to soft ECC */ - nand->ecc.mode = NAND_ECC_SOFT; - nand->ecc.read_page = NULL; - nand->ecc.postpad = 0; - nand->ecc.prepad = 0; - nand->ecc.bytes = 0; - return 0; - } - - /* Allocate data for PMECC computation */ - if (pmecc_data_alloc(host)) { - dev_err(host->dev, "Cannot allocate memory for PMECC computation!\n"); - return -ENOMEM; - } - - nand->ecc.read_page = atmel_nand_pmecc_read_page; - nand->ecc.write_page = atmel_nand_pmecc_write_page; - nand->ecc.strength = cap; - - atmel_pmecc_core_init(mtd); - - return 0; -} - -#else - -/* oob layout for large page size - * bad block info is on bytes 0 and 1 - * the bytes have to be consecutives to avoid - * several NAND_CMD_RNDOUT during read - */ -static struct nand_ecclayout atmel_oobinfo_large = { - .eccbytes = 4, - .eccpos = {60, 61, 62, 63}, - .oobfree = { - {2, 58} - }, -}; - -/* oob layout for small page size - * bad block info is on bytes 4 and 5 - * the bytes have to be consecutives to avoid - * several NAND_CMD_RNDOUT during read - */ -static struct nand_ecclayout atmel_oobinfo_small = { - .eccbytes = 4, - .eccpos = {0, 1, 2, 3}, - .oobfree = { - {6, 10} - }, -}; - -/* - * Calculate HW ECC - * - * function called after a write - * - * mtd: MTD block structure - * dat: raw data (unused) - * ecc_code: buffer for ECC - */ -static int atmel_nand_calculate(struct mtd_info *mtd, - const u_char *dat, unsigned char *ecc_code) -{ - unsigned int ecc_value; - - /* get the first 2 ECC bytes */ - ecc_value = ecc_readl(CONFIG_SYS_NAND_ECC_BASE, PR); - - ecc_code[0] = ecc_value & 0xFF; - ecc_code[1] = (ecc_value >> 8) & 0xFF; - - /* get the last 2 ECC bytes */ - ecc_value = ecc_readl(CONFIG_SYS_NAND_ECC_BASE, NPR) & ATMEL_ECC_NPARITY; - - ecc_code[2] = ecc_value & 0xFF; - ecc_code[3] = (ecc_value >> 8) & 0xFF; - - return 0; -} - -/* - * HW ECC read page function - * - * mtd: mtd info structure - * chip: nand chip info structure - * buf: buffer to store read data - * oob_required: caller expects OOB data read to chip->oob_poi - */ -static int atmel_nand_read_page(struct mtd_info *mtd, struct nand_chip *chip, - uint8_t *buf, int oob_required, int page) -{ - int eccsize = chip->ecc.size; - int eccbytes = chip->ecc.bytes; - uint32_t *eccpos = chip->ecc.layout->eccpos; - uint8_t *p = buf; - uint8_t *oob = chip->oob_poi; - uint8_t *ecc_pos; - int stat; - - /* read the page */ - chip->read_buf(mtd, p, eccsize); - - /* move to ECC position if needed */ - if (eccpos[0] != 0) { - /* This only works on large pages - * because the ECC controller waits for - * NAND_CMD_RNDOUTSTART after the - * NAND_CMD_RNDOUT. - * anyway, for small pages, the eccpos[0] == 0 - */ - chip->cmdfunc(mtd, NAND_CMD_RNDOUT, - mtd->writesize + eccpos[0], -1); - } - - /* the ECC controller needs to read the ECC just after the data */ - ecc_pos = oob + eccpos[0]; - chip->read_buf(mtd, ecc_pos, eccbytes); - - /* check if there's an error */ - stat = chip->ecc.correct(mtd, p, oob, NULL); - - if (stat < 0) - mtd->ecc_stats.failed++; - else - mtd->ecc_stats.corrected += stat; - - /* get back to oob start (end of page) */ - chip->cmdfunc(mtd, NAND_CMD_RNDOUT, mtd->writesize, -1); - - /* read the oob */ - chip->read_buf(mtd, oob, mtd->oobsize); - - return 0; -} - -/* - * HW ECC Correction - * - * function called after a read - * - * mtd: MTD block structure - * dat: raw data read from the chip - * read_ecc: ECC from the chip (unused) - * isnull: unused - * - * Detect and correct a 1 bit error for a page - */ -static int atmel_nand_correct(struct mtd_info *mtd, u_char *dat, - u_char *read_ecc, u_char *isnull) -{ - struct nand_chip *nand_chip = mtd->priv; - unsigned int ecc_status; - unsigned int ecc_word, ecc_bit; - - /* get the status from the Status Register */ - ecc_status = ecc_readl(CONFIG_SYS_NAND_ECC_BASE, SR); - - /* if there's no error */ - if (likely(!(ecc_status & ATMEL_ECC_RECERR))) - return 0; - - /* get error bit offset (4 bits) */ - ecc_bit = ecc_readl(CONFIG_SYS_NAND_ECC_BASE, PR) & ATMEL_ECC_BITADDR; - /* get word address (12 bits) */ - ecc_word = ecc_readl(CONFIG_SYS_NAND_ECC_BASE, PR) & ATMEL_ECC_WORDADDR; - ecc_word >>= 4; - - /* if there are multiple errors */ - if (ecc_status & ATMEL_ECC_MULERR) { - /* check if it is a freshly erased block - * (filled with 0xff) */ - if ((ecc_bit == ATMEL_ECC_BITADDR) - && (ecc_word == (ATMEL_ECC_WORDADDR >> 4))) { - /* the block has just been erased, return OK */ - return 0; - } - /* it doesn't seems to be a freshly - * erased block. - * We can't correct so many errors */ - dev_warn(host->dev, "atmel_nand : multiple errors detected." - " Unable to correct.\n"); - return -EIO; - } - - /* if there's a single bit error : we can correct it */ - if (ecc_status & ATMEL_ECC_ECCERR) { - /* there's nothing much to do here. - * the bit error is on the ECC itself. - */ - dev_warn(host->dev, "atmel_nand : one bit error on ECC code." - " Nothing to correct\n"); - return 0; - } - - dev_warn(host->dev, "atmel_nand : one bit error on data." - " (word offset in the page :" - " 0x%x bit offset : 0x%x)\n", - ecc_word, ecc_bit); - /* correct the error */ - if (nand_chip->options & NAND_BUSWIDTH_16) { - /* 16 bits words */ - ((unsigned short *) dat)[ecc_word] ^= (1 << ecc_bit); - } else { - /* 8 bits words */ - dat[ecc_word] ^= (1 << ecc_bit); - } - dev_warn(host->dev, "atmel_nand : error corrected\n"); - return 1; -} - -/* - * Enable HW ECC : unused on most chips - */ -static void atmel_nand_hwctl(struct mtd_info *mtd, int mode) -{ -} - -int atmel_hwecc_nand_init_param(struct nand_chip *nand, struct mtd_info *mtd) -{ - nand->ecc.mode = NAND_ECC_HW; - nand->ecc.calculate = atmel_nand_calculate; - nand->ecc.correct = atmel_nand_correct; - nand->ecc.hwctl = atmel_nand_hwctl; - nand->ecc.read_page = atmel_nand_read_page; - nand->ecc.bytes = 4; - - if (nand->ecc.mode == NAND_ECC_HW) { - /* ECC is calculated for the whole page (1 step) */ - nand->ecc.size = mtd->writesize; - - /* set ECC page size and oob layout */ - switch (mtd->writesize) { - case 512: - nand->ecc.layout = &atmel_oobinfo_small; - ecc_writel(CONFIG_SYS_NAND_ECC_BASE, MR, - ATMEL_ECC_PAGESIZE_528); - break; - case 1024: - nand->ecc.layout = &atmel_oobinfo_large; - ecc_writel(CONFIG_SYS_NAND_ECC_BASE, MR, - ATMEL_ECC_PAGESIZE_1056); - break; - case 2048: - nand->ecc.layout = &atmel_oobinfo_large; - ecc_writel(CONFIG_SYS_NAND_ECC_BASE, MR, - ATMEL_ECC_PAGESIZE_2112); - break; - case 4096: - nand->ecc.layout = &atmel_oobinfo_large; - ecc_writel(CONFIG_SYS_NAND_ECC_BASE, MR, - ATMEL_ECC_PAGESIZE_4224); - break; - default: - /* page size not handled by HW ECC */ - /* switching back to soft ECC */ - nand->ecc.mode = NAND_ECC_SOFT; - nand->ecc.calculate = NULL; - nand->ecc.correct = NULL; - nand->ecc.hwctl = NULL; - nand->ecc.read_page = NULL; - nand->ecc.postpad = 0; - nand->ecc.prepad = 0; - nand->ecc.bytes = 0; - break; - } - } - - return 0; -} - -#endif /* CONFIG_ATMEL_NAND_HW_PMECC */ - -#endif /* CONFIG_ATMEL_NAND_HWECC */ - -static void at91_nand_hwcontrol(struct mtd_info *mtd, - int cmd, unsigned int ctrl) -{ - struct nand_chip *this = mtd->priv; - - if (ctrl & NAND_CTRL_CHANGE) { - ulong IO_ADDR_W = (ulong) this->IO_ADDR_W; - IO_ADDR_W &= ~(CONFIG_SYS_NAND_MASK_ALE - | CONFIG_SYS_NAND_MASK_CLE); - - if (ctrl & NAND_CLE) - IO_ADDR_W |= CONFIG_SYS_NAND_MASK_CLE; - if (ctrl & NAND_ALE) - IO_ADDR_W |= CONFIG_SYS_NAND_MASK_ALE; - -#ifdef CONFIG_SYS_NAND_ENABLE_PIN - gpio_set_value(CONFIG_SYS_NAND_ENABLE_PIN, !(ctrl & NAND_NCE)); -#endif - this->IO_ADDR_W = (void *) IO_ADDR_W; - } - - if (cmd != NAND_CMD_NONE) - writeb(cmd, this->IO_ADDR_W); -} - -#ifdef CONFIG_SYS_NAND_READY_PIN -static int at91_nand_ready(struct mtd_info *mtd) -{ - return gpio_get_value(CONFIG_SYS_NAND_READY_PIN); -} -#endif - -#ifdef CONFIG_SPL_BUILD -/* The following code is for SPL */ -static nand_info_t mtd; -static struct nand_chip nand_chip; - -static int nand_command(int block, int page, uint32_t offs, u8 cmd) -{ - struct nand_chip *this = mtd.priv; - int page_addr = page + block * CONFIG_SYS_NAND_PAGE_COUNT; - void (*hwctrl)(struct mtd_info *mtd, int cmd, - unsigned int ctrl) = this->cmd_ctrl; - - while (this->dev_ready(&mtd)) - ; - - if (cmd == NAND_CMD_READOOB) { - offs += CONFIG_SYS_NAND_PAGE_SIZE; - cmd = NAND_CMD_READ0; - } - - hwctrl(&mtd, cmd, NAND_CTRL_CLE | NAND_CTRL_CHANGE); - - if (this->options & NAND_BUSWIDTH_16) - offs >>= 1; - - hwctrl(&mtd, offs & 0xff, NAND_CTRL_ALE | NAND_CTRL_CHANGE); - hwctrl(&mtd, (offs >> 8) & 0xff, NAND_CTRL_ALE); - hwctrl(&mtd, (page_addr & 0xff), NAND_CTRL_ALE); - hwctrl(&mtd, ((page_addr >> 8) & 0xff), NAND_CTRL_ALE); -#ifdef CONFIG_SYS_NAND_5_ADDR_CYCLE - hwctrl(&mtd, (page_addr >> 16) & 0x0f, NAND_CTRL_ALE); -#endif - hwctrl(&mtd, NAND_CMD_NONE, NAND_NCE | NAND_CTRL_CHANGE); - - hwctrl(&mtd, NAND_CMD_READSTART, NAND_CTRL_CLE | NAND_CTRL_CHANGE); - hwctrl(&mtd, NAND_CMD_NONE, NAND_NCE | NAND_CTRL_CHANGE); - - while (this->dev_ready(&mtd)) - ; - - return 0; -} - -static int nand_is_bad_block(int block) -{ - struct nand_chip *this = mtd.priv; - - nand_command(block, 0, CONFIG_SYS_NAND_BAD_BLOCK_POS, NAND_CMD_READOOB); - - if (this->options & NAND_BUSWIDTH_16) { - if (readw(this->IO_ADDR_R) != 0xffff) - return 1; - } else { - if (readb(this->IO_ADDR_R) != 0xff) - return 1; - } - - return 0; -} - -#ifdef CONFIG_SPL_NAND_ECC -static int nand_ecc_pos[] = CONFIG_SYS_NAND_ECCPOS; -#define ECCSTEPS (CONFIG_SYS_NAND_PAGE_SIZE / \ - CONFIG_SYS_NAND_ECCSIZE) -#define ECCTOTAL (ECCSTEPS * CONFIG_SYS_NAND_ECCBYTES) - -static int nand_read_page(int block, int page, void *dst) -{ - struct nand_chip *this = mtd.priv; - u_char ecc_calc[ECCTOTAL]; - u_char ecc_code[ECCTOTAL]; - u_char oob_data[CONFIG_SYS_NAND_OOBSIZE]; - int eccsize = CONFIG_SYS_NAND_ECCSIZE; - int eccbytes = CONFIG_SYS_NAND_ECCBYTES; - int eccsteps = ECCSTEPS; - int i; - uint8_t *p = dst; - nand_command(block, page, 0, NAND_CMD_READ0); - - for (i = 0; eccsteps; eccsteps--, i += eccbytes, p += eccsize) { - if (this->ecc.mode != NAND_ECC_SOFT) - this->ecc.hwctl(&mtd, NAND_ECC_READ); - this->read_buf(&mtd, p, eccsize); - this->ecc.calculate(&mtd, p, &ecc_calc[i]); - } - this->read_buf(&mtd, oob_data, CONFIG_SYS_NAND_OOBSIZE); - - for (i = 0; i < ECCTOTAL; i++) - ecc_code[i] = oob_data[nand_ecc_pos[i]]; - - eccsteps = ECCSTEPS; - p = dst; - - for (i = 0; eccsteps; eccsteps--, i += eccbytes, p += eccsize) - this->ecc.correct(&mtd, p, &ecc_code[i], &ecc_calc[i]); - - return 0; -} -#else -static int nand_read_page(int block, int page, void *dst) -{ - struct nand_chip *this = mtd.priv; - - nand_command(block, page, 0, NAND_CMD_READ0); - atmel_nand_pmecc_read_page(&mtd, this, dst, 0, page); - - return 0; -} -#endif /* CONFIG_SPL_NAND_ECC */ - -int nand_spl_load_image(uint32_t offs, unsigned int size, void *dst) -{ - unsigned int block, lastblock; - unsigned int page; - - block = offs / CONFIG_SYS_NAND_BLOCK_SIZE; - lastblock = (offs + size - 1) / CONFIG_SYS_NAND_BLOCK_SIZE; - page = (offs % CONFIG_SYS_NAND_BLOCK_SIZE) / CONFIG_SYS_NAND_PAGE_SIZE; - - while (block <= lastblock) { - if (!nand_is_bad_block(block)) { - while (page < CONFIG_SYS_NAND_PAGE_COUNT) { - nand_read_page(block, page, dst); - dst += CONFIG_SYS_NAND_PAGE_SIZE; - page++; - } - - page = 0; - } else { - lastblock++; - } - - block++; - } - - return 0; -} - -int at91_nand_wait_ready(struct mtd_info *mtd) -{ - struct nand_chip *this = mtd->priv; - - udelay(this->chip_delay); - - return 0; -} - -int board_nand_init(struct nand_chip *nand) -{ - int ret = 0; - - nand->ecc.mode = NAND_ECC_SOFT; -#ifdef CONFIG_SYS_NAND_DBW_16 - nand->options = NAND_BUSWIDTH_16; - nand->read_buf = nand_read_buf16; -#else - nand->read_buf = nand_read_buf; -#endif - nand->cmd_ctrl = at91_nand_hwcontrol; -#ifdef CONFIG_SYS_NAND_READY_PIN - nand->dev_ready = at91_nand_ready; -#else - nand->dev_ready = at91_nand_wait_ready; -#endif - nand->chip_delay = 20; - -#ifdef CONFIG_ATMEL_NAND_HWECC -#ifdef CONFIG_ATMEL_NAND_HW_PMECC - ret = atmel_pmecc_nand_init_params(nand, &mtd); -#endif -#endif - - return ret; -} - -void nand_init(void) -{ - mtd.writesize = CONFIG_SYS_NAND_PAGE_SIZE; - mtd.oobsize = CONFIG_SYS_NAND_OOBSIZE; - mtd.priv = &nand_chip; - nand_chip.IO_ADDR_R = (void __iomem *)CONFIG_SYS_NAND_BASE; - nand_chip.IO_ADDR_W = (void __iomem *)CONFIG_SYS_NAND_BASE; - board_nand_init(&nand_chip); - -#ifdef CONFIG_SPL_NAND_ECC - if (nand_chip.ecc.mode == NAND_ECC_SOFT) { - nand_chip.ecc.calculate = nand_calculate_ecc; - nand_chip.ecc.correct = nand_correct_data; - } -#endif - - if (nand_chip.select_chip) - nand_chip.select_chip(&mtd, 0); -} - -void nand_deselect(void) -{ - if (nand_chip.select_chip) - nand_chip.select_chip(&mtd, -1); -} - -#else - -#ifndef CONFIG_SYS_NAND_BASE_LIST -#define CONFIG_SYS_NAND_BASE_LIST { CONFIG_SYS_NAND_BASE } -#endif -static struct nand_chip nand_chip[CONFIG_SYS_MAX_NAND_DEVICE]; -static ulong base_addr[CONFIG_SYS_MAX_NAND_DEVICE] = CONFIG_SYS_NAND_BASE_LIST; - -int atmel_nand_chip_init(int devnum, ulong base_addr) -{ - int ret; - struct mtd_info *mtd = &nand_info[devnum]; - struct nand_chip *nand = &nand_chip[devnum]; - - mtd->priv = nand; - nand->IO_ADDR_R = nand->IO_ADDR_W = (void __iomem *)base_addr; - -#ifdef CONFIG_NAND_ECC_BCH - nand->ecc.mode = NAND_ECC_SOFT_BCH; -#else - nand->ecc.mode = NAND_ECC_SOFT; -#endif -#ifdef CONFIG_SYS_NAND_DBW_16 - nand->options = NAND_BUSWIDTH_16; -#endif - nand->cmd_ctrl = at91_nand_hwcontrol; -#ifdef CONFIG_SYS_NAND_READY_PIN - nand->dev_ready = at91_nand_ready; -#endif - nand->chip_delay = 75; - - ret = nand_scan_ident(mtd, CONFIG_SYS_NAND_MAX_CHIPS, NULL); - if (ret) - return ret; - -#ifdef CONFIG_ATMEL_NAND_HWECC -#ifdef CONFIG_ATMEL_NAND_HW_PMECC - ret = atmel_pmecc_nand_init_params(nand, mtd); -#else - ret = atmel_hwecc_nand_init_param(nand, mtd); -#endif - if (ret) - return ret; -#endif - - ret = nand_scan_tail(mtd); - if (!ret) - nand_register(devnum); - - return ret; -} - -void board_nand_init(void) -{ - int i; - for (i = 0; i < CONFIG_SYS_MAX_NAND_DEVICE; i++) - if (atmel_nand_chip_init(i, base_addr[i])) - dev_err(host->dev, "atmel_nand: Fail to initialize #%d chip", - i); -} -#endif /* CONFIG_SPL_BUILD */ diff --git a/qemu/roms/u-boot/drivers/mtd/nand/atmel_nand_ecc.h b/qemu/roms/u-boot/drivers/mtd/nand/atmel_nand_ecc.h deleted file mode 100644 index 55d7711c8..000000000 --- a/qemu/roms/u-boot/drivers/mtd/nand/atmel_nand_ecc.h +++ /dev/null @@ -1,146 +0,0 @@ -/* - * Error Corrected Code Controller (ECC) - System peripherals regsters. - * Based on AT91SAM9260 datasheet revision B. - * - * SPDX-License-Identifier: GPL-2.0+ - */ - -#ifndef ATMEL_NAND_ECC_H -#define ATMEL_NAND_ECC_H - -#define ATMEL_ECC_CR 0x00 /* Control register */ -#define ATMEL_ECC_RST (1 << 0) /* Reset parity */ - -#define ATMEL_ECC_MR 0x04 /* Mode register */ -#define ATMEL_ECC_PAGESIZE (3 << 0) /* Page Size */ -#define ATMEL_ECC_PAGESIZE_528 (0) -#define ATMEL_ECC_PAGESIZE_1056 (1) -#define ATMEL_ECC_PAGESIZE_2112 (2) -#define ATMEL_ECC_PAGESIZE_4224 (3) - -#define ATMEL_ECC_SR 0x08 /* Status register */ -#define ATMEL_ECC_RECERR (1 << 0) /* Recoverable Error */ -#define ATMEL_ECC_ECCERR (1 << 1) /* ECC Single Bit Error */ -#define ATMEL_ECC_MULERR (1 << 2) /* Multiple Errors */ - -#define ATMEL_ECC_PR 0x0c /* Parity register */ -#define ATMEL_ECC_BITADDR (0xf << 0) /* Bit Error Address */ -#define ATMEL_ECC_WORDADDR (0xfff << 4) /* Word Error Address */ - -#define ATMEL_ECC_NPR 0x10 /* NParity register */ -#define ATMEL_ECC_NPARITY (0xffff << 0) /* NParity */ - -/* Register access macros for PMECC */ -#define pmecc_readl(addr, reg) \ - readl(&addr->reg) - -#define pmecc_writel(addr, reg, value) \ - writel((value), &addr->reg) - -/* PMECC Register Definitions */ -#define PMECC_MAX_SECTOR_NUM 8 -struct pmecc_regs { - u32 cfg; /* 0x00 PMECC Configuration Register */ - u32 sarea; /* 0x04 PMECC Spare Area Size Register */ - u32 saddr; /* 0x08 PMECC Start Address Register */ - u32 eaddr; /* 0x0C PMECC End Address Register */ - u32 clk; /* 0x10 PMECC Clock Control Register */ - u32 ctrl; /* 0x14 PMECC Control Register */ - u32 sr; /* 0x18 PMECC Status Register */ - u32 ier; /* 0x1C PMECC Interrupt Enable Register */ - u32 idr; /* 0x20 PMECC Interrupt Disable Register */ - u32 imr; /* 0x24 PMECC Interrupt Mask Register */ - u32 isr; /* 0x28 PMECC Interrupt Status Register */ - u32 reserved0[5]; /* 0x2C-0x3C Reserved */ - - /* 0x40 + sector_num * (0x40), Redundancy Registers */ - struct { - u8 ecc[44]; /* PMECC Generated Redundancy Byte Per Sector */ - u32 reserved1[5]; - } ecc_port[PMECC_MAX_SECTOR_NUM]; - - /* 0x240 + sector_num * (0x40) Remainder Registers */ - struct { - u32 rem[12]; - u32 reserved2[4]; - } rem_port[PMECC_MAX_SECTOR_NUM]; - u32 reserved3[16]; /* 0x440-0x47C Reserved */ -}; - -/* For PMECC Configuration Register */ -#define PMECC_CFG_BCH_ERR2 (0 << 0) -#define PMECC_CFG_BCH_ERR4 (1 << 0) -#define PMECC_CFG_BCH_ERR8 (2 << 0) -#define PMECC_CFG_BCH_ERR12 (3 << 0) -#define PMECC_CFG_BCH_ERR24 (4 << 0) - -#define PMECC_CFG_SECTOR512 (0 << 4) -#define PMECC_CFG_SECTOR1024 (1 << 4) - -#define PMECC_CFG_PAGE_1SECTOR (0 << 8) -#define PMECC_CFG_PAGE_2SECTORS (1 << 8) -#define PMECC_CFG_PAGE_4SECTORS (2 << 8) -#define PMECC_CFG_PAGE_8SECTORS (3 << 8) - -#define PMECC_CFG_READ_OP (0 << 12) -#define PMECC_CFG_WRITE_OP (1 << 12) - -#define PMECC_CFG_SPARE_ENABLE (1 << 16) -#define PMECC_CFG_SPARE_DISABLE (0 << 16) - -#define PMECC_CFG_AUTO_ENABLE (1 << 20) -#define PMECC_CFG_AUTO_DISABLE (0 << 20) - -/* For PMECC Clock Control Register */ -#define PMECC_CLK_133MHZ (2 << 0) - -/* For PMECC Control Register */ -#define PMECC_CTRL_RST (1 << 0) -#define PMECC_CTRL_DATA (1 << 1) -#define PMECC_CTRL_USER (1 << 2) -#define PMECC_CTRL_ENABLE (1 << 4) -#define PMECC_CTRL_DISABLE (1 << 5) - -/* For PMECC Status Register */ -#define PMECC_SR_BUSY (1 << 0) -#define PMECC_SR_ENABLE (1 << 4) - -/* PMERRLOC Register Definitions */ -struct pmecc_errloc_regs { - u32 elcfg; /* 0x00 Error Location Configuration Register */ - u32 elprim; /* 0x04 Error Location Primitive Register */ - u32 elen; /* 0x08 Error Location Enable Register */ - u32 eldis; /* 0x0C Error Location Disable Register */ - u32 elsr; /* 0x10 Error Location Status Register */ - u32 elier; /* 0x14 Error Location Interrupt Enable Register */ - u32 elidr; /* 0x08 Error Location Interrupt Disable Register */ - u32 elimr; /* 0x0C Error Location Interrupt Mask Register */ - u32 elisr; /* 0x20 Error Location Interrupt Status Register */ - u32 reserved0; /* 0x24 Reserved */ - u32 sigma[25]; /* 0x28-0x88 Error Location Sigma Registers */ - u32 el[24]; /* 0x8C-0xE8 Error Location Registers */ - u32 reserved1[5]; /* 0xEC-0xFC Reserved */ -}; - -/* For Error Location Configuration Register */ -#define PMERRLOC_ELCFG_SECTOR_512 (0 << 0) -#define PMERRLOC_ELCFG_SECTOR_1024 (1 << 0) -#define PMERRLOC_ELCFG_NUM_ERRORS(n) ((n) << 16) - -/* For Error Location Disable Register */ -#define PMERRLOC_DISABLE (1 << 0) - -/* For Error Location Interrupt Status Register */ -#define PMERRLOC_ERR_NUM_MASK (0x1f << 8) -#define PMERRLOC_CALC_DONE (1 << 0) - -/* Galois field dimension */ -#define PMECC_GF_DIMENSION_13 13 -#define PMECC_GF_DIMENSION_14 14 - -#define PMECC_INDEX_TABLE_SIZE_512 0x2000 -#define PMECC_INDEX_TABLE_SIZE_1024 0x4000 - -#define PMECC_MAX_TIMEOUT_US (100 * 1000) - -#endif diff --git a/qemu/roms/u-boot/drivers/mtd/nand/bfin_nand.c b/qemu/roms/u-boot/drivers/mtd/nand/bfin_nand.c deleted file mode 100644 index 7e755e896..000000000 --- a/qemu/roms/u-boot/drivers/mtd/nand/bfin_nand.c +++ /dev/null @@ -1,393 +0,0 @@ -/* - * Driver for Blackfin on-chip NAND controller. - * - * Enter bugs at http://blackfin.uclinux.org/ - * - * Copyright (c) 2007-2008 Analog Devices Inc. - * - * Licensed under the GPL-2 or later. - */ - -/* TODO: - * - move bit defines into mach-common/bits/nand.h - * - try and replace all IRQSTAT usage with STAT polling - * - have software ecc mode use same algo as hw ecc ? - */ - -#include <common.h> -#include <asm/io.h> - -#ifdef DEBUG -# define pr_stamp() printf("%s:%s:%i: here i am\n", __FILE__, __func__, __LINE__) -#else -# define pr_stamp() -#endif - -#include <nand.h> - -#include <asm/blackfin.h> -#include <asm/portmux.h> - -/* Bit masks for NFC_CTL */ - -#define WR_DLY 0xf /* Write Strobe Delay */ -#define RD_DLY 0xf0 /* Read Strobe Delay */ -#define NWIDTH 0x100 /* NAND Data Width */ -#define PG_SIZE 0x200 /* Page Size */ - -/* Bit masks for NFC_STAT */ - -#define NBUSY 0x1 /* Not Busy */ -#define WB_FULL 0x2 /* Write Buffer Full */ -#define PG_WR_STAT 0x4 /* Page Write Pending */ -#define PG_RD_STAT 0x8 /* Page Read Pending */ -#define WB_EMPTY 0x10 /* Write Buffer Empty */ - -/* Bit masks for NFC_IRQSTAT */ - -#define NBUSYIRQ 0x1 /* Not Busy IRQ */ -#define WB_OVF 0x2 /* Write Buffer Overflow */ -#define WB_EDGE 0x4 /* Write Buffer Edge Detect */ -#define RD_RDY 0x8 /* Read Data Ready */ -#define WR_DONE 0x10 /* Page Write Done */ - -#define NAND_IS_512() (CONFIG_BFIN_NFC_CTL_VAL & 0x200) - -/* - * hardware specific access to control-lines - */ -static void bfin_nfc_cmd_ctrl(struct mtd_info *mtd, int cmd, unsigned int ctrl) -{ - pr_stamp(); - - if (cmd == NAND_CMD_NONE) - return; - - while (bfin_read_NFC_STAT() & WB_FULL) - continue; - - if (ctrl & NAND_CLE) - bfin_write_NFC_CMD(cmd); - else - bfin_write_NFC_ADDR(cmd); - SSYNC(); -} - -static int bfin_nfc_devready(struct mtd_info *mtd) -{ - pr_stamp(); - return (bfin_read_NFC_STAT() & NBUSY) ? 1 : 0; -} - -/* - * PIO mode for buffer writing and reading - */ -static void bfin_nfc_read_buf(struct mtd_info *mtd, uint8_t *buf, int len) -{ - pr_stamp(); - - int i; - - /* - * Data reads are requested by first writing to NFC_DATA_RD - * and then reading back from NFC_READ. - */ - for (i = 0; i < len; ++i) { - while (bfin_read_NFC_STAT() & WB_FULL) - if (ctrlc()) - return; - - /* Contents do not matter */ - bfin_write_NFC_DATA_RD(0x0000); - SSYNC(); - - while (!(bfin_read_NFC_IRQSTAT() & RD_RDY)) - if (ctrlc()) - return; - - buf[i] = bfin_read_NFC_READ(); - - bfin_write_NFC_IRQSTAT(RD_RDY); - } -} - -static uint8_t bfin_nfc_read_byte(struct mtd_info *mtd) -{ - pr_stamp(); - - uint8_t val; - bfin_nfc_read_buf(mtd, &val, 1); - return val; -} - -static void bfin_nfc_write_buf(struct mtd_info *mtd, const uint8_t *buf, int len) -{ - pr_stamp(); - - int i; - - for (i = 0; i < len; ++i) { - while (bfin_read_NFC_STAT() & WB_FULL) - if (ctrlc()) - return; - - bfin_write_NFC_DATA_WR(buf[i]); - } - - /* Wait for the buffer to drain before we return */ - while (!(bfin_read_NFC_STAT() & WB_EMPTY)) - if (ctrlc()) - return; -} - -/* - * ECC functions - * These allow the bfin to use the controller's ECC - * generator block to ECC the data as it passes through - */ - -/* - * ECC error correction function - */ -static int bfin_nfc_correct_data_256(struct mtd_info *mtd, u_char *dat, - u_char *read_ecc, u_char *calc_ecc) -{ - u32 syndrome[5]; - u32 calced, stored; - unsigned short failing_bit, failing_byte; - u_char data; - - pr_stamp(); - - calced = calc_ecc[0] | (calc_ecc[1] << 8) | (calc_ecc[2] << 16); - stored = read_ecc[0] | (read_ecc[1] << 8) | (read_ecc[2] << 16); - - syndrome[0] = (calced ^ stored); - - /* - * syndrome 0: all zero - * No error in data - * No action - */ - if (!syndrome[0] || !calced || !stored) - return 0; - - /* - * sysdrome 0: only one bit is one - * ECC data was incorrect - * No action - */ - if (hweight32(syndrome[0]) == 1) - return 1; - - syndrome[1] = (calced & 0x7FF) ^ (stored & 0x7FF); - syndrome[2] = (calced & 0x7FF) ^ ((calced >> 11) & 0x7FF); - syndrome[3] = (stored & 0x7FF) ^ ((stored >> 11) & 0x7FF); - syndrome[4] = syndrome[2] ^ syndrome[3]; - - /* - * sysdrome 0: exactly 11 bits are one, each parity - * and parity' pair is 1 & 0 or 0 & 1. - * 1-bit correctable error - * Correct the error - */ - if (hweight32(syndrome[0]) == 11 && syndrome[4] == 0x7FF) { - failing_bit = syndrome[1] & 0x7; - failing_byte = syndrome[1] >> 0x3; - data = *(dat + failing_byte); - data = data ^ (0x1 << failing_bit); - *(dat + failing_byte) = data; - - return 0; - } - - /* - * sysdrome 0: random data - * More than 1-bit error, non-correctable error - * Discard data, mark bad block - */ - - return 1; -} - -static int bfin_nfc_correct_data(struct mtd_info *mtd, u_char *dat, - u_char *read_ecc, u_char *calc_ecc) -{ - int ret; - - pr_stamp(); - - ret = bfin_nfc_correct_data_256(mtd, dat, read_ecc, calc_ecc); - - /* If page size is 512, correct second 256 bytes */ - if (NAND_IS_512()) { - dat += 256; - read_ecc += 8; - calc_ecc += 8; - ret |= bfin_nfc_correct_data_256(mtd, dat, read_ecc, calc_ecc); - } - - return ret; -} - -static void reset_ecc(void) -{ - bfin_write_NFC_RST(0x1); - while (bfin_read_NFC_RST() & 1) - continue; -} - -static void bfin_nfc_enable_hwecc(struct mtd_info *mtd, int mode) -{ - reset_ecc(); -} - -static int bfin_nfc_calculate_ecc(struct mtd_info *mtd, - const u_char *dat, u_char *ecc_code) -{ - u16 ecc0, ecc1; - u32 code[2]; - u8 *p; - - pr_stamp(); - - /* first 4 bytes ECC code for 256 page size */ - ecc0 = bfin_read_NFC_ECC0(); - ecc1 = bfin_read_NFC_ECC1(); - - code[0] = (ecc0 & 0x7FF) | ((ecc1 & 0x7FF) << 11); - - /* first 3 bytes in ecc_code for 256 page size */ - p = (u8 *) code; - memcpy(ecc_code, p, 3); - - /* second 4 bytes ECC code for 512 page size */ - if (NAND_IS_512()) { - ecc0 = bfin_read_NFC_ECC2(); - ecc1 = bfin_read_NFC_ECC3(); - code[1] = (ecc0 & 0x7FF) | ((ecc1 & 0x7FF) << 11); - - /* second 3 bytes in ecc_code for second 256 - * bytes of 512 page size - */ - p = (u8 *) (code + 1); - memcpy((ecc_code + 3), p, 3); - } - - reset_ecc(); - - return 0; -} - -#ifdef CONFIG_BFIN_NFC_BOOTROM_ECC -# define BOOTROM_ECC 1 -#else -# define BOOTROM_ECC 0 -#endif - -static uint8_t bbt_pattern[] = { 0xff }; - -static struct nand_bbt_descr bootrom_bbt = { - .options = 0, - .offs = 63, - .len = 1, - .pattern = bbt_pattern, -}; - -static struct nand_ecclayout bootrom_ecclayout = { - .eccbytes = 24, - .eccpos = { - 0x8 * 0, 0x8 * 0 + 1, 0x8 * 0 + 2, - 0x8 * 1, 0x8 * 1 + 1, 0x8 * 1 + 2, - 0x8 * 2, 0x8 * 2 + 1, 0x8 * 2 + 2, - 0x8 * 3, 0x8 * 3 + 1, 0x8 * 3 + 2, - 0x8 * 4, 0x8 * 4 + 1, 0x8 * 4 + 2, - 0x8 * 5, 0x8 * 5 + 1, 0x8 * 5 + 2, - 0x8 * 6, 0x8 * 6 + 1, 0x8 * 6 + 2, - 0x8 * 7, 0x8 * 7 + 1, 0x8 * 7 + 2 - }, - .oobfree = { - { 0x8 * 0 + 3, 5 }, - { 0x8 * 1 + 3, 5 }, - { 0x8 * 2 + 3, 5 }, - { 0x8 * 3 + 3, 5 }, - { 0x8 * 4 + 3, 5 }, - { 0x8 * 5 + 3, 5 }, - { 0x8 * 6 + 3, 5 }, - { 0x8 * 7 + 3, 5 }, - } -}; - -/* - * Board-specific NAND initialization. The following members of the - * argument are board-specific (per include/linux/mtd/nand.h): - * - IO_ADDR_R?: address to read the 8 I/O lines of the flash device - * - IO_ADDR_W?: address to write the 8 I/O lines of the flash device - * - cmd_ctrl: hardwarespecific function for accesing control-lines - * - dev_ready: hardwarespecific function for accesing device ready/busy line - * - enable_hwecc?: function to enable (reset) hardware ecc generator. Must - * only be provided if a hardware ECC is available - * - ecc.mode: mode of ecc, see defines - * - chip_delay: chip dependent delay for transfering data from array to - * read regs (tR) - * - options: various chip options. They can partly be set to inform - * nand_scan about special functionality. See the defines for further - * explanation - * Members with a "?" were not set in the merged testing-NAND branch, - * so they are not set here either. - */ -int board_nand_init(struct nand_chip *chip) -{ - const unsigned short pins[] = { - P_NAND_CE, P_NAND_RB, P_NAND_D0, P_NAND_D1, P_NAND_D2, - P_NAND_D3, P_NAND_D4, P_NAND_D5, P_NAND_D6, P_NAND_D7, - P_NAND_WE, P_NAND_RE, P_NAND_CLE, P_NAND_ALE, 0, - }; - - pr_stamp(); - - /* set width/ecc/timings/etc... */ - bfin_write_NFC_CTL(CONFIG_BFIN_NFC_CTL_VAL); - - /* clear interrupt status */ - bfin_write_NFC_IRQMASK(0x0); - bfin_write_NFC_IRQSTAT(0xffff); - - /* enable GPIO function enable register */ - peripheral_request_list(pins, "bfin_nand"); - - chip->cmd_ctrl = bfin_nfc_cmd_ctrl; - chip->read_buf = bfin_nfc_read_buf; - chip->write_buf = bfin_nfc_write_buf; - chip->read_byte = bfin_nfc_read_byte; - -#ifdef CONFIG_BFIN_NFC_NO_HW_ECC -# define ECC_HW 0 -#else -# define ECC_HW 1 -#endif - if (ECC_HW) { - if (BOOTROM_ECC) { - chip->badblock_pattern = &bootrom_bbt; - chip->ecc.layout = &bootrom_ecclayout; - } - if (!NAND_IS_512()) { - chip->ecc.bytes = 3; - chip->ecc.size = 256; - chip->ecc.strength = 1; - } else { - chip->ecc.bytes = 6; - chip->ecc.size = 512; - chip->ecc.strength = 2; - } - chip->ecc.mode = NAND_ECC_HW; - chip->ecc.calculate = bfin_nfc_calculate_ecc; - chip->ecc.correct = bfin_nfc_correct_data; - chip->ecc.hwctl = bfin_nfc_enable_hwecc; - } else - chip->ecc.mode = NAND_ECC_SOFT; - chip->dev_ready = bfin_nfc_devready; - chip->chip_delay = 0; - - return 0; -} diff --git a/qemu/roms/u-boot/drivers/mtd/nand/davinci_nand.c b/qemu/roms/u-boot/drivers/mtd/nand/davinci_nand.c deleted file mode 100644 index 75b03a74b..000000000 --- a/qemu/roms/u-boot/drivers/mtd/nand/davinci_nand.c +++ /dev/null @@ -1,653 +0,0 @@ -/* - * NAND driver for TI DaVinci based boards. - * - * Copyright (C) 2007 Sergey Kubushyn <ksi@koi8.net> - * - * Based on Linux DaVinci NAND driver by TI. Original copyright follows: - */ - -/* - * - * linux/drivers/mtd/nand/nand_davinci.c - * - * NAND Flash Driver - * - * Copyright (C) 2006 Texas Instruments. - * - * ---------------------------------------------------------------------------- - * - * SPDX-License-Identifier: GPL-2.0+ - * - * ---------------------------------------------------------------------------- - * - * Overview: - * This is a device driver for the NAND flash device found on the - * DaVinci board which utilizes the Samsung k9k2g08 part. - * - Modifications: - ver. 1.0: Feb 2005, Vinod/Sudhakar - - - */ - -#include <common.h> -#include <asm/io.h> -#include <nand.h> -#include <asm/arch/nand_defs.h> -#include <asm/arch/emif_defs.h> - -/* Definitions for 4-bit hardware ECC */ -#define NAND_TIMEOUT 10240 -#define NAND_ECC_BUSY 0xC -#define NAND_4BITECC_MASK 0x03FF03FF -#define EMIF_NANDFSR_ECC_STATE_MASK 0x00000F00 -#define ECC_STATE_NO_ERR 0x0 -#define ECC_STATE_TOO_MANY_ERRS 0x1 -#define ECC_STATE_ERR_CORR_COMP_P 0x2 -#define ECC_STATE_ERR_CORR_COMP_N 0x3 - -/* - * Exploit the little endianness of the ARM to do multi-byte transfers - * per device read. This can perform over twice as quickly as individual - * byte transfers when buffer alignment is conducive. - * - * NOTE: This only works if the NAND is not connected to the 2 LSBs of - * the address bus. On Davinci EVM platforms this has always been true. - */ -static void nand_davinci_read_buf(struct mtd_info *mtd, uint8_t *buf, int len) -{ - struct nand_chip *chip = mtd->priv; - const u32 *nand = chip->IO_ADDR_R; - - /* Make sure that buf is 32 bit aligned */ - if (((int)buf & 0x3) != 0) { - if (((int)buf & 0x1) != 0) { - if (len) { - *buf = readb(nand); - buf += 1; - len--; - } - } - - if (((int)buf & 0x3) != 0) { - if (len >= 2) { - *(u16 *)buf = readw(nand); - buf += 2; - len -= 2; - } - } - } - - /* copy aligned data */ - while (len >= 4) { - *(u32 *)buf = __raw_readl(nand); - buf += 4; - len -= 4; - } - - /* mop up any remaining bytes */ - if (len) { - if (len >= 2) { - *(u16 *)buf = readw(nand); - buf += 2; - len -= 2; - } - - if (len) - *buf = readb(nand); - } -} - -static void nand_davinci_write_buf(struct mtd_info *mtd, const uint8_t *buf, - int len) -{ - struct nand_chip *chip = mtd->priv; - const u32 *nand = chip->IO_ADDR_W; - - /* Make sure that buf is 32 bit aligned */ - if (((int)buf & 0x3) != 0) { - if (((int)buf & 0x1) != 0) { - if (len) { - writeb(*buf, nand); - buf += 1; - len--; - } - } - - if (((int)buf & 0x3) != 0) { - if (len >= 2) { - writew(*(u16 *)buf, nand); - buf += 2; - len -= 2; - } - } - } - - /* copy aligned data */ - while (len >= 4) { - __raw_writel(*(u32 *)buf, nand); - buf += 4; - len -= 4; - } - - /* mop up any remaining bytes */ - if (len) { - if (len >= 2) { - writew(*(u16 *)buf, nand); - buf += 2; - len -= 2; - } - - if (len) - writeb(*buf, nand); - } -} - -static void nand_davinci_hwcontrol(struct mtd_info *mtd, int cmd, - unsigned int ctrl) -{ - struct nand_chip *this = mtd->priv; - u_int32_t IO_ADDR_W = (u_int32_t)this->IO_ADDR_W; - - if (ctrl & NAND_CTRL_CHANGE) { - IO_ADDR_W &= ~(MASK_ALE|MASK_CLE); - - if (ctrl & NAND_CLE) - IO_ADDR_W |= MASK_CLE; - if (ctrl & NAND_ALE) - IO_ADDR_W |= MASK_ALE; - this->IO_ADDR_W = (void __iomem *) IO_ADDR_W; - } - - if (cmd != NAND_CMD_NONE) - writeb(cmd, IO_ADDR_W); -} - -#ifdef CONFIG_SYS_NAND_HW_ECC - -static u_int32_t nand_davinci_readecc(struct mtd_info *mtd) -{ - u_int32_t ecc = 0; - - ecc = __raw_readl(&(davinci_emif_regs->nandfecc[ - CONFIG_SYS_NAND_CS - 2])); - - return ecc; -} - -static void nand_davinci_enable_hwecc(struct mtd_info *mtd, int mode) -{ - u_int32_t val; - - /* reading the ECC result register resets the ECC calculation */ - nand_davinci_readecc(mtd); - - val = __raw_readl(&davinci_emif_regs->nandfcr); - val |= DAVINCI_NANDFCR_NAND_ENABLE(CONFIG_SYS_NAND_CS); - val |= DAVINCI_NANDFCR_1BIT_ECC_START(CONFIG_SYS_NAND_CS); - __raw_writel(val, &davinci_emif_regs->nandfcr); -} - -static int nand_davinci_calculate_ecc(struct mtd_info *mtd, const u_char *dat, - u_char *ecc_code) -{ - u_int32_t tmp; - - tmp = nand_davinci_readecc(mtd); - - /* Squeeze 4 bytes ECC into 3 bytes by removing RESERVED bits - * and shifting. RESERVED bits are 31 to 28 and 15 to 12. */ - tmp = (tmp & 0x00000fff) | ((tmp & 0x0fff0000) >> 4); - - /* Invert so that erased block ECC is correct */ - tmp = ~tmp; - - *ecc_code++ = tmp; - *ecc_code++ = tmp >> 8; - *ecc_code++ = tmp >> 16; - - /* NOTE: the above code matches mainline Linux: - * .PQR.stu ==> ~PQRstu - * - * MontaVista/TI kernels encode those bytes differently, use - * complicated (and allegedly sometimes-wrong) correction code, - * and usually shipped with U-Boot that uses software ECC: - * .PQR.stu ==> PsQRtu - * - * If you need MV/TI compatible NAND I/O in U-Boot, it should - * be possible to (a) change the mangling above, (b) reverse - * that mangling in nand_davinci_correct_data() below. - */ - - return 0; -} - -static int nand_davinci_correct_data(struct mtd_info *mtd, u_char *dat, - u_char *read_ecc, u_char *calc_ecc) -{ - struct nand_chip *this = mtd->priv; - u_int32_t ecc_nand = read_ecc[0] | (read_ecc[1] << 8) | - (read_ecc[2] << 16); - u_int32_t ecc_calc = calc_ecc[0] | (calc_ecc[1] << 8) | - (calc_ecc[2] << 16); - u_int32_t diff = ecc_calc ^ ecc_nand; - - if (diff) { - if ((((diff >> 12) ^ diff) & 0xfff) == 0xfff) { - /* Correctable error */ - if ((diff >> (12 + 3)) < this->ecc.size) { - uint8_t find_bit = 1 << ((diff >> 12) & 7); - uint32_t find_byte = diff >> (12 + 3); - - dat[find_byte] ^= find_bit; - MTDDEBUG(MTD_DEBUG_LEVEL0, "Correcting single " - "bit ECC error at offset: %d, bit: " - "%d\n", find_byte, find_bit); - return 1; - } else { - return -1; - } - } else if (!(diff & (diff - 1))) { - /* Single bit ECC error in the ECC itself, - nothing to fix */ - MTDDEBUG(MTD_DEBUG_LEVEL0, "Single bit ECC error in " - "ECC.\n"); - return 1; - } else { - /* Uncorrectable error */ - MTDDEBUG(MTD_DEBUG_LEVEL0, "ECC UNCORRECTED_ERROR 1\n"); - return -1; - } - } - return 0; -} -#endif /* CONFIG_SYS_NAND_HW_ECC */ - -#ifdef CONFIG_SYS_NAND_4BIT_HW_ECC_OOBFIRST -static struct nand_ecclayout nand_davinci_4bit_layout_oobfirst = { -#if defined(CONFIG_SYS_NAND_PAGE_2K) - .eccbytes = 40, -#ifdef CONFIG_NAND_6BYTES_OOB_FREE_10BYTES_ECC - .eccpos = { - 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, - 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, - 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, - 54, 55, 56, 57, 58, 59, 60, 61, 62, 63, - }, - .oobfree = { - {2, 4}, {16, 6}, {32, 6}, {48, 6}, - }, -#else - .eccpos = { - 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, - }, - .oobfree = { - {.offset = 2, .length = 22, }, - }, -#endif /* #ifdef CONFIG_NAND_6BYTES_OOB_FREE_10BYTES_ECC */ -#elif defined(CONFIG_SYS_NAND_PAGE_4K) - .eccbytes = 80, - .eccpos = { - 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, - }, - .oobfree = { - {.offset = 2, .length = 46, }, - }, -#endif -}; - -static void nand_davinci_4bit_enable_hwecc(struct mtd_info *mtd, int mode) -{ - u32 val; - - switch (mode) { - case NAND_ECC_WRITE: - case NAND_ECC_READ: - /* - * Start a new ECC calculation for reading or writing 512 bytes - * of data. - */ - val = __raw_readl(&davinci_emif_regs->nandfcr); - val &= ~DAVINCI_NANDFCR_4BIT_ECC_SEL_MASK; - val |= DAVINCI_NANDFCR_NAND_ENABLE(CONFIG_SYS_NAND_CS); - val |= DAVINCI_NANDFCR_4BIT_ECC_SEL(CONFIG_SYS_NAND_CS); - val |= DAVINCI_NANDFCR_4BIT_ECC_START; - __raw_writel(val, &davinci_emif_regs->nandfcr); - break; - case NAND_ECC_READSYN: - val = __raw_readl(&davinci_emif_regs->nand4bitecc[0]); - break; - default: - break; - } -} - -static u32 nand_davinci_4bit_readecc(struct mtd_info *mtd, unsigned int ecc[4]) -{ - int i; - - for (i = 0; i < 4; i++) { - ecc[i] = __raw_readl(&davinci_emif_regs->nand4bitecc[i]) & - NAND_4BITECC_MASK; - } - - return 0; -} - -static int nand_davinci_4bit_calculate_ecc(struct mtd_info *mtd, - const uint8_t *dat, - uint8_t *ecc_code) -{ - unsigned int hw_4ecc[4]; - unsigned int i; - - nand_davinci_4bit_readecc(mtd, hw_4ecc); - - /*Convert 10 bit ecc value to 8 bit */ - for (i = 0; i < 2; i++) { - unsigned int hw_ecc_low = hw_4ecc[i * 2]; - unsigned int hw_ecc_hi = hw_4ecc[(i * 2) + 1]; - - /* Take first 8 bits from val1 (count1=0) or val5 (count1=1) */ - *ecc_code++ = hw_ecc_low & 0xFF; - - /* - * Take 2 bits as LSB bits from val1 (count1=0) or val5 - * (count1=1) and 6 bits from val2 (count1=0) or - * val5 (count1=1) - */ - *ecc_code++ = - ((hw_ecc_low >> 8) & 0x3) | ((hw_ecc_low >> 14) & 0xFC); - - /* - * Take 4 bits from val2 (count1=0) or val5 (count1=1) and - * 4 bits from val3 (count1=0) or val6 (count1=1) - */ - *ecc_code++ = - ((hw_ecc_low >> 22) & 0xF) | ((hw_ecc_hi << 4) & 0xF0); - - /* - * Take 6 bits from val3(count1=0) or val6 (count1=1) and - * 2 bits from val4 (count1=0) or val7 (count1=1) - */ - *ecc_code++ = - ((hw_ecc_hi >> 4) & 0x3F) | ((hw_ecc_hi >> 10) & 0xC0); - - /* Take 8 bits from val4 (count1=0) or val7 (count1=1) */ - *ecc_code++ = (hw_ecc_hi >> 18) & 0xFF; - } - - return 0; -} - -static int nand_davinci_4bit_correct_data(struct mtd_info *mtd, uint8_t *dat, - uint8_t *read_ecc, uint8_t *calc_ecc) -{ - int i; - unsigned int hw_4ecc[4]; - unsigned int iserror; - unsigned short *ecc16; - unsigned int numerrors, erroraddress, errorvalue; - u32 val; - - /* - * Check for an ECC where all bytes are 0xFF. If this is the case, we - * will assume we are looking at an erased page and we should ignore - * the ECC. - */ - for (i = 0; i < 10; i++) { - if (read_ecc[i] != 0xFF) - break; - } - if (i == 10) - return 0; - - /* Convert 8 bit in to 10 bit */ - ecc16 = (unsigned short *)&read_ecc[0]; - - /* - * Write the parity values in the NAND Flash 4-bit ECC Load register. - * Write each parity value one at a time starting from 4bit_ecc_val8 - * to 4bit_ecc_val1. - */ - - /*Take 2 bits from 8th byte and 8 bits from 9th byte */ - __raw_writel(((ecc16[4]) >> 6) & 0x3FF, - &davinci_emif_regs->nand4biteccload); - - /* Take 4 bits from 7th byte and 6 bits from 8th byte */ - __raw_writel((((ecc16[3]) >> 12) & 0xF) | ((((ecc16[4])) << 4) & 0x3F0), - &davinci_emif_regs->nand4biteccload); - - /* Take 6 bits from 6th byte and 4 bits from 7th byte */ - __raw_writel((ecc16[3] >> 2) & 0x3FF, - &davinci_emif_regs->nand4biteccload); - - /* Take 8 bits from 5th byte and 2 bits from 6th byte */ - __raw_writel(((ecc16[2]) >> 8) | ((((ecc16[3])) << 8) & 0x300), - &davinci_emif_regs->nand4biteccload); - - /*Take 2 bits from 3rd byte and 8 bits from 4th byte */ - __raw_writel((((ecc16[1]) >> 14) & 0x3) | ((((ecc16[2])) << 2) & 0x3FC), - &davinci_emif_regs->nand4biteccload); - - /* Take 4 bits form 2nd bytes and 6 bits from 3rd bytes */ - __raw_writel(((ecc16[1]) >> 4) & 0x3FF, - &davinci_emif_regs->nand4biteccload); - - /* Take 6 bits from 1st byte and 4 bits from 2nd byte */ - __raw_writel((((ecc16[0]) >> 10) & 0x3F) | (((ecc16[1]) << 6) & 0x3C0), - &davinci_emif_regs->nand4biteccload); - - /* Take 10 bits from 0th and 1st bytes */ - __raw_writel((ecc16[0]) & 0x3FF, - &davinci_emif_regs->nand4biteccload); - - /* - * Perform a dummy read to the EMIF Revision Code and Status register. - * This is required to ensure time for syndrome calculation after - * writing the ECC values in previous step. - */ - - val = __raw_readl(&davinci_emif_regs->nandfsr); - - /* - * Read the syndrome from the NAND Flash 4-Bit ECC 1-4 registers. - * A syndrome value of 0 means no bit errors. If the syndrome is - * non-zero then go further otherwise return. - */ - nand_davinci_4bit_readecc(mtd, hw_4ecc); - - if (!(hw_4ecc[0] | hw_4ecc[1] | hw_4ecc[2] | hw_4ecc[3])) - return 0; - - /* - * Clear any previous address calculation by doing a dummy read of an - * error address register. - */ - val = __raw_readl(&davinci_emif_regs->nanderradd1); - - /* - * Set the addr_calc_st bit(bit no 13) in the NAND Flash Control - * register to 1. - */ - __raw_writel(DAVINCI_NANDFCR_4BIT_CALC_START, - &davinci_emif_regs->nandfcr); - - /* - * Wait for the corr_state field (bits 8 to 11) in the - * NAND Flash Status register to be not equal to 0x0, 0x1, 0x2, or 0x3. - * Otherwise ECC calculation has not even begun and the next loop might - * fail because of a false positive! - */ - i = NAND_TIMEOUT; - do { - val = __raw_readl(&davinci_emif_regs->nandfsr); - val &= 0xc00; - i--; - } while ((i > 0) && !val); - - /* - * Wait for the corr_state field (bits 8 to 11) in the - * NAND Flash Status register to be equal to 0x0, 0x1, 0x2, or 0x3. - */ - i = NAND_TIMEOUT; - do { - val = __raw_readl(&davinci_emif_regs->nandfsr); - val &= 0xc00; - i--; - } while ((i > 0) && val); - - iserror = __raw_readl(&davinci_emif_regs->nandfsr); - iserror &= EMIF_NANDFSR_ECC_STATE_MASK; - iserror = iserror >> 8; - - /* - * ECC_STATE_TOO_MANY_ERRS (0x1) means errors cannot be - * corrected (five or more errors). The number of errors - * calculated (err_num field) differs from the number of errors - * searched. ECC_STATE_ERR_CORR_COMP_P (0x2) means error - * correction complete (errors on bit 8 or 9). - * ECC_STATE_ERR_CORR_COMP_N (0x3) means error correction - * complete (error exists). - */ - - if (iserror == ECC_STATE_NO_ERR) { - val = __raw_readl(&davinci_emif_regs->nanderrval1); - return 0; - } else if (iserror == ECC_STATE_TOO_MANY_ERRS) { - val = __raw_readl(&davinci_emif_regs->nanderrval1); - return -1; - } - - numerrors = ((__raw_readl(&davinci_emif_regs->nandfsr) >> 16) - & 0x3) + 1; - - /* Read the error address, error value and correct */ - for (i = 0; i < numerrors; i++) { - if (i > 1) { - erroraddress = - ((__raw_readl(&davinci_emif_regs->nanderradd2) >> - (16 * (i & 1))) & 0x3FF); - erroraddress = ((512 + 7) - erroraddress); - errorvalue = - ((__raw_readl(&davinci_emif_regs->nanderrval2) >> - (16 * (i & 1))) & 0xFF); - } else { - erroraddress = - ((__raw_readl(&davinci_emif_regs->nanderradd1) >> - (16 * (i & 1))) & 0x3FF); - erroraddress = ((512 + 7) - erroraddress); - errorvalue = - ((__raw_readl(&davinci_emif_regs->nanderrval1) >> - (16 * (i & 1))) & 0xFF); - } - /* xor the corrupt data with error value */ - if (erroraddress < 512) - dat[erroraddress] ^= errorvalue; - } - - return numerrors; -} -#endif /* CONFIG_SYS_NAND_4BIT_HW_ECC_OOBFIRST */ - -static int nand_davinci_dev_ready(struct mtd_info *mtd) -{ - return __raw_readl(&davinci_emif_regs->nandfsr) & 0x1; -} - -static void nand_flash_init(void) -{ - /* This is for DM6446 EVM and *very* similar. DO NOT GROW THIS! - * Instead, have your board_init() set EMIF timings, based on its - * knowledge of the clocks and what devices are hooked up ... and - * don't even do that unless no UBL handled it. - */ -#ifdef CONFIG_SOC_DM644X - u_int32_t acfg1 = 0x3ffffffc; - - /*------------------------------------------------------------------* - * NAND FLASH CHIP TIMEOUT @ 459 MHz * - * * - * AEMIF.CLK freq = PLL1/6 = 459/6 = 76.5 MHz * - * AEMIF.CLK period = 1/76.5 MHz = 13.1 ns * - * * - *------------------------------------------------------------------*/ - acfg1 = 0 - | (0 << 31) /* selectStrobe */ - | (0 << 30) /* extWait */ - | (1 << 26) /* writeSetup 10 ns */ - | (3 << 20) /* writeStrobe 40 ns */ - | (1 << 17) /* writeHold 10 ns */ - | (1 << 13) /* readSetup 10 ns */ - | (5 << 7) /* readStrobe 60 ns */ - | (1 << 4) /* readHold 10 ns */ - | (3 << 2) /* turnAround ?? ns */ - | (0 << 0) /* asyncSize 8-bit bus */ - ; - - __raw_writel(acfg1, &davinci_emif_regs->ab1cr); /* CS2 */ - - /* NAND flash on CS2 */ - __raw_writel(0x00000101, &davinci_emif_regs->nandfcr); -#endif -} - -void davinci_nand_init(struct nand_chip *nand) -{ - nand->chip_delay = 0; -#ifdef CONFIG_SYS_NAND_USE_FLASH_BBT - nand->bbt_options |= NAND_BBT_USE_FLASH; -#endif -#ifdef CONFIG_SYS_NAND_NO_SUBPAGE_WRITE - nand->options |= NAND_NO_SUBPAGE_WRITE; -#endif -#ifdef CONFIG_SYS_NAND_HW_ECC - nand->ecc.mode = NAND_ECC_HW; - nand->ecc.size = 512; - nand->ecc.bytes = 3; - nand->ecc.strength = 1; - nand->ecc.calculate = nand_davinci_calculate_ecc; - nand->ecc.correct = nand_davinci_correct_data; - nand->ecc.hwctl = nand_davinci_enable_hwecc; -#else - nand->ecc.mode = NAND_ECC_SOFT; -#endif /* CONFIG_SYS_NAND_HW_ECC */ -#ifdef CONFIG_SYS_NAND_4BIT_HW_ECC_OOBFIRST - nand->ecc.mode = NAND_ECC_HW_OOB_FIRST; - nand->ecc.size = 512; - nand->ecc.bytes = 10; - nand->ecc.strength = 4; - nand->ecc.calculate = nand_davinci_4bit_calculate_ecc; - nand->ecc.correct = nand_davinci_4bit_correct_data; - nand->ecc.hwctl = nand_davinci_4bit_enable_hwecc; - nand->ecc.layout = &nand_davinci_4bit_layout_oobfirst; -#endif - /* Set address of hardware control function */ - nand->cmd_ctrl = nand_davinci_hwcontrol; - - nand->read_buf = nand_davinci_read_buf; - nand->write_buf = nand_davinci_write_buf; - - nand->dev_ready = nand_davinci_dev_ready; - - nand_flash_init(); -} - -int board_nand_init(struct nand_chip *chip) __attribute__((weak)); - -int board_nand_init(struct nand_chip *chip) -{ - davinci_nand_init(chip); - return 0; -} diff --git a/qemu/roms/u-boot/drivers/mtd/nand/docg4.c b/qemu/roms/u-boot/drivers/mtd/nand/docg4.c deleted file mode 100644 index b9121c397..000000000 --- a/qemu/roms/u-boot/drivers/mtd/nand/docg4.c +++ /dev/null @@ -1,1028 +0,0 @@ -/* - * drivers/mtd/nand/docg4.c - * - * Copyright (C) 2013 Mike Dunn <mikedunn@newsguy.com> - * - * SPDX-License-Identifier: GPL-2.0+ - * - * mtd nand driver for M-Systems DiskOnChip G4 - * - * Tested on the Palm Treo 680. The G4 is also present on Toshiba Portege, Asus - * P526, some HTC smartphones (Wizard, Prophet, ...), O2 XDA Zinc, maybe others. - * Should work on these as well. Let me know! - * - * TODO: - * - * Mechanism for management of password-protected areas - * - * Hamming ecc when reading oob only - * - * According to the M-Sys documentation, this device is also available in a - * "dual-die" configuration having a 256MB capacity, but no mechanism for - * detecting this variant is documented. Currently this driver assumes 128MB - * capacity. - * - * Support for multiple cascaded devices ("floors"). Not sure which gadgets - * contain multiple G4s in a cascaded configuration, if any. - */ - - -#include <common.h> -#include <asm/arch/hardware.h> -#include <asm/io.h> -#include <asm/bitops.h> -#include <asm/errno.h> -#include <malloc.h> -#include <nand.h> -#include <linux/bch.h> -#include <linux/bitrev.h> -#include <linux/mtd/docg4.h> - -/* - * The device has a nop register which M-Sys claims is for the purpose of - * inserting precise delays. But beware; at least some operations fail if the - * nop writes are replaced with a generic delay! - */ -static inline void write_nop(void __iomem *docptr) -{ - writew(0, docptr + DOC_NOP); -} - - -static int poll_status(void __iomem *docptr) -{ - /* - * Busy-wait for the FLASHREADY bit to be set in the FLASHCONTROL - * register. Operations known to take a long time (e.g., block erase) - * should sleep for a while before calling this. - */ - - uint8_t flash_status; - - /* hardware quirk requires reading twice initially */ - flash_status = readb(docptr + DOC_FLASHCONTROL); - - do { - flash_status = readb(docptr + DOC_FLASHCONTROL); - } while (!(flash_status & DOC_CTRL_FLASHREADY)); - - return 0; -} - -static void write_addr(void __iomem *docptr, uint32_t docg4_addr) -{ - /* write the four address bytes packed in docg4_addr to the device */ - - writeb(docg4_addr & 0xff, docptr + DOC_FLASHADDRESS); - docg4_addr >>= 8; - writeb(docg4_addr & 0xff, docptr + DOC_FLASHADDRESS); - docg4_addr >>= 8; - writeb(docg4_addr & 0xff, docptr + DOC_FLASHADDRESS); - docg4_addr >>= 8; - writeb(docg4_addr & 0xff, docptr + DOC_FLASHADDRESS); -} - -/* - * This is a module parameter in the linux kernel version of this driver. It is - * hard-coded to 'off' for u-boot. This driver uses oob to mark bad blocks. - * This can be problematic when dealing with data not intended for the mtd/nand - * subsystem. For example, on boards that boot from the docg4 and use the IPL - * to load an spl + u-boot image, the blocks containing the image will be - * reported as "bad" because the oob of the first page of each block contains a - * magic number that the IPL looks for, which causes the badblock scan to - * erroneously add them to the bad block table. To erase such a block, use - * u-boot's 'nand scrub'. scrub is safe for the docg4. The device does have a - * factory bad block table, but it is read-only, and is used in conjunction with - * oob bad block markers that are written by mtd/nand when a block is deemed to - * be bad. To read data from "bad" blocks, use 'read.raw'. Unfortunately, - * read.raw does not use ecc, which would still work fine on such misidentified - * bad blocks. TODO: u-boot nand utilities need the ability to ignore bad - * blocks. - */ -static const int ignore_badblocks; /* remains false */ - -struct docg4_priv { - int status; - struct { - unsigned int command; - int column; - int page; - } last_command; - uint8_t oob_buf[16]; - uint8_t ecc_buf[7]; - int oob_page; - struct bch_control *bch; -}; -/* - * Oob bytes 0 - 6 are available to the user. - * Byte 7 is hamming ecc for first 7 bytes. Bytes 8 - 14 are hw-generated ecc. - * Byte 15 (the last) is used by the driver as a "page written" flag. - */ -static struct nand_ecclayout docg4_oobinfo = { - .eccbytes = 9, - .eccpos = {7, 8, 9, 10, 11, 12, 13, 14, 15}, - .oobavail = 7, - .oobfree = { {0, 7} } -}; - -static void reset(void __iomem *docptr) -{ - /* full device reset */ - - writew(DOC_ASICMODE_RESET | DOC_ASICMODE_MDWREN, docptr + DOC_ASICMODE); - writew(~(DOC_ASICMODE_RESET | DOC_ASICMODE_MDWREN), - docptr + DOC_ASICMODECONFIRM); - write_nop(docptr); - - writew(DOC_ASICMODE_NORMAL | DOC_ASICMODE_MDWREN, - docptr + DOC_ASICMODE); - writew(~(DOC_ASICMODE_NORMAL | DOC_ASICMODE_MDWREN), - docptr + DOC_ASICMODECONFIRM); - - writew(DOC_ECCCONF1_ECC_ENABLE, docptr + DOC_ECCCONF1); - - poll_status(docptr); -} - -static void docg4_select_chip(struct mtd_info *mtd, int chip) -{ - /* - * Select among multiple cascaded chips ("floors"). Multiple floors are - * not yet supported, so the only valid non-negative value is 0. - */ - void __iomem *docptr = CONFIG_SYS_NAND_BASE; - - if (chip < 0) - return; /* deselected */ - - if (chip > 0) - printf("multiple floors currently unsupported\n"); - - writew(0, docptr + DOC_DEVICESELECT); -} - -static void read_hw_ecc(void __iomem *docptr, uint8_t *ecc_buf) -{ - /* read the 7 hw-generated ecc bytes */ - - int i; - for (i = 0; i < 7; i++) { /* hw quirk; read twice */ - ecc_buf[i] = readb(docptr + DOC_BCH_SYNDROM(i)); - ecc_buf[i] = readb(docptr + DOC_BCH_SYNDROM(i)); - } -} - -static int correct_data(struct mtd_info *mtd, uint8_t *buf, int page) -{ - /* - * Called after a page read when hardware reports bitflips. - * Up to four bitflips can be corrected. - */ - - struct nand_chip *nand = mtd->priv; - struct docg4_priv *doc = nand->priv; - void __iomem *docptr = CONFIG_SYS_NAND_BASE; - int i, numerrs; - unsigned int errpos[4]; - const uint8_t blank_read_hwecc[8] = { - 0xcf, 0x72, 0xfc, 0x1b, 0xa9, 0xc7, 0xb9, 0 }; - - read_hw_ecc(docptr, doc->ecc_buf); /* read 7 hw-generated ecc bytes */ - - /* check if read error is due to a blank page */ - if (!memcmp(doc->ecc_buf, blank_read_hwecc, 7)) - return 0; /* yes */ - - /* skip additional check of "written flag" if ignore_badblocks */ - if (!ignore_badblocks) { - /* - * If the hw ecc bytes are not those of a blank page, there's - * still a chance that the page is blank, but was read with - * errors. Check the "written flag" in last oob byte, which - * is set to zero when a page is written. If more than half - * the bits are set, assume a blank page. Unfortunately, the - * bit flips(s) are not reported in stats. - */ - - if (doc->oob_buf[15]) { - int bit, numsetbits = 0; - unsigned long written_flag = doc->oob_buf[15]; - - for (bit = 0; bit < 8; bit++) { - if (written_flag & 0x01) - numsetbits++; - written_flag >>= 1; - } - if (numsetbits > 4) { /* assume blank */ - printf("errors in blank page at offset %08x\n", - page * DOCG4_PAGE_SIZE); - return 0; - } - } - } - - /* - * The hardware ecc unit produces oob_ecc ^ calc_ecc. The kernel's bch - * algorithm is used to decode this. However the hw operates on page - * data in a bit order that is the reverse of that of the bch alg, - * requiring that the bits be reversed on the result. Thanks to Ivan - * Djelic for his analysis! - */ - for (i = 0; i < 7; i++) - doc->ecc_buf[i] = bitrev8(doc->ecc_buf[i]); - - numerrs = decode_bch(doc->bch, NULL, DOCG4_USERDATA_LEN, NULL, - doc->ecc_buf, NULL, errpos); - - if (numerrs == -EBADMSG) { - printf("uncorrectable errors at offset %08x\n", - page * DOCG4_PAGE_SIZE); - return -EBADMSG; - } - - BUG_ON(numerrs < 0); /* -EINVAL, or anything other than -EBADMSG */ - - /* undo last step in BCH alg (modulo mirroring not needed) */ - for (i = 0; i < numerrs; i++) - errpos[i] = (errpos[i] & ~7)|(7-(errpos[i] & 7)); - - /* fix the errors */ - for (i = 0; i < numerrs; i++) { - /* ignore if error within oob ecc bytes */ - if (errpos[i] > DOCG4_USERDATA_LEN * 8) - continue; - - /* if error within oob area preceeding ecc bytes... */ - if (errpos[i] > DOCG4_PAGE_SIZE * 8) - __change_bit(errpos[i] - DOCG4_PAGE_SIZE * 8, - (unsigned long *)doc->oob_buf); - - else /* error in page data */ - __change_bit(errpos[i], (unsigned long *)buf); - } - - printf("%d error(s) corrected at offset %08x\n", - numerrs, page * DOCG4_PAGE_SIZE); - - return numerrs; -} - -static int read_progstatus(struct docg4_priv *doc, void __iomem *docptr) -{ - /* - * This apparently checks the status of programming. Done after an - * erasure, and after page data is written. On error, the status is - * saved, to be later retrieved by the nand infrastructure code. - */ - - /* status is read from the I/O reg */ - uint16_t status1 = readw(docptr + DOC_IOSPACE_DATA); - uint16_t status2 = readw(docptr + DOC_IOSPACE_DATA); - uint16_t status3 = readw(docptr + DOCG4_MYSTERY_REG); - - MTDDEBUG(MTD_DEBUG_LEVEL3, "docg4: %s: %02x %02x %02x\n", - __func__, status1, status2, status3); - - if (status1 != DOCG4_PROGSTATUS_GOOD || - status2 != DOCG4_PROGSTATUS_GOOD_2 || - status3 != DOCG4_PROGSTATUS_GOOD_2) { - doc->status = NAND_STATUS_FAIL; - printf("read_progstatus failed: %02x, %02x, %02x\n", - status1, status2, status3); - return -EIO; - } - return 0; -} - -static int pageprog(struct mtd_info *mtd) -{ - /* - * Final step in writing a page. Writes the contents of its - * internal buffer out to the flash array, or some such. - */ - - struct nand_chip *nand = mtd->priv; - struct docg4_priv *doc = nand->priv; - void __iomem *docptr = CONFIG_SYS_NAND_BASE; - int retval = 0; - - MTDDEBUG(MTD_DEBUG_LEVEL3, "docg4: %s\n", __func__); - - writew(DOCG4_SEQ_PAGEPROG, docptr + DOC_FLASHSEQUENCE); - writew(DOC_CMD_PROG_CYCLE2, docptr + DOC_FLASHCOMMAND); - write_nop(docptr); - write_nop(docptr); - - /* Just busy-wait; usleep_range() slows things down noticeably. */ - poll_status(docptr); - - writew(DOCG4_SEQ_FLUSH, docptr + DOC_FLASHSEQUENCE); - writew(DOCG4_CMD_FLUSH, docptr + DOC_FLASHCOMMAND); - writew(DOC_ECCCONF0_READ_MODE | 4, docptr + DOC_ECCCONF0); - write_nop(docptr); - write_nop(docptr); - write_nop(docptr); - write_nop(docptr); - write_nop(docptr); - - retval = read_progstatus(doc, docptr); - writew(0, docptr + DOC_DATAEND); - write_nop(docptr); - poll_status(docptr); - write_nop(docptr); - - return retval; -} - -static void sequence_reset(void __iomem *docptr) -{ - /* common starting sequence for all operations */ - - writew(DOC_CTRL_UNKNOWN | DOC_CTRL_CE, docptr + DOC_FLASHCONTROL); - writew(DOC_SEQ_RESET, docptr + DOC_FLASHSEQUENCE); - writew(DOC_CMD_RESET, docptr + DOC_FLASHCOMMAND); - write_nop(docptr); - write_nop(docptr); - poll_status(docptr); - write_nop(docptr); -} - -static void read_page_prologue(void __iomem *docptr, uint32_t docg4_addr) -{ - /* first step in reading a page */ - - sequence_reset(docptr); - - writew(DOCG4_SEQ_PAGE_READ, docptr + DOC_FLASHSEQUENCE); - writew(DOCG4_CMD_PAGE_READ, docptr + DOC_FLASHCOMMAND); - write_nop(docptr); - - write_addr(docptr, docg4_addr); - - write_nop(docptr); - writew(DOCG4_CMD_READ2, docptr + DOC_FLASHCOMMAND); - write_nop(docptr); - write_nop(docptr); - - poll_status(docptr); -} - -static void write_page_prologue(void __iomem *docptr, uint32_t docg4_addr) -{ - /* first step in writing a page */ - - sequence_reset(docptr); - writew(DOCG4_SEQ_PAGEWRITE, docptr + DOC_FLASHSEQUENCE); - writew(DOCG4_CMD_PAGEWRITE, docptr + DOC_FLASHCOMMAND); - write_nop(docptr); - write_addr(docptr, docg4_addr); - write_nop(docptr); - write_nop(docptr); - poll_status(docptr); -} - -static uint32_t mtd_to_docg4_address(int page, int column) -{ - /* - * Convert mtd address to format used by the device, 32 bit packed. - * - * Some notes on G4 addressing... The M-Sys documentation on this device - * claims that pages are 2K in length, and indeed, the format of the - * address used by the device reflects that. But within each page are - * four 512 byte "sub-pages", each with its own oob data that is - * read/written immediately after the 512 bytes of page data. This oob - * data contains the ecc bytes for the preceeding 512 bytes. - * - * Rather than tell the mtd nand infrastructure that page size is 2k, - * with four sub-pages each, we engage in a little subterfuge and tell - * the infrastructure code that pages are 512 bytes in size. This is - * done because during the course of reverse-engineering the device, I - * never observed an instance where an entire 2K "page" was read or - * written as a unit. Each "sub-page" is always addressed individually, - * its data read/written, and ecc handled before the next "sub-page" is - * addressed. - * - * This requires us to convert addresses passed by the mtd nand - * infrastructure code to those used by the device. - * - * The address that is written to the device consists of four bytes: the - * first two are the 2k page number, and the second is the index into - * the page. The index is in terms of 16-bit half-words and includes - * the preceeding oob data, so e.g., the index into the second - * "sub-page" is 0x108, and the full device address of the start of mtd - * page 0x201 is 0x00800108. - */ - int g4_page = page / 4; /* device's 2K page */ - int g4_index = (page % 4) * 0x108 + column/2; /* offset into page */ - return (g4_page << 16) | g4_index; /* pack */ -} - -static void docg4_command(struct mtd_info *mtd, unsigned command, int column, - int page_addr) -{ - /* handle standard nand commands */ - - struct nand_chip *nand = mtd->priv; - struct docg4_priv *doc = nand->priv; - uint32_t g4_addr = mtd_to_docg4_address(page_addr, column); - - MTDDEBUG(MTD_DEBUG_LEVEL3, "%s %x, page_addr=%x, column=%x\n", - __func__, command, page_addr, column); - - /* - * Save the command and its arguments. This enables emulation of - * standard flash devices, and also some optimizations. - */ - doc->last_command.command = command; - doc->last_command.column = column; - doc->last_command.page = page_addr; - - switch (command) { - case NAND_CMD_RESET: - reset(CONFIG_SYS_NAND_BASE); - break; - - case NAND_CMD_READ0: - read_page_prologue(CONFIG_SYS_NAND_BASE, g4_addr); - break; - - case NAND_CMD_STATUS: - /* next call to read_byte() will expect a status */ - break; - - case NAND_CMD_SEQIN: - write_page_prologue(CONFIG_SYS_NAND_BASE, g4_addr); - - /* hack for deferred write of oob bytes */ - if (doc->oob_page == page_addr) - memcpy(nand->oob_poi, doc->oob_buf, 16); - break; - - case NAND_CMD_PAGEPROG: - pageprog(mtd); - break; - - /* we don't expect these, based on review of nand_base.c */ - case NAND_CMD_READOOB: - case NAND_CMD_READID: - case NAND_CMD_ERASE1: - case NAND_CMD_ERASE2: - printf("docg4_command: unexpected nand command 0x%x\n", - command); - break; - } -} - -static void docg4_read_buf(struct mtd_info *mtd, uint8_t *buf, int len) -{ - int i; - struct nand_chip *nand = mtd->priv; - uint16_t *p = (uint16_t *)buf; - len >>= 1; - - for (i = 0; i < len; i++) - p[i] = readw(nand->IO_ADDR_R); -} - -static int docg4_read_oob(struct mtd_info *mtd, struct nand_chip *nand, - int page) -{ - struct docg4_priv *doc = nand->priv; - void __iomem *docptr = CONFIG_SYS_NAND_BASE; - uint16_t status; - - MTDDEBUG(MTD_DEBUG_LEVEL3, "%s: page %x\n", __func__, page); - - /* - * Oob bytes are read as part of a normal page read. If the previous - * nand command was a read of the page whose oob is now being read, just - * copy the oob bytes that we saved in a local buffer and avoid a - * separate oob read. - */ - if (doc->last_command.command == NAND_CMD_READ0 && - doc->last_command.page == page) { - memcpy(nand->oob_poi, doc->oob_buf, 16); - return 0; - } - - /* - * Separate read of oob data only. - */ - docg4_command(mtd, NAND_CMD_READ0, nand->ecc.size, page); - - writew(DOC_ECCCONF0_READ_MODE | DOCG4_OOB_SIZE, docptr + DOC_ECCCONF0); - write_nop(docptr); - write_nop(docptr); - write_nop(docptr); - write_nop(docptr); - write_nop(docptr); - - /* the 1st byte from the I/O reg is a status; the rest is oob data */ - status = readw(docptr + DOC_IOSPACE_DATA); - if (status & DOCG4_READ_ERROR) { - printf("docg4_read_oob failed: status = 0x%02x\n", status); - return -EIO; - } - - MTDDEBUG(MTD_DEBUG_LEVEL3, "%s: status = 0x%x\n", __func__, status); - - docg4_read_buf(mtd, nand->oob_poi, 16); - - write_nop(docptr); - write_nop(docptr); - write_nop(docptr); - writew(0, docptr + DOC_DATAEND); - write_nop(docptr); - - return 0; -} - -static int docg4_write_oob(struct mtd_info *mtd, struct nand_chip *nand, - int page) -{ - /* - * Writing oob-only is not really supported, because MLC nand must write - * oob bytes at the same time as page data. Nonetheless, we save the - * oob buffer contents here, and then write it along with the page data - * if the same page is subsequently written. This allows user space - * utilities that write the oob data prior to the page data to work - * (e.g., nandwrite). The disdvantage is that, if the intention was to - * write oob only, the operation is quietly ignored. Also, oob can get - * corrupted if two concurrent processes are running nandwrite. - */ - - /* note that bytes 7..14 are hw generated hamming/ecc and overwritten */ - struct docg4_priv *doc = nand->priv; - doc->oob_page = page; - memcpy(doc->oob_buf, nand->oob_poi, 16); - return 0; -} - -static int docg4_block_neverbad(struct mtd_info *mtd, loff_t ofs, int getchip) -{ - /* only called when module_param ignore_badblocks is set */ - return 0; -} - -static void docg4_write_buf16(struct mtd_info *mtd, const uint8_t *buf, int len) -{ - int i; - struct nand_chip *nand = mtd->priv; - uint16_t *p = (uint16_t *)buf; - len >>= 1; - - for (i = 0; i < len; i++) - writew(p[i], nand->IO_ADDR_W); -} - -static int write_page(struct mtd_info *mtd, struct nand_chip *nand, - const uint8_t *buf, int use_ecc) -{ - void __iomem *docptr = CONFIG_SYS_NAND_BASE; - uint8_t ecc_buf[8]; - - writew(DOC_ECCCONF0_ECC_ENABLE | - DOC_ECCCONF0_UNKNOWN | - DOCG4_BCH_SIZE, - docptr + DOC_ECCCONF0); - write_nop(docptr); - - /* write the page data */ - docg4_write_buf16(mtd, buf, DOCG4_PAGE_SIZE); - - /* oob bytes 0 through 5 are written to I/O reg */ - docg4_write_buf16(mtd, nand->oob_poi, 6); - - /* oob byte 6 written to a separate reg */ - writew(nand->oob_poi[6], docptr + DOCG4_OOB_6_7); - - write_nop(docptr); - write_nop(docptr); - - /* write hw-generated ecc bytes to oob */ - if (likely(use_ecc)) { - /* oob byte 7 is hamming code */ - uint8_t hamming = readb(docptr + DOC_HAMMINGPARITY); - hamming = readb(docptr + DOC_HAMMINGPARITY); /* 2nd read */ - writew(hamming, docptr + DOCG4_OOB_6_7); - write_nop(docptr); - - /* read the 7 bch bytes from ecc regs */ - read_hw_ecc(docptr, ecc_buf); - ecc_buf[7] = 0; /* clear the "page written" flag */ - } - - /* write user-supplied bytes to oob */ - else { - writew(nand->oob_poi[7], docptr + DOCG4_OOB_6_7); - write_nop(docptr); - memcpy(ecc_buf, &nand->oob_poi[8], 8); - } - - docg4_write_buf16(mtd, ecc_buf, 8); - write_nop(docptr); - write_nop(docptr); - writew(0, docptr + DOC_DATAEND); - write_nop(docptr); - - return 0; -} - -static int docg4_write_page_raw(struct mtd_info *mtd, struct nand_chip *nand, - const uint8_t *buf, int oob_required) -{ - return write_page(mtd, nand, buf, 0); -} - -static int docg4_write_page(struct mtd_info *mtd, struct nand_chip *nand, - const uint8_t *buf, int oob_required) -{ - return write_page(mtd, nand, buf, 1); -} - -static int read_page(struct mtd_info *mtd, struct nand_chip *nand, - uint8_t *buf, int page, int use_ecc) -{ - struct docg4_priv *doc = nand->priv; - void __iomem *docptr = CONFIG_SYS_NAND_BASE; - uint16_t status, edc_err, *buf16; - - writew(DOC_ECCCONF0_READ_MODE | - DOC_ECCCONF0_ECC_ENABLE | - DOC_ECCCONF0_UNKNOWN | - DOCG4_BCH_SIZE, - docptr + DOC_ECCCONF0); - write_nop(docptr); - write_nop(docptr); - write_nop(docptr); - write_nop(docptr); - write_nop(docptr); - - /* the 1st byte from the I/O reg is a status; the rest is page data */ - status = readw(docptr + DOC_IOSPACE_DATA); - if (status & DOCG4_READ_ERROR) { - printf("docg4_read_page: bad status: 0x%02x\n", status); - writew(0, docptr + DOC_DATAEND); - return -EIO; - } - - docg4_read_buf(mtd, buf, DOCG4_PAGE_SIZE); /* read the page data */ - - /* first 14 oob bytes read from I/O reg */ - docg4_read_buf(mtd, nand->oob_poi, 14); - - /* last 2 read from another reg */ - buf16 = (uint16_t *)(nand->oob_poi + 14); - *buf16 = readw(docptr + DOCG4_MYSTERY_REG); - - /* - * Diskonchips read oob immediately after a page read. Mtd - * infrastructure issues a separate command for reading oob after the - * page is read. So we save the oob bytes in a local buffer and just - * copy it if the next command reads oob from the same page. - */ - memcpy(doc->oob_buf, nand->oob_poi, 16); - - write_nop(docptr); - - if (likely(use_ecc)) { - /* read the register that tells us if bitflip(s) detected */ - edc_err = readw(docptr + DOC_ECCCONF1); - edc_err = readw(docptr + DOC_ECCCONF1); - - /* If bitflips are reported, attempt to correct with ecc */ - if (edc_err & DOC_ECCCONF1_BCH_SYNDROM_ERR) { - int bits_corrected = correct_data(mtd, buf, page); - if (bits_corrected == -EBADMSG) - mtd->ecc_stats.failed++; - else - mtd->ecc_stats.corrected += bits_corrected; - } - } - - writew(0, docptr + DOC_DATAEND); - return 0; -} - - -static int docg4_read_page_raw(struct mtd_info *mtd, struct nand_chip *nand, - uint8_t *buf, int oob_required, int page) -{ - return read_page(mtd, nand, buf, page, 0); -} - -static int docg4_read_page(struct mtd_info *mtd, struct nand_chip *nand, - uint8_t *buf, int oob_required, int page) -{ - return read_page(mtd, nand, buf, page, 1); -} - -static void docg4_erase_block(struct mtd_info *mtd, int page) -{ - struct nand_chip *nand = mtd->priv; - struct docg4_priv *doc = nand->priv; - void __iomem *docptr = CONFIG_SYS_NAND_BASE; - uint16_t g4_page; - - MTDDEBUG(MTD_DEBUG_LEVEL3, "%s: page %04x\n", __func__, page); - - sequence_reset(docptr); - - writew(DOCG4_SEQ_BLOCKERASE, docptr + DOC_FLASHSEQUENCE); - writew(DOC_CMD_PROG_BLOCK_ADDR, docptr + DOC_FLASHCOMMAND); - write_nop(docptr); - - /* only 2 bytes of address are written to specify erase block */ - g4_page = (uint16_t)(page / 4); /* to g4's 2k page addressing */ - writeb(g4_page & 0xff, docptr + DOC_FLASHADDRESS); - g4_page >>= 8; - writeb(g4_page & 0xff, docptr + DOC_FLASHADDRESS); - write_nop(docptr); - - /* start the erasure */ - writew(DOC_CMD_ERASECYCLE2, docptr + DOC_FLASHCOMMAND); - write_nop(docptr); - write_nop(docptr); - - poll_status(docptr); - writew(DOCG4_SEQ_FLUSH, docptr + DOC_FLASHSEQUENCE); - writew(DOCG4_CMD_FLUSH, docptr + DOC_FLASHCOMMAND); - writew(DOC_ECCCONF0_READ_MODE | 4, docptr + DOC_ECCCONF0); - write_nop(docptr); - write_nop(docptr); - write_nop(docptr); - write_nop(docptr); - write_nop(docptr); - - read_progstatus(doc, docptr); - - writew(0, docptr + DOC_DATAEND); - write_nop(docptr); - poll_status(docptr); - write_nop(docptr); -} - -static int read_factory_bbt(struct mtd_info *mtd) -{ - /* - * The device contains a read-only factory bad block table. Read it and - * update the memory-based bbt accordingly. - */ - - struct nand_chip *nand = mtd->priv; - uint32_t g4_addr = mtd_to_docg4_address(DOCG4_FACTORY_BBT_PAGE, 0); - uint8_t *buf; - int i, block, status; - - buf = kzalloc(DOCG4_PAGE_SIZE, GFP_KERNEL); - if (buf == NULL) - return -ENOMEM; - - read_page_prologue(CONFIG_SYS_NAND_BASE, g4_addr); - status = docg4_read_page(mtd, nand, buf, 0, DOCG4_FACTORY_BBT_PAGE); - if (status) - goto exit; - - /* - * If no memory-based bbt was created, exit. This will happen if module - * parameter ignore_badblocks is set. Then why even call this function? - * For an unknown reason, block erase always fails if it's the first - * operation after device power-up. The above read ensures it never is. - * Ugly, I know. - */ - if (nand->bbt == NULL) /* no memory-based bbt */ - goto exit; - - /* - * Parse factory bbt and update memory-based bbt. Factory bbt format is - * simple: one bit per block, block numbers increase left to right (msb - * to lsb). Bit clear means bad block. - */ - for (i = block = 0; block < DOCG4_NUMBLOCKS; block += 8, i++) { - int bitnum; - uint8_t mask; - for (bitnum = 0, mask = 0x80; - bitnum < 8; bitnum++, mask >>= 1) { - if (!(buf[i] & mask)) { - int badblock = block + bitnum; - nand->bbt[badblock / 4] |= - 0x03 << ((badblock % 4) * 2); - mtd->ecc_stats.badblocks++; - printf("factory-marked bad block: %d\n", - badblock); - } - } - } - exit: - kfree(buf); - return status; -} - -static int docg4_block_markbad(struct mtd_info *mtd, loff_t ofs) -{ - /* - * Mark a block as bad. Bad blocks are marked in the oob area of the - * first page of the block. The default scan_bbt() in the nand - * infrastructure code works fine for building the memory-based bbt - * during initialization, as does the nand infrastructure function that - * checks if a block is bad by reading the bbt. This function replaces - * the nand default because writes to oob-only are not supported. - */ - - int ret, i; - uint8_t *buf; - struct nand_chip *nand = mtd->priv; - struct nand_bbt_descr *bbtd = nand->badblock_pattern; - int block = (int)(ofs >> nand->bbt_erase_shift); - int page = (int)(ofs >> nand->page_shift); - uint32_t g4_addr = mtd_to_docg4_address(page, 0); - - MTDDEBUG(MTD_DEBUG_LEVEL3, "%s: %08llx\n", __func__, ofs); - - if (unlikely(ofs & (DOCG4_BLOCK_SIZE - 1))) - printf("%s: ofs %llx not start of block!\n", - __func__, ofs); - - /* allocate blank buffer for page data */ - buf = kzalloc(DOCG4_PAGE_SIZE, GFP_KERNEL); - if (buf == NULL) - return -ENOMEM; - - /* update bbt in memory */ - nand->bbt[block / 4] |= 0x01 << ((block & 0x03) * 2); - - /* write bit-wise negation of pattern to oob buffer */ - memset(nand->oob_poi, 0xff, mtd->oobsize); - for (i = 0; i < bbtd->len; i++) - nand->oob_poi[bbtd->offs + i] = ~bbtd->pattern[i]; - - /* write first page of block */ - write_page_prologue(CONFIG_SYS_NAND_BASE, g4_addr); - docg4_write_page(mtd, nand, buf, 1); - ret = pageprog(mtd); - if (!ret) - mtd->ecc_stats.badblocks++; - - kfree(buf); - - return ret; -} - -static uint8_t docg4_read_byte(struct mtd_info *mtd) -{ - struct nand_chip *nand = mtd->priv; - struct docg4_priv *doc = nand->priv; - - MTDDEBUG(MTD_DEBUG_LEVEL3, "%s\n", __func__); - - if (doc->last_command.command == NAND_CMD_STATUS) { - int status; - - /* - * Previous nand command was status request, so nand - * infrastructure code expects to read the status here. If an - * error occurred in a previous operation, report it. - */ - doc->last_command.command = 0; - - if (doc->status) { - status = doc->status; - doc->status = 0; - } - - /* why is NAND_STATUS_WP inverse logic?? */ - else - status = NAND_STATUS_WP | NAND_STATUS_READY; - - return status; - } - - printf("unexpectd call to read_byte()\n"); - - return 0; -} - -static int docg4_wait(struct mtd_info *mtd, struct nand_chip *nand) -{ - struct docg4_priv *doc = nand->priv; - int status = NAND_STATUS_WP; /* inverse logic?? */ - MTDDEBUG(MTD_DEBUG_LEVEL3, "%s...\n", __func__); - - /* report any previously unreported error */ - if (doc->status) { - status |= doc->status; - doc->status = 0; - return status; - } - - status |= poll_status(CONFIG_SYS_NAND_BASE); - return status; -} - -int docg4_nand_init(struct mtd_info *mtd, struct nand_chip *nand, int devnum) -{ - uint16_t id1, id2; - struct docg4_priv *docg4; - int retval; - - docg4 = kzalloc(sizeof(*docg4), GFP_KERNEL); - if (!docg4) - return -1; - - mtd->priv = nand; - nand->priv = docg4; - - /* These must be initialized here because the docg4 is non-standard - * and doesn't produce an id that the nand code can use to look up - * these values (nand_scan_ident() not called). - */ - mtd->size = DOCG4_CHIP_SIZE; - mtd->name = "Msys_Diskonchip_G4"; - mtd->writesize = DOCG4_PAGE_SIZE; - mtd->erasesize = DOCG4_BLOCK_SIZE; - mtd->oobsize = DOCG4_OOB_SIZE; - - nand->IO_ADDR_R = - (void __iomem *)CONFIG_SYS_NAND_BASE + DOC_IOSPACE_DATA; - nand->IO_ADDR_W = nand->IO_ADDR_R; - nand->chipsize = DOCG4_CHIP_SIZE; - nand->chip_shift = DOCG4_CHIP_SHIFT; - nand->bbt_erase_shift = DOCG4_ERASE_SHIFT; - nand->phys_erase_shift = DOCG4_ERASE_SHIFT; - nand->chip_delay = 20; - nand->page_shift = DOCG4_PAGE_SHIFT; - nand->pagemask = 0x3ffff; - nand->badblockpos = NAND_LARGE_BADBLOCK_POS; - nand->badblockbits = 8; - nand->ecc.layout = &docg4_oobinfo; - nand->ecc.mode = NAND_ECC_HW_SYNDROME; - nand->ecc.size = DOCG4_PAGE_SIZE; - nand->ecc.prepad = 8; - nand->ecc.bytes = 8; - nand->ecc.strength = DOCG4_T; - nand->options = NAND_BUSWIDTH_16 | NAND_NO_SUBPAGE_WRITE; - nand->controller = &nand->hwcontrol; - - /* methods */ - nand->cmdfunc = docg4_command; - nand->waitfunc = docg4_wait; - nand->select_chip = docg4_select_chip; - nand->read_byte = docg4_read_byte; - 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; - nand->ecc.read_page_raw = docg4_read_page_raw; - nand->ecc.write_page_raw = docg4_write_page_raw; - nand->ecc.read_oob = docg4_read_oob; - nand->ecc.write_oob = docg4_write_oob; - - /* - * The way the nand infrastructure code is written, a memory-based bbt - * is not created if NAND_SKIP_BBTSCAN is set. With no memory bbt, - * nand->block_bad() is used. So when ignoring bad blocks, we skip the - * scan and define a dummy block_bad() which always returns 0. - */ - if (ignore_badblocks) { - nand->options |= NAND_SKIP_BBTSCAN; - nand->block_bad = docg4_block_neverbad; - } - - reset(CONFIG_SYS_NAND_BASE); - - /* check for presence of g4 chip by reading id registers */ - id1 = readw(CONFIG_SYS_NAND_BASE + DOC_CHIPID); - id1 = readw(CONFIG_SYS_NAND_BASE + DOCG4_MYSTERY_REG); - id2 = readw(CONFIG_SYS_NAND_BASE + DOC_CHIPID_INV); - id2 = readw(CONFIG_SYS_NAND_BASE + DOCG4_MYSTERY_REG); - if (id1 != DOCG4_IDREG1_VALUE || id2 != DOCG4_IDREG2_VALUE) - return -1; - - /* initialize bch algorithm */ - docg4->bch = init_bch(DOCG4_M, DOCG4_T, DOCG4_PRIMITIVE_POLY); - if (docg4->bch == NULL) - return -1; - - retval = nand_scan_tail(mtd); - if (retval) - return -1; - - /* - * Scan for bad blocks and create bbt here, then add the factory-marked - * bad blocks to the bbt. - */ - nand->scan_bbt(mtd); - nand->options |= NAND_BBT_SCANNED; - retval = read_factory_bbt(mtd); - if (retval) - return -1; - - retval = nand_register(devnum); - if (retval) - return -1; - - return 0; -} diff --git a/qemu/roms/u-boot/drivers/mtd/nand/docg4_spl.c b/qemu/roms/u-boot/drivers/mtd/nand/docg4_spl.c deleted file mode 100644 index 351b75a09..000000000 --- a/qemu/roms/u-boot/drivers/mtd/nand/docg4_spl.c +++ /dev/null @@ -1,219 +0,0 @@ -/* - * SPL driver for Diskonchip G4 nand flash - * - * Copyright (C) 2013 Mike Dunn <mikedunn@newsguy.com> - * - * SPDX-License-Identifier: GPL-2.0+ - * - * This driver basically mimics the load functionality of a typical IPL (initial - * program loader) resident in the 2k NOR-like region of the docg4 that is - * mapped to the reset vector. It allows the u-boot SPL to continue loading if - * the IPL loads a fixed number of flash blocks that is insufficient to contain - * the entire u-boot image. In this case, a concatenated spl + u-boot image is - * written at the flash offset from which the IPL loads an image, and when the - * IPL jumps to the SPL, the SPL resumes loading where the IPL left off. See - * the palmtreo680 for an example. - * - * This driver assumes that the data was written to the flash using the device's - * "reliable" mode, and also assumes that each 512 byte page is stored - * redundantly in the subsequent page. This storage format is likely to be used - * by all boards that boot from the docg4. The format compensates for the lack - * of ecc in the IPL. - * - * Reliable mode reduces the capacity of a block by half, and the redundant - * pages reduce it by half again. As a result, the normal 256k capacity of a - * block is reduced to 64k for the purposes of the IPL/SPL. - */ - -#include <asm/io.h> -#include <linux/mtd/docg4.h> - -/* forward declarations */ -static inline void write_nop(void __iomem *docptr); -static int poll_status(void __iomem *docptr); -static void write_addr(void __iomem *docptr, uint32_t docg4_addr); -static void address_sequence(unsigned int g4_page, unsigned int g4_index, - void __iomem *docptr); -static int docg4_load_block_reliable(uint32_t flash_offset, void *dest_addr); - -int nand_spl_load_image(uint32_t offs, unsigned int size, void *dst) -{ - void *load_addr = dst; - uint32_t flash_offset = offs; - const unsigned int block_count = - (size + DOCG4_BLOCK_CAPACITY_SPL - 1) - / DOCG4_BLOCK_CAPACITY_SPL; - int i; - - for (i = 0; i < block_count; i++) { - int ret = docg4_load_block_reliable(flash_offset, load_addr); - if (ret) - return ret; - load_addr += DOCG4_BLOCK_CAPACITY_SPL; - flash_offset += DOCG4_BLOCK_SIZE; - } - return 0; -} - -static inline void write_nop(void __iomem *docptr) -{ - writew(0, docptr + DOC_NOP); -} - -static int poll_status(void __iomem *docptr) -{ - /* - * Busy-wait for the FLASHREADY bit to be set in the FLASHCONTROL - * register. Operations known to take a long time (e.g., block erase) - * should sleep for a while before calling this. - */ - - uint8_t flash_status; - - /* hardware quirk requires reading twice initially */ - flash_status = readb(docptr + DOC_FLASHCONTROL); - - do { - flash_status = readb(docptr + DOC_FLASHCONTROL); - } while (!(flash_status & DOC_CTRL_FLASHREADY)); - - return 0; -} - -static void write_addr(void __iomem *docptr, uint32_t docg4_addr) -{ - /* write the four address bytes packed in docg4_addr to the device */ - - writeb(docg4_addr & 0xff, docptr + DOC_FLASHADDRESS); - docg4_addr >>= 8; - writeb(docg4_addr & 0xff, docptr + DOC_FLASHADDRESS); - docg4_addr >>= 8; - writeb(docg4_addr & 0xff, docptr + DOC_FLASHADDRESS); - docg4_addr >>= 8; - writeb(docg4_addr & 0xff, docptr + DOC_FLASHADDRESS); -} - -static void address_sequence(unsigned int g4_page, unsigned int g4_index, - void __iomem *docptr) -{ - writew(DOCG4_SEQ_PAGE_READ, docptr + DOC_FLASHSEQUENCE); - writew(DOCG4_CMD_PAGE_READ, docptr + DOC_FLASHCOMMAND); - write_nop(docptr); - write_addr(docptr, ((uint32_t)g4_page << 16) | g4_index); - write_nop(docptr); -} - -static int docg4_load_block_reliable(uint32_t flash_offset, void *dest_addr) -{ - void __iomem *docptr = (void *)CONFIG_SYS_NAND_BASE; - unsigned int g4_page = flash_offset >> 11; /* 2k page */ - const unsigned int last_g4_page = g4_page + 0x80; /* last in block */ - int g4_index = 0; - uint16_t flash_status; - uint16_t *buf; - - /* flash_offset must be aligned to the start of a block */ - if (flash_offset & 0x3ffff) - return -1; - - writew(DOC_SEQ_RESET, docptr + DOC_FLASHSEQUENCE); - writew(DOC_CMD_RESET, docptr + DOC_FLASHCOMMAND); - write_nop(docptr); - write_nop(docptr); - poll_status(docptr); - write_nop(docptr); - writew(0x45, docptr + DOC_FLASHSEQUENCE); - writew(0xa3, docptr + DOC_FLASHCOMMAND); - write_nop(docptr); - writew(0x22, docptr + DOC_FLASHCOMMAND); - write_nop(docptr); - - /* read 1st 4 oob bytes of first subpage of block */ - address_sequence(g4_page, 0x0100, docptr); /* index at oob */ - write_nop(docptr); - flash_status = readw(docptr + DOC_FLASHCONTROL); - flash_status = readw(docptr + DOC_FLASHCONTROL); - if (flash_status & 0x06) /* sequence or protection errors */ - return -1; - writew(DOCG4_CMD_READ2, docptr + DOC_FLASHCOMMAND); - write_nop(docptr); - write_nop(docptr); - poll_status(docptr); - writew(DOC_ECCCONF0_READ_MODE | 4, docptr + DOC_ECCCONF0); - write_nop(docptr); - write_nop(docptr); - write_nop(docptr); - write_nop(docptr); - write_nop(docptr); - - /* - * Here we read the first four oob bytes of the first page of the block. - * The IPL on the palmtreo680 requires that this contain a 32 bit magic - * number, or the load aborts. We'll ignore it. - */ - readw(docptr + 0x103c); /* hw quirk; 1st read discarded */ - readw(docptr + 0x103c); /* lower 16 bits of magic number */ - readw(docptr + DOCG4_MYSTERY_REG); /* upper 16 bits of magic number */ - writew(0, docptr + DOC_DATAEND); - write_nop(docptr); - write_nop(docptr); - - /* load contents of block to memory */ - buf = (uint16_t *)dest_addr; - do { - int i; - - address_sequence(g4_page, g4_index, docptr); - writew(DOCG4_CMD_READ2, - docptr + DOC_FLASHCOMMAND); - write_nop(docptr); - write_nop(docptr); - poll_status(docptr); - writew(DOC_ECCCONF0_READ_MODE | - DOC_ECCCONF0_ECC_ENABLE | - DOCG4_BCH_SIZE, - docptr + DOC_ECCCONF0); - write_nop(docptr); - write_nop(docptr); - write_nop(docptr); - write_nop(docptr); - write_nop(docptr); - - /* read the 512 bytes of page data, 2 bytes at a time */ - readw(docptr + 0x103c); /* hw quirk */ - for (i = 0; i < 256; i++) - *buf++ = readw(docptr + 0x103c); - - /* read oob, but discard it */ - for (i = 0; i < 7; i++) - readw(docptr + 0x103c); - readw(docptr + DOCG4_OOB_6_7); - readw(docptr + DOCG4_OOB_6_7); - - writew(0, docptr + DOC_DATAEND); - write_nop(docptr); - write_nop(docptr); - - if (!(g4_index & 0x100)) { - /* not redundant subpage read; check for ecc error */ - write_nop(docptr); - flash_status = readw(docptr + DOC_ECCCONF1); - flash_status = readw(docptr + DOC_ECCCONF1); - if (flash_status & 0x80) { /* ecc error */ - g4_index += 0x108; /* read redundant subpage */ - buf -= 256; /* back up ram ptr */ - continue; - } else /* no ecc error */ - g4_index += 0x210; /* skip redundant subpage */ - } else /* redundant page was just read; skip ecc error check */ - g4_index += 0x108; - - if (g4_index == 0x420) { /* finished with 2k page */ - g4_index = 0; - g4_page += 2; /* odd-numbered 2k pages skipped */ - } - - } while (g4_page != last_g4_page); /* while still on same block */ - - return 0; -} diff --git a/qemu/roms/u-boot/drivers/mtd/nand/fsl_elbc_nand.c b/qemu/roms/u-boot/drivers/mtd/nand/fsl_elbc_nand.c deleted file mode 100644 index 2f31fc96a..000000000 --- a/qemu/roms/u-boot/drivers/mtd/nand/fsl_elbc_nand.c +++ /dev/null @@ -1,829 +0,0 @@ -/* Freescale Enhanced Local Bus Controller FCM NAND driver - * - * Copyright (c) 2006-2008 Freescale Semiconductor - * - * Authors: Nick Spence <nick.spence@freescale.com>, - * Scott Wood <scottwood@freescale.com> - * - * SPDX-License-Identifier: GPL-2.0+ - */ - -#include <common.h> -#include <malloc.h> -#include <nand.h> - -#include <linux/mtd/mtd.h> -#include <linux/mtd/nand.h> -#include <linux/mtd/nand_ecc.h> - -#include <asm/io.h> -#include <asm/errno.h> - -#ifdef VERBOSE_DEBUG -#define DEBUG_ELBC -#define vdbg(format, arg...) printf("DEBUG: " format, ##arg) -#else -#define vdbg(format, arg...) do {} while (0) -#endif - -/* Can't use plain old DEBUG because the linux mtd - * headers define it as a macro. - */ -#ifdef DEBUG_ELBC -#define dbg(format, arg...) printf("DEBUG: " format, ##arg) -#else -#define dbg(format, arg...) do {} while (0) -#endif - -#define MAX_BANKS 8 -#define ERR_BYTE 0xFF /* Value returned for read bytes when read failed */ -#define FCM_TIMEOUT_MSECS 10 /* Maximum number of mSecs to wait for FCM */ - -#define LTESR_NAND_MASK (LTESR_FCT | LTESR_PAR | LTESR_CC) - -struct fsl_elbc_ctrl; - -/* mtd information per set */ - -struct fsl_elbc_mtd { - struct nand_chip chip; - struct fsl_elbc_ctrl *ctrl; - - struct device *dev; - int bank; /* Chip select bank number */ - u8 __iomem *vbase; /* Chip select base virtual address */ - int page_size; /* NAND page size (0=512, 1=2048) */ - unsigned int fmr; /* FCM Flash Mode Register value */ -}; - -/* overview of the fsl elbc controller */ - -struct fsl_elbc_ctrl { - struct nand_hw_control controller; - struct fsl_elbc_mtd *chips[MAX_BANKS]; - - /* device info */ - fsl_lbc_t *regs; - u8 __iomem *addr; /* Address of assigned FCM buffer */ - unsigned int page; /* Last page written to / read from */ - unsigned int read_bytes; /* Number of bytes read during command */ - unsigned int column; /* Saved column from SEQIN */ - unsigned int index; /* Pointer to next byte to 'read' */ - unsigned int status; /* status read from LTESR after last op */ - unsigned int mdr; /* UPM/FCM Data Register value */ - unsigned int use_mdr; /* Non zero if the MDR is to be set */ - unsigned int oob; /* Non zero if operating on OOB data */ -}; - -/* These map to the positions used by the FCM hardware ECC generator */ - -/* Small Page FLASH with FMR[ECCM] = 0 */ -static struct nand_ecclayout fsl_elbc_oob_sp_eccm0 = { - .eccbytes = 3, - .eccpos = {6, 7, 8}, - .oobfree = { {0, 5}, {9, 7} }, -}; - -/* Small Page FLASH with FMR[ECCM] = 1 */ -static struct nand_ecclayout fsl_elbc_oob_sp_eccm1 = { - .eccbytes = 3, - .eccpos = {8, 9, 10}, - .oobfree = { {0, 5}, {6, 2}, {11, 5} }, -}; - -/* Large Page FLASH with FMR[ECCM] = 0 */ -static struct nand_ecclayout fsl_elbc_oob_lp_eccm0 = { - .eccbytes = 12, - .eccpos = {6, 7, 8, 22, 23, 24, 38, 39, 40, 54, 55, 56}, - .oobfree = { {1, 5}, {9, 13}, {25, 13}, {41, 13}, {57, 7} }, -}; - -/* Large Page FLASH with FMR[ECCM] = 1 */ -static struct nand_ecclayout fsl_elbc_oob_lp_eccm1 = { - .eccbytes = 12, - .eccpos = {8, 9, 10, 24, 25, 26, 40, 41, 42, 56, 57, 58}, - .oobfree = { {1, 7}, {11, 13}, {27, 13}, {43, 13}, {59, 5} }, -}; - -/* - * fsl_elbc_oob_lp_eccm* specify that LP NAND's OOB free area starts at offset - * 1, so we have to adjust bad block pattern. This pattern should be used for - * x8 chips only. So far hardware does not support x16 chips anyway. - */ -static u8 scan_ff_pattern[] = { 0xff, }; - -static struct nand_bbt_descr largepage_memorybased = { - .options = 0, - .offs = 0, - .len = 1, - .pattern = scan_ff_pattern, -}; - -/* - * ELBC may use HW ECC, so that OOB offsets, that NAND core uses for bbt, - * interfere with ECC positions, that's why we implement our own descriptors. - * OOB {11, 5}, works for both SP and LP chips, with ECCM = 1 and ECCM = 0. - */ -static u8 bbt_pattern[] = {'B', 'b', 't', '0' }; -static u8 mirror_pattern[] = {'1', 't', 'b', 'B' }; - -static struct nand_bbt_descr bbt_main_descr = { - .options = NAND_BBT_LASTBLOCK | NAND_BBT_CREATE | NAND_BBT_WRITE | - NAND_BBT_2BIT | NAND_BBT_VERSION, - .offs = 11, - .len = 4, - .veroffs = 15, - .maxblocks = 4, - .pattern = bbt_pattern, -}; - -static struct nand_bbt_descr bbt_mirror_descr = { - .options = NAND_BBT_LASTBLOCK | NAND_BBT_CREATE | NAND_BBT_WRITE | - NAND_BBT_2BIT | NAND_BBT_VERSION, - .offs = 11, - .len = 4, - .veroffs = 15, - .maxblocks = 4, - .pattern = mirror_pattern, -}; - -/*=================================*/ - -/* - * Set up the FCM hardware block and page address fields, and the fcm - * structure addr field to point to the correct FCM buffer in memory - */ -static void set_addr(struct mtd_info *mtd, int column, int page_addr, int oob) -{ - struct nand_chip *chip = mtd->priv; - struct fsl_elbc_mtd *priv = chip->priv; - struct fsl_elbc_ctrl *ctrl = priv->ctrl; - fsl_lbc_t *lbc = ctrl->regs; - int buf_num; - - ctrl->page = page_addr; - - if (priv->page_size) { - out_be32(&lbc->fbar, page_addr >> 6); - out_be32(&lbc->fpar, - ((page_addr << FPAR_LP_PI_SHIFT) & FPAR_LP_PI) | - (oob ? FPAR_LP_MS : 0) | column); - buf_num = (page_addr & 1) << 2; - } else { - out_be32(&lbc->fbar, page_addr >> 5); - out_be32(&lbc->fpar, - ((page_addr << FPAR_SP_PI_SHIFT) & FPAR_SP_PI) | - (oob ? FPAR_SP_MS : 0) | column); - buf_num = page_addr & 7; - } - - ctrl->addr = priv->vbase + buf_num * 1024; - ctrl->index = column; - - /* for OOB data point to the second half of the buffer */ - if (oob) - ctrl->index += priv->page_size ? 2048 : 512; - - vdbg("set_addr: bank=%d, ctrl->addr=0x%p (0x%p), " - "index %x, pes %d ps %d\n", - buf_num, ctrl->addr, priv->vbase, ctrl->index, - chip->phys_erase_shift, chip->page_shift); -} - -/* - * execute FCM command and wait for it to complete - */ -static int fsl_elbc_run_command(struct mtd_info *mtd) -{ - struct nand_chip *chip = mtd->priv; - struct fsl_elbc_mtd *priv = chip->priv; - struct fsl_elbc_ctrl *ctrl = priv->ctrl; - fsl_lbc_t *lbc = ctrl->regs; - long long end_tick; - u32 ltesr; - - /* Setup the FMR[OP] to execute without write protection */ - out_be32(&lbc->fmr, priv->fmr | 3); - if (ctrl->use_mdr) - out_be32(&lbc->mdr, ctrl->mdr); - - vdbg("fsl_elbc_run_command: fmr=%08x fir=%08x fcr=%08x\n", - in_be32(&lbc->fmr), in_be32(&lbc->fir), in_be32(&lbc->fcr)); - vdbg("fsl_elbc_run_command: fbar=%08x fpar=%08x " - "fbcr=%08x bank=%d\n", - in_be32(&lbc->fbar), in_be32(&lbc->fpar), - in_be32(&lbc->fbcr), priv->bank); - - /* execute special operation */ - out_be32(&lbc->lsor, priv->bank); - - /* wait for FCM complete flag or timeout */ - end_tick = usec2ticks(FCM_TIMEOUT_MSECS * 1000) + get_ticks(); - - ltesr = 0; - while (end_tick > get_ticks()) { - ltesr = in_be32(&lbc->ltesr); - if (ltesr & LTESR_CC) - break; - } - - ctrl->status = ltesr & LTESR_NAND_MASK; - out_be32(&lbc->ltesr, ctrl->status); - out_be32(&lbc->lteatr, 0); - - /* store mdr value in case it was needed */ - if (ctrl->use_mdr) - ctrl->mdr = in_be32(&lbc->mdr); - - ctrl->use_mdr = 0; - - vdbg("fsl_elbc_run_command: stat=%08x mdr=%08x fmr=%08x\n", - ctrl->status, ctrl->mdr, in_be32(&lbc->fmr)); - - /* returns 0 on success otherwise non-zero) */ - return ctrl->status == LTESR_CC ? 0 : -EIO; -} - -static void fsl_elbc_do_read(struct nand_chip *chip, int oob) -{ - struct fsl_elbc_mtd *priv = chip->priv; - struct fsl_elbc_ctrl *ctrl = priv->ctrl; - fsl_lbc_t *lbc = ctrl->regs; - - if (priv->page_size) { - out_be32(&lbc->fir, - (FIR_OP_CW0 << FIR_OP0_SHIFT) | - (FIR_OP_CA << FIR_OP1_SHIFT) | - (FIR_OP_PA << FIR_OP2_SHIFT) | - (FIR_OP_CW1 << FIR_OP3_SHIFT) | - (FIR_OP_RBW << FIR_OP4_SHIFT)); - - out_be32(&lbc->fcr, (NAND_CMD_READ0 << FCR_CMD0_SHIFT) | - (NAND_CMD_READSTART << FCR_CMD1_SHIFT)); - } else { - out_be32(&lbc->fir, - (FIR_OP_CW0 << FIR_OP0_SHIFT) | - (FIR_OP_CA << FIR_OP1_SHIFT) | - (FIR_OP_PA << FIR_OP2_SHIFT) | - (FIR_OP_RBW << FIR_OP3_SHIFT)); - - if (oob) - out_be32(&lbc->fcr, - NAND_CMD_READOOB << FCR_CMD0_SHIFT); - else - out_be32(&lbc->fcr, NAND_CMD_READ0 << FCR_CMD0_SHIFT); - } -} - -/* cmdfunc send commands to the FCM */ -static void fsl_elbc_cmdfunc(struct mtd_info *mtd, unsigned int command, - int column, int page_addr) -{ - struct nand_chip *chip = mtd->priv; - struct fsl_elbc_mtd *priv = chip->priv; - struct fsl_elbc_ctrl *ctrl = priv->ctrl; - fsl_lbc_t *lbc = ctrl->regs; - - ctrl->use_mdr = 0; - - /* clear the read buffer */ - ctrl->read_bytes = 0; - if (command != NAND_CMD_PAGEPROG) - ctrl->index = 0; - - switch (command) { - /* READ0 and READ1 read the entire buffer to use hardware ECC. */ - case NAND_CMD_READ1: - column += 256; - - /* fall-through */ - case NAND_CMD_READ0: - vdbg("fsl_elbc_cmdfunc: NAND_CMD_READ0, page_addr:" - " 0x%x, column: 0x%x.\n", page_addr, column); - - out_be32(&lbc->fbcr, 0); /* read entire page to enable ECC */ - set_addr(mtd, 0, page_addr, 0); - - ctrl->read_bytes = mtd->writesize + mtd->oobsize; - ctrl->index += column; - - fsl_elbc_do_read(chip, 0); - fsl_elbc_run_command(mtd); - return; - - /* READOOB reads only the OOB because no ECC is performed. */ - case NAND_CMD_READOOB: - vdbg("fsl_elbc_cmdfunc: NAND_CMD_READOOB, page_addr:" - " 0x%x, column: 0x%x.\n", page_addr, column); - - out_be32(&lbc->fbcr, mtd->oobsize - column); - set_addr(mtd, column, page_addr, 1); - - ctrl->read_bytes = mtd->writesize + mtd->oobsize; - - fsl_elbc_do_read(chip, 1); - fsl_elbc_run_command(mtd); - - return; - - /* READID must read all 5 possible bytes while CEB is active */ - case NAND_CMD_READID: - case NAND_CMD_PARAM: - vdbg("fsl_elbc_cmdfunc: NAND_CMD 0x%x.\n", command); - - out_be32(&lbc->fir, (FIR_OP_CW0 << FIR_OP0_SHIFT) | - (FIR_OP_UA << FIR_OP1_SHIFT) | - (FIR_OP_RBW << FIR_OP2_SHIFT)); - out_be32(&lbc->fcr, command << FCR_CMD0_SHIFT); - /* - * although currently it's 8 bytes for READID, we always read - * the maximum 256 bytes(for PARAM) - */ - out_be32(&lbc->fbcr, 256); - ctrl->read_bytes = 256; - ctrl->use_mdr = 1; - ctrl->mdr = column; - set_addr(mtd, 0, 0, 0); - fsl_elbc_run_command(mtd); - return; - - /* ERASE1 stores the block and page address */ - case NAND_CMD_ERASE1: - vdbg("fsl_elbc_cmdfunc: NAND_CMD_ERASE1, " - "page_addr: 0x%x.\n", page_addr); - set_addr(mtd, 0, page_addr, 0); - return; - - /* ERASE2 uses the block and page address from ERASE1 */ - case NAND_CMD_ERASE2: - vdbg("fsl_elbc_cmdfunc: NAND_CMD_ERASE2.\n"); - - out_be32(&lbc->fir, - (FIR_OP_CW0 << FIR_OP0_SHIFT) | - (FIR_OP_PA << FIR_OP1_SHIFT) | - (FIR_OP_CM1 << FIR_OP2_SHIFT)); - - out_be32(&lbc->fcr, - (NAND_CMD_ERASE1 << FCR_CMD0_SHIFT) | - (NAND_CMD_ERASE2 << FCR_CMD1_SHIFT)); - - out_be32(&lbc->fbcr, 0); - ctrl->read_bytes = 0; - - fsl_elbc_run_command(mtd); - return; - - /* SEQIN sets up the addr buffer and all registers except the length */ - case NAND_CMD_SEQIN: { - u32 fcr; - vdbg("fsl_elbc_cmdfunc: NAND_CMD_SEQIN/PAGE_PROG, " - "page_addr: 0x%x, column: 0x%x.\n", - page_addr, column); - - ctrl->column = column; - ctrl->oob = 0; - - if (priv->page_size) { - fcr = (NAND_CMD_SEQIN << FCR_CMD0_SHIFT) | - (NAND_CMD_PAGEPROG << FCR_CMD1_SHIFT); - - out_be32(&lbc->fir, - (FIR_OP_CW0 << FIR_OP0_SHIFT) | - (FIR_OP_CA << FIR_OP1_SHIFT) | - (FIR_OP_PA << FIR_OP2_SHIFT) | - (FIR_OP_WB << FIR_OP3_SHIFT) | - (FIR_OP_CW1 << FIR_OP4_SHIFT)); - } else { - fcr = (NAND_CMD_PAGEPROG << FCR_CMD1_SHIFT) | - (NAND_CMD_SEQIN << FCR_CMD2_SHIFT); - - out_be32(&lbc->fir, - (FIR_OP_CW0 << FIR_OP0_SHIFT) | - (FIR_OP_CM2 << FIR_OP1_SHIFT) | - (FIR_OP_CA << FIR_OP2_SHIFT) | - (FIR_OP_PA << FIR_OP3_SHIFT) | - (FIR_OP_WB << FIR_OP4_SHIFT) | - (FIR_OP_CW1 << FIR_OP5_SHIFT)); - - if (column >= mtd->writesize) { - /* OOB area --> READOOB */ - column -= mtd->writesize; - fcr |= NAND_CMD_READOOB << FCR_CMD0_SHIFT; - ctrl->oob = 1; - } else if (column < 256) { - /* First 256 bytes --> READ0 */ - fcr |= NAND_CMD_READ0 << FCR_CMD0_SHIFT; - } else { - /* Second 256 bytes --> READ1 */ - fcr |= NAND_CMD_READ1 << FCR_CMD0_SHIFT; - } - } - - out_be32(&lbc->fcr, fcr); - set_addr(mtd, column, page_addr, ctrl->oob); - return; - } - - /* PAGEPROG reuses all of the setup from SEQIN and adds the length */ - case NAND_CMD_PAGEPROG: { - vdbg("fsl_elbc_cmdfunc: NAND_CMD_PAGEPROG " - "writing %d bytes.\n", ctrl->index); - - /* if the write did not start at 0 or is not a full page - * then set the exact length, otherwise use a full page - * write so the HW generates the ECC. - */ - if (ctrl->oob || ctrl->column != 0 || - ctrl->index != mtd->writesize + mtd->oobsize) - out_be32(&lbc->fbcr, ctrl->index); - else - out_be32(&lbc->fbcr, 0); - - fsl_elbc_run_command(mtd); - - return; - } - - /* CMD_STATUS must read the status byte while CEB is active */ - /* Note - it does not wait for the ready line */ - case NAND_CMD_STATUS: - out_be32(&lbc->fir, - (FIR_OP_CM0 << FIR_OP0_SHIFT) | - (FIR_OP_RBW << FIR_OP1_SHIFT)); - out_be32(&lbc->fcr, NAND_CMD_STATUS << FCR_CMD0_SHIFT); - out_be32(&lbc->fbcr, 1); - set_addr(mtd, 0, 0, 0); - ctrl->read_bytes = 1; - - fsl_elbc_run_command(mtd); - - /* The chip always seems to report that it is - * write-protected, even when it is not. - */ - out_8(ctrl->addr, in_8(ctrl->addr) | NAND_STATUS_WP); - return; - - /* RESET without waiting for the ready line */ - case NAND_CMD_RESET: - dbg("fsl_elbc_cmdfunc: NAND_CMD_RESET.\n"); - out_be32(&lbc->fir, FIR_OP_CM0 << FIR_OP0_SHIFT); - out_be32(&lbc->fcr, NAND_CMD_RESET << FCR_CMD0_SHIFT); - fsl_elbc_run_command(mtd); - return; - - default: - printf("fsl_elbc_cmdfunc: error, unsupported command 0x%x.\n", - command); - } -} - -static void fsl_elbc_select_chip(struct mtd_info *mtd, int chip) -{ - /* The hardware does not seem to support multiple - * chips per bank. - */ -} - -/* - * Write buf to the FCM Controller Data Buffer - */ -static void fsl_elbc_write_buf(struct mtd_info *mtd, const u8 *buf, int len) -{ - struct nand_chip *chip = mtd->priv; - struct fsl_elbc_mtd *priv = chip->priv; - struct fsl_elbc_ctrl *ctrl = priv->ctrl; - unsigned int bufsize = mtd->writesize + mtd->oobsize; - - if (len <= 0) { - printf("write_buf of %d bytes", len); - ctrl->status = 0; - return; - } - - if ((unsigned int)len > bufsize - ctrl->index) { - printf("write_buf beyond end of buffer " - "(%d requested, %u available)\n", - len, bufsize - ctrl->index); - len = bufsize - ctrl->index; - } - - memcpy_toio(&ctrl->addr[ctrl->index], buf, len); - /* - * This is workaround for the weird elbc hangs during nand write, - * Scott Wood says: "...perhaps difference in how long it takes a - * write to make it through the localbus compared to a write to IMMR - * is causing problems, and sync isn't helping for some reason." - * Reading back the last byte helps though. - */ - in_8(&ctrl->addr[ctrl->index] + len - 1); - - ctrl->index += len; -} - -/* - * read a byte from either the FCM hardware buffer if it has any data left - * otherwise issue a command to read a single byte. - */ -static u8 fsl_elbc_read_byte(struct mtd_info *mtd) -{ - struct nand_chip *chip = mtd->priv; - struct fsl_elbc_mtd *priv = chip->priv; - struct fsl_elbc_ctrl *ctrl = priv->ctrl; - - /* If there are still bytes in the FCM, then use the next byte. */ - if (ctrl->index < ctrl->read_bytes) - return in_8(&ctrl->addr[ctrl->index++]); - - printf("read_byte beyond end of buffer\n"); - return ERR_BYTE; -} - -/* - * Read from the FCM Controller Data Buffer - */ -static void fsl_elbc_read_buf(struct mtd_info *mtd, u8 *buf, int len) -{ - struct nand_chip *chip = mtd->priv; - struct fsl_elbc_mtd *priv = chip->priv; - struct fsl_elbc_ctrl *ctrl = priv->ctrl; - int avail; - - if (len < 0) - return; - - avail = min((unsigned int)len, ctrl->read_bytes - ctrl->index); - memcpy_fromio(buf, &ctrl->addr[ctrl->index], avail); - ctrl->index += avail; - - if (len > avail) - printf("read_buf beyond end of buffer " - "(%d requested, %d available)\n", - len, avail); -} - -/* - * Verify buffer against the FCM Controller Data Buffer - */ -static int fsl_elbc_verify_buf(struct mtd_info *mtd, - const u_char *buf, int len) -{ - struct nand_chip *chip = mtd->priv; - struct fsl_elbc_mtd *priv = chip->priv; - struct fsl_elbc_ctrl *ctrl = priv->ctrl; - int i; - - if (len < 0) { - printf("write_buf of %d bytes", len); - return -EINVAL; - } - - if ((unsigned int)len > ctrl->read_bytes - ctrl->index) { - printf("verify_buf beyond end of buffer " - "(%d requested, %u available)\n", - len, ctrl->read_bytes - ctrl->index); - - ctrl->index = ctrl->read_bytes; - return -EINVAL; - } - - for (i = 0; i < len; i++) - if (in_8(&ctrl->addr[ctrl->index + i]) != buf[i]) - break; - - ctrl->index += len; - return i == len && ctrl->status == LTESR_CC ? 0 : -EIO; -} - -/* This function is called after Program and Erase Operations to - * check for success or failure. - */ -static int fsl_elbc_wait(struct mtd_info *mtd, struct nand_chip *chip) -{ - struct fsl_elbc_mtd *priv = chip->priv; - struct fsl_elbc_ctrl *ctrl = priv->ctrl; - fsl_lbc_t *lbc = ctrl->regs; - - if (ctrl->status != LTESR_CC) - return NAND_STATUS_FAIL; - - /* Use READ_STATUS command, but wait for the device to be ready */ - ctrl->use_mdr = 0; - out_be32(&lbc->fir, - (FIR_OP_CW0 << FIR_OP0_SHIFT) | - (FIR_OP_RBW << FIR_OP1_SHIFT)); - out_be32(&lbc->fcr, NAND_CMD_STATUS << FCR_CMD0_SHIFT); - out_be32(&lbc->fbcr, 1); - set_addr(mtd, 0, 0, 0); - ctrl->read_bytes = 1; - - fsl_elbc_run_command(mtd); - - if (ctrl->status != LTESR_CC) - return NAND_STATUS_FAIL; - - /* The chip always seems to report that it is - * write-protected, even when it is not. - */ - out_8(ctrl->addr, in_8(ctrl->addr) | NAND_STATUS_WP); - return fsl_elbc_read_byte(mtd); -} - -static int fsl_elbc_read_page(struct mtd_info *mtd, struct nand_chip *chip, - uint8_t *buf, int oob_required, int page) -{ - fsl_elbc_read_buf(mtd, buf, mtd->writesize); - fsl_elbc_read_buf(mtd, chip->oob_poi, mtd->oobsize); - - if (fsl_elbc_wait(mtd, chip) & NAND_STATUS_FAIL) - mtd->ecc_stats.failed++; - - return 0; -} - -/* ECC will be calculated automatically, and errors will be detected in - * waitfunc. - */ -static int fsl_elbc_write_page(struct mtd_info *mtd, struct nand_chip *chip, - const uint8_t *buf, int oob_required) -{ - fsl_elbc_write_buf(mtd, buf, mtd->writesize); - fsl_elbc_write_buf(mtd, chip->oob_poi, mtd->oobsize); - - return 0; -} - -static struct fsl_elbc_ctrl *elbc_ctrl; - -static void fsl_elbc_ctrl_init(void) -{ - elbc_ctrl = kzalloc(sizeof(*elbc_ctrl), GFP_KERNEL); - if (!elbc_ctrl) - return; - - elbc_ctrl->regs = LBC_BASE_ADDR; - - /* clear event registers */ - out_be32(&elbc_ctrl->regs->ltesr, LTESR_NAND_MASK); - out_be32(&elbc_ctrl->regs->lteatr, 0); - - /* Enable interrupts for any detected events */ - out_be32(&elbc_ctrl->regs->lteir, LTESR_NAND_MASK); - - elbc_ctrl->read_bytes = 0; - elbc_ctrl->index = 0; - elbc_ctrl->addr = NULL; -} - -static int fsl_elbc_chip_init(int devnum, u8 *addr) -{ - struct mtd_info *mtd = &nand_info[devnum]; - struct nand_chip *nand; - struct fsl_elbc_mtd *priv; - uint32_t br = 0, or = 0; - int ret; - - if (!elbc_ctrl) { - fsl_elbc_ctrl_init(); - if (!elbc_ctrl) - return -1; - } - - priv = kzalloc(sizeof(*priv), GFP_KERNEL); - if (!priv) - return -ENOMEM; - - priv->ctrl = elbc_ctrl; - priv->vbase = addr; - - /* Find which chip select it is connected to. It'd be nice - * if we could pass more than one datum to the NAND driver... - */ - for (priv->bank = 0; priv->bank < MAX_BANKS; priv->bank++) { - phys_addr_t phys_addr = virt_to_phys(addr); - - br = in_be32(&elbc_ctrl->regs->bank[priv->bank].br); - or = in_be32(&elbc_ctrl->regs->bank[priv->bank].or); - - if ((br & BR_V) && (br & BR_MSEL) == BR_MS_FCM && - (br & or & BR_BA) == BR_PHYS_ADDR(phys_addr)) - break; - } - - if (priv->bank >= MAX_BANKS) { - printf("fsl_elbc_nand: address did not match any " - "chip selects\n"); - return -ENODEV; - } - - nand = &priv->chip; - mtd->priv = nand; - - elbc_ctrl->chips[priv->bank] = priv; - - /* fill in nand_chip structure */ - /* set up function call table */ - nand->read_byte = fsl_elbc_read_byte; - nand->write_buf = fsl_elbc_write_buf; - nand->read_buf = fsl_elbc_read_buf; - nand->verify_buf = fsl_elbc_verify_buf; - nand->select_chip = fsl_elbc_select_chip; - nand->cmdfunc = fsl_elbc_cmdfunc; - nand->waitfunc = fsl_elbc_wait; - - /* set up nand options */ - nand->bbt_td = &bbt_main_descr; - nand->bbt_md = &bbt_mirror_descr; - - /* set up nand options */ - nand->options = NAND_NO_SUBPAGE_WRITE; - nand->bbt_options = NAND_BBT_USE_FLASH; - - nand->controller = &elbc_ctrl->controller; - nand->priv = priv; - - nand->ecc.read_page = fsl_elbc_read_page; - nand->ecc.write_page = fsl_elbc_write_page; - - priv->fmr = (15 << FMR_CWTO_SHIFT) | (2 << FMR_AL_SHIFT); - - /* If CS Base Register selects full hardware ECC then use it */ - if ((br & BR_DECC) == BR_DECC_CHK_GEN) { - nand->ecc.mode = NAND_ECC_HW; - - nand->ecc.layout = (priv->fmr & FMR_ECCM) ? - &fsl_elbc_oob_sp_eccm1 : - &fsl_elbc_oob_sp_eccm0; - - nand->ecc.size = 512; - nand->ecc.bytes = 3; - nand->ecc.steps = 1; - nand->ecc.strength = 1; - } else { - /* otherwise fall back to software ECC */ -#if defined(CONFIG_NAND_ECC_BCH) - nand->ecc.mode = NAND_ECC_SOFT_BCH; -#else - nand->ecc.mode = NAND_ECC_SOFT; -#endif - } - - ret = nand_scan_ident(mtd, 1, NULL); - if (ret) - return ret; - - /* Large-page-specific setup */ - if (mtd->writesize == 2048) { - setbits_be32(&elbc_ctrl->regs->bank[priv->bank].or, - OR_FCM_PGS); - in_be32(&elbc_ctrl->regs->bank[priv->bank].or); - - priv->page_size = 1; - nand->badblock_pattern = &largepage_memorybased; - - /* - * Hardware expects small page has ECCM0, large page has - * ECCM1 when booting from NAND, and we follow that even - * when not booting from NAND. - */ - priv->fmr |= FMR_ECCM; - - /* adjust ecc setup if needed */ - if ((br & BR_DECC) == BR_DECC_CHK_GEN) { - nand->ecc.steps = 4; - nand->ecc.layout = (priv->fmr & FMR_ECCM) ? - &fsl_elbc_oob_lp_eccm1 : - &fsl_elbc_oob_lp_eccm0; - } - } else if (mtd->writesize == 512) { - clrbits_be32(&elbc_ctrl->regs->bank[priv->bank].or, - OR_FCM_PGS); - in_be32(&elbc_ctrl->regs->bank[priv->bank].or); - } else { - return -ENODEV; - } - - ret = nand_scan_tail(mtd); - if (ret) - return ret; - - ret = nand_register(devnum); - if (ret) - return ret; - - return 0; -} - -#ifndef CONFIG_SYS_NAND_BASE_LIST -#define CONFIG_SYS_NAND_BASE_LIST { CONFIG_SYS_NAND_BASE } -#endif - -static unsigned long base_address[CONFIG_SYS_MAX_NAND_DEVICE] = - CONFIG_SYS_NAND_BASE_LIST; - -void board_nand_init(void) -{ - int i; - - for (i = 0; i < CONFIG_SYS_MAX_NAND_DEVICE; i++) - fsl_elbc_chip_init(i, (u8 *)base_address[i]); -} diff --git a/qemu/roms/u-boot/drivers/mtd/nand/fsl_elbc_spl.c b/qemu/roms/u-boot/drivers/mtd/nand/fsl_elbc_spl.c deleted file mode 100644 index 29521359a..000000000 --- a/qemu/roms/u-boot/drivers/mtd/nand/fsl_elbc_spl.c +++ /dev/null @@ -1,168 +0,0 @@ -/* - * NAND boot for Freescale Enhanced Local Bus Controller, Flash Control Machine - * - * (C) Copyright 2006-2008 - * Stefan Roese, DENX Software Engineering, sr@denx.de. - * - * Copyright (c) 2008 Freescale Semiconductor, Inc. - * Author: Scott Wood <scottwood@freescale.com> - * - * SPDX-License-Identifier: GPL-2.0+ - */ - -#include <common.h> -#include <asm/io.h> -#include <asm/fsl_lbc.h> -#include <nand.h> - -#define WINDOW_SIZE 8192 - -static void nand_wait(void) -{ - fsl_lbc_t *regs = LBC_BASE_ADDR; - - for (;;) { - uint32_t status = in_be32(®s->ltesr); - - if (status == 1) - return; - - if (status & 1) { - puts("read failed (ltesr)\n"); - for (;;); - } - } -} - -#ifdef CONFIG_TPL_BUILD -int nand_spl_load_image(uint32_t offs, unsigned int uboot_size, void *vdst) -#else -static int nand_load_image(uint32_t offs, unsigned int uboot_size, void *vdst) -#endif -{ - fsl_lbc_t *regs = LBC_BASE_ADDR; - uchar *buf = (uchar *)CONFIG_SYS_NAND_BASE; - const int large = CONFIG_SYS_NAND_OR_PRELIM & OR_FCM_PGS; - const int block_shift = large ? 17 : 14; - const int block_size = 1 << block_shift; - const int page_size = large ? 2048 : 512; - const int bad_marker = large ? page_size + 0 : page_size + 5; - int fmr = (15 << FMR_CWTO_SHIFT) | (2 << FMR_AL_SHIFT) | 2; - int pos = 0; - char *dst = vdst; - - if (offs & (block_size - 1)) { - puts("bad offset\n"); - for (;;); - } - - if (large) { - fmr |= FMR_ECCM; - out_be32(®s->fcr, (NAND_CMD_READ0 << FCR_CMD0_SHIFT) | - (NAND_CMD_READSTART << FCR_CMD1_SHIFT)); - out_be32(®s->fir, - (FIR_OP_CW0 << FIR_OP0_SHIFT) | - (FIR_OP_CA << FIR_OP1_SHIFT) | - (FIR_OP_PA << FIR_OP2_SHIFT) | - (FIR_OP_CW1 << FIR_OP3_SHIFT) | - (FIR_OP_RBW << FIR_OP4_SHIFT)); - } else { - out_be32(®s->fcr, NAND_CMD_READ0 << FCR_CMD0_SHIFT); - out_be32(®s->fir, - (FIR_OP_CW0 << FIR_OP0_SHIFT) | - (FIR_OP_CA << FIR_OP1_SHIFT) | - (FIR_OP_PA << FIR_OP2_SHIFT) | - (FIR_OP_RBW << FIR_OP3_SHIFT)); - } - - out_be32(®s->fbcr, 0); - clrsetbits_be32(®s->bank[0].br, BR_DECC, BR_DECC_CHK_GEN); - - while (pos < uboot_size) { - int i = 0; - out_be32(®s->fbar, offs >> block_shift); - - do { - int j; - unsigned int page_offs = (offs & (block_size - 1)) << 1; - - out_be32(®s->ltesr, ~0); - out_be32(®s->lteatr, 0); - out_be32(®s->fpar, page_offs); - out_be32(®s->fmr, fmr); - out_be32(®s->lsor, 0); - nand_wait(); - - page_offs %= WINDOW_SIZE; - - /* - * If either of the first two pages are marked bad, - * continue to the next block. - */ - if (i++ < 2 && buf[page_offs + bad_marker] != 0xff) { - puts("skipping\n"); - offs = (offs + block_size) & ~(block_size - 1); - pos &= ~(block_size - 1); - break; - } - - for (j = 0; j < page_size; j++) - dst[pos + j] = buf[page_offs + j]; - - pos += page_size; - offs += page_size; - } while ((offs & (block_size - 1)) && (pos < uboot_size)); - } - - return 0; -} - -/* - * Defines a static function nand_load_image() here, because non-static makes - * the code too large for certain SPLs(minimal SPL, maximum size <= 4Kbytes) - */ -#ifndef CONFIG_TPL_BUILD -#define nand_spl_load_image(offs, uboot_size, vdst) \ - nand_load_image(offs, uboot_size, vdst) -#endif - -/* - * The main entry for NAND booting. It's necessary that SDRAM is already - * configured and available since this code loads the main U-Boot image - * from NAND into SDRAM and starts it from there. - */ -void nand_boot(void) -{ - __attribute__((noreturn)) void (*uboot)(void); - /* - * Load U-Boot image from NAND into RAM - */ - nand_spl_load_image(CONFIG_SYS_NAND_U_BOOT_OFFS, - CONFIG_SYS_NAND_U_BOOT_SIZE, - (void *)CONFIG_SYS_NAND_U_BOOT_DST); - -#ifdef CONFIG_NAND_ENV_DST - nand_spl_load_image(CONFIG_ENV_OFFSET, CONFIG_ENV_SIZE, - (void *)CONFIG_NAND_ENV_DST); - -#ifdef CONFIG_ENV_OFFSET_REDUND - nand_spl_load_image(CONFIG_ENV_OFFSET_REDUND, CONFIG_ENV_SIZE, - (void *)CONFIG_NAND_ENV_DST + CONFIG_ENV_SIZE); -#endif -#endif - -#ifdef CONFIG_SPL_FLUSH_IMAGE - /* - * Clean d-cache and invalidate i-cache, to - * make sure that no stale data is executed. - */ - flush_cache(CONFIG_SYS_NAND_U_BOOT_DST, CONFIG_SYS_NAND_U_BOOT_SIZE); -#endif - - puts("transfering control\n"); - /* - * Jump to U-Boot image - */ - uboot = (void *)CONFIG_SYS_NAND_U_BOOT_START; - (*uboot)(); -} diff --git a/qemu/roms/u-boot/drivers/mtd/nand/fsl_ifc_nand.c b/qemu/roms/u-boot/drivers/mtd/nand/fsl_ifc_nand.c deleted file mode 100644 index be5a16a1b..000000000 --- a/qemu/roms/u-boot/drivers/mtd/nand/fsl_ifc_nand.c +++ /dev/null @@ -1,1039 +0,0 @@ -/* Integrated Flash Controller NAND Machine Driver - * - * Copyright (c) 2012 Freescale Semiconductor, Inc - * - * Authors: Dipen Dudhat <Dipen.Dudhat@freescale.com> - * - * SPDX-License-Identifier: GPL-2.0+ - */ - -#include <common.h> -#include <malloc.h> -#include <nand.h> - -#include <linux/mtd/mtd.h> -#include <linux/mtd/nand.h> -#include <linux/mtd/nand_ecc.h> - -#include <asm/io.h> -#include <asm/errno.h> -#include <fsl_ifc.h> - -#define FSL_IFC_V1_1_0 0x01010000 -#define MAX_BANKS 4 -#define ERR_BYTE 0xFF /* Value returned for read bytes - when read failed */ -#define IFC_TIMEOUT_MSECS 10 /* Maximum number of mSecs to wait for IFC - NAND Machine */ - -struct fsl_ifc_ctrl; - -/* mtd information per set */ -struct fsl_ifc_mtd { - struct nand_chip chip; - struct fsl_ifc_ctrl *ctrl; - - struct device *dev; - int bank; /* Chip select bank number */ - unsigned int bufnum_mask; /* bufnum = page & bufnum_mask */ - u8 __iomem *vbase; /* Chip select base virtual address */ -}; - -/* overview of the fsl ifc controller */ -struct fsl_ifc_ctrl { - struct nand_hw_control controller; - struct fsl_ifc_mtd *chips[MAX_BANKS]; - - /* device info */ - struct fsl_ifc *regs; - uint8_t __iomem *addr; /* Address of assigned IFC buffer */ - unsigned int cs_nand; /* On which chipsel NAND is connected */ - unsigned int page; /* Last page written to / read from */ - unsigned int read_bytes; /* Number of bytes read during command */ - unsigned int column; /* Saved column from SEQIN */ - unsigned int index; /* Pointer to next byte to 'read' */ - unsigned int status; /* status read from NEESR after last op */ - unsigned int oob; /* Non zero if operating on OOB data */ - unsigned int eccread; /* Non zero for a full-page ECC read */ -}; - -static struct fsl_ifc_ctrl *ifc_ctrl; - -/* 512-byte page with 4-bit ECC, 8-bit */ -static struct nand_ecclayout oob_512_8bit_ecc4 = { - .eccbytes = 8, - .eccpos = {8, 9, 10, 11, 12, 13, 14, 15}, - .oobfree = { {0, 5}, {6, 2} }, -}; - -/* 512-byte page with 4-bit ECC, 16-bit */ -static struct nand_ecclayout oob_512_16bit_ecc4 = { - .eccbytes = 8, - .eccpos = {8, 9, 10, 11, 12, 13, 14, 15}, - .oobfree = { {2, 6}, }, -}; - -/* 2048-byte page size with 4-bit ECC */ -static struct nand_ecclayout oob_2048_ecc4 = { - .eccbytes = 32, - .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, - }, - .oobfree = { {2, 6}, {40, 24} }, -}; - -/* 4096-byte page size with 4-bit ECC */ -static struct nand_ecclayout oob_4096_ecc4 = { - .eccbytes = 64, - .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, - }, - .oobfree = { {2, 6}, {72, 56} }, -}; - -/* 4096-byte page size with 8-bit ECC -- requires 218-byte OOB */ -static struct nand_ecclayout oob_4096_ecc8 = { - .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, 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 - */ -static u8 bbt_pattern[] = {'B', 'b', 't', '0' }; -static u8 mirror_pattern[] = {'1', 't', 'b', 'B' }; - -static struct nand_bbt_descr bbt_main_descr = { - .options = NAND_BBT_LASTBLOCK | NAND_BBT_CREATE | NAND_BBT_WRITE | - NAND_BBT_2BIT | NAND_BBT_VERSION, - .offs = 2, /* 0 on 8-bit small page */ - .len = 4, - .veroffs = 6, - .maxblocks = 4, - .pattern = bbt_pattern, -}; - -static struct nand_bbt_descr bbt_mirror_descr = { - .options = NAND_BBT_LASTBLOCK | NAND_BBT_CREATE | NAND_BBT_WRITE | - NAND_BBT_2BIT | NAND_BBT_VERSION, - .offs = 2, /* 0 on 8-bit small page */ - .len = 4, - .veroffs = 6, - .maxblocks = 4, - .pattern = mirror_pattern, -}; - -/* - * Set up the IFC hardware block and page address fields, and the ifc nand - * structure addr field to point to the correct IFC buffer in memory - */ -static void set_addr(struct mtd_info *mtd, int column, int page_addr, int oob) -{ - struct nand_chip *chip = mtd->priv; - struct fsl_ifc_mtd *priv = chip->priv; - struct fsl_ifc_ctrl *ctrl = priv->ctrl; - struct fsl_ifc *ifc = ctrl->regs; - int buf_num; - - ctrl->page = page_addr; - - /* Program ROW0/COL0 */ - ifc_out32(&ifc->ifc_nand.row0, page_addr); - ifc_out32(&ifc->ifc_nand.col0, (oob ? IFC_NAND_COL_MS : 0) | column); - - buf_num = page_addr & priv->bufnum_mask; - - ctrl->addr = priv->vbase + buf_num * (mtd->writesize * 2); - ctrl->index = column; - - /* for OOB data point to the second half of the buffer */ - if (oob) - ctrl->index += mtd->writesize; -} - -static int is_blank(struct mtd_info *mtd, struct fsl_ifc_ctrl *ctrl, - unsigned int bufnum) -{ - struct nand_chip *chip = mtd->priv; - struct fsl_ifc_mtd *priv = chip->priv; - u8 __iomem *addr = priv->vbase + bufnum * (mtd->writesize * 2); - u32 __iomem *main = (u32 *)addr; - u8 __iomem *oob = addr + mtd->writesize; - int i; - - for (i = 0; i < mtd->writesize / 4; i++) { - if (__raw_readl(&main[i]) != 0xffffffff) - return 0; - } - - for (i = 0; i < chip->ecc.layout->eccbytes; i++) { - int pos = chip->ecc.layout->eccpos[i]; - - if (__raw_readb(&oob[pos]) != 0xff) - return 0; - } - - return 1; -} - -/* returns nonzero if entire page is blank */ -static int check_read_ecc(struct mtd_info *mtd, struct fsl_ifc_ctrl *ctrl, - u32 *eccstat, unsigned int bufnum) -{ - u32 reg = eccstat[bufnum / 4]; - int errors; - - errors = (reg >> ((3 - bufnum % 4) * 8)) & 15; - - return errors; -} - -/* - * execute IFC NAND command and wait for it to complete - */ -static int fsl_ifc_run_command(struct mtd_info *mtd) -{ - struct nand_chip *chip = mtd->priv; - struct fsl_ifc_mtd *priv = chip->priv; - struct fsl_ifc_ctrl *ctrl = priv->ctrl; - struct fsl_ifc *ifc = ctrl->regs; - long long end_tick; - u32 eccstat[4]; - int i; - - /* set the chip select for NAND Transaction */ - ifc_out32(&ifc->ifc_nand.nand_csel, ifc_ctrl->cs_nand); - - /* start read/write seq */ - ifc_out32(&ifc->ifc_nand.nandseq_strt, - IFC_NAND_SEQ_STRT_FIR_STRT); - - /* wait for NAND Machine complete flag or timeout */ - end_tick = usec2ticks(IFC_TIMEOUT_MSECS * 1000) + get_ticks(); - - while (end_tick > get_ticks()) { - ctrl->status = ifc_in32(&ifc->ifc_nand.nand_evter_stat); - - if (ctrl->status & IFC_NAND_EVTER_STAT_OPC) - break; - } - - ifc_out32(&ifc->ifc_nand.nand_evter_stat, ctrl->status); - - if (ctrl->status & IFC_NAND_EVTER_STAT_FTOER) - printf("%s: Flash Time Out Error\n", __func__); - if (ctrl->status & IFC_NAND_EVTER_STAT_WPER) - printf("%s: Write Protect Error\n", __func__); - - if (ctrl->eccread) { - int errors; - int bufnum = ctrl->page & priv->bufnum_mask; - int sector = bufnum * chip->ecc.steps; - int sector_end = sector + chip->ecc.steps - 1; - - for (i = sector / 4; i <= sector_end / 4; i++) - eccstat[i] = ifc_in32(&ifc->ifc_nand.nand_eccstat[i]); - - for (i = sector; i <= sector_end; i++) { - errors = check_read_ecc(mtd, ctrl, eccstat, i); - - if (errors == 15) { - /* - * Uncorrectable error. - * OK only if the whole page is blank. - * - * We disable ECCER reporting due to erratum - * IFC-A002770 -- so report it now if we - * see an uncorrectable error in ECCSTAT. - */ - if (!is_blank(mtd, ctrl, bufnum)) - ctrl->status |= - IFC_NAND_EVTER_STAT_ECCER; - break; - } - - mtd->ecc_stats.corrected += errors; - } - - ctrl->eccread = 0; - } - - /* returns 0 on success otherwise non-zero) */ - return ctrl->status == IFC_NAND_EVTER_STAT_OPC ? 0 : -EIO; -} - -static void fsl_ifc_do_read(struct nand_chip *chip, - int oob, - struct mtd_info *mtd) -{ - struct fsl_ifc_mtd *priv = chip->priv; - struct fsl_ifc_ctrl *ctrl = priv->ctrl; - struct fsl_ifc *ifc = ctrl->regs; - - /* Program FIR/IFC_NAND_FCR0 for Small/Large page */ - if (mtd->writesize > 512) { - ifc_out32(&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_CMD1 << IFC_NAND_FIR0_OP3_SHIFT) | - (IFC_FIR_OP_RBCD << IFC_NAND_FIR0_OP4_SHIFT)); - ifc_out32(&ifc->ifc_nand.nand_fir1, 0x0); - - ifc_out32(&ifc->ifc_nand.nand_fcr0, - (NAND_CMD_READ0 << IFC_NAND_FCR0_CMD0_SHIFT) | - (NAND_CMD_READSTART << IFC_NAND_FCR0_CMD1_SHIFT)); - } else { - ifc_out32(&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_RBCD << IFC_NAND_FIR0_OP3_SHIFT)); - - if (oob) - ifc_out32(&ifc->ifc_nand.nand_fcr0, - NAND_CMD_READOOB << IFC_NAND_FCR0_CMD0_SHIFT); - else - ifc_out32(&ifc->ifc_nand.nand_fcr0, - NAND_CMD_READ0 << IFC_NAND_FCR0_CMD0_SHIFT); - } -} - -/* cmdfunc send commands to the IFC NAND Machine */ -static void fsl_ifc_cmdfunc(struct mtd_info *mtd, unsigned int command, - int column, int page_addr) -{ - struct nand_chip *chip = mtd->priv; - struct fsl_ifc_mtd *priv = chip->priv; - struct fsl_ifc_ctrl *ctrl = priv->ctrl; - struct fsl_ifc *ifc = ctrl->regs; - - /* clear the read buffer */ - ctrl->read_bytes = 0; - if (command != NAND_CMD_PAGEPROG) - ctrl->index = 0; - - switch (command) { - /* READ0 read the entire buffer to use hardware ECC. */ - case NAND_CMD_READ0: { - ifc_out32(&ifc->ifc_nand.nand_fbcr, 0); - set_addr(mtd, 0, page_addr, 0); - - ctrl->read_bytes = mtd->writesize + mtd->oobsize; - ctrl->index += column; - - if (chip->ecc.mode == NAND_ECC_HW) - ctrl->eccread = 1; - - fsl_ifc_do_read(chip, 0, mtd); - fsl_ifc_run_command(mtd); - return; - } - - /* READOOB reads only the OOB because no ECC is performed. */ - case NAND_CMD_READOOB: - ifc_out32(&ifc->ifc_nand.nand_fbcr, mtd->oobsize - column); - set_addr(mtd, column, page_addr, 1); - - ctrl->read_bytes = mtd->writesize + mtd->oobsize; - - fsl_ifc_do_read(chip, 1, mtd); - fsl_ifc_run_command(mtd); - - return; - - /* READID must read all possible bytes while CEB is active */ - case NAND_CMD_READID: - case NAND_CMD_PARAM: { - int timing = IFC_FIR_OP_RB; - if (command == NAND_CMD_PARAM) - timing = IFC_FIR_OP_RBCD; - - ifc_out32(&ifc->ifc_nand.nand_fir0, - (IFC_FIR_OP_CW0 << IFC_NAND_FIR0_OP0_SHIFT) | - (IFC_FIR_OP_UA << IFC_NAND_FIR0_OP1_SHIFT) | - (timing << IFC_NAND_FIR0_OP2_SHIFT)); - ifc_out32(&ifc->ifc_nand.nand_fcr0, - command << IFC_NAND_FCR0_CMD0_SHIFT); - ifc_out32(&ifc->ifc_nand.row3, column); - - /* - * although currently it's 8 bytes for READID, we always read - * the maximum 256 bytes(for PARAM) - */ - ifc_out32(&ifc->ifc_nand.nand_fbcr, 256); - ctrl->read_bytes = 256; - - set_addr(mtd, 0, 0, 0); - fsl_ifc_run_command(mtd); - return; - } - - /* ERASE1 stores the block and page address */ - case NAND_CMD_ERASE1: - set_addr(mtd, 0, page_addr, 0); - return; - - /* ERASE2 uses the block and page address from ERASE1 */ - case NAND_CMD_ERASE2: - ifc_out32(&ifc->ifc_nand.nand_fir0, - (IFC_FIR_OP_CW0 << IFC_NAND_FIR0_OP0_SHIFT) | - (IFC_FIR_OP_RA0 << IFC_NAND_FIR0_OP1_SHIFT) | - (IFC_FIR_OP_CMD1 << IFC_NAND_FIR0_OP2_SHIFT)); - - ifc_out32(&ifc->ifc_nand.nand_fcr0, - (NAND_CMD_ERASE1 << IFC_NAND_FCR0_CMD0_SHIFT) | - (NAND_CMD_ERASE2 << IFC_NAND_FCR0_CMD1_SHIFT)); - - ifc_out32(&ifc->ifc_nand.nand_fbcr, 0); - ctrl->read_bytes = 0; - fsl_ifc_run_command(mtd); - return; - - /* SEQIN sets up the addr buffer and all registers except the length */ - case NAND_CMD_SEQIN: { - u32 nand_fcr0; - ctrl->column = column; - ctrl->oob = 0; - - if (mtd->writesize > 512) { - nand_fcr0 = - (NAND_CMD_SEQIN << IFC_NAND_FCR0_CMD0_SHIFT) | - (NAND_CMD_STATUS << IFC_NAND_FCR0_CMD1_SHIFT) | - (NAND_CMD_PAGEPROG << IFC_NAND_FCR0_CMD2_SHIFT); - - ifc_out32(&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_out32(&ifc->ifc_nand.nand_fir1, - (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)); - } else { - nand_fcr0 = ((NAND_CMD_PAGEPROG << - IFC_NAND_FCR0_CMD1_SHIFT) | - (NAND_CMD_SEQIN << - IFC_NAND_FCR0_CMD2_SHIFT) | - (NAND_CMD_STATUS << - IFC_NAND_FCR0_CMD3_SHIFT)); - - ifc_out32(&ifc->ifc_nand.nand_fir0, - (IFC_FIR_OP_CW0 << IFC_NAND_FIR0_OP0_SHIFT) | - (IFC_FIR_OP_CMD2 << IFC_NAND_FIR0_OP1_SHIFT) | - (IFC_FIR_OP_CA0 << IFC_NAND_FIR0_OP2_SHIFT) | - (IFC_FIR_OP_RA0 << IFC_NAND_FIR0_OP3_SHIFT) | - (IFC_FIR_OP_WBCD << IFC_NAND_FIR0_OP4_SHIFT)); - ifc_out32(&ifc->ifc_nand.nand_fir1, - (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)); - - if (column >= mtd->writesize) - nand_fcr0 |= - NAND_CMD_READOOB << IFC_NAND_FCR0_CMD0_SHIFT; - else - nand_fcr0 |= - NAND_CMD_READ0 << IFC_NAND_FCR0_CMD0_SHIFT; - } - - if (column >= mtd->writesize) { - /* OOB area --> READOOB */ - column -= mtd->writesize; - ctrl->oob = 1; - } - ifc_out32(&ifc->ifc_nand.nand_fcr0, nand_fcr0); - set_addr(mtd, column, page_addr, ctrl->oob); - return; - } - - /* PAGEPROG reuses all of the setup from SEQIN and adds the length */ - case NAND_CMD_PAGEPROG: - if (ctrl->oob) - ifc_out32(&ifc->ifc_nand.nand_fbcr, - ctrl->index - ctrl->column); - else - ifc_out32(&ifc->ifc_nand.nand_fbcr, 0); - - fsl_ifc_run_command(mtd); - return; - - case NAND_CMD_STATUS: - ifc_out32(&ifc->ifc_nand.nand_fir0, - (IFC_FIR_OP_CW0 << IFC_NAND_FIR0_OP0_SHIFT) | - (IFC_FIR_OP_RB << IFC_NAND_FIR0_OP1_SHIFT)); - ifc_out32(&ifc->ifc_nand.nand_fcr0, - NAND_CMD_STATUS << IFC_NAND_FCR0_CMD0_SHIFT); - ifc_out32(&ifc->ifc_nand.nand_fbcr, 1); - set_addr(mtd, 0, 0, 0); - ctrl->read_bytes = 1; - - fsl_ifc_run_command(mtd); - - /* Chip sometimes reporting write protect even when it's not */ - out_8(ctrl->addr, in_8(ctrl->addr) | NAND_STATUS_WP); - return; - - case NAND_CMD_RESET: - ifc_out32(&ifc->ifc_nand.nand_fir0, - IFC_FIR_OP_CW0 << IFC_NAND_FIR0_OP0_SHIFT); - ifc_out32(&ifc->ifc_nand.nand_fcr0, - NAND_CMD_RESET << IFC_NAND_FCR0_CMD0_SHIFT); - fsl_ifc_run_command(mtd); - return; - - default: - printf("%s: error, unsupported command 0x%x.\n", - __func__, command); - } -} - -/* - * Write buf to the IFC NAND Controller Data Buffer - */ -static void fsl_ifc_write_buf(struct mtd_info *mtd, const u8 *buf, int len) -{ - struct nand_chip *chip = mtd->priv; - struct fsl_ifc_mtd *priv = chip->priv; - struct fsl_ifc_ctrl *ctrl = priv->ctrl; - unsigned int bufsize = mtd->writesize + mtd->oobsize; - - if (len <= 0) { - printf("%s of %d bytes", __func__, len); - ctrl->status = 0; - return; - } - - if ((unsigned int)len > bufsize - ctrl->index) { - printf("%s beyond end of buffer " - "(%d requested, %u available)\n", - __func__, len, bufsize - ctrl->index); - len = bufsize - ctrl->index; - } - - memcpy_toio(&ctrl->addr[ctrl->index], buf, len); - ctrl->index += len; -} - -/* - * read a byte from either the IFC hardware buffer if it has any data left - * otherwise issue a command to read a single byte. - */ -static u8 fsl_ifc_read_byte(struct mtd_info *mtd) -{ - struct nand_chip *chip = mtd->priv; - struct fsl_ifc_mtd *priv = chip->priv; - struct fsl_ifc_ctrl *ctrl = priv->ctrl; - - /* If there are still bytes in the IFC buffer, then use the - * next byte. */ - if (ctrl->index < ctrl->read_bytes) - return in_8(&ctrl->addr[ctrl->index++]); - - printf("%s beyond end of buffer\n", __func__); - return ERR_BYTE; -} - -/* - * Read two bytes from the IFC hardware buffer - * read function for 16-bit buswith - */ -static uint8_t fsl_ifc_read_byte16(struct mtd_info *mtd) -{ - struct nand_chip *chip = mtd->priv; - struct fsl_ifc_mtd *priv = chip->priv; - struct fsl_ifc_ctrl *ctrl = priv->ctrl; - uint16_t data; - - /* - * If there are still bytes in the IFC buffer, then use the - * next byte. - */ - if (ctrl->index < ctrl->read_bytes) { - data = ifc_in16((uint16_t *)&ctrl-> - addr[ctrl->index]); - ctrl->index += 2; - return (uint8_t)data; - } - - printf("%s beyond end of buffer\n", __func__); - return ERR_BYTE; -} - -/* - * Read from the IFC Controller Data Buffer - */ -static void fsl_ifc_read_buf(struct mtd_info *mtd, u8 *buf, int len) -{ - struct nand_chip *chip = mtd->priv; - struct fsl_ifc_mtd *priv = chip->priv; - struct fsl_ifc_ctrl *ctrl = priv->ctrl; - int avail; - - if (len < 0) - return; - - avail = min((unsigned int)len, ctrl->read_bytes - ctrl->index); - memcpy_fromio(buf, &ctrl->addr[ctrl->index], avail); - ctrl->index += avail; - - if (len > avail) - printf("%s beyond end of buffer " - "(%d requested, %d available)\n", - __func__, len, avail); -} - -/* - * Verify buffer against the IFC Controller Data Buffer - */ -static int fsl_ifc_verify_buf(struct mtd_info *mtd, - const u_char *buf, int len) -{ - struct nand_chip *chip = mtd->priv; - struct fsl_ifc_mtd *priv = chip->priv; - struct fsl_ifc_ctrl *ctrl = priv->ctrl; - int i; - - if (len < 0) { - printf("%s of %d bytes", __func__, len); - return -EINVAL; - } - - if ((unsigned int)len > ctrl->read_bytes - ctrl->index) { - printf("%s beyond end of buffer " - "(%d requested, %u available)\n", - __func__, len, ctrl->read_bytes - ctrl->index); - - ctrl->index = ctrl->read_bytes; - return -EINVAL; - } - - for (i = 0; i < len; i++) - if (in_8(&ctrl->addr[ctrl->index + i]) != buf[i]) - break; - - ctrl->index += len; - return i == len && ctrl->status == IFC_NAND_EVTER_STAT_OPC ? 0 : -EIO; -} - -/* This function is called after Program and Erase Operations to - * check for success or failure. - */ -static int fsl_ifc_wait(struct mtd_info *mtd, struct nand_chip *chip) -{ - struct fsl_ifc_mtd *priv = chip->priv; - struct fsl_ifc_ctrl *ctrl = priv->ctrl; - struct fsl_ifc *ifc = ctrl->regs; - u32 nand_fsr; - - if (ctrl->status != IFC_NAND_EVTER_STAT_OPC) - return NAND_STATUS_FAIL; - - /* Use READ_STATUS command, but wait for the device to be ready */ - ifc_out32(&ifc->ifc_nand.nand_fir0, - (IFC_FIR_OP_CW0 << IFC_NAND_FIR0_OP0_SHIFT) | - (IFC_FIR_OP_RDSTAT << IFC_NAND_FIR0_OP1_SHIFT)); - ifc_out32(&ifc->ifc_nand.nand_fcr0, NAND_CMD_STATUS << - IFC_NAND_FCR0_CMD0_SHIFT); - ifc_out32(&ifc->ifc_nand.nand_fbcr, 1); - set_addr(mtd, 0, 0, 0); - ctrl->read_bytes = 1; - - fsl_ifc_run_command(mtd); - - if (ctrl->status != IFC_NAND_EVTER_STAT_OPC) - return NAND_STATUS_FAIL; - - nand_fsr = ifc_in32(&ifc->ifc_nand.nand_fsr); - - /* Chip sometimes reporting write protect even when it's not */ - nand_fsr = nand_fsr | NAND_STATUS_WP; - return nand_fsr; -} - -static int fsl_ifc_read_page(struct mtd_info *mtd, struct nand_chip *chip, - uint8_t *buf, int oob_required, int page) -{ - struct fsl_ifc_mtd *priv = chip->priv; - struct fsl_ifc_ctrl *ctrl = priv->ctrl; - - fsl_ifc_read_buf(mtd, buf, mtd->writesize); - fsl_ifc_read_buf(mtd, chip->oob_poi, mtd->oobsize); - - if (ctrl->status != IFC_NAND_EVTER_STAT_OPC) - mtd->ecc_stats.failed++; - - return 0; -} - -/* ECC will be calculated automatically, and errors will be detected in - * waitfunc. - */ -static int fsl_ifc_write_page(struct mtd_info *mtd, struct nand_chip *chip, - const uint8_t *buf, int oob_required) -{ - fsl_ifc_write_buf(mtd, buf, mtd->writesize); - fsl_ifc_write_buf(mtd, chip->oob_poi, mtd->oobsize); - - return 0; -} - -static void fsl_ifc_ctrl_init(void) -{ - ifc_ctrl = kzalloc(sizeof(*ifc_ctrl), GFP_KERNEL); - if (!ifc_ctrl) - return; - - ifc_ctrl->regs = IFC_BASE_ADDR; - - /* clear event registers */ - ifc_out32(&ifc_ctrl->regs->ifc_nand.nand_evter_stat, ~0U); - ifc_out32(&ifc_ctrl->regs->ifc_nand.pgrdcmpl_evt_stat, ~0U); - - /* Enable error and event for any detected errors */ - ifc_out32(&ifc_ctrl->regs->ifc_nand.nand_evter_en, - IFC_NAND_EVTER_EN_OPC_EN | - IFC_NAND_EVTER_EN_PGRDCMPL_EN | - IFC_NAND_EVTER_EN_FTOER_EN | - IFC_NAND_EVTER_EN_WPER_EN); - - ifc_out32(&ifc_ctrl->regs->ifc_nand.ncfgr, 0x0); -} - -static void fsl_ifc_select_chip(struct mtd_info *mtd, int chip) -{ -} - -static void fsl_ifc_sram_init(void) -{ - struct fsl_ifc *ifc = ifc_ctrl->regs; - uint32_t cs = 0, csor = 0, csor_8k = 0, csor_ext = 0; - long long end_tick; - - cs = ifc_ctrl->cs_nand >> IFC_NAND_CSEL_SHIFT; - - /* Save CSOR and CSOR_ext */ - csor = ifc_in32(&ifc_ctrl->regs->csor_cs[cs].csor); - csor_ext = ifc_in32(&ifc_ctrl->regs->csor_cs[cs].csor_ext); - - /* chage PageSize 8K and SpareSize 1K*/ - csor_8k = (csor & ~(CSOR_NAND_PGS_MASK)) | 0x0018C000; - ifc_out32(&ifc_ctrl->regs->csor_cs[cs].csor, csor_8k); - ifc_out32(&ifc_ctrl->regs->csor_cs[cs].csor_ext, 0x0000400); - - /* READID */ - ifc_out32(&ifc->ifc_nand.nand_fir0, - (IFC_FIR_OP_CW0 << IFC_NAND_FIR0_OP0_SHIFT) | - (IFC_FIR_OP_UA << IFC_NAND_FIR0_OP1_SHIFT) | - (IFC_FIR_OP_RB << IFC_NAND_FIR0_OP2_SHIFT)); - ifc_out32(&ifc->ifc_nand.nand_fcr0, - NAND_CMD_READID << IFC_NAND_FCR0_CMD0_SHIFT); - ifc_out32(&ifc->ifc_nand.row3, 0x0); - - ifc_out32(&ifc->ifc_nand.nand_fbcr, 0x0); - - /* Program ROW0/COL0 */ - ifc_out32(&ifc->ifc_nand.row0, 0x0); - ifc_out32(&ifc->ifc_nand.col0, 0x0); - - /* set the chip select for NAND Transaction */ - ifc_out32(&ifc->ifc_nand.nand_csel, ifc_ctrl->cs_nand); - - /* start read seq */ - ifc_out32(&ifc->ifc_nand.nandseq_strt, IFC_NAND_SEQ_STRT_FIR_STRT); - - /* wait for NAND Machine complete flag or timeout */ - end_tick = usec2ticks(IFC_TIMEOUT_MSECS * 1000) + get_ticks(); - - while (end_tick > get_ticks()) { - ifc_ctrl->status = ifc_in32(&ifc->ifc_nand.nand_evter_stat); - - if (ifc_ctrl->status & IFC_NAND_EVTER_STAT_OPC) - break; - } - - ifc_out32(&ifc->ifc_nand.nand_evter_stat, ifc_ctrl->status); - - /* Restore CSOR and CSOR_ext */ - ifc_out32(&ifc_ctrl->regs->csor_cs[cs].csor, csor); - ifc_out32(&ifc_ctrl->regs->csor_cs[cs].csor_ext, csor_ext); -} - -static int fsl_ifc_chip_init(int devnum, u8 *addr) -{ - struct mtd_info *mtd = &nand_info[devnum]; - struct nand_chip *nand; - struct fsl_ifc_mtd *priv; - struct nand_ecclayout *layout; - uint32_t cspr = 0, csor = 0, ver = 0; - int ret; - - if (!ifc_ctrl) { - fsl_ifc_ctrl_init(); - if (!ifc_ctrl) - return -1; - } - - priv = kzalloc(sizeof(*priv), GFP_KERNEL); - if (!priv) - return -ENOMEM; - - priv->ctrl = ifc_ctrl; - priv->vbase = addr; - - /* Find which chip select it is connected to. - */ - for (priv->bank = 0; priv->bank < MAX_BANKS; priv->bank++) { - phys_addr_t phys_addr = virt_to_phys(addr); - - cspr = ifc_in32(&ifc_ctrl->regs->cspr_cs[priv->bank].cspr); - csor = ifc_in32(&ifc_ctrl->regs->csor_cs[priv->bank].csor); - - if ((cspr & CSPR_V) && (cspr & CSPR_MSEL) == CSPR_MSEL_NAND && - (cspr & CSPR_BA) == CSPR_PHYS_ADDR(phys_addr)) { - ifc_ctrl->cs_nand = priv->bank << IFC_NAND_CSEL_SHIFT; - break; - } - } - - if (priv->bank >= MAX_BANKS) { - printf("%s: address did not match any " - "chip selects\n", __func__); - kfree(priv); - return -ENODEV; - } - - nand = &priv->chip; - mtd->priv = nand; - - ifc_ctrl->chips[priv->bank] = priv; - - /* fill in nand_chip structure */ - /* set up function call table */ - - nand->write_buf = fsl_ifc_write_buf; - nand->read_buf = fsl_ifc_read_buf; - nand->verify_buf = fsl_ifc_verify_buf; - nand->select_chip = fsl_ifc_select_chip; - nand->cmdfunc = fsl_ifc_cmdfunc; - nand->waitfunc = fsl_ifc_wait; - - /* set up nand options */ - nand->bbt_td = &bbt_main_descr; - nand->bbt_md = &bbt_mirror_descr; - - /* set up nand options */ - nand->options = NAND_NO_SUBPAGE_WRITE; - nand->bbt_options = NAND_BBT_USE_FLASH; - - if (cspr & CSPR_PORT_SIZE_16) { - nand->read_byte = fsl_ifc_read_byte16; - nand->options |= NAND_BUSWIDTH_16; - } else { - nand->read_byte = fsl_ifc_read_byte; - } - - nand->controller = &ifc_ctrl->controller; - nand->priv = priv; - - nand->ecc.read_page = fsl_ifc_read_page; - nand->ecc.write_page = fsl_ifc_write_page; - - /* Hardware generates ECC per 512 Bytes */ - nand->ecc.size = 512; - nand->ecc.bytes = 8; - - switch (csor & CSOR_NAND_PGS_MASK) { - case CSOR_NAND_PGS_512: - if (nand->options & NAND_BUSWIDTH_16) { - layout = &oob_512_16bit_ecc4; - } else { - layout = &oob_512_8bit_ecc4; - - /* Avoid conflict with bad block marker */ - bbt_main_descr.offs = 0; - bbt_mirror_descr.offs = 0; - } - - nand->ecc.strength = 4; - priv->bufnum_mask = 15; - break; - - case CSOR_NAND_PGS_2K: - layout = &oob_2048_ecc4; - nand->ecc.strength = 4; - priv->bufnum_mask = 3; - break; - - case CSOR_NAND_PGS_4K: - if ((csor & CSOR_NAND_ECC_MODE_MASK) == - CSOR_NAND_ECC_MODE_4) { - layout = &oob_4096_ecc4; - nand->ecc.strength = 4; - } else { - layout = &oob_4096_ecc8; - nand->ecc.strength = 8; - nand->ecc.bytes = 16; - } - - 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; - nand->ecc.strength = 4; - } else { - layout = &oob_8192_ecc8; - nand->ecc.strength = 8; - nand->ecc.bytes = 16; - } - - priv->bufnum_mask = 0; - break; - - - default: - printf("ifc nand: bad csor %#x: bad page size\n", csor); - return -ENODEV; - } - - /* Must also set CSOR_NAND_ECC_ENC_EN if DEC_EN set */ - if (csor & CSOR_NAND_ECC_DEC_EN) { - nand->ecc.mode = NAND_ECC_HW; - nand->ecc.layout = layout; - } else { - nand->ecc.mode = NAND_ECC_SOFT; - } - - ver = ifc_in32(&ifc_ctrl->regs->ifc_rev); - if (ver == FSL_IFC_V1_1_0) - fsl_ifc_sram_init(); - - ret = nand_scan_ident(mtd, 1, NULL); - if (ret) - return ret; - - ret = nand_scan_tail(mtd); - if (ret) - return ret; - - ret = nand_register(devnum); - if (ret) - return ret; - return 0; -} - -#ifndef CONFIG_SYS_NAND_BASE_LIST -#define CONFIG_SYS_NAND_BASE_LIST { CONFIG_SYS_NAND_BASE } -#endif - -static unsigned long base_address[CONFIG_SYS_MAX_NAND_DEVICE] = - CONFIG_SYS_NAND_BASE_LIST; - -void board_nand_init(void) -{ - int i; - - for (i = 0; i < CONFIG_SYS_MAX_NAND_DEVICE; i++) - fsl_ifc_chip_init(i, (u8 *)base_address[i]); -} diff --git a/qemu/roms/u-boot/drivers/mtd/nand/fsl_ifc_spl.c b/qemu/roms/u-boot/drivers/mtd/nand/fsl_ifc_spl.c deleted file mode 100644 index 510077282..000000000 --- a/qemu/roms/u-boot/drivers/mtd/nand/fsl_ifc_spl.c +++ /dev/null @@ -1,252 +0,0 @@ -/* - * NAND boot for Freescale Integrated Flash Controller, NAND FCM - * - * Copyright 2011 Freescale Semiconductor, Inc. - * Author: Dipen Dudhat <dipen.dudhat@freescale.com> - * - * SPDX-License-Identifier: GPL-2.0+ - */ - -#include <common.h> -#include <asm/io.h> -#include <fsl_ifc.h> -#include <linux/mtd/nand.h> - -static inline int is_blank(uchar *addr, int page_size) -{ - int i; - - for (i = 0; i < page_size; i++) { - if (__raw_readb(&addr[i]) != 0xff) - return 0; - } - - /* - * For the SPL, don't worry about uncorrectable errors - * where the main area is all FFs but shouldn't be. - */ - return 1; -} - -/* returns nonzero if entire page is blank */ -static inline int check_read_ecc(uchar *buf, u32 *eccstat, - unsigned int bufnum, int page_size) -{ - u32 reg = eccstat[bufnum / 4]; - int errors = (reg >> ((3 - bufnum % 4) * 8)) & 0xf; - - if (errors == 0xf) { /* uncorrectable */ - /* Blank pages fail hw ECC checks */ - if (is_blank(buf, page_size)) - return 1; - - puts("ecc error\n"); - for (;;) - ; - } - - return 0; -} - -static inline void nand_wait(uchar *buf, int bufnum, int page_size) -{ - struct fsl_ifc *ifc = IFC_BASE_ADDR; - u32 status; - u32 eccstat[4]; - int bufperpage = page_size / 512; - int bufnum_end, i; - - bufnum *= bufperpage; - bufnum_end = bufnum + bufperpage - 1; - - do { - status = ifc_in32(&ifc->ifc_nand.nand_evter_stat); - } while (!(status & IFC_NAND_EVTER_STAT_OPC)); - - if (status & IFC_NAND_EVTER_STAT_FTOER) { - puts("flash time out error\n"); - for (;;) - ; - } - - for (i = bufnum / 4; i <= bufnum_end / 4; i++) - eccstat[i] = ifc_in32(&ifc->ifc_nand.nand_eccstat[i]); - - for (i = bufnum; i <= bufnum_end; i++) { - if (check_read_ecc(buf, eccstat, i, page_size)) - break; - } - - ifc_out32(&ifc->ifc_nand.nand_evter_stat, status); -} - -static inline int bad_block(uchar *marker, int port_size) -{ - if (port_size == 8) - return __raw_readb(marker) != 0xff; - else - return __raw_readw((u16 *)marker) != 0xffff; -} - -int nand_spl_load_image(uint32_t offs, unsigned int uboot_size, void *vdst) -{ - struct fsl_ifc *ifc = IFC_BASE_ADDR; - uchar *buf = (uchar *)CONFIG_SYS_NAND_BASE; - int page_size; - int port_size; - int pages_per_blk; - int blk_size; - int bad_marker = 0; - int bufnum_mask, bufnum; - - int csor, cspr; - int pos = 0; - int j = 0; - - int sram_addr; - int pg_no; - uchar *dst = vdst; - - /* Get NAND Flash configuration */ - csor = CONFIG_SYS_NAND_CSOR; - cspr = CONFIG_SYS_NAND_CSPR; - - port_size = (cspr & CSPR_PORT_SIZE_16) ? 16 : 8; - - if ((csor & CSOR_NAND_PGS_MASK) == CSOR_NAND_PGS_8K) { - page_size = 8192; - bufnum_mask = 0x0; - } else if ((csor & CSOR_NAND_PGS_MASK) == CSOR_NAND_PGS_4K) { - page_size = 4096; - bufnum_mask = 0x1; - } else if ((csor & CSOR_NAND_PGS_MASK) == CSOR_NAND_PGS_2K) { - page_size = 2048; - bufnum_mask = 0x3; - } else { - page_size = 512; - bufnum_mask = 0xf; - - if (port_size == 8) - bad_marker = 5; - } - - pages_per_blk = - 32 << ((csor & CSOR_NAND_PB_MASK) >> CSOR_NAND_PB_SHIFT); - - blk_size = pages_per_blk * page_size; - - /* Open Full SRAM mapping for spare are access */ - ifc_out32(&ifc->ifc_nand.ncfgr, 0x0); - - /* Clear Boot events */ - ifc_out32(&ifc->ifc_nand.nand_evter_stat, 0xffffffff); - - /* Program FIR/FCR for Large/Small page */ - if (page_size > 512) { - ifc_out32(&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_CMD1 << IFC_NAND_FIR0_OP3_SHIFT) | - (IFC_FIR_OP_BTRD << IFC_NAND_FIR0_OP4_SHIFT)); - ifc_out32(&ifc->ifc_nand.nand_fir1, 0x0); - - ifc_out32(&ifc->ifc_nand.nand_fcr0, - (NAND_CMD_READ0 << IFC_NAND_FCR0_CMD0_SHIFT) | - (NAND_CMD_READSTART << IFC_NAND_FCR0_CMD1_SHIFT)); - } else { - ifc_out32(&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_BTRD << IFC_NAND_FIR0_OP3_SHIFT)); - ifc_out32(&ifc->ifc_nand.nand_fir1, 0x0); - - ifc_out32(&ifc->ifc_nand.nand_fcr0, - NAND_CMD_READ0 << IFC_NAND_FCR0_CMD0_SHIFT); - } - - /* Program FBCR = 0 for full page read */ - ifc_out32(&ifc->ifc_nand.nand_fbcr, 0); - - /* Read and copy u-boot on SDRAM from NAND device, In parallel - * check for Bad block if found skip it and read continue to - * next Block - */ - while (pos < uboot_size) { - int i = 0; - do { - pg_no = offs / page_size; - bufnum = pg_no & bufnum_mask; - sram_addr = bufnum * page_size * 2; - - ifc_out32(&ifc->ifc_nand.row0, pg_no); - ifc_out32(&ifc->ifc_nand.col0, 0); - /* start read */ - ifc_out32(&ifc->ifc_nand.nandseq_strt, - IFC_NAND_SEQ_STRT_FIR_STRT); - - /* wait for read to complete */ - nand_wait(&buf[sram_addr], bufnum, page_size); - - /* - * If either of the first two pages are marked bad, - * continue to the next block. - */ - if (i++ < 2 && - bad_block(&buf[sram_addr + page_size + bad_marker], - port_size)) { - puts("skipping\n"); - offs = (offs + blk_size) & ~(blk_size - 1); - pos &= ~(blk_size - 1); - break; - } - - for (j = 0; j < page_size; j++) - dst[pos + j] = __raw_readb(&buf[sram_addr + j]); - - pos += page_size; - offs += page_size; - } while ((offs & (blk_size - 1)) && (pos < uboot_size)); - } - - return 0; -} - -/* - * Main entrypoint for NAND Boot. It's necessary that SDRAM is already - * configured and available since this code loads the main U-boot image - * from NAND into SDRAM and starts from there. - */ -void nand_boot(void) -{ - __attribute__((noreturn)) void (*uboot)(void); - /* - * Load U-Boot image from NAND into RAM - */ - nand_spl_load_image(CONFIG_SYS_NAND_U_BOOT_OFFS, - CONFIG_SYS_NAND_U_BOOT_SIZE, - (uchar *)CONFIG_SYS_NAND_U_BOOT_DST); - -#ifdef CONFIG_NAND_ENV_DST - nand_spl_load_image(CONFIG_ENV_OFFSET, CONFIG_ENV_SIZE, - (uchar *)CONFIG_NAND_ENV_DST); - -#ifdef CONFIG_ENV_OFFSET_REDUND - nand_spl_load_image(CONFIG_ENV_OFFSET_REDUND, CONFIG_ENV_SIZE, - (uchar *)CONFIG_NAND_ENV_DST + CONFIG_ENV_SIZE); -#endif -#endif - /* - * Jump to U-Boot image - */ -#ifdef CONFIG_SPL_FLUSH_IMAGE - /* - * Clean d-cache and invalidate i-cache, to - * make sure that no stale data is executed. - */ - flush_cache(CONFIG_SYS_NAND_U_BOOT_DST, CONFIG_SYS_NAND_U_BOOT_SIZE); -#endif - uboot = (void *)CONFIG_SYS_NAND_U_BOOT_START; - uboot(); -} diff --git a/qemu/roms/u-boot/drivers/mtd/nand/fsl_upm.c b/qemu/roms/u-boot/drivers/mtd/nand/fsl_upm.c deleted file mode 100644 index 3ae0044f2..000000000 --- a/qemu/roms/u-boot/drivers/mtd/nand/fsl_upm.c +++ /dev/null @@ -1,199 +0,0 @@ -/* - * FSL UPM NAND driver - * - * Copyright (C) 2007 MontaVista Software, Inc. - * Anton Vorontsov <avorontsov@ru.mvista.com> - * - * SPDX-License-Identifier: GPL-2.0+ - */ - -#include <config.h> -#include <common.h> -#include <asm/io.h> -#include <asm/errno.h> -#include <linux/mtd/mtd.h> -#include <linux/mtd/fsl_upm.h> -#include <nand.h> - -static void fsl_upm_start_pattern(struct fsl_upm *upm, u32 pat_offset) -{ - clrsetbits_be32(upm->mxmr, MxMR_MAD_MSK, MxMR_OP_RUNP | pat_offset); - (void)in_be32(upm->mxmr); -} - -static void fsl_upm_end_pattern(struct fsl_upm *upm) -{ - clrbits_be32(upm->mxmr, MxMR_OP_RUNP); - - while (in_be32(upm->mxmr) & MxMR_OP_RUNP) - eieio(); -} - -static void fsl_upm_run_pattern(struct fsl_upm *upm, int width, - void __iomem *io_addr, u32 mar) -{ - out_be32(upm->mar, mar); - (void)in_be32(upm->mar); - switch (width) { - case 8: - out_8(io_addr, 0x0); - break; - case 16: - out_be16(io_addr, 0x0); - break; - case 32: - out_be32(io_addr, 0x0); - break; - } -} - -static void fun_wait(struct fsl_upm_nand *fun) -{ - if (fun->dev_ready) { - while (!fun->dev_ready(fun->chip_nr)) - debug("unexpected busy state\n"); - } else { - /* - * If the R/B pin is not connected, - * a short delay is necessary. - */ - udelay(1); - } -} - -#if CONFIG_SYS_NAND_MAX_CHIPS > 1 -static void fun_select_chip(struct mtd_info *mtd, int chip_nr) -{ - struct nand_chip *chip = mtd->priv; - struct fsl_upm_nand *fun = chip->priv; - - if (chip_nr >= 0) { - fun->chip_nr = chip_nr; - chip->IO_ADDR_R = chip->IO_ADDR_W = - fun->upm.io_addr + fun->chip_offset * chip_nr; - } else if (chip_nr == -1) { - chip->cmd_ctrl(mtd, NAND_CMD_NONE, 0 | NAND_CTRL_CHANGE); - } -} -#endif - -static void fun_cmd_ctrl(struct mtd_info *mtd, int cmd, unsigned int ctrl) -{ - struct nand_chip *chip = mtd->priv; - struct fsl_upm_nand *fun = chip->priv; - void __iomem *io_addr; - u32 mar; - - if (!(ctrl & fun->last_ctrl)) { - fsl_upm_end_pattern(&fun->upm); - - if (cmd == NAND_CMD_NONE) - return; - - fun->last_ctrl = ctrl & (NAND_ALE | NAND_CLE); - } - - if (ctrl & NAND_CTRL_CHANGE) { - if (ctrl & NAND_ALE) - fsl_upm_start_pattern(&fun->upm, fun->upm_addr_offset); - else if (ctrl & NAND_CLE) - fsl_upm_start_pattern(&fun->upm, fun->upm_cmd_offset); - } - - mar = cmd << (32 - fun->width); - io_addr = fun->upm.io_addr; -#if CONFIG_SYS_NAND_MAX_CHIPS > 1 - if (fun->chip_nr > 0) { - io_addr += fun->chip_offset * fun->chip_nr; - if (fun->upm_mar_chip_offset) - mar |= fun->upm_mar_chip_offset * fun->chip_nr; - } -#endif - fsl_upm_run_pattern(&fun->upm, fun->width, io_addr, mar); - - /* - * Some boards/chips needs this. At least the MPC8360E-RDK - * needs it. Probably weird chip, because I don't see any - * need for this on MPC8555E + Samsung K9F1G08U0A. Usually - * here are 0-2 unexpected busy states per block read. - */ - if (fun->wait_flags & FSL_UPM_WAIT_RUN_PATTERN) - fun_wait(fun); -} - -static u8 upm_nand_read_byte(struct mtd_info *mtd) -{ - struct nand_chip *chip = mtd->priv; - - return in_8(chip->IO_ADDR_R); -} - -static void upm_nand_write_buf(struct mtd_info *mtd, const u_char *buf, int len) -{ - int i; - struct nand_chip *chip = mtd->priv; - struct fsl_upm_nand *fun = chip->priv; - - for (i = 0; i < len; i++) { - out_8(chip->IO_ADDR_W, buf[i]); - if (fun->wait_flags & FSL_UPM_WAIT_WRITE_BYTE) - fun_wait(fun); - } - - if (fun->wait_flags & FSL_UPM_WAIT_WRITE_BUFFER) - fun_wait(fun); -} - -static void upm_nand_read_buf(struct mtd_info *mtd, u_char *buf, int len) -{ - int i; - struct nand_chip *chip = mtd->priv; - - for (i = 0; i < len; i++) - buf[i] = in_8(chip->IO_ADDR_R); -} - -static int upm_nand_verify_buf(struct mtd_info *mtd, const u_char *buf, int len) -{ - int i; - struct nand_chip *chip = mtd->priv; - - for (i = 0; i < len; i++) { - if (buf[i] != in_8(chip->IO_ADDR_R)) - return -EFAULT; - } - - return 0; -} - -static int nand_dev_ready(struct mtd_info *mtd) -{ - struct nand_chip *chip = mtd->priv; - struct fsl_upm_nand *fun = chip->priv; - - return fun->dev_ready(fun->chip_nr); -} - -int fsl_upm_nand_init(struct nand_chip *chip, struct fsl_upm_nand *fun) -{ - if (fun->width != 8 && fun->width != 16 && fun->width != 32) - return -ENOSYS; - - fun->last_ctrl = NAND_CLE; - - chip->priv = fun; - chip->chip_delay = fun->chip_delay; - chip->ecc.mode = NAND_ECC_SOFT; - chip->cmd_ctrl = fun_cmd_ctrl; -#if CONFIG_SYS_NAND_MAX_CHIPS > 1 - chip->select_chip = fun_select_chip; -#endif - chip->read_byte = upm_nand_read_byte; - chip->read_buf = upm_nand_read_buf; - chip->write_buf = upm_nand_write_buf; - chip->verify_buf = upm_nand_verify_buf; - if (fun->dev_ready) - chip->dev_ready = nand_dev_ready; - - return 0; -} diff --git a/qemu/roms/u-boot/drivers/mtd/nand/fsmc_nand.c b/qemu/roms/u-boot/drivers/mtd/nand/fsmc_nand.c deleted file mode 100644 index 567eff091..000000000 --- a/qemu/roms/u-boot/drivers/mtd/nand/fsmc_nand.c +++ /dev/null @@ -1,473 +0,0 @@ -/* - * (C) Copyright 2010 - * Vipin Kumar, ST Microelectronics, vipin.kumar@st.com. - * - * (C) Copyright 2012 - * Amit Virdi, ST Microelectronics, amit.virdi@st.com. - * - * SPDX-License-Identifier: GPL-2.0+ - */ - -#include <common.h> -#include <nand.h> -#include <asm/io.h> -#include <linux/bitops.h> -#include <linux/err.h> -#include <linux/mtd/nand_ecc.h> -#include <linux/mtd/fsmc_nand.h> -#include <asm/arch/hardware.h> - -static u32 fsmc_version; -static struct fsmc_regs *const fsmc_regs_p = (struct fsmc_regs *) - CONFIG_SYS_FSMC_BASE; - -/* - * ECC4 and ECC1 have 13 bytes and 3 bytes of ecc respectively for 512 bytes of - * data. ECC4 can correct up to 8 bits in 512 bytes of data while ECC1 can - * correct 1 bit in 512 bytes - */ - -static struct nand_ecclayout fsmc_ecc4_lp_layout = { - .eccbytes = 104, - .eccpos = { 2, 3, 4, 5, 6, 7, 8, - 9, 10, 11, 12, 13, 14, - 18, 19, 20, 21, 22, 23, 24, - 25, 26, 27, 28, 29, 30, - 34, 35, 36, 37, 38, 39, 40, - 41, 42, 43, 44, 45, 46, - 50, 51, 52, 53, 54, 55, 56, - 57, 58, 59, 60, 61, 62, - 66, 67, 68, 69, 70, 71, 72, - 73, 74, 75, 76, 77, 78, - 82, 83, 84, 85, 86, 87, 88, - 89, 90, 91, 92, 93, 94, - 98, 99, 100, 101, 102, 103, 104, - 105, 106, 107, 108, 109, 110, - 114, 115, 116, 117, 118, 119, 120, - 121, 122, 123, 124, 125, 126 - }, - .oobfree = { - {.offset = 15, .length = 3}, - {.offset = 31, .length = 3}, - {.offset = 47, .length = 3}, - {.offset = 63, .length = 3}, - {.offset = 79, .length = 3}, - {.offset = 95, .length = 3}, - {.offset = 111, .length = 3}, - {.offset = 127, .length = 1} - } -}; - -/* - * ECC4 layout for NAND of pagesize 4096 bytes & OOBsize 224 bytes. 13*8 bytes - * of OOB size is reserved for ECC, Byte no. 0 & 1 reserved for bad block & 118 - * bytes are free for use. - */ -static struct nand_ecclayout fsmc_ecc4_224_layout = { - .eccbytes = 104, - .eccpos = { 2, 3, 4, 5, 6, 7, 8, - 9, 10, 11, 12, 13, 14, - 18, 19, 20, 21, 22, 23, 24, - 25, 26, 27, 28, 29, 30, - 34, 35, 36, 37, 38, 39, 40, - 41, 42, 43, 44, 45, 46, - 50, 51, 52, 53, 54, 55, 56, - 57, 58, 59, 60, 61, 62, - 66, 67, 68, 69, 70, 71, 72, - 73, 74, 75, 76, 77, 78, - 82, 83, 84, 85, 86, 87, 88, - 89, 90, 91, 92, 93, 94, - 98, 99, 100, 101, 102, 103, 104, - 105, 106, 107, 108, 109, 110, - 114, 115, 116, 117, 118, 119, 120, - 121, 122, 123, 124, 125, 126 - }, - .oobfree = { - {.offset = 15, .length = 3}, - {.offset = 31, .length = 3}, - {.offset = 47, .length = 3}, - {.offset = 63, .length = 3}, - {.offset = 79, .length = 3}, - {.offset = 95, .length = 3}, - {.offset = 111, .length = 3}, - {.offset = 127, .length = 97} - } -}; - -/* - * ECC placement definitions in oobfree type format - * There are 13 bytes of ecc for every 512 byte block and it has to be read - * consecutively and immediately after the 512 byte data block for hardware to - * generate the error bit offsets in 512 byte data - * Managing the ecc bytes in the following way makes it easier for software to - * read ecc bytes consecutive to data bytes. This way is similar to - * oobfree structure maintained already in u-boot nand driver - */ -static struct fsmc_eccplace fsmc_eccpl_lp = { - .eccplace = { - {.offset = 2, .length = 13}, - {.offset = 18, .length = 13}, - {.offset = 34, .length = 13}, - {.offset = 50, .length = 13}, - {.offset = 66, .length = 13}, - {.offset = 82, .length = 13}, - {.offset = 98, .length = 13}, - {.offset = 114, .length = 13} - } -}; - -static struct nand_ecclayout fsmc_ecc4_sp_layout = { - .eccbytes = 13, - .eccpos = { 0, 1, 2, 3, 6, 7, 8, - 9, 10, 11, 12, 13, 14 - }, - .oobfree = { - {.offset = 15, .length = 1}, - } -}; - -static struct fsmc_eccplace fsmc_eccpl_sp = { - .eccplace = { - {.offset = 0, .length = 4}, - {.offset = 6, .length = 9} - } -}; - -static struct nand_ecclayout fsmc_ecc1_layout = { - .eccbytes = 24, - .eccpos = {2, 3, 4, 18, 19, 20, 34, 35, 36, 50, 51, 52, - 66, 67, 68, 82, 83, 84, 98, 99, 100, 114, 115, 116}, - .oobfree = { - {.offset = 8, .length = 8}, - {.offset = 24, .length = 8}, - {.offset = 40, .length = 8}, - {.offset = 56, .length = 8}, - {.offset = 72, .length = 8}, - {.offset = 88, .length = 8}, - {.offset = 104, .length = 8}, - {.offset = 120, .length = 8} - } -}; - -/* Count the number of 0's in buff upto a max of max_bits */ -static int count_written_bits(uint8_t *buff, int size, int max_bits) -{ - int k, written_bits = 0; - - for (k = 0; k < size; k++) { - written_bits += hweight8(~buff[k]); - if (written_bits > max_bits) - break; - } - - return written_bits; -} - -static void fsmc_nand_hwcontrol(struct mtd_info *mtd, int cmd, uint ctrl) -{ - struct nand_chip *this = mtd->priv; - ulong IO_ADDR_W; - - if (ctrl & NAND_CTRL_CHANGE) { - IO_ADDR_W = (ulong)this->IO_ADDR_W; - - IO_ADDR_W &= ~(CONFIG_SYS_NAND_CLE | CONFIG_SYS_NAND_ALE); - if (ctrl & NAND_CLE) - IO_ADDR_W |= CONFIG_SYS_NAND_CLE; - if (ctrl & NAND_ALE) - IO_ADDR_W |= CONFIG_SYS_NAND_ALE; - - if (ctrl & NAND_NCE) { - writel(readl(&fsmc_regs_p->pc) | - FSMC_ENABLE, &fsmc_regs_p->pc); - } else { - writel(readl(&fsmc_regs_p->pc) & - ~FSMC_ENABLE, &fsmc_regs_p->pc); - } - this->IO_ADDR_W = (void *)IO_ADDR_W; - } - - if (cmd != NAND_CMD_NONE) - writeb(cmd, this->IO_ADDR_W); -} - -static int fsmc_bch8_correct_data(struct mtd_info *mtd, u_char *dat, - u_char *read_ecc, u_char *calc_ecc) -{ - /* The calculated ecc is actually the correction index in data */ - u32 err_idx[8]; - u32 num_err, i; - u32 ecc1, ecc2, ecc3, ecc4; - - num_err = (readl(&fsmc_regs_p->sts) >> 10) & 0xF; - - if (likely(num_err == 0)) - return 0; - - if (unlikely(num_err > 8)) { - /* - * This is a temporary erase check. A newly erased page read - * would result in an ecc error because the oob data is also - * erased to FF and the calculated ecc for an FF data is not - * FF..FF. - * This is a workaround to skip performing correction in case - * data is FF..FF - * - * Logic: - * For every page, each bit written as 0 is counted until these - * number of bits are greater than 8 (the maximum correction - * capability of FSMC for each 512 + 13 bytes) - */ - - int bits_ecc = count_written_bits(read_ecc, 13, 8); - int bits_data = count_written_bits(dat, 512, 8); - - if ((bits_ecc + bits_data) <= 8) { - if (bits_data) - memset(dat, 0xff, 512); - return bits_data + bits_ecc; - } - - return -EBADMSG; - } - - ecc1 = readl(&fsmc_regs_p->ecc1); - ecc2 = readl(&fsmc_regs_p->ecc2); - ecc3 = readl(&fsmc_regs_p->ecc3); - ecc4 = readl(&fsmc_regs_p->sts); - - err_idx[0] = (ecc1 >> 0) & 0x1FFF; - err_idx[1] = (ecc1 >> 13) & 0x1FFF; - err_idx[2] = (((ecc2 >> 0) & 0x7F) << 6) | ((ecc1 >> 26) & 0x3F); - err_idx[3] = (ecc2 >> 7) & 0x1FFF; - err_idx[4] = (((ecc3 >> 0) & 0x1) << 12) | ((ecc2 >> 20) & 0xFFF); - err_idx[5] = (ecc3 >> 1) & 0x1FFF; - err_idx[6] = (ecc3 >> 14) & 0x1FFF; - err_idx[7] = (((ecc4 >> 16) & 0xFF) << 5) | ((ecc3 >> 27) & 0x1F); - - i = 0; - while (i < num_err) { - err_idx[i] ^= 3; - - if (err_idx[i] < 512 * 8) - __change_bit(err_idx[i], dat); - - i++; - } - - return num_err; -} - -static int fsmc_read_hwecc(struct mtd_info *mtd, - const u_char *data, u_char *ecc) -{ - u_int ecc_tmp; - int timeout = CONFIG_SYS_HZ; - ulong start; - - switch (fsmc_version) { - case FSMC_VER8: - start = get_timer(0); - while (get_timer(start) < timeout) { - /* - * Busy waiting for ecc computation - * to finish for 512 bytes - */ - if (readl(&fsmc_regs_p->sts) & FSMC_CODE_RDY) - break; - } - - ecc_tmp = readl(&fsmc_regs_p->ecc1); - ecc[0] = (u_char) (ecc_tmp >> 0); - ecc[1] = (u_char) (ecc_tmp >> 8); - ecc[2] = (u_char) (ecc_tmp >> 16); - ecc[3] = (u_char) (ecc_tmp >> 24); - - ecc_tmp = readl(&fsmc_regs_p->ecc2); - ecc[4] = (u_char) (ecc_tmp >> 0); - ecc[5] = (u_char) (ecc_tmp >> 8); - ecc[6] = (u_char) (ecc_tmp >> 16); - ecc[7] = (u_char) (ecc_tmp >> 24); - - ecc_tmp = readl(&fsmc_regs_p->ecc3); - ecc[8] = (u_char) (ecc_tmp >> 0); - ecc[9] = (u_char) (ecc_tmp >> 8); - ecc[10] = (u_char) (ecc_tmp >> 16); - ecc[11] = (u_char) (ecc_tmp >> 24); - - ecc_tmp = readl(&fsmc_regs_p->sts); - ecc[12] = (u_char) (ecc_tmp >> 16); - break; - - default: - ecc_tmp = readl(&fsmc_regs_p->ecc1); - ecc[0] = (u_char) (ecc_tmp >> 0); - ecc[1] = (u_char) (ecc_tmp >> 8); - ecc[2] = (u_char) (ecc_tmp >> 16); - break; - } - - return 0; -} - -void fsmc_enable_hwecc(struct mtd_info *mtd, int mode) -{ - writel(readl(&fsmc_regs_p->pc) & ~FSMC_ECCPLEN_256, - &fsmc_regs_p->pc); - writel(readl(&fsmc_regs_p->pc) & ~FSMC_ECCEN, - &fsmc_regs_p->pc); - writel(readl(&fsmc_regs_p->pc) | FSMC_ECCEN, - &fsmc_regs_p->pc); -} - -/* - * fsmc_read_page_hwecc - * @mtd: mtd info structure - * @chip: nand chip info structure - * @buf: buffer to store read data - * @oob_required: caller expects OOB data read to chip->oob_poi - * @page: page number to read - * - * This routine is needed for fsmc verison 8 as reading from NAND chip has to be - * performed in a strict sequence as follows: - * data(512 byte) -> ecc(13 byte) - * After this read, fsmc hardware generates and reports error data bits(upto a - * max of 8 bits) - */ -static int fsmc_read_page_hwecc(struct mtd_info *mtd, struct nand_chip *chip, - uint8_t *buf, int oob_required, int page) -{ - struct fsmc_eccplace *fsmc_eccpl; - int i, j, s, stat, eccsize = chip->ecc.size; - int eccbytes = chip->ecc.bytes; - int eccsteps = chip->ecc.steps; - uint8_t *p = buf; - uint8_t *ecc_calc = chip->buffers->ecccalc; - uint8_t *ecc_code = chip->buffers->ecccode; - int off, len, group = 0; - uint8_t oob[13] __attribute__ ((aligned (2))); - - /* Differentiate between small and large page ecc place definitions */ - if (mtd->writesize == 512) - fsmc_eccpl = &fsmc_eccpl_sp; - else - fsmc_eccpl = &fsmc_eccpl_lp; - - for (i = 0, s = 0; s < eccsteps; s++, i += eccbytes, p += eccsize) { - - chip->cmdfunc(mtd, NAND_CMD_READ0, s * eccsize, page); - chip->ecc.hwctl(mtd, NAND_ECC_READ); - chip->read_buf(mtd, p, eccsize); - - for (j = 0; j < eccbytes;) { - off = fsmc_eccpl->eccplace[group].offset; - len = fsmc_eccpl->eccplace[group].length; - group++; - - /* - * length is intentionally kept a higher multiple of 2 - * to read at least 13 bytes even in case of 16 bit NAND - * devices - */ - if (chip->options & NAND_BUSWIDTH_16) - len = roundup(len, 2); - chip->cmdfunc(mtd, NAND_CMD_READOOB, off, page); - chip->read_buf(mtd, oob + j, len); - j += len; - } - - memcpy(&ecc_code[i], oob, 13); - chip->ecc.calculate(mtd, p, &ecc_calc[i]); - - stat = chip->ecc.correct(mtd, p, &ecc_code[i], - &ecc_calc[i]); - if (stat < 0) - mtd->ecc_stats.failed++; - else - mtd->ecc_stats.corrected += stat; - } - - return 0; -} - -int fsmc_nand_init(struct nand_chip *nand) -{ - static int chip_nr; - struct mtd_info *mtd; - int i; - u32 peripid2 = readl(&fsmc_regs_p->peripid2); - - fsmc_version = (peripid2 >> FSMC_REVISION_SHFT) & - FSMC_REVISION_MSK; - - writel(readl(&fsmc_regs_p->ctrl) | FSMC_WP, &fsmc_regs_p->ctrl); - -#if defined(CONFIG_SYS_FSMC_NAND_16BIT) - writel(FSMC_DEVWID_16 | FSMC_DEVTYPE_NAND | FSMC_ENABLE | FSMC_WAITON, - &fsmc_regs_p->pc); -#elif defined(CONFIG_SYS_FSMC_NAND_8BIT) - writel(FSMC_DEVWID_8 | FSMC_DEVTYPE_NAND | FSMC_ENABLE | FSMC_WAITON, - &fsmc_regs_p->pc); -#else -#error Please define CONFIG_SYS_FSMC_NAND_16BIT or CONFIG_SYS_FSMC_NAND_8BIT -#endif - writel(readl(&fsmc_regs_p->pc) | FSMC_TCLR_1 | FSMC_TAR_1, - &fsmc_regs_p->pc); - writel(FSMC_THIZ_1 | FSMC_THOLD_4 | FSMC_TWAIT_6 | FSMC_TSET_0, - &fsmc_regs_p->comm); - writel(FSMC_THIZ_1 | FSMC_THOLD_4 | FSMC_TWAIT_6 | FSMC_TSET_0, - &fsmc_regs_p->attrib); - - nand->options = 0; -#if defined(CONFIG_SYS_FSMC_NAND_16BIT) - nand->options |= NAND_BUSWIDTH_16; -#endif - nand->ecc.mode = NAND_ECC_HW; - nand->ecc.size = 512; - nand->ecc.calculate = fsmc_read_hwecc; - nand->ecc.hwctl = fsmc_enable_hwecc; - nand->cmd_ctrl = fsmc_nand_hwcontrol; - nand->IO_ADDR_R = nand->IO_ADDR_W = - (void __iomem *)CONFIG_SYS_NAND_BASE; - nand->badblockbits = 7; - - mtd = &nand_info[chip_nr++]; - mtd->priv = nand; - - switch (fsmc_version) { - case FSMC_VER8: - nand->ecc.bytes = 13; - nand->ecc.strength = 8; - nand->ecc.correct = fsmc_bch8_correct_data; - nand->ecc.read_page = fsmc_read_page_hwecc; - if (mtd->writesize == 512) - nand->ecc.layout = &fsmc_ecc4_sp_layout; - else { - if (mtd->oobsize == 224) - nand->ecc.layout = &fsmc_ecc4_224_layout; - else - nand->ecc.layout = &fsmc_ecc4_lp_layout; - } - - break; - default: - nand->ecc.bytes = 3; - nand->ecc.strength = 1; - nand->ecc.layout = &fsmc_ecc1_layout; - nand->ecc.correct = nand_correct_data; - break; - } - - /* Detect NAND chips */ - if (nand_scan_ident(mtd, CONFIG_SYS_MAX_NAND_DEVICE, NULL)) - return -ENXIO; - - if (nand_scan_tail(mtd)) - return -ENXIO; - - for (i = 0; i < CONFIG_SYS_MAX_NAND_DEVICE; i++) - if (nand_register(i)) - return -ENXIO; - - return 0; -} diff --git a/qemu/roms/u-boot/drivers/mtd/nand/jz4740_nand.c b/qemu/roms/u-boot/drivers/mtd/nand/jz4740_nand.c deleted file mode 100644 index 7a62cc336..000000000 --- a/qemu/roms/u-boot/drivers/mtd/nand/jz4740_nand.c +++ /dev/null @@ -1,259 +0,0 @@ -/* - * Platform independend driver for JZ4740. - * - * Copyright (c) 2007 Ingenic Semiconductor Inc. - * Author: <jlwei@ingenic.cn> - * - * SPDX-License-Identifier: GPL-2.0+ - */ -#include <common.h> - -#include <nand.h> -#include <asm/io.h> -#include <asm/jz4740.h> - -#define JZ_NAND_DATA_ADDR ((void __iomem *)0xB8000000) -#define JZ_NAND_CMD_ADDR (JZ_NAND_DATA_ADDR + 0x8000) -#define JZ_NAND_ADDR_ADDR (JZ_NAND_DATA_ADDR + 0x10000) - -#define BIT(x) (1 << (x)) -#define JZ_NAND_ECC_CTRL_ENCODING BIT(3) -#define JZ_NAND_ECC_CTRL_RS BIT(2) -#define JZ_NAND_ECC_CTRL_RESET BIT(1) -#define JZ_NAND_ECC_CTRL_ENABLE BIT(0) - -#define EMC_SMCR1_OPT_NAND 0x094c4400 -/* Optimize the timing of nand */ - -static struct jz4740_emc * emc = (struct jz4740_emc *)JZ4740_EMC_BASE; - -static struct nand_ecclayout qi_lb60_ecclayout_2gb = { - .eccbytes = 72, - .eccpos = { - 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 }, - .oobfree = { - {.offset = 2, - .length = 10 }, - {.offset = 84, - .length = 44 } } -}; - -static int is_reading; - -static void jz_nand_cmd_ctrl(struct mtd_info *mtd, int cmd, unsigned int ctrl) -{ - struct nand_chip *this = mtd->priv; - uint32_t reg; - - if (ctrl & NAND_CTRL_CHANGE) { - if (ctrl & NAND_ALE) - this->IO_ADDR_W = JZ_NAND_ADDR_ADDR; - else if (ctrl & NAND_CLE) - this->IO_ADDR_W = JZ_NAND_CMD_ADDR; - else - this->IO_ADDR_W = JZ_NAND_DATA_ADDR; - - reg = readl(&emc->nfcsr); - if (ctrl & NAND_NCE) - reg |= EMC_NFCSR_NFCE1; - else - reg &= ~EMC_NFCSR_NFCE1; - writel(reg, &emc->nfcsr); - } - - if (cmd != NAND_CMD_NONE) - writeb(cmd, this->IO_ADDR_W); -} - -static int jz_nand_device_ready(struct mtd_info *mtd) -{ - return (readl(GPIO_PXPIN(2)) & 0x40000000) ? 1 : 0; -} - -void board_nand_select_device(struct nand_chip *nand, int chip) -{ - /* - * Don't use "chip" to address the NAND device, - * generate the cs from the address where it is encoded. - */ -} - -static int jz_nand_rs_calculate_ecc(struct mtd_info *mtd, const u_char *dat, - u_char *ecc_code) -{ - uint32_t status; - int i; - - if (is_reading) - return 0; - - do { - status = readl(&emc->nfints); - } while (!(status & EMC_NFINTS_ENCF)); - - /* disable ecc */ - writel(readl(&emc->nfecr) & ~EMC_NFECR_ECCE, &emc->nfecr); - - for (i = 0; i < 9; i++) - ecc_code[i] = readb(&emc->nfpar[i]); - - return 0; -} - -static void jz_nand_hwctl(struct mtd_info *mtd, int mode) -{ - uint32_t reg; - - writel(0, &emc->nfints); - reg = readl(&emc->nfecr); - reg |= JZ_NAND_ECC_CTRL_RESET; - reg |= JZ_NAND_ECC_CTRL_ENABLE; - reg |= JZ_NAND_ECC_CTRL_RS; - - switch (mode) { - case NAND_ECC_READ: - reg &= ~JZ_NAND_ECC_CTRL_ENCODING; - is_reading = 1; - break; - case NAND_ECC_WRITE: - reg |= JZ_NAND_ECC_CTRL_ENCODING; - is_reading = 0; - break; - default: - break; - } - - writel(reg, &emc->nfecr); -} - -/* Correct 1~9-bit errors in 512-bytes data */ -static void jz_rs_correct(unsigned char *dat, int idx, int mask) -{ - int i; - - idx--; - - i = idx + (idx >> 3); - if (i >= 512) - return; - - mask <<= (idx & 0x7); - - dat[i] ^= mask & 0xff; - if (i < 511) - dat[i + 1] ^= (mask >> 8) & 0xff; -} - -static int jz_nand_rs_correct_data(struct mtd_info *mtd, u_char *dat, - u_char *read_ecc, u_char *calc_ecc) -{ - int k; - uint32_t errcnt, index, mask, status; - - /* Set PAR values */ - const uint8_t all_ff_ecc[] = { - 0xcd, 0x9d, 0x90, 0x58, 0xf4, 0x8b, 0xff, 0xb7, 0x6f }; - - if (read_ecc[0] == 0xff && read_ecc[1] == 0xff && - read_ecc[2] == 0xff && read_ecc[3] == 0xff && - read_ecc[4] == 0xff && read_ecc[5] == 0xff && - read_ecc[6] == 0xff && read_ecc[7] == 0xff && - read_ecc[8] == 0xff) { - for (k = 0; k < 9; k++) - writeb(all_ff_ecc[k], &emc->nfpar[k]); - } else { - for (k = 0; k < 9; k++) - writeb(read_ecc[k], &emc->nfpar[k]); - } - /* Set PRDY */ - writel(readl(&emc->nfecr) | EMC_NFECR_PRDY, &emc->nfecr); - - /* Wait for completion */ - do { - status = readl(&emc->nfints); - } while (!(status & EMC_NFINTS_DECF)); - - /* disable ecc */ - writel(readl(&emc->nfecr) & ~EMC_NFECR_ECCE, &emc->nfecr); - - /* Check decoding */ - if (!(status & EMC_NFINTS_ERR)) - return 0; - - if (status & EMC_NFINTS_UNCOR) { - printf("uncorrectable ecc\n"); - return -1; - } - - errcnt = (status & EMC_NFINTS_ERRCNT_MASK) >> EMC_NFINTS_ERRCNT_BIT; - - switch (errcnt) { - case 4: - index = (readl(&emc->nferr[3]) & EMC_NFERR_INDEX_MASK) >> - EMC_NFERR_INDEX_BIT; - mask = (readl(&emc->nferr[3]) & EMC_NFERR_MASK_MASK) >> - EMC_NFERR_MASK_BIT; - jz_rs_correct(dat, index, mask); - case 3: - index = (readl(&emc->nferr[2]) & EMC_NFERR_INDEX_MASK) >> - EMC_NFERR_INDEX_BIT; - mask = (readl(&emc->nferr[2]) & EMC_NFERR_MASK_MASK) >> - EMC_NFERR_MASK_BIT; - jz_rs_correct(dat, index, mask); - case 2: - index = (readl(&emc->nferr[1]) & EMC_NFERR_INDEX_MASK) >> - EMC_NFERR_INDEX_BIT; - mask = (readl(&emc->nferr[1]) & EMC_NFERR_MASK_MASK) >> - EMC_NFERR_MASK_BIT; - jz_rs_correct(dat, index, mask); - case 1: - index = (readl(&emc->nferr[0]) & EMC_NFERR_INDEX_MASK) >> - EMC_NFERR_INDEX_BIT; - mask = (readl(&emc->nferr[0]) & EMC_NFERR_MASK_MASK) >> - EMC_NFERR_MASK_BIT; - jz_rs_correct(dat, index, mask); - default: - break; - } - - return errcnt; -} - -/* - * Main initialization routine - */ -int board_nand_init(struct nand_chip *nand) -{ - uint32_t reg; - - reg = readl(&emc->nfcsr); - reg |= EMC_NFCSR_NFE1; /* EMC setup, Set NFE bit */ - writel(reg, &emc->nfcsr); - - writel(EMC_SMCR1_OPT_NAND, &emc->smcr[1]); - - nand->IO_ADDR_R = JZ_NAND_DATA_ADDR; - nand->IO_ADDR_W = JZ_NAND_DATA_ADDR; - nand->cmd_ctrl = jz_nand_cmd_ctrl; - nand->dev_ready = jz_nand_device_ready; - nand->ecc.hwctl = jz_nand_hwctl; - nand->ecc.correct = jz_nand_rs_correct_data; - nand->ecc.calculate = jz_nand_rs_calculate_ecc; - nand->ecc.mode = NAND_ECC_HW_OOB_FIRST; - nand->ecc.size = CONFIG_SYS_NAND_ECCSIZE; - nand->ecc.bytes = CONFIG_SYS_NAND_ECCBYTES; - nand->ecc.strength = 4; - nand->ecc.layout = &qi_lb60_ecclayout_2gb; - nand->chip_delay = 50; - nand->bbt_options |= NAND_BBT_USE_FLASH; - - return 0; -} diff --git a/qemu/roms/u-boot/drivers/mtd/nand/kb9202_nand.c b/qemu/roms/u-boot/drivers/mtd/nand/kb9202_nand.c deleted file mode 100644 index 22c562540..000000000 --- a/qemu/roms/u-boot/drivers/mtd/nand/kb9202_nand.c +++ /dev/null @@ -1,134 +0,0 @@ -/* - * (C) Copyright 2006 - * KwikByte <kb9200_dev@kwikbyte.com> - * - * (C) Copyright 2009 - * Matthias Kaehlcke <matthias@kaehlcke.net> - * - * SPDX-License-Identifier: GPL-2.0+ - */ - -#include <common.h> -#include <asm/io.h> -#include <asm/arch/AT91RM9200.h> -#include <asm/arch/hardware.h> - -#include <nand.h> - -/* - * hardware specific access to control-lines - */ - -#define MASK_ALE (1 << 22) /* our ALE is A22 */ -#define MASK_CLE (1 << 21) /* our CLE is A21 */ - -#define KB9202_NAND_NCE (1 << 28) /* EN* on D28 */ -#define KB9202_NAND_BUSY (1 << 29) /* RB* on D29 */ - -#define KB9202_SMC2_NWS (1 << 2) -#define KB9202_SMC2_TDF (1 << 8) -#define KB9202_SMC2_RWSETUP (1 << 24) -#define KB9202_SMC2_RWHOLD (1 << 29) - -/* - * Board-specific function to access device control signals - */ -static void kb9202_nand_hwcontrol(struct mtd_info *mtd, int cmd, unsigned int ctrl) -{ - struct nand_chip *this = mtd->priv; - - if (ctrl & NAND_CTRL_CHANGE) { - ulong IO_ADDR_W = (ulong) this->IO_ADDR_W; - - /* clear ALE and CLE bits */ - IO_ADDR_W &= ~(MASK_ALE | MASK_CLE); - - if (ctrl & NAND_CLE) - IO_ADDR_W |= MASK_CLE; - - if (ctrl & NAND_ALE) - IO_ADDR_W |= MASK_ALE; - - this->IO_ADDR_W = (void *) IO_ADDR_W; - - if (ctrl & NAND_NCE) - writel(KB9202_NAND_NCE, AT91C_PIOC_CODR); - else - writel(KB9202_NAND_NCE, AT91C_PIOC_SODR); - } - - if (cmd != NAND_CMD_NONE) - writeb(cmd, this->IO_ADDR_W); -} - - -/* - * Board-specific function to access the device ready signal. - */ -static int kb9202_nand_ready(struct mtd_info *mtd) -{ - return readl(AT91C_PIOC_PDSR) & KB9202_NAND_BUSY; -} - - -/* - * Board-specific NAND init. Copied from include/linux/mtd/nand.h for reference. - * - * struct nand_chip - NAND Private Flash Chip Data - * @IO_ADDR_R: [BOARDSPECIFIC] address to read the 8 I/O lines of the flash device - * @IO_ADDR_W: [BOARDSPECIFIC] address to write the 8 I/O lines of the flash device - * @hwcontrol: [BOARDSPECIFIC] hardwarespecific function for accesing control-lines - * @dev_ready: [BOARDSPECIFIC] hardwarespecific function for accesing device ready/busy line - * If set to NULL no access to ready/busy is available and the ready/busy information - * is read from the chip status register - * @enable_hwecc: [BOARDSPECIFIC] function to enable (reset) hardware ecc generator. Must only - * be provided if a hardware ECC is available - * @eccmode: [BOARDSPECIFIC] mode of ecc, see defines - * @chip_delay: [BOARDSPECIFIC] chip dependent delay for transfering data from array to read regs (tR) - * @options: [BOARDSPECIFIC] various chip options. They can partly be set to inform nand_scan about - * special functionality. See the defines for further explanation -*/ -/* - * This routine initializes controller and GPIOs. - */ -int board_nand_init(struct nand_chip *nand) -{ - unsigned int value; - - nand->ecc.mode = NAND_ECC_SOFT; - nand->cmd_ctrl = kb9202_nand_hwcontrol; - nand->dev_ready = kb9202_nand_ready; - - /* in case running outside of bootloader */ - writel(1 << AT91C_ID_PIOC, AT91C_PMC_PCER); - - /* setup nand flash access (allow ample margin) */ - /* 4 wait states, 1 setup, 1 hold, 1 float for 8-bit device */ - writel(AT91C_SMC2_WSEN | KB9202_SMC2_NWS | KB9202_SMC2_TDF | - AT91C_SMC2_DBW_8 | KB9202_SMC2_RWSETUP | KB9202_SMC2_RWHOLD, - AT91C_SMC_CSR3); - - /* enable internal NAND controller */ - value = readl(AT91C_EBI_CSA); - value |= AT91C_EBI_CS3A_SMC_SmartMedia; - writel(value, AT91C_EBI_CSA); - - /* enable SMOE/SMWE */ - writel(AT91C_PC1_BFRDY_SMOE | AT91C_PC3_BFBAA_SMWE, AT91C_PIOC_ASR); - writel(AT91C_PC1_BFRDY_SMOE | AT91C_PC3_BFBAA_SMWE, AT91C_PIOC_PDR); - writel(AT91C_PC1_BFRDY_SMOE | AT91C_PC3_BFBAA_SMWE, AT91C_PIOC_OER); - - /* set NCE to high */ - writel(KB9202_NAND_NCE, AT91C_PIOC_SODR); - - /* disable output on pin connected to the busy line of the NAND */ - writel(KB9202_NAND_BUSY, AT91C_PIOC_ODR); - - /* enable the PIO to control NCE and BUSY */ - writel(KB9202_NAND_NCE | KB9202_NAND_BUSY, AT91C_PIOC_PER); - - /* enable output for NCE */ - writel(KB9202_NAND_NCE, AT91C_PIOC_OER); - - return (0); -} diff --git a/qemu/roms/u-boot/drivers/mtd/nand/kirkwood_nand.c b/qemu/roms/u-boot/drivers/mtd/nand/kirkwood_nand.c deleted file mode 100644 index 72687a1da..000000000 --- a/qemu/roms/u-boot/drivers/mtd/nand/kirkwood_nand.c +++ /dev/null @@ -1,70 +0,0 @@ -/* - * (C) Copyright 2009 - * Marvell Semiconductor <www.marvell.com> - * Written-by: Prafulla Wadaskar <prafulla@marvell.com> - * - * SPDX-License-Identifier: GPL-2.0+ - */ - -#include <common.h> -#include <asm/io.h> -#include <asm/arch/kirkwood.h> -#include <nand.h> - -/* NAND Flash Soc registers */ -struct kwnandf_registers { - u32 rd_params; /* 0x10418 */ - u32 wr_param; /* 0x1041c */ - u8 pad[0x10470 - 0x1041c - 4]; - u32 ctrl; /* 0x10470 */ -}; - -static struct kwnandf_registers *nf_reg = - (struct kwnandf_registers *)KW_NANDF_BASE; - -/* - * hardware specific access to control-lines/bits - */ -#define NAND_ACTCEBOOT_BIT 0x02 - -static void kw_nand_hwcontrol(struct mtd_info *mtd, int cmd, - unsigned int ctrl) -{ - struct nand_chip *nc = mtd->priv; - u32 offs; - - if (cmd == NAND_CMD_NONE) - return; - - if (ctrl & NAND_CLE) - offs = (1 << 0); /* Commands with A[1:0] == 01 */ - else if (ctrl & NAND_ALE) - offs = (1 << 1); /* Addresses with A[1:0] == 10 */ - else - return; - - writeb(cmd, nc->IO_ADDR_W + offs); -} - -void kw_nand_select_chip(struct mtd_info *mtd, int chip) -{ - u32 data; - - data = readl(&nf_reg->ctrl); - data |= NAND_ACTCEBOOT_BIT; - writel(data, &nf_reg->ctrl); -} - -int board_nand_init(struct nand_chip *nand) -{ - nand->options = NAND_COPYBACK | NAND_CACHEPRG | NAND_NO_PADDING; -#if defined(CONFIG_NAND_ECC_BCH) - nand->ecc.mode = NAND_ECC_SOFT_BCH; -#else - nand->ecc.mode = NAND_ECC_SOFT; -#endif - nand->cmd_ctrl = kw_nand_hwcontrol; - nand->chip_delay = 40; - nand->select_chip = kw_nand_select_chip; - return 0; -} diff --git a/qemu/roms/u-boot/drivers/mtd/nand/kmeter1_nand.c b/qemu/roms/u-boot/drivers/mtd/nand/kmeter1_nand.c deleted file mode 100644 index df0bde579..000000000 --- a/qemu/roms/u-boot/drivers/mtd/nand/kmeter1_nand.c +++ /dev/null @@ -1,123 +0,0 @@ -/* - * (C) Copyright 2009 - * Heiko Schocher, DENX Software Engineering, hs@denx.de - * - * SPDX-License-Identifier: GPL-2.0+ - */ - -#include <common.h> -#include <nand.h> -#include <asm/io.h> - -#define CONFIG_NAND_MODE_REG (void *)(CONFIG_SYS_NAND_BASE + 0x20000) -#define CONFIG_NAND_DATA_REG (void *)(CONFIG_SYS_NAND_BASE + 0x30000) - -#define read_mode() in_8(CONFIG_NAND_MODE_REG) -#define write_mode(val) out_8(CONFIG_NAND_MODE_REG, val) -#define read_data() in_8(CONFIG_NAND_DATA_REG) -#define write_data(val) out_8(CONFIG_NAND_DATA_REG, val) - -#define KPN_RDY2 (1 << 7) -#define KPN_RDY1 (1 << 6) -#define KPN_WPN (1 << 4) -#define KPN_CE2N (1 << 3) -#define KPN_CE1N (1 << 2) -#define KPN_ALE (1 << 1) -#define KPN_CLE (1 << 0) - -#define KPN_DEFAULT_CHIP_DELAY 50 - -static int kpn_chip_ready(void) -{ - if (read_mode() & KPN_RDY1) - return 1; - - return 0; -} - -static void kpn_wait_rdy(void) -{ - int cnt = 1000000; - - while (--cnt && !kpn_chip_ready()) - udelay(1); - - if (!cnt) - printf ("timeout while waiting for RDY\n"); -} - -static void kpn_nand_hwcontrol(struct mtd_info *mtd, int cmd, unsigned int ctrl) -{ - u8 reg_val = read_mode(); - - if (ctrl & NAND_CTRL_CHANGE) { - reg_val = reg_val & ~(KPN_ALE + KPN_CLE); - - if (ctrl & NAND_CLE) - reg_val = reg_val | KPN_CLE; - if (ctrl & NAND_ALE) - reg_val = reg_val | KPN_ALE; - if (ctrl & NAND_NCE) - reg_val = reg_val & ~KPN_CE1N; - else - reg_val = reg_val | KPN_CE1N; - - write_mode(reg_val); - } - if (cmd != NAND_CMD_NONE) - write_data(cmd); - - /* wait until flash is ready */ - kpn_wait_rdy(); -} - -static u_char kpn_nand_read_byte(struct mtd_info *mtd) -{ - return read_data(); -} - -static void kpn_nand_write_buf(struct mtd_info *mtd, const u_char *buf, int len) -{ - int i; - - for (i = 0; i < len; i++) { - write_data(buf[i]); - kpn_wait_rdy(); - } -} - -static void kpn_nand_read_buf(struct mtd_info *mtd, u_char *buf, int len) -{ - int i; - - for (i = 0; i < len; i++) - buf[i] = read_data(); -} - -static int kpn_nand_dev_ready(struct mtd_info *mtd) -{ - kpn_wait_rdy(); - - return 1; -} - -int board_nand_init(struct nand_chip *nand) -{ -#if defined(CONFIG_NAND_ECC_BCH) - nand->ecc.mode = NAND_ECC_SOFT_BCH; -#else - nand->ecc.mode = NAND_ECC_SOFT; -#endif - - /* Reference hardware control function */ - nand->cmd_ctrl = kpn_nand_hwcontrol; - nand->read_byte = kpn_nand_read_byte; - nand->write_buf = kpn_nand_write_buf; - nand->read_buf = kpn_nand_read_buf; - nand->dev_ready = kpn_nand_dev_ready; - nand->chip_delay = KPN_DEFAULT_CHIP_DELAY; - - /* reset mode register */ - write_mode(KPN_CE1N + KPN_CE2N + KPN_WPN); - return 0; -} diff --git a/qemu/roms/u-boot/drivers/mtd/nand/mpc5121_nfc.c b/qemu/roms/u-boot/drivers/mtd/nand/mpc5121_nfc.c deleted file mode 100644 index d0f3a3532..000000000 --- a/qemu/roms/u-boot/drivers/mtd/nand/mpc5121_nfc.c +++ /dev/null @@ -1,681 +0,0 @@ -/* - * Copyright 2004-2008 Freescale Semiconductor, Inc. - * Copyright 2009 Semihalf. - * (C) Copyright 2009 Stefan Roese <sr@denx.de> - * - * Based on original driver from Freescale Semiconductor - * written by John Rigby <jrigby@freescale.com> on basis - * of drivers/mtd/nand/mxc_nand.c. Reworked and extended - * Piotr Ziecik <kosmo@semihalf.com>. - * - * SPDX-License-Identifier: GPL-2.0+ - */ - -#include <common.h> -#include <malloc.h> - -#include <linux/mtd/mtd.h> -#include <linux/mtd/nand.h> -#include <linux/mtd/nand_ecc.h> -#include <linux/compat.h> - -#include <asm/errno.h> -#include <asm/io.h> -#include <asm/processor.h> -#include <nand.h> - -#define DRV_NAME "mpc5121_nfc" - -/* Timeouts */ -#define NFC_RESET_TIMEOUT 1000 /* 1 ms */ -#define NFC_TIMEOUT 2000 /* 2000 us */ - -/* Addresses for NFC MAIN RAM BUFFER areas */ -#define NFC_MAIN_AREA(n) ((n) * 0x200) - -/* Addresses for NFC SPARE BUFFER areas */ -#define NFC_SPARE_BUFFERS 8 -#define NFC_SPARE_LEN 0x40 -#define NFC_SPARE_AREA(n) (0x1000 + ((n) * NFC_SPARE_LEN)) - -/* MPC5121 NFC registers */ -#define NFC_BUF_ADDR 0x1E04 -#define NFC_FLASH_ADDR 0x1E06 -#define NFC_FLASH_CMD 0x1E08 -#define NFC_CONFIG 0x1E0A -#define NFC_ECC_STATUS1 0x1E0C -#define NFC_ECC_STATUS2 0x1E0E -#define NFC_SPAS 0x1E10 -#define NFC_WRPROT 0x1E12 -#define NFC_NF_WRPRST 0x1E18 -#define NFC_CONFIG1 0x1E1A -#define NFC_CONFIG2 0x1E1C -#define NFC_UNLOCKSTART_BLK0 0x1E20 -#define NFC_UNLOCKEND_BLK0 0x1E22 -#define NFC_UNLOCKSTART_BLK1 0x1E24 -#define NFC_UNLOCKEND_BLK1 0x1E26 -#define NFC_UNLOCKSTART_BLK2 0x1E28 -#define NFC_UNLOCKEND_BLK2 0x1E2A -#define NFC_UNLOCKSTART_BLK3 0x1E2C -#define NFC_UNLOCKEND_BLK3 0x1E2E - -/* Bit Definitions: NFC_BUF_ADDR */ -#define NFC_RBA_MASK (7 << 0) -#define NFC_ACTIVE_CS_SHIFT 5 -#define NFC_ACTIVE_CS_MASK (3 << NFC_ACTIVE_CS_SHIFT) - -/* Bit Definitions: NFC_CONFIG */ -#define NFC_BLS_UNLOCKED (1 << 1) - -/* Bit Definitions: NFC_CONFIG1 */ -#define NFC_ECC_4BIT (1 << 0) -#define NFC_FULL_PAGE_DMA (1 << 1) -#define NFC_SPARE_ONLY (1 << 2) -#define NFC_ECC_ENABLE (1 << 3) -#define NFC_INT_MASK (1 << 4) -#define NFC_BIG_ENDIAN (1 << 5) -#define NFC_RESET (1 << 6) -#define NFC_CE (1 << 7) -#define NFC_ONE_CYCLE (1 << 8) -#define NFC_PPB_32 (0 << 9) -#define NFC_PPB_64 (1 << 9) -#define NFC_PPB_128 (2 << 9) -#define NFC_PPB_256 (3 << 9) -#define NFC_PPB_MASK (3 << 9) -#define NFC_FULL_PAGE_INT (1 << 11) - -/* Bit Definitions: NFC_CONFIG2 */ -#define NFC_COMMAND (1 << 0) -#define NFC_ADDRESS (1 << 1) -#define NFC_INPUT (1 << 2) -#define NFC_OUTPUT (1 << 3) -#define NFC_ID (1 << 4) -#define NFC_STATUS (1 << 5) -#define NFC_CMD_FAIL (1 << 15) -#define NFC_INT (1 << 15) - -/* Bit Definitions: NFC_WRPROT */ -#define NFC_WPC_LOCK_TIGHT (1 << 0) -#define NFC_WPC_LOCK (1 << 1) -#define NFC_WPC_UNLOCK (1 << 2) - -struct mpc5121_nfc_prv { - struct mtd_info mtd; - struct nand_chip chip; - int irq; - void __iomem *regs; - struct clk *clk; - uint column; - int spareonly; - int chipsel; -}; - -int mpc5121_nfc_chip = 0; - -static void mpc5121_nfc_done(struct mtd_info *mtd); - -/* Read NFC register */ -static inline u16 nfc_read(struct mtd_info *mtd, uint reg) -{ - struct nand_chip *chip = mtd->priv; - struct mpc5121_nfc_prv *prv = chip->priv; - - return in_be16(prv->regs + reg); -} - -/* Write NFC register */ -static inline void nfc_write(struct mtd_info *mtd, uint reg, u16 val) -{ - struct nand_chip *chip = mtd->priv; - struct mpc5121_nfc_prv *prv = chip->priv; - - out_be16(prv->regs + reg, val); -} - -/* Set bits in NFC register */ -static inline void nfc_set(struct mtd_info *mtd, uint reg, u16 bits) -{ - nfc_write(mtd, reg, nfc_read(mtd, reg) | bits); -} - -/* Clear bits in NFC register */ -static inline void nfc_clear(struct mtd_info *mtd, uint reg, u16 bits) -{ - nfc_write(mtd, reg, nfc_read(mtd, reg) & ~bits); -} - -/* Invoke address cycle */ -static inline void mpc5121_nfc_send_addr(struct mtd_info *mtd, u16 addr) -{ - nfc_write(mtd, NFC_FLASH_ADDR, addr); - nfc_write(mtd, NFC_CONFIG2, NFC_ADDRESS); - mpc5121_nfc_done(mtd); -} - -/* Invoke command cycle */ -static inline void mpc5121_nfc_send_cmd(struct mtd_info *mtd, u16 cmd) -{ - nfc_write(mtd, NFC_FLASH_CMD, cmd); - nfc_write(mtd, NFC_CONFIG2, NFC_COMMAND); - mpc5121_nfc_done(mtd); -} - -/* Send data from NFC buffers to NAND flash */ -static inline void mpc5121_nfc_send_prog_page(struct mtd_info *mtd) -{ - nfc_clear(mtd, NFC_BUF_ADDR, NFC_RBA_MASK); - nfc_write(mtd, NFC_CONFIG2, NFC_INPUT); - mpc5121_nfc_done(mtd); -} - -/* Receive data from NAND flash */ -static inline void mpc5121_nfc_send_read_page(struct mtd_info *mtd) -{ - nfc_clear(mtd, NFC_BUF_ADDR, NFC_RBA_MASK); - nfc_write(mtd, NFC_CONFIG2, NFC_OUTPUT); - mpc5121_nfc_done(mtd); -} - -/* Receive ID from NAND flash */ -static inline void mpc5121_nfc_send_read_id(struct mtd_info *mtd) -{ - nfc_clear(mtd, NFC_BUF_ADDR, NFC_RBA_MASK); - nfc_write(mtd, NFC_CONFIG2, NFC_ID); - mpc5121_nfc_done(mtd); -} - -/* Receive status from NAND flash */ -static inline void mpc5121_nfc_send_read_status(struct mtd_info *mtd) -{ - nfc_clear(mtd, NFC_BUF_ADDR, NFC_RBA_MASK); - nfc_write(mtd, NFC_CONFIG2, NFC_STATUS); - mpc5121_nfc_done(mtd); -} - -static void mpc5121_nfc_done(struct mtd_info *mtd) -{ - int max_retries = NFC_TIMEOUT; - - while (1) { - max_retries--; - if (nfc_read(mtd, NFC_CONFIG2) & NFC_INT) - break; - udelay(1); - } - - if (max_retries <= 0) - printk(KERN_WARNING DRV_NAME - ": Timeout while waiting for completion.\n"); -} - -/* Do address cycle(s) */ -static void mpc5121_nfc_addr_cycle(struct mtd_info *mtd, int column, int page) -{ - struct nand_chip *chip = mtd->priv; - u32 pagemask = chip->pagemask; - - if (column != -1) { - mpc5121_nfc_send_addr(mtd, column); - if (mtd->writesize > 512) - mpc5121_nfc_send_addr(mtd, column >> 8); - } - - if (page != -1) { - do { - mpc5121_nfc_send_addr(mtd, page & 0xFF); - page >>= 8; - pagemask >>= 8; - } while (pagemask); - } -} - -/* Control chip select signals */ - -/* - * Selecting the active device: - * - * This is different than the linux version. Switching between chips - * is done via board_nand_select_device(). The Linux select_chip - * function used here in U-Boot has only 2 valid chip numbers: - * 0 select - * -1 deselect - */ - -/* - * Implement it as a weak default, so that boards with a specific - * chip-select routine can use their own function. - */ -void __mpc5121_nfc_select_chip(struct mtd_info *mtd, int chip) -{ - if (chip < 0) { - nfc_clear(mtd, NFC_CONFIG1, NFC_CE); - return; - } - - nfc_clear(mtd, NFC_BUF_ADDR, NFC_ACTIVE_CS_MASK); - nfc_set(mtd, NFC_BUF_ADDR, (chip << NFC_ACTIVE_CS_SHIFT) & - NFC_ACTIVE_CS_MASK); - nfc_set(mtd, NFC_CONFIG1, NFC_CE); -} -void mpc5121_nfc_select_chip(struct mtd_info *mtd, int chip) - __attribute__((weak, alias("__mpc5121_nfc_select_chip"))); - -void board_nand_select_device(struct nand_chip *nand, int chip) -{ - /* - * Only save this chip number in global variable here. This - * will be used later in mpc5121_nfc_select_chip(). - */ - mpc5121_nfc_chip = chip; -} - -/* Read NAND Ready/Busy signal */ -static int mpc5121_nfc_dev_ready(struct mtd_info *mtd) -{ - /* - * NFC handles ready/busy signal internally. Therefore, this function - * always returns status as ready. - */ - return 1; -} - -/* Write command to NAND flash */ -static void mpc5121_nfc_command(struct mtd_info *mtd, unsigned command, - int column, int page) -{ - struct nand_chip *chip = mtd->priv; - struct mpc5121_nfc_prv *prv = chip->priv; - - prv->column = (column >= 0) ? column : 0; - prv->spareonly = 0; - - switch (command) { - case NAND_CMD_PAGEPROG: - mpc5121_nfc_send_prog_page(mtd); - break; - /* - * NFC does not support sub-page reads and writes, - * so emulate them using full page transfers. - */ - case NAND_CMD_READ0: - column = 0; - break; - - case NAND_CMD_READ1: - prv->column += 256; - command = NAND_CMD_READ0; - column = 0; - break; - - case NAND_CMD_READOOB: - prv->spareonly = 1; - command = NAND_CMD_READ0; - column = 0; - break; - - case NAND_CMD_SEQIN: - mpc5121_nfc_command(mtd, NAND_CMD_READ0, column, page); - column = 0; - break; - - case NAND_CMD_ERASE1: - case NAND_CMD_ERASE2: - case NAND_CMD_READID: - case NAND_CMD_STATUS: - case NAND_CMD_RESET: - break; - - default: - return; - } - - mpc5121_nfc_send_cmd(mtd, command); - mpc5121_nfc_addr_cycle(mtd, column, page); - - switch (command) { - case NAND_CMD_READ0: - if (mtd->writesize > 512) - mpc5121_nfc_send_cmd(mtd, NAND_CMD_READSTART); - mpc5121_nfc_send_read_page(mtd); - break; - - case NAND_CMD_READID: - mpc5121_nfc_send_read_id(mtd); - break; - - case NAND_CMD_STATUS: - mpc5121_nfc_send_read_status(mtd); - if (chip->options & NAND_BUSWIDTH_16) - prv->column = 1; - else - prv->column = 0; - break; - } -} - -/* Copy data from/to NFC spare buffers. */ -static void mpc5121_nfc_copy_spare(struct mtd_info *mtd, uint offset, - u8 * buffer, uint size, int wr) -{ - struct nand_chip *nand = mtd->priv; - struct mpc5121_nfc_prv *prv = nand->priv; - uint o, s, sbsize, blksize; - - /* - * NAND spare area is available through NFC spare buffers. - * The NFC divides spare area into (page_size / 512) chunks. - * Each chunk is placed into separate spare memory area, using - * first (spare_size / num_of_chunks) bytes of the buffer. - * - * For NAND device in which the spare area is not divided fully - * by the number of chunks, number of used bytes in each spare - * buffer is rounded down to the nearest even number of bytes, - * and all remaining bytes are added to the last used spare area. - * - * For more information read section 26.6.10 of MPC5121e - * Microcontroller Reference Manual, Rev. 3. - */ - - /* Calculate number of valid bytes in each spare buffer */ - sbsize = (mtd->oobsize / (mtd->writesize / 512)) & ~1; - - while (size) { - /* Calculate spare buffer number */ - s = offset / sbsize; - if (s > NFC_SPARE_BUFFERS - 1) - s = NFC_SPARE_BUFFERS - 1; - - /* - * Calculate offset to requested data block in selected spare - * buffer and its size. - */ - o = offset - (s * sbsize); - blksize = min(sbsize - o, size); - - if (wr) - memcpy_toio(prv->regs + NFC_SPARE_AREA(s) + o, - buffer, blksize); - else - memcpy_fromio(buffer, - prv->regs + NFC_SPARE_AREA(s) + o, - blksize); - - buffer += blksize; - offset += blksize; - size -= blksize; - }; -} - -/* Copy data from/to NFC main and spare buffers */ -static void mpc5121_nfc_buf_copy(struct mtd_info *mtd, u_char * buf, int len, - int wr) -{ - struct nand_chip *chip = mtd->priv; - struct mpc5121_nfc_prv *prv = chip->priv; - uint c = prv->column; - uint l; - - /* Handle spare area access */ - if (prv->spareonly || c >= mtd->writesize) { - /* Calculate offset from beginning of spare area */ - if (c >= mtd->writesize) - c -= mtd->writesize; - - prv->column += len; - mpc5121_nfc_copy_spare(mtd, c, buf, len, wr); - return; - } - - /* - * Handle main area access - limit copy length to prevent - * crossing main/spare boundary. - */ - l = min((uint) len, mtd->writesize - c); - prv->column += l; - - if (wr) - memcpy_toio(prv->regs + NFC_MAIN_AREA(0) + c, buf, l); - else - memcpy_fromio(buf, prv->regs + NFC_MAIN_AREA(0) + c, l); - - /* Handle crossing main/spare boundary */ - if (l != len) { - buf += l; - len -= l; - mpc5121_nfc_buf_copy(mtd, buf, len, wr); - } -} - -/* Read data from NFC buffers */ -static void mpc5121_nfc_read_buf(struct mtd_info *mtd, u_char * buf, int len) -{ - mpc5121_nfc_buf_copy(mtd, buf, len, 0); -} - -/* Write data to NFC buffers */ -static void mpc5121_nfc_write_buf(struct mtd_info *mtd, - const u_char * buf, int len) -{ - mpc5121_nfc_buf_copy(mtd, (u_char *) buf, len, 1); -} - -/* Compare buffer with NAND flash */ -static int mpc5121_nfc_verify_buf(struct mtd_info *mtd, - const u_char * buf, int len) -{ - u_char tmp[256]; - uint bsize; - - while (len) { - bsize = min(len, 256); - mpc5121_nfc_read_buf(mtd, tmp, bsize); - - if (memcmp(buf, tmp, bsize)) - return 1; - - buf += bsize; - len -= bsize; - } - - return 0; -} - -/* Read byte from NFC buffers */ -static u8 mpc5121_nfc_read_byte(struct mtd_info *mtd) -{ - u8 tmp; - - mpc5121_nfc_read_buf(mtd, &tmp, sizeof(tmp)); - - return tmp; -} - -/* Read word from NFC buffers */ -static u16 mpc5121_nfc_read_word(struct mtd_info *mtd) -{ - u16 tmp; - - mpc5121_nfc_read_buf(mtd, (u_char *) & tmp, sizeof(tmp)); - - return tmp; -} - -/* - * Read NFC configuration from Reset Config Word - * - * NFC is configured during reset in basis of information stored - * in Reset Config Word. There is no other way to set NAND block - * size, spare size and bus width. - */ -static int mpc5121_nfc_read_hw_config(struct mtd_info *mtd) -{ - immap_t *im = (immap_t *)CONFIG_SYS_IMMR; - struct nand_chip *chip = mtd->priv; - uint rcw_pagesize = 0; - uint rcw_sparesize = 0; - uint rcw_width; - uint rcwh; - uint romloc, ps; - - rcwh = in_be32(&(im->reset.rcwh)); - - /* Bit 6: NFC bus width */ - rcw_width = ((rcwh >> 6) & 0x1) ? 2 : 1; - - /* Bit 7: NFC Page/Spare size */ - ps = (rcwh >> 7) & 0x1; - - /* Bits [22:21]: ROM Location */ - romloc = (rcwh >> 21) & 0x3; - - /* Decode RCW bits */ - switch ((ps << 2) | romloc) { - case 0x00: - case 0x01: - rcw_pagesize = 512; - rcw_sparesize = 16; - break; - case 0x02: - case 0x03: - rcw_pagesize = 4096; - rcw_sparesize = 128; - break; - case 0x04: - case 0x05: - rcw_pagesize = 2048; - rcw_sparesize = 64; - break; - case 0x06: - case 0x07: - rcw_pagesize = 4096; - rcw_sparesize = 218; - break; - } - - mtd->writesize = rcw_pagesize; - mtd->oobsize = rcw_sparesize; - if (rcw_width == 2) - chip->options |= NAND_BUSWIDTH_16; - - debug(KERN_NOTICE DRV_NAME ": Configured for " - "%u-bit NAND, page size %u with %u spare.\n", - rcw_width * 8, rcw_pagesize, rcw_sparesize); - return 0; -} - -int board_nand_init(struct nand_chip *chip) -{ - struct mpc5121_nfc_prv *prv; - struct mtd_info *mtd; - int resettime = 0; - int retval = 0; - int rev; - static int chip_nr = 0; - - /* - * Check SoC revision. This driver supports only NFC - * in MPC5121 revision 2. - */ - rev = (mfspr(SPRN_SVR) >> 4) & 0xF; - if (rev != 2) { - printk(KERN_ERR DRV_NAME - ": SoC revision %u is not supported!\n", rev); - return -ENXIO; - } - - prv = malloc(sizeof(*prv)); - if (!prv) { - printk(KERN_ERR DRV_NAME ": Memory exhausted!\n"); - return -ENOMEM; - } - - mtd = &nand_info[chip_nr++]; - mtd->priv = chip; - chip->priv = prv; - - /* Read NFC configuration from Reset Config Word */ - retval = mpc5121_nfc_read_hw_config(mtd); - if (retval) { - printk(KERN_ERR DRV_NAME ": Unable to read NFC config!\n"); - return retval; - } - - prv->regs = (void __iomem *)CONFIG_SYS_NAND_BASE; - chip->dev_ready = mpc5121_nfc_dev_ready; - chip->cmdfunc = mpc5121_nfc_command; - chip->read_byte = mpc5121_nfc_read_byte; - chip->read_word = mpc5121_nfc_read_word; - chip->read_buf = mpc5121_nfc_read_buf; - chip->write_buf = mpc5121_nfc_write_buf; - chip->verify_buf = mpc5121_nfc_verify_buf; - chip->select_chip = mpc5121_nfc_select_chip; - chip->bbt_options = NAND_BBT_USE_FLASH; - chip->ecc.mode = NAND_ECC_SOFT; - - /* Reset NAND Flash controller */ - nfc_set(mtd, NFC_CONFIG1, NFC_RESET); - while (nfc_read(mtd, NFC_CONFIG1) & NFC_RESET) { - if (resettime++ >= NFC_RESET_TIMEOUT) { - printk(KERN_ERR DRV_NAME - ": Timeout while resetting NFC!\n"); - retval = -EINVAL; - goto error; - } - - udelay(1); - } - - /* Enable write to NFC memory */ - nfc_write(mtd, NFC_CONFIG, NFC_BLS_UNLOCKED); - - /* Enable write to all NAND pages */ - nfc_write(mtd, NFC_UNLOCKSTART_BLK0, 0x0000); - nfc_write(mtd, NFC_UNLOCKEND_BLK0, 0xFFFF); - nfc_write(mtd, NFC_WRPROT, NFC_WPC_UNLOCK); - - /* - * Setup NFC: - * - Big Endian transfers, - * - Interrupt after full page read/write. - */ - nfc_write(mtd, NFC_CONFIG1, NFC_BIG_ENDIAN | NFC_INT_MASK | - NFC_FULL_PAGE_INT); - - /* Set spare area size */ - nfc_write(mtd, NFC_SPAS, mtd->oobsize >> 1); - - /* Detect NAND chips */ - if (nand_scan(mtd, 1)) { - printk(KERN_ERR DRV_NAME ": NAND Flash not found !\n"); - retval = -ENXIO; - goto error; - } - - /* Set erase block size */ - switch (mtd->erasesize / mtd->writesize) { - case 32: - nfc_set(mtd, NFC_CONFIG1, NFC_PPB_32); - break; - - case 64: - nfc_set(mtd, NFC_CONFIG1, NFC_PPB_64); - break; - - case 128: - nfc_set(mtd, NFC_CONFIG1, NFC_PPB_128); - break; - - case 256: - nfc_set(mtd, NFC_CONFIG1, NFC_PPB_256); - break; - - default: - printk(KERN_ERR DRV_NAME ": Unsupported NAND flash!\n"); - retval = -ENXIO; - goto error; - } - - return 0; -error: - return retval; -} diff --git a/qemu/roms/u-boot/drivers/mtd/nand/mxc_nand.c b/qemu/roms/u-boot/drivers/mtd/nand/mxc_nand.c deleted file mode 100644 index ed0ca3aca..000000000 --- a/qemu/roms/u-boot/drivers/mtd/nand/mxc_nand.c +++ /dev/null @@ -1,1342 +0,0 @@ -/* - * Copyright 2004-2007 Freescale Semiconductor, Inc. - * Copyright 2008 Sascha Hauer, kernel@pengutronix.de - * Copyright 2009 Ilya Yanok, <yanok@emcraft.com> - * - * SPDX-License-Identifier: GPL-2.0+ - */ - -#include <common.h> -#include <nand.h> -#include <linux/err.h> -#include <asm/io.h> -#if defined(CONFIG_MX25) || defined(CONFIG_MX27) || defined(CONFIG_MX35) || \ - defined(CONFIG_MX51) || defined(CONFIG_MX53) -#include <asm/arch/imx-regs.h> -#endif -#include "mxc_nand.h" - -#define DRIVER_NAME "mxc_nand" - -struct mxc_nand_host { - struct mtd_info mtd; - struct nand_chip *nand; - - struct mxc_nand_regs __iomem *regs; -#ifdef MXC_NFC_V3_2 - struct mxc_nand_ip_regs __iomem *ip_regs; -#endif - int spare_only; - int status_request; - int pagesize_2k; - int clk_act; - uint16_t col_addr; - unsigned int page_addr; -}; - -static struct mxc_nand_host mxc_host; -static struct mxc_nand_host *host = &mxc_host; - -/* Define delays in microsec for NAND device operations */ -#define TROP_US_DELAY 2000 -/* Macros to get byte and bit positions of ECC */ -#define COLPOS(x) ((x) >> 3) -#define BITPOS(x) ((x) & 0xf) - -/* Define single bit Error positions in Main & Spare area */ -#define MAIN_SINGLEBIT_ERROR 0x4 -#define SPARE_SINGLEBIT_ERROR 0x1 - -/* OOB placement block for use with hardware ecc generation */ -#if defined(MXC_NFC_V1) -#ifndef CONFIG_SYS_NAND_LARGEPAGE -static struct nand_ecclayout nand_hw_eccoob = { - .eccbytes = 5, - .eccpos = {6, 7, 8, 9, 10}, - .oobfree = { {0, 5}, {11, 5}, } -}; -#else -static struct nand_ecclayout nand_hw_eccoob2k = { - .eccbytes = 20, - .eccpos = { - 6, 7, 8, 9, 10, - 22, 23, 24, 25, 26, - 38, 39, 40, 41, 42, - 54, 55, 56, 57, 58, - }, - .oobfree = { {2, 4}, {11, 11}, {27, 11}, {43, 11}, {59, 5} }, -}; -#endif -#elif defined(MXC_NFC_V2_1) || defined(MXC_NFC_V3_2) -#ifndef CONFIG_SYS_NAND_LARGEPAGE -static struct nand_ecclayout nand_hw_eccoob = { - .eccbytes = 9, - .eccpos = {7, 8, 9, 10, 11, 12, 13, 14, 15}, - .oobfree = { {2, 5} } -}; -#else -static struct nand_ecclayout nand_hw_eccoob2k = { - .eccbytes = 36, - .eccpos = { - 7, 8, 9, 10, 11, 12, 13, 14, 15, - 23, 24, 25, 26, 27, 28, 29, 30, 31, - 39, 40, 41, 42, 43, 44, 45, 46, 47, - 55, 56, 57, 58, 59, 60, 61, 62, 63, - }, - .oobfree = { {2, 5}, {16, 7}, {32, 7}, {48, 7} }, -}; -#endif -#endif - -static int is_16bit_nand(void) -{ -#if defined(CONFIG_SYS_NAND_BUSWIDTH_16BIT) - return 1; -#else - return 0; -#endif -} - -static uint32_t *mxc_nand_memcpy32(uint32_t *dest, uint32_t *source, size_t size) -{ - uint32_t *d = dest; - - size >>= 2; - while (size--) - __raw_writel(__raw_readl(source++), d++); - return dest; -} - -/* - * This function polls the NANDFC to wait for the basic operation to - * complete by checking the INT bit. - */ -static void wait_op_done(struct mxc_nand_host *host, int max_retries, - uint16_t param) -{ - uint32_t tmp; - - while (max_retries-- > 0) { -#if defined(MXC_NFC_V1) || defined(MXC_NFC_V2_1) - tmp = readnfc(&host->regs->config2); - if (tmp & NFC_V1_V2_CONFIG2_INT) { - tmp &= ~NFC_V1_V2_CONFIG2_INT; - writenfc(tmp, &host->regs->config2); -#elif defined(MXC_NFC_V3_2) - tmp = readnfc(&host->ip_regs->ipc); - if (tmp & NFC_V3_IPC_INT) { - tmp &= ~NFC_V3_IPC_INT; - writenfc(tmp, &host->ip_regs->ipc); -#endif - break; - } - udelay(1); - } - if (max_retries < 0) { - MTDDEBUG(MTD_DEBUG_LEVEL0, "%s(%d): INT not set\n", - __func__, param); - } -} - -/* - * This function issues the specified command to the NAND device and - * waits for completion. - */ -static void send_cmd(struct mxc_nand_host *host, uint16_t cmd) -{ - MTDDEBUG(MTD_DEBUG_LEVEL3, "send_cmd(host, 0x%x)\n", cmd); - - writenfc(cmd, &host->regs->flash_cmd); - writenfc(NFC_CMD, &host->regs->operation); - - /* Wait for operation to complete */ - wait_op_done(host, TROP_US_DELAY, cmd); -} - -/* - * This function sends an address (or partial address) to the - * NAND device. The address is used to select the source/destination for - * a NAND command. - */ -static void send_addr(struct mxc_nand_host *host, uint16_t addr) -{ - MTDDEBUG(MTD_DEBUG_LEVEL3, "send_addr(host, 0x%x)\n", addr); - - writenfc(addr, &host->regs->flash_addr); - writenfc(NFC_ADDR, &host->regs->operation); - - /* Wait for operation to complete */ - wait_op_done(host, TROP_US_DELAY, addr); -} - -/* - * This function requests the NANDFC to initiate the transfer - * of data currently in the NANDFC RAM buffer to the NAND device. - */ -static void send_prog_page(struct mxc_nand_host *host, uint8_t buf_id, - int spare_only) -{ - if (spare_only) - MTDDEBUG(MTD_DEBUG_LEVEL1, "send_prog_page (%d)\n", spare_only); - - if (is_mxc_nfc_21() || is_mxc_nfc_32()) { - int i; - /* - * The controller copies the 64 bytes of spare data from - * the first 16 bytes of each of the 4 64 byte spare buffers. - * Copy the contiguous data starting in spare_area[0] to - * the four spare area buffers. - */ - for (i = 1; i < 4; i++) { - void __iomem *src = &host->regs->spare_area[0][i * 16]; - void __iomem *dst = &host->regs->spare_area[i][0]; - - mxc_nand_memcpy32(dst, src, 16); - } - } - -#if defined(MXC_NFC_V1) || defined(MXC_NFC_V2_1) - writenfc(buf_id, &host->regs->buf_addr); -#elif defined(MXC_NFC_V3_2) - uint32_t tmp = readnfc(&host->regs->config1); - tmp &= ~NFC_V3_CONFIG1_RBA_MASK; - tmp |= NFC_V3_CONFIG1_RBA(buf_id); - writenfc(tmp, &host->regs->config1); -#endif - - /* Configure spare or page+spare access */ - if (!host->pagesize_2k) { - uint32_t config1 = readnfc(&host->regs->config1); - if (spare_only) - config1 |= NFC_CONFIG1_SP_EN; - else - config1 &= ~NFC_CONFIG1_SP_EN; - writenfc(config1, &host->regs->config1); - } - - writenfc(NFC_INPUT, &host->regs->operation); - - /* Wait for operation to complete */ - wait_op_done(host, TROP_US_DELAY, spare_only); -} - -/* - * Requests NANDFC to initiate the transfer of data from the - * NAND device into in the NANDFC ram buffer. - */ -static void send_read_page(struct mxc_nand_host *host, uint8_t buf_id, - int spare_only) -{ - MTDDEBUG(MTD_DEBUG_LEVEL3, "send_read_page (%d)\n", spare_only); - -#if defined(MXC_NFC_V1) || defined(MXC_NFC_V2_1) - writenfc(buf_id, &host->regs->buf_addr); -#elif defined(MXC_NFC_V3_2) - uint32_t tmp = readnfc(&host->regs->config1); - tmp &= ~NFC_V3_CONFIG1_RBA_MASK; - tmp |= NFC_V3_CONFIG1_RBA(buf_id); - writenfc(tmp, &host->regs->config1); -#endif - - /* Configure spare or page+spare access */ - if (!host->pagesize_2k) { - uint32_t config1 = readnfc(&host->regs->config1); - if (spare_only) - config1 |= NFC_CONFIG1_SP_EN; - else - config1 &= ~NFC_CONFIG1_SP_EN; - writenfc(config1, &host->regs->config1); - } - - writenfc(NFC_OUTPUT, &host->regs->operation); - - /* Wait for operation to complete */ - wait_op_done(host, TROP_US_DELAY, spare_only); - - if (is_mxc_nfc_21() || is_mxc_nfc_32()) { - int i; - - /* - * The controller copies the 64 bytes of spare data to - * the first 16 bytes of each of the 4 spare buffers. - * Make the data contiguous starting in spare_area[0]. - */ - for (i = 1; i < 4; i++) { - void __iomem *src = &host->regs->spare_area[i][0]; - void __iomem *dst = &host->regs->spare_area[0][i * 16]; - - mxc_nand_memcpy32(dst, src, 16); - } - } -} - -/* Request the NANDFC to perform a read of the NAND device ID. */ -static void send_read_id(struct mxc_nand_host *host) -{ - uint32_t tmp; - -#if defined(MXC_NFC_V1) || defined(MXC_NFC_V2_1) - /* NANDFC buffer 0 is used for device ID output */ - writenfc(0x0, &host->regs->buf_addr); -#elif defined(MXC_NFC_V3_2) - tmp = readnfc(&host->regs->config1); - tmp &= ~NFC_V3_CONFIG1_RBA_MASK; - writenfc(tmp, &host->regs->config1); -#endif - - /* Read ID into main buffer */ - tmp = readnfc(&host->regs->config1); - tmp &= ~NFC_CONFIG1_SP_EN; - writenfc(tmp, &host->regs->config1); - - writenfc(NFC_ID, &host->regs->operation); - - /* Wait for operation to complete */ - wait_op_done(host, TROP_US_DELAY, 0); -} - -/* - * This function requests the NANDFC to perform a read of the - * NAND device status and returns the current status. - */ -static uint16_t get_dev_status(struct mxc_nand_host *host) -{ -#if defined(MXC_NFC_V1) || defined(MXC_NFC_V2_1) - void __iomem *main_buf = host->regs->main_area[1]; - uint32_t store; -#endif - uint32_t ret, tmp; - /* Issue status request to NAND device */ - -#if defined(MXC_NFC_V1) || defined(MXC_NFC_V2_1) - /* store the main area1 first word, later do recovery */ - store = readl(main_buf); - /* NANDFC buffer 1 is used for device status */ - writenfc(1, &host->regs->buf_addr); -#endif - - /* Read status into main buffer */ - tmp = readnfc(&host->regs->config1); - tmp &= ~NFC_CONFIG1_SP_EN; - writenfc(tmp, &host->regs->config1); - - writenfc(NFC_STATUS, &host->regs->operation); - - /* Wait for operation to complete */ - wait_op_done(host, TROP_US_DELAY, 0); - -#if defined(MXC_NFC_V1) || defined(MXC_NFC_V2_1) - /* - * Status is placed in first word of main buffer - * get status, then recovery area 1 data - */ - ret = readw(main_buf); - writel(store, main_buf); -#elif defined(MXC_NFC_V3_2) - ret = readnfc(&host->regs->config1) >> 16; -#endif - - return ret; -} - -/* This function is used by upper layer to checks if device is ready */ -static int mxc_nand_dev_ready(struct mtd_info *mtd) -{ - /* - * NFC handles R/B internally. Therefore, this function - * always returns status as ready. - */ - return 1; -} - -static void _mxc_nand_enable_hwecc(struct mtd_info *mtd, int on) -{ - struct nand_chip *nand_chip = mtd->priv; - struct mxc_nand_host *host = nand_chip->priv; -#if defined(MXC_NFC_V1) || defined(MXC_NFC_V2_1) - uint16_t tmp = readnfc(&host->regs->config1); - - if (on) - tmp |= NFC_V1_V2_CONFIG1_ECC_EN; - else - tmp &= ~NFC_V1_V2_CONFIG1_ECC_EN; - writenfc(tmp, &host->regs->config1); -#elif defined(MXC_NFC_V3_2) - uint32_t tmp = readnfc(&host->ip_regs->config2); - - if (on) - tmp |= NFC_V3_CONFIG2_ECC_EN; - else - tmp &= ~NFC_V3_CONFIG2_ECC_EN; - writenfc(tmp, &host->ip_regs->config2); -#endif -} - -#ifdef CONFIG_MXC_NAND_HWECC -static void mxc_nand_enable_hwecc(struct mtd_info *mtd, int mode) -{ - /* - * If HW ECC is enabled, we turn it on during init. There is - * no need to enable again here. - */ -} - -#if defined(MXC_NFC_V2_1) || defined(MXC_NFC_V3_2) -static int mxc_nand_read_oob_syndrome(struct mtd_info *mtd, - struct nand_chip *chip, - int page) -{ - struct mxc_nand_host *host = chip->priv; - uint8_t *buf = chip->oob_poi; - int length = mtd->oobsize; - int eccpitch = chip->ecc.bytes + chip->ecc.prepad + chip->ecc.postpad; - uint8_t *bufpoi = buf; - int i, toread; - - MTDDEBUG(MTD_DEBUG_LEVEL0, - "%s: Reading OOB area of page %u to oob %p\n", - __func__, page, buf); - - chip->cmdfunc(mtd, NAND_CMD_READOOB, mtd->writesize, page); - for (i = 0; i < chip->ecc.steps; i++) { - toread = min_t(int, length, chip->ecc.prepad); - if (toread) { - chip->read_buf(mtd, bufpoi, toread); - bufpoi += toread; - length -= toread; - } - bufpoi += chip->ecc.bytes; - host->col_addr += chip->ecc.bytes; - length -= chip->ecc.bytes; - - toread = min_t(int, length, chip->ecc.postpad); - if (toread) { - chip->read_buf(mtd, bufpoi, toread); - bufpoi += toread; - length -= toread; - } - } - if (length > 0) - chip->read_buf(mtd, bufpoi, length); - - _mxc_nand_enable_hwecc(mtd, 0); - chip->cmdfunc(mtd, NAND_CMD_READOOB, - mtd->writesize + chip->ecc.prepad, page); - bufpoi = buf + chip->ecc.prepad; - length = mtd->oobsize - chip->ecc.prepad; - for (i = 0; i < chip->ecc.steps; i++) { - toread = min_t(int, length, chip->ecc.bytes); - chip->read_buf(mtd, bufpoi, toread); - bufpoi += eccpitch; - length -= eccpitch; - host->col_addr += chip->ecc.postpad + chip->ecc.prepad; - } - _mxc_nand_enable_hwecc(mtd, 1); - return 1; -} - -static int mxc_nand_read_page_raw_syndrome(struct mtd_info *mtd, - struct nand_chip *chip, - uint8_t *buf, - int oob_required, - int page) -{ - struct mxc_nand_host *host = chip->priv; - int eccsize = chip->ecc.size; - int eccbytes = chip->ecc.bytes; - int eccpitch = eccbytes + chip->ecc.prepad + chip->ecc.postpad; - uint8_t *oob = chip->oob_poi; - int steps, size; - int n; - - _mxc_nand_enable_hwecc(mtd, 0); - chip->cmdfunc(mtd, NAND_CMD_READ0, 0x00, page); - - for (n = 0, steps = chip->ecc.steps; steps > 0; n++, steps--) { - host->col_addr = n * eccsize; - chip->read_buf(mtd, buf, eccsize); - buf += eccsize; - - host->col_addr = mtd->writesize + n * eccpitch; - if (chip->ecc.prepad) { - chip->read_buf(mtd, oob, chip->ecc.prepad); - oob += chip->ecc.prepad; - } - - chip->read_buf(mtd, oob, eccbytes); - oob += eccbytes; - - if (chip->ecc.postpad) { - chip->read_buf(mtd, oob, chip->ecc.postpad); - oob += chip->ecc.postpad; - } - } - - size = mtd->oobsize - (oob - chip->oob_poi); - if (size) - chip->read_buf(mtd, oob, size); - _mxc_nand_enable_hwecc(mtd, 1); - - return 0; -} - -static int mxc_nand_read_page_syndrome(struct mtd_info *mtd, - struct nand_chip *chip, - uint8_t *buf, - int oob_required, - int page) -{ - struct mxc_nand_host *host = chip->priv; - int n, eccsize = chip->ecc.size; - int eccbytes = chip->ecc.bytes; - int eccpitch = eccbytes + chip->ecc.prepad + chip->ecc.postpad; - int eccsteps = chip->ecc.steps; - uint8_t *p = buf; - uint8_t *oob = chip->oob_poi; - - MTDDEBUG(MTD_DEBUG_LEVEL1, "Reading page %u to buf %p oob %p\n", - page, buf, oob); - - /* first read the data area and the available portion of OOB */ - for (n = 0; eccsteps; n++, eccsteps--, p += eccsize) { - int stat; - - host->col_addr = n * eccsize; - - chip->read_buf(mtd, p, eccsize); - - host->col_addr = mtd->writesize + n * eccpitch; - - if (chip->ecc.prepad) { - chip->read_buf(mtd, oob, chip->ecc.prepad); - oob += chip->ecc.prepad; - } - - stat = chip->ecc.correct(mtd, p, oob, NULL); - - if (stat < 0) - mtd->ecc_stats.failed++; - else - mtd->ecc_stats.corrected += stat; - oob += eccbytes; - - if (chip->ecc.postpad) { - chip->read_buf(mtd, oob, chip->ecc.postpad); - oob += chip->ecc.postpad; - } - } - - /* Calculate remaining oob bytes */ - n = mtd->oobsize - (oob - chip->oob_poi); - if (n) - chip->read_buf(mtd, oob, n); - - /* Then switch ECC off and read the OOB area to get the ECC code */ - _mxc_nand_enable_hwecc(mtd, 0); - chip->cmdfunc(mtd, NAND_CMD_READOOB, mtd->writesize, page); - eccsteps = chip->ecc.steps; - oob = chip->oob_poi + chip->ecc.prepad; - for (n = 0; eccsteps; n++, eccsteps--, p += eccsize) { - host->col_addr = mtd->writesize + - n * eccpitch + - chip->ecc.prepad; - chip->read_buf(mtd, oob, eccbytes); - oob += eccbytes + chip->ecc.postpad; - } - _mxc_nand_enable_hwecc(mtd, 1); - return 0; -} - -static int mxc_nand_write_oob_syndrome(struct mtd_info *mtd, - struct nand_chip *chip, int page) -{ - struct mxc_nand_host *host = chip->priv; - int eccpitch = chip->ecc.bytes + chip->ecc.prepad + chip->ecc.postpad; - int length = mtd->oobsize; - int i, len, status, steps = chip->ecc.steps; - const uint8_t *bufpoi = chip->oob_poi; - - chip->cmdfunc(mtd, NAND_CMD_SEQIN, mtd->writesize, page); - for (i = 0; i < steps; i++) { - len = min_t(int, length, eccpitch); - - chip->write_buf(mtd, bufpoi, len); - bufpoi += len; - length -= len; - host->col_addr += chip->ecc.prepad + chip->ecc.postpad; - } - if (length > 0) - chip->write_buf(mtd, bufpoi, length); - - chip->cmdfunc(mtd, NAND_CMD_PAGEPROG, -1, -1); - status = chip->waitfunc(mtd, chip); - return status & NAND_STATUS_FAIL ? -EIO : 0; -} - -static int mxc_nand_write_page_raw_syndrome(struct mtd_info *mtd, - struct nand_chip *chip, - const uint8_t *buf, - int oob_required) -{ - struct mxc_nand_host *host = chip->priv; - int eccsize = chip->ecc.size; - int eccbytes = chip->ecc.bytes; - int eccpitch = eccbytes + chip->ecc.prepad + chip->ecc.postpad; - uint8_t *oob = chip->oob_poi; - int steps, size; - int n; - - for (n = 0, steps = chip->ecc.steps; steps > 0; n++, steps--) { - host->col_addr = n * eccsize; - chip->write_buf(mtd, buf, eccsize); - buf += eccsize; - - host->col_addr = mtd->writesize + n * eccpitch; - - if (chip->ecc.prepad) { - chip->write_buf(mtd, oob, chip->ecc.prepad); - oob += chip->ecc.prepad; - } - - host->col_addr += eccbytes; - oob += eccbytes; - - if (chip->ecc.postpad) { - chip->write_buf(mtd, oob, chip->ecc.postpad); - oob += chip->ecc.postpad; - } - } - - size = mtd->oobsize - (oob - chip->oob_poi); - if (size) - chip->write_buf(mtd, oob, size); - return 0; -} - -static int mxc_nand_write_page_syndrome(struct mtd_info *mtd, - struct nand_chip *chip, - const uint8_t *buf, - int oob_required) -{ - struct mxc_nand_host *host = chip->priv; - int i, n, eccsize = chip->ecc.size; - int eccbytes = chip->ecc.bytes; - int eccpitch = eccbytes + chip->ecc.prepad + chip->ecc.postpad; - int eccsteps = chip->ecc.steps; - const uint8_t *p = buf; - uint8_t *oob = chip->oob_poi; - - chip->ecc.hwctl(mtd, NAND_ECC_WRITE); - - for (i = n = 0; - eccsteps; - n++, eccsteps--, i += eccbytes, p += eccsize) { - host->col_addr = n * eccsize; - - chip->write_buf(mtd, p, eccsize); - - host->col_addr = mtd->writesize + n * eccpitch; - - if (chip->ecc.prepad) { - chip->write_buf(mtd, oob, chip->ecc.prepad); - oob += chip->ecc.prepad; - } - - chip->write_buf(mtd, oob, eccbytes); - oob += eccbytes; - - if (chip->ecc.postpad) { - chip->write_buf(mtd, oob, chip->ecc.postpad); - oob += chip->ecc.postpad; - } - } - - /* Calculate remaining oob bytes */ - i = mtd->oobsize - (oob - chip->oob_poi); - if (i) - chip->write_buf(mtd, oob, i); - return 0; -} - -static int mxc_nand_correct_data(struct mtd_info *mtd, u_char *dat, - u_char *read_ecc, u_char *calc_ecc) -{ - struct nand_chip *nand_chip = mtd->priv; - struct mxc_nand_host *host = nand_chip->priv; - uint32_t ecc_status = readl(&host->regs->ecc_status_result); - int subpages = mtd->writesize / nand_chip->subpagesize; - int pg2blk_shift = nand_chip->phys_erase_shift - - nand_chip->page_shift; - - do { - if ((ecc_status & 0xf) > 4) { - static int last_bad = -1; - - if (last_bad != host->page_addr >> pg2blk_shift) { - last_bad = host->page_addr >> pg2blk_shift; - printk(KERN_DEBUG - "MXC_NAND: HWECC uncorrectable ECC error" - " in block %u page %u subpage %d\n", - last_bad, host->page_addr, - mtd->writesize / nand_chip->subpagesize - - subpages); - } - return -1; - } - ecc_status >>= 4; - subpages--; - } while (subpages > 0); - - return 0; -} -#else -#define mxc_nand_read_page_syndrome NULL -#define mxc_nand_read_page_raw_syndrome NULL -#define mxc_nand_read_oob_syndrome NULL -#define mxc_nand_write_page_syndrome NULL -#define mxc_nand_write_page_raw_syndrome NULL -#define mxc_nand_write_oob_syndrome NULL - -static int mxc_nand_correct_data(struct mtd_info *mtd, u_char *dat, - u_char *read_ecc, u_char *calc_ecc) -{ - struct nand_chip *nand_chip = mtd->priv; - struct mxc_nand_host *host = nand_chip->priv; - - /* - * 1-Bit errors are automatically corrected in HW. No need for - * additional correction. 2-Bit errors cannot be corrected by - * HW ECC, so we need to return failure - */ - uint16_t ecc_status = readnfc(&host->regs->ecc_status_result); - - if (((ecc_status & 0x3) == 2) || ((ecc_status >> 2) == 2)) { - MTDDEBUG(MTD_DEBUG_LEVEL0, - "MXC_NAND: HWECC uncorrectable 2-bit ECC error\n"); - return -1; - } - - return 0; -} -#endif - -static int mxc_nand_calculate_ecc(struct mtd_info *mtd, const u_char *dat, - u_char *ecc_code) -{ - return 0; -} -#endif - -static u_char mxc_nand_read_byte(struct mtd_info *mtd) -{ - struct nand_chip *nand_chip = mtd->priv; - struct mxc_nand_host *host = nand_chip->priv; - uint8_t ret = 0; - uint16_t col; - uint16_t __iomem *main_buf = - (uint16_t __iomem *)host->regs->main_area[0]; - uint16_t __iomem *spare_buf = - (uint16_t __iomem *)host->regs->spare_area[0]; - union { - uint16_t word; - uint8_t bytes[2]; - } nfc_word; - - /* Check for status request */ - if (host->status_request) - return get_dev_status(host) & 0xFF; - - /* Get column for 16-bit access */ - col = host->col_addr >> 1; - - /* If we are accessing the spare region */ - if (host->spare_only) - nfc_word.word = readw(&spare_buf[col]); - else - nfc_word.word = readw(&main_buf[col]); - - /* Pick upper/lower byte of word from RAM buffer */ - ret = nfc_word.bytes[host->col_addr & 0x1]; - - /* Update saved column address */ - if (nand_chip->options & NAND_BUSWIDTH_16) - host->col_addr += 2; - else - host->col_addr++; - - return ret; -} - -static uint16_t mxc_nand_read_word(struct mtd_info *mtd) -{ - struct nand_chip *nand_chip = mtd->priv; - struct mxc_nand_host *host = nand_chip->priv; - uint16_t col, ret; - uint16_t __iomem *p; - - MTDDEBUG(MTD_DEBUG_LEVEL3, - "mxc_nand_read_word(col = %d)\n", host->col_addr); - - col = host->col_addr; - /* Adjust saved column address */ - if (col < mtd->writesize && host->spare_only) - col += mtd->writesize; - - if (col < mtd->writesize) { - p = (uint16_t __iomem *)(host->regs->main_area[0] + - (col >> 1)); - } else { - p = (uint16_t __iomem *)(host->regs->spare_area[0] + - ((col - mtd->writesize) >> 1)); - } - - if (col & 1) { - union { - uint16_t word; - uint8_t bytes[2]; - } nfc_word[3]; - - nfc_word[0].word = readw(p); - nfc_word[1].word = readw(p + 1); - - nfc_word[2].bytes[0] = nfc_word[0].bytes[1]; - nfc_word[2].bytes[1] = nfc_word[1].bytes[0]; - - ret = nfc_word[2].word; - } else { - ret = readw(p); - } - - /* Update saved column address */ - host->col_addr = col + 2; - - return ret; -} - -/* - * Write data of length len to buffer buf. The data to be - * written on NAND Flash is first copied to RAMbuffer. After the Data Input - * Operation by the NFC, the data is written to NAND Flash - */ -static void mxc_nand_write_buf(struct mtd_info *mtd, - const u_char *buf, int len) -{ - struct nand_chip *nand_chip = mtd->priv; - struct mxc_nand_host *host = nand_chip->priv; - int n, col, i = 0; - - MTDDEBUG(MTD_DEBUG_LEVEL3, - "mxc_nand_write_buf(col = %d, len = %d)\n", host->col_addr, - len); - - col = host->col_addr; - - /* Adjust saved column address */ - if (col < mtd->writesize && host->spare_only) - col += mtd->writesize; - - n = mtd->writesize + mtd->oobsize - col; - n = min(len, n); - - MTDDEBUG(MTD_DEBUG_LEVEL3, - "%s:%d: col = %d, n = %d\n", __func__, __LINE__, col, n); - - while (n > 0) { - void __iomem *p; - - if (col < mtd->writesize) { - p = host->regs->main_area[0] + (col & ~3); - } else { - p = host->regs->spare_area[0] - - mtd->writesize + (col & ~3); - } - - MTDDEBUG(MTD_DEBUG_LEVEL3, "%s:%d: p = %p\n", __func__, - __LINE__, p); - - if (((col | (unsigned long)&buf[i]) & 3) || n < 4) { - union { - uint32_t word; - uint8_t bytes[4]; - } nfc_word; - - nfc_word.word = readl(p); - nfc_word.bytes[col & 3] = buf[i++]; - n--; - col++; - - writel(nfc_word.word, p); - } else { - int m = mtd->writesize - col; - - if (col >= mtd->writesize) - m += mtd->oobsize; - - m = min(n, m) & ~3; - - MTDDEBUG(MTD_DEBUG_LEVEL3, - "%s:%d: n = %d, m = %d, i = %d, col = %d\n", - __func__, __LINE__, n, m, i, col); - - mxc_nand_memcpy32(p, (uint32_t *)&buf[i], m); - col += m; - i += m; - n -= m; - } - } - /* Update saved column address */ - host->col_addr = col; -} - -/* - * Read the data buffer from the NAND Flash. To read the data from NAND - * Flash first the data output cycle is initiated by the NFC, which copies - * the data to RAMbuffer. This data of length len is then copied to buffer buf. - */ -static void mxc_nand_read_buf(struct mtd_info *mtd, u_char *buf, int len) -{ - struct nand_chip *nand_chip = mtd->priv; - struct mxc_nand_host *host = nand_chip->priv; - int n, col, i = 0; - - MTDDEBUG(MTD_DEBUG_LEVEL3, - "mxc_nand_read_buf(col = %d, len = %d)\n", host->col_addr, len); - - col = host->col_addr; - - /* Adjust saved column address */ - if (col < mtd->writesize && host->spare_only) - col += mtd->writesize; - - n = mtd->writesize + mtd->oobsize - col; - n = min(len, n); - - while (n > 0) { - void __iomem *p; - - if (col < mtd->writesize) { - p = host->regs->main_area[0] + (col & ~3); - } else { - p = host->regs->spare_area[0] - - mtd->writesize + (col & ~3); - } - - if (((col | (int)&buf[i]) & 3) || n < 4) { - union { - uint32_t word; - uint8_t bytes[4]; - } nfc_word; - - nfc_word.word = readl(p); - buf[i++] = nfc_word.bytes[col & 3]; - n--; - col++; - } else { - int m = mtd->writesize - col; - - if (col >= mtd->writesize) - m += mtd->oobsize; - - m = min(n, m) & ~3; - mxc_nand_memcpy32((uint32_t *)&buf[i], p, m); - - col += m; - i += m; - n -= m; - } - } - /* Update saved column address */ - host->col_addr = col; -} - -/* - * Used by the upper layer to verify the data in NAND Flash - * with the data in the buf. - */ -static int mxc_nand_verify_buf(struct mtd_info *mtd, - const u_char *buf, int len) -{ - u_char tmp[256]; - uint bsize; - - while (len) { - bsize = min(len, 256); - mxc_nand_read_buf(mtd, tmp, bsize); - - if (memcmp(buf, tmp, bsize)) - return 1; - - buf += bsize; - len -= bsize; - } - - return 0; -} - -/* - * This function is used by upper layer for select and - * deselect of the NAND chip - */ -static void mxc_nand_select_chip(struct mtd_info *mtd, int chip) -{ - struct nand_chip *nand_chip = mtd->priv; - struct mxc_nand_host *host = nand_chip->priv; - - switch (chip) { - case -1: - /* TODO: Disable the NFC clock */ - if (host->clk_act) - host->clk_act = 0; - break; - case 0: - /* TODO: Enable the NFC clock */ - if (!host->clk_act) - host->clk_act = 1; - break; - - default: - break; - } -} - -/* - * Used by the upper layer to write command to NAND Flash for - * different operations to be carried out on NAND Flash - */ -void mxc_nand_command(struct mtd_info *mtd, unsigned command, - int column, int page_addr) -{ - struct nand_chip *nand_chip = mtd->priv; - struct mxc_nand_host *host = nand_chip->priv; - - MTDDEBUG(MTD_DEBUG_LEVEL3, - "mxc_nand_command (cmd = 0x%x, col = 0x%x, page = 0x%x)\n", - command, column, page_addr); - - /* Reset command state information */ - host->status_request = false; - - /* Command pre-processing step */ - switch (command) { - - case NAND_CMD_STATUS: - host->col_addr = 0; - host->status_request = true; - break; - - case NAND_CMD_READ0: - host->page_addr = page_addr; - host->col_addr = column; - host->spare_only = false; - break; - - case NAND_CMD_READOOB: - host->col_addr = column; - host->spare_only = true; - if (host->pagesize_2k) - command = NAND_CMD_READ0; /* only READ0 is valid */ - break; - - case NAND_CMD_SEQIN: - if (column >= mtd->writesize) { - /* - * before sending SEQIN command for partial write, - * we need read one page out. FSL NFC does not support - * partial write. It always sends out 512+ecc+512+ecc - * for large page nand flash. But for small page nand - * flash, it does support SPARE ONLY operation. - */ - if (host->pagesize_2k) { - /* call ourself to read a page */ - mxc_nand_command(mtd, NAND_CMD_READ0, 0, - page_addr); - } - - host->col_addr = column - mtd->writesize; - host->spare_only = true; - - /* Set program pointer to spare region */ - if (!host->pagesize_2k) - send_cmd(host, NAND_CMD_READOOB); - } else { - host->spare_only = false; - host->col_addr = column; - - /* Set program pointer to page start */ - if (!host->pagesize_2k) - send_cmd(host, NAND_CMD_READ0); - } - break; - - case NAND_CMD_PAGEPROG: - send_prog_page(host, 0, host->spare_only); - - if (host->pagesize_2k && is_mxc_nfc_1()) { - /* data in 4 areas */ - send_prog_page(host, 1, host->spare_only); - send_prog_page(host, 2, host->spare_only); - send_prog_page(host, 3, host->spare_only); - } - - break; - } - - /* Write out the command to the device. */ - send_cmd(host, command); - - /* Write out column address, if necessary */ - if (column != -1) { - /* - * MXC NANDFC can only perform full page+spare or - * spare-only read/write. When the upper layers perform - * a read/write buffer operation, we will use the saved - * column address to index into the full page. - */ - send_addr(host, 0); - if (host->pagesize_2k) - /* another col addr cycle for 2k page */ - send_addr(host, 0); - } - - /* Write out page address, if necessary */ - if (page_addr != -1) { - u32 page_mask = nand_chip->pagemask; - do { - send_addr(host, page_addr & 0xFF); - page_addr >>= 8; - page_mask >>= 8; - } while (page_mask); - } - - /* Command post-processing step */ - switch (command) { - - case NAND_CMD_RESET: - break; - - case NAND_CMD_READOOB: - case NAND_CMD_READ0: - if (host->pagesize_2k) { - /* send read confirm command */ - send_cmd(host, NAND_CMD_READSTART); - /* read for each AREA */ - send_read_page(host, 0, host->spare_only); - if (is_mxc_nfc_1()) { - send_read_page(host, 1, host->spare_only); - send_read_page(host, 2, host->spare_only); - send_read_page(host, 3, host->spare_only); - } - } else { - send_read_page(host, 0, host->spare_only); - } - break; - - case NAND_CMD_READID: - host->col_addr = 0; - send_read_id(host); - break; - - case NAND_CMD_PAGEPROG: - break; - - case NAND_CMD_STATUS: - break; - - case NAND_CMD_ERASE2: - break; - } -} - -#ifdef CONFIG_SYS_NAND_USE_FLASH_BBT - -static u8 bbt_pattern[] = {'B', 'b', 't', '0' }; -static u8 mirror_pattern[] = {'1', 't', 'b', 'B' }; - -static struct nand_bbt_descr bbt_main_descr = { - .options = NAND_BBT_LASTBLOCK | NAND_BBT_CREATE | NAND_BBT_WRITE | - NAND_BBT_2BIT | NAND_BBT_VERSION | NAND_BBT_PERCHIP, - .offs = 0, - .len = 4, - .veroffs = 4, - .maxblocks = 4, - .pattern = bbt_pattern, -}; - -static struct nand_bbt_descr bbt_mirror_descr = { - .options = NAND_BBT_LASTBLOCK | NAND_BBT_CREATE | NAND_BBT_WRITE | - NAND_BBT_2BIT | NAND_BBT_VERSION | NAND_BBT_PERCHIP, - .offs = 0, - .len = 4, - .veroffs = 4, - .maxblocks = 4, - .pattern = mirror_pattern, -}; - -#endif - -int board_nand_init(struct nand_chip *this) -{ - struct mtd_info *mtd; -#if defined(MXC_NFC_V2_1) || defined(MXC_NFC_V3_2) - uint32_t tmp; -#endif - -#ifdef CONFIG_SYS_NAND_USE_FLASH_BBT - this->bbt_options |= NAND_BBT_USE_FLASH; - this->bbt_td = &bbt_main_descr; - this->bbt_md = &bbt_mirror_descr; -#endif - - /* structures must be linked */ - mtd = &host->mtd; - mtd->priv = this; - host->nand = this; - - /* 5 us command delay time */ - this->chip_delay = 5; - - this->priv = host; - this->dev_ready = mxc_nand_dev_ready; - this->cmdfunc = mxc_nand_command; - this->select_chip = mxc_nand_select_chip; - this->read_byte = mxc_nand_read_byte; - this->read_word = mxc_nand_read_word; - this->write_buf = mxc_nand_write_buf; - this->read_buf = mxc_nand_read_buf; - this->verify_buf = mxc_nand_verify_buf; - - host->regs = (struct mxc_nand_regs __iomem *)CONFIG_MXC_NAND_REGS_BASE; -#ifdef MXC_NFC_V3_2 - host->ip_regs = - (struct mxc_nand_ip_regs __iomem *)CONFIG_MXC_NAND_IP_REGS_BASE; -#endif - host->clk_act = 1; - -#ifdef CONFIG_MXC_NAND_HWECC - this->ecc.calculate = mxc_nand_calculate_ecc; - this->ecc.hwctl = mxc_nand_enable_hwecc; - this->ecc.correct = mxc_nand_correct_data; - if (is_mxc_nfc_21() || is_mxc_nfc_32()) { - this->ecc.mode = NAND_ECC_HW_SYNDROME; - this->ecc.read_page = mxc_nand_read_page_syndrome; - this->ecc.read_page_raw = mxc_nand_read_page_raw_syndrome; - this->ecc.read_oob = mxc_nand_read_oob_syndrome; - this->ecc.write_page = mxc_nand_write_page_syndrome; - this->ecc.write_page_raw = mxc_nand_write_page_raw_syndrome; - this->ecc.write_oob = mxc_nand_write_oob_syndrome; - this->ecc.bytes = 9; - this->ecc.prepad = 7; - } else { - this->ecc.mode = NAND_ECC_HW; - } - - if (is_mxc_nfc_1()) - this->ecc.strength = 1; - else - this->ecc.strength = 4; - - host->pagesize_2k = 0; - - this->ecc.size = 512; - _mxc_nand_enable_hwecc(mtd, 1); -#else - this->ecc.layout = &nand_soft_eccoob; - this->ecc.mode = NAND_ECC_SOFT; - _mxc_nand_enable_hwecc(mtd, 0); -#endif - /* Reset NAND */ - this->cmdfunc(mtd, NAND_CMD_RESET, -1, -1); - - /* NAND bus width determines access functions used by upper layer */ - if (is_16bit_nand()) - this->options |= NAND_BUSWIDTH_16; - -#ifdef CONFIG_SYS_NAND_LARGEPAGE - host->pagesize_2k = 1; - this->ecc.layout = &nand_hw_eccoob2k; -#else - host->pagesize_2k = 0; - this->ecc.layout = &nand_hw_eccoob; -#endif - -#if defined(MXC_NFC_V1) || defined(MXC_NFC_V2_1) -#ifdef MXC_NFC_V2_1 - tmp = readnfc(&host->regs->config1); - tmp |= NFC_V2_CONFIG1_ONE_CYCLE; - tmp |= NFC_V2_CONFIG1_ECC_MODE_4; - writenfc(tmp, &host->regs->config1); - if (host->pagesize_2k) - writenfc(64/2, &host->regs->spare_area_size); - else - writenfc(16/2, &host->regs->spare_area_size); -#endif - - /* - * preset operation - * Unlock the internal RAM Buffer - */ - writenfc(0x2, &host->regs->config); - - /* Blocks to be unlocked */ - writenfc(0x0, &host->regs->unlockstart_blkaddr); - /* Originally (Freescale LTIB 2.6.21) 0x4000 was written to the - * unlockend_blkaddr, but the magic 0x4000 does not always work - * when writing more than some 32 megabytes (on 2k page nands) - * However 0xFFFF doesn't seem to have this kind - * of limitation (tried it back and forth several times). - * The linux kernel driver sets this to 0xFFFF for the v2 controller - * only, but probably this was not tested there for v1. - * The very same limitation seems to apply to this kernel driver. - * This might be NAND chip specific and the i.MX31 datasheet is - * extremely vague about the semantics of this register. - */ - writenfc(0xFFFF, &host->regs->unlockend_blkaddr); - - /* Unlock Block Command for given address range */ - writenfc(0x4, &host->regs->wrprot); -#elif defined(MXC_NFC_V3_2) - writenfc(NFC_V3_CONFIG1_RBA(0), &host->regs->config1); - writenfc(NFC_V3_IPC_CREQ, &host->ip_regs->ipc); - - /* Unlock the internal RAM Buffer */ - writenfc(NFC_V3_WRPROT_BLS_UNLOCK | NFC_V3_WRPROT_UNLOCK, - &host->ip_regs->wrprot); - - /* Blocks to be unlocked */ - for (tmp = 0; tmp < CONFIG_SYS_NAND_MAX_CHIPS; tmp++) - writenfc(0x0 | 0xFFFF << 16, - &host->ip_regs->wrprot_unlock_blkaddr[tmp]); - - writenfc(0, &host->ip_regs->ipc); - - tmp = readnfc(&host->ip_regs->config2); - tmp &= ~(NFC_V3_CONFIG2_SPAS_MASK | NFC_V3_CONFIG2_EDC_MASK | - NFC_V3_CONFIG2_ECC_MODE_8 | NFC_V3_CONFIG2_PS_MASK); - tmp |= NFC_V3_CONFIG2_ONE_CYCLE; - - if (host->pagesize_2k) { - tmp |= NFC_V3_CONFIG2_SPAS(64/2); - tmp |= NFC_V3_CONFIG2_PS_2048; - } else { - tmp |= NFC_V3_CONFIG2_SPAS(16/2); - tmp |= NFC_V3_CONFIG2_PS_512; - } - - writenfc(tmp, &host->ip_regs->config2); - - tmp = NFC_V3_CONFIG3_NUM_OF_DEVS(0) | - NFC_V3_CONFIG3_NO_SDMA | - NFC_V3_CONFIG3_RBB_MODE | - NFC_V3_CONFIG3_SBB(6) | /* Reset default */ - NFC_V3_CONFIG3_ADD_OP(0); - - if (!(this->options & NAND_BUSWIDTH_16)) - tmp |= NFC_V3_CONFIG3_FW8; - - writenfc(tmp, &host->ip_regs->config3); - - writenfc(0, &host->ip_regs->delay_line); -#endif - - return 0; -} diff --git a/qemu/roms/u-boot/drivers/mtd/nand/mxc_nand.h b/qemu/roms/u-boot/drivers/mtd/nand/mxc_nand.h deleted file mode 100644 index a02d6e0a5..000000000 --- a/qemu/roms/u-boot/drivers/mtd/nand/mxc_nand.h +++ /dev/null @@ -1,209 +0,0 @@ -/* - * (c) 2009 Magnus Lilja <lilja.magnus@gmail.com> - * - * SPDX-License-Identifier: GPL-2.0+ - */ - -#ifndef __MXC_NAND_H -#define __MXC_NAND_H - -/* - * Register map and bit definitions for the Freescale NAND Flash Controller - * present in various i.MX devices. - * - * MX31 and MX27 have version 1, which has: - * 4 512-byte main buffers and - * 4 16-byte spare buffers - * to support up to 2K byte pagesize nand. - * Reading or writing a 2K page requires 4 FDI/FDO cycles. - * - * MX25 and MX35 have version 2.1, and MX51 and MX53 have version 3.2, which - * have: - * 8 512-byte main buffers and - * 8 64-byte spare buffers - * to support up to 4K byte pagesize nand. - * Reading or writing a 2K or 4K page requires only 1 FDI/FDO cycle. - * Also some of registers are moved and/or changed meaning as seen below. - */ -#if defined(CONFIG_MX27) || defined(CONFIG_MX31) -#define MXC_NFC_V1 -#define is_mxc_nfc_1() 1 -#define is_mxc_nfc_21() 0 -#define is_mxc_nfc_32() 0 -#elif defined(CONFIG_MX25) || defined(CONFIG_MX35) -#define MXC_NFC_V2_1 -#define is_mxc_nfc_1() 0 -#define is_mxc_nfc_21() 1 -#define is_mxc_nfc_32() 0 -#elif defined(CONFIG_MX51) || defined(CONFIG_MX53) -#define MXC_NFC_V3 -#define MXC_NFC_V3_2 -#define is_mxc_nfc_1() 0 -#define is_mxc_nfc_21() 0 -#define is_mxc_nfc_32() 1 -#else -#error "MXC NFC implementation not supported" -#endif -#define is_mxc_nfc_3() is_mxc_nfc_32() - -#if defined(MXC_NFC_V1) -#define NAND_MXC_NR_BUFS 4 -#define NAND_MXC_SPARE_BUF_SIZE 16 -#define NAND_MXC_REG_OFFSET 0xe00 -#define NAND_MXC_2K_MULTI_CYCLE -#elif defined(MXC_NFC_V2_1) || defined(MXC_NFC_V3_2) -#define NAND_MXC_NR_BUFS 8 -#define NAND_MXC_SPARE_BUF_SIZE 64 -#define NAND_MXC_REG_OFFSET 0x1e00 -#endif - -struct mxc_nand_regs { - u8 main_area[NAND_MXC_NR_BUFS][0x200]; - u8 spare_area[NAND_MXC_NR_BUFS][NAND_MXC_SPARE_BUF_SIZE]; - /* - * reserved size is offset of nfc registers - * minus total main and spare sizes - */ - u8 reserved1[NAND_MXC_REG_OFFSET - - NAND_MXC_NR_BUFS * (512 + NAND_MXC_SPARE_BUF_SIZE)]; -#if defined(MXC_NFC_V1) - u16 buf_size; - u16 reserved2; - u16 buf_addr; - u16 flash_addr; - u16 flash_cmd; - u16 config; - u16 ecc_status_result; - u16 rsltmain_area; - u16 rsltspare_area; - u16 wrprot; - u16 unlockstart_blkaddr; - u16 unlockend_blkaddr; - u16 nf_wrprst; - u16 config1; - u16 config2; -#elif defined(MXC_NFC_V2_1) - u16 reserved2[2]; - u16 buf_addr; - u16 flash_addr; - u16 flash_cmd; - u16 config; - u32 ecc_status_result; - u16 spare_area_size; - u16 wrprot; - u16 reserved3[2]; - u16 nf_wrprst; - u16 config1; - u16 config2; - u16 reserved4; - u16 unlockstart_blkaddr; - u16 unlockend_blkaddr; - u16 unlockstart_blkaddr1; - u16 unlockend_blkaddr1; - u16 unlockstart_blkaddr2; - u16 unlockend_blkaddr2; - u16 unlockstart_blkaddr3; - u16 unlockend_blkaddr3; -#elif defined(MXC_NFC_V3_2) - u32 flash_cmd; - u32 flash_addr[12]; - u32 config1; - u32 ecc_status_result; - u32 status_sum; - u32 launch; -#endif -}; - -#ifdef MXC_NFC_V3_2 -struct mxc_nand_ip_regs { - u32 wrprot; - u32 wrprot_unlock_blkaddr[8]; - u32 config2; - u32 config3; - u32 ipc; - u32 err_addr; - u32 delay_line; -}; -#endif - -/* Set FCMD to 1, rest to 0 for Command operation */ -#define NFC_CMD 0x1 - -/* Set FADD to 1, rest to 0 for Address operation */ -#define NFC_ADDR 0x2 - -/* Set FDI to 1, rest to 0 for Input operation */ -#define NFC_INPUT 0x4 - -/* Set FDO to 001, rest to 0 for Data Output operation */ -#define NFC_OUTPUT 0x8 - -/* Set FDO to 010, rest to 0 for Read ID operation */ -#define NFC_ID 0x10 - -/* Set FDO to 100, rest to 0 for Read Status operation */ -#define NFC_STATUS 0x20 - -#if defined(MXC_NFC_V1) || defined(MXC_NFC_V2_1) -#define NFC_CONFIG1_SP_EN (1 << 2) -#define NFC_CONFIG1_RST (1 << 6) -#define NFC_CONFIG1_CE (1 << 7) -#elif defined(MXC_NFC_V3_2) -#define NFC_CONFIG1_SP_EN (1 << 0) -#define NFC_CONFIG1_CE (1 << 1) -#define NFC_CONFIG1_RST (1 << 2) -#endif -#define NFC_V1_V2_CONFIG1_ECC_EN (1 << 3) -#define NFC_V1_V2_CONFIG1_INT_MSK (1 << 4) -#define NFC_V1_V2_CONFIG1_BIG (1 << 5) -#define NFC_V2_CONFIG1_ECC_MODE_4 (1 << 0) -#define NFC_V2_CONFIG1_ONE_CYCLE (1 << 8) -#define NFC_V2_CONFIG1_FP_INT (1 << 11) -#define NFC_V3_CONFIG1_RBA_MASK (0x7 << 4) -#define NFC_V3_CONFIG1_RBA(x) (((x) & 0x7) << 4) - -#define NFC_V1_V2_CONFIG2_INT (1 << 15) -#define NFC_V3_CONFIG2_PS_MASK (0x3 << 0) -#define NFC_V3_CONFIG2_PS_512 (0 << 0) -#define NFC_V3_CONFIG2_PS_2048 (1 << 0) -#define NFC_V3_CONFIG2_PS_4096 (2 << 0) -#define NFC_V3_CONFIG2_ONE_CYCLE (1 << 2) -#define NFC_V3_CONFIG2_ECC_EN (1 << 3) -#define NFC_V3_CONFIG2_2CMD_PHASES (1 << 4) -#define NFC_V3_CONFIG2_NUM_ADDR_PH0 (1 << 5) -#define NFC_V3_CONFIG2_ECC_MODE_8 (1 << 6) -#define NFC_V3_CONFIG2_PPB_MASK (0x3 << 7) -#define NFC_V3_CONFIG2_PPB(x) (((x) & 0x3) << 7) -#define NFC_V3_CONFIG2_EDC_MASK (0x7 << 9) -#define NFC_V3_CONFIG2_EDC(x) (((x) & 0x7) << 9) -#define NFC_V3_CONFIG2_NUM_ADDR_PH1(x) (((x) & 0x3) << 12) -#define NFC_V3_CONFIG2_INT_MSK (1 << 15) -#define NFC_V3_CONFIG2_SPAS_MASK (0xff << 16) -#define NFC_V3_CONFIG2_SPAS(x) (((x) & 0xff) << 16) -#define NFC_V3_CONFIG2_ST_CMD_MASK (0xff << 24) -#define NFC_V3_CONFIG2_ST_CMD(x) (((x) & 0xff) << 24) - -#define NFC_V3_CONFIG3_ADD_OP(x) (((x) & 0x3) << 0) -#define NFC_V3_CONFIG3_FW8 (1 << 3) -#define NFC_V3_CONFIG3_SBB(x) (((x) & 0x7) << 8) -#define NFC_V3_CONFIG3_NUM_OF_DEVS(x) (((x) & 0x7) << 12) -#define NFC_V3_CONFIG3_RBB_MODE (1 << 15) -#define NFC_V3_CONFIG3_NO_SDMA (1 << 20) - -#define NFC_V3_WRPROT_UNLOCK (1 << 2) -#define NFC_V3_WRPROT_BLS_UNLOCK (2 << 6) - -#define NFC_V3_IPC_CREQ (1 << 0) -#define NFC_V3_IPC_INT (1 << 31) - -#if defined(MXC_NFC_V1) || defined(MXC_NFC_V2_1) -#define operation config2 -#define readnfc readw -#define writenfc writew -#elif defined(MXC_NFC_V3_2) -#define operation launch -#define readnfc readl -#define writenfc writel -#endif - -#endif /* __MXC_NAND_H */ diff --git a/qemu/roms/u-boot/drivers/mtd/nand/mxc_nand_spl.c b/qemu/roms/u-boot/drivers/mtd/nand/mxc_nand_spl.c deleted file mode 100644 index 69b736a84..000000000 --- a/qemu/roms/u-boot/drivers/mtd/nand/mxc_nand_spl.c +++ /dev/null @@ -1,351 +0,0 @@ -/* - * (C) Copyright 2009 - * Magnus Lilja <lilja.magnus@gmail.com> - * - * (C) Copyright 2008 - * Maxim Artamonov, <scn1874 at yandex.ru> - * - * (C) Copyright 2006-2008 - * Stefan Roese, DENX Software Engineering, sr at denx.de. - * - * SPDX-License-Identifier: GPL-2.0+ - */ - -#include <common.h> -#include <nand.h> -#include <asm/arch/imx-regs.h> -#include <asm/io.h> -#include "mxc_nand.h" - -#if defined(MXC_NFC_V1) || defined(MXC_NFC_V2_1) -static struct mxc_nand_regs *const nfc = (void *)NFC_BASE_ADDR; -#elif defined(MXC_NFC_V3_2) -static struct mxc_nand_regs *const nfc = (void *)NFC_BASE_ADDR_AXI; -static struct mxc_nand_ip_regs *const nfc_ip = (void *)NFC_BASE_ADDR; -#endif - -static void nfc_wait_ready(void) -{ - uint32_t tmp; - -#if defined(MXC_NFC_V1) || defined(MXC_NFC_V2_1) - while (!(readnfc(&nfc->config2) & NFC_V1_V2_CONFIG2_INT)) - ; - - /* Reset interrupt flag */ - tmp = readnfc(&nfc->config2); - tmp &= ~NFC_V1_V2_CONFIG2_INT; - writenfc(tmp, &nfc->config2); -#elif defined(MXC_NFC_V3_2) - while (!(readnfc(&nfc_ip->ipc) & NFC_V3_IPC_INT)) - ; - - /* Reset interrupt flag */ - tmp = readnfc(&nfc_ip->ipc); - tmp &= ~NFC_V3_IPC_INT; - writenfc(tmp, &nfc_ip->ipc); -#endif -} - -static void nfc_nand_init(void) -{ -#if defined(MXC_NFC_V3_2) - int ecc_per_page = CONFIG_SYS_NAND_PAGE_SIZE / 512; - int tmp; - - tmp = (readnfc(&nfc_ip->config2) & ~(NFC_V3_CONFIG2_SPAS_MASK | - NFC_V3_CONFIG2_EDC_MASK | NFC_V3_CONFIG2_PS_MASK)) | - NFC_V3_CONFIG2_SPAS(CONFIG_SYS_NAND_OOBSIZE / 2) | - NFC_V3_CONFIG2_INT_MSK | NFC_V3_CONFIG2_ECC_EN | - NFC_V3_CONFIG2_ONE_CYCLE; - if (CONFIG_SYS_NAND_PAGE_SIZE == 4096) - tmp |= NFC_V3_CONFIG2_PS_4096; - else if (CONFIG_SYS_NAND_PAGE_SIZE == 2048) - tmp |= NFC_V3_CONFIG2_PS_2048; - else if (CONFIG_SYS_NAND_PAGE_SIZE == 512) - tmp |= NFC_V3_CONFIG2_PS_512; - /* - * if spare size is larger that 16 bytes per 512 byte hunk - * then use 8 symbol correction instead of 4 - */ - if (CONFIG_SYS_NAND_OOBSIZE / ecc_per_page > 16) - tmp |= NFC_V3_CONFIG2_ECC_MODE_8; - else - tmp &= ~NFC_V3_CONFIG2_ECC_MODE_8; - writenfc(tmp, &nfc_ip->config2); - - tmp = NFC_V3_CONFIG3_NUM_OF_DEVS(0) | - NFC_V3_CONFIG3_NO_SDMA | - NFC_V3_CONFIG3_RBB_MODE | - NFC_V3_CONFIG3_SBB(6) | /* Reset default */ - NFC_V3_CONFIG3_ADD_OP(0); -#ifndef CONFIG_SYS_NAND_BUSWIDTH_16 - tmp |= NFC_V3_CONFIG3_FW8; -#endif - writenfc(tmp, &nfc_ip->config3); - - writenfc(0, &nfc_ip->delay_line); -#elif defined(MXC_NFC_V2_1) - int ecc_per_page = CONFIG_SYS_NAND_PAGE_SIZE / 512; - int config1; - - writenfc(CONFIG_SYS_NAND_OOBSIZE / 2, &nfc->spare_area_size); - - /* unlocking RAM Buff */ - writenfc(0x2, &nfc->config); - - /* hardware ECC checking and correct */ - config1 = readnfc(&nfc->config1) | NFC_V1_V2_CONFIG1_ECC_EN | - NFC_V1_V2_CONFIG1_INT_MSK | NFC_V2_CONFIG1_ONE_CYCLE | - NFC_V2_CONFIG1_FP_INT; - /* - * if spare size is larger that 16 bytes per 512 byte hunk - * then use 8 symbol correction instead of 4 - */ - if (CONFIG_SYS_NAND_OOBSIZE / ecc_per_page > 16) - config1 &= ~NFC_V2_CONFIG1_ECC_MODE_4; - else - config1 |= NFC_V2_CONFIG1_ECC_MODE_4; - writenfc(config1, &nfc->config1); -#elif defined(MXC_NFC_V1) - /* unlocking RAM Buff */ - writenfc(0x2, &nfc->config); - - /* hardware ECC checking and correct */ - writenfc(NFC_V1_V2_CONFIG1_ECC_EN | NFC_V1_V2_CONFIG1_INT_MSK, - &nfc->config1); -#endif -} - -static void nfc_nand_command(unsigned short command) -{ - writenfc(command, &nfc->flash_cmd); - writenfc(NFC_CMD, &nfc->operation); - nfc_wait_ready(); -} - -static void nfc_nand_address(unsigned short address) -{ - writenfc(address, &nfc->flash_addr); - writenfc(NFC_ADDR, &nfc->operation); - nfc_wait_ready(); -} - -static void nfc_nand_page_address(unsigned int page_address) -{ - unsigned int page_count; - - nfc_nand_address(0x00); - - /* code only for large page flash */ - if (CONFIG_SYS_NAND_PAGE_SIZE > 512) - nfc_nand_address(0x00); - - page_count = CONFIG_SYS_NAND_SIZE / CONFIG_SYS_NAND_PAGE_SIZE; - - if (page_address <= page_count) { - page_count--; /* transform 0x01000000 to 0x00ffffff */ - do { - nfc_nand_address(page_address & 0xff); - page_address = page_address >> 8; - page_count = page_count >> 8; - } while (page_count); - } - - nfc_nand_address(0x00); -} - -static void nfc_nand_data_output(void) -{ -#ifdef NAND_MXC_2K_MULTI_CYCLE - int i; -#endif - -#if defined(MXC_NFC_V1) || defined(MXC_NFC_V2_1) - writenfc(0, &nfc->buf_addr); -#elif defined(MXC_NFC_V3_2) - int config1 = readnfc(&nfc->config1); - config1 &= ~NFC_V3_CONFIG1_RBA_MASK; - writenfc(config1, &nfc->config1); -#endif - writenfc(NFC_OUTPUT, &nfc->operation); - nfc_wait_ready(); -#ifdef NAND_MXC_2K_MULTI_CYCLE - /* - * This NAND controller requires multiple input commands - * for pages larger than 512 bytes. - */ - for (i = 1; i < CONFIG_SYS_NAND_PAGE_SIZE / 512; i++) { - writenfc(i, &nfc->buf_addr); - writenfc(NFC_OUTPUT, &nfc->operation); - nfc_wait_ready(); - } -#endif -} - -static int nfc_nand_check_ecc(void) -{ -#if defined(MXC_NFC_V1) - u16 ecc_status = readw(&nfc->ecc_status_result); - return (ecc_status & 0x3) == 2 || (ecc_status >> 2) == 2; -#elif defined(MXC_NFC_V2_1) || defined(MXC_NFC_V3_2) - u32 ecc_status = readl(&nfc->ecc_status_result); - int ecc_per_page = CONFIG_SYS_NAND_PAGE_SIZE / 512; - int err_limit = CONFIG_SYS_NAND_OOBSIZE / ecc_per_page > 16 ? 8 : 4; - int subpages = CONFIG_SYS_NAND_PAGE_SIZE / 512; - - do { - if ((ecc_status & 0xf) > err_limit) - return 1; - ecc_status >>= 4; - } while (--subpages); - - return 0; -#endif -} - -static void nfc_nand_read_page(unsigned int page_address) -{ - /* read in first 0 buffer */ -#if defined(MXC_NFC_V1) || defined(MXC_NFC_V2_1) - writenfc(0, &nfc->buf_addr); -#elif defined(MXC_NFC_V3_2) - int config1 = readnfc(&nfc->config1); - config1 &= ~NFC_V3_CONFIG1_RBA_MASK; - writenfc(config1, &nfc->config1); -#endif - nfc_nand_command(NAND_CMD_READ0); - nfc_nand_page_address(page_address); - - if (CONFIG_SYS_NAND_PAGE_SIZE > 512) - nfc_nand_command(NAND_CMD_READSTART); - - nfc_nand_data_output(); /* fill the main buffer 0 */ -} - -static int nfc_read_page(unsigned int page_address, unsigned char *buf) -{ - int i; - u32 *src; - u32 *dst; - - nfc_nand_read_page(page_address); - - if (nfc_nand_check_ecc()) - return -1; - - src = (u32 *)&nfc->main_area[0][0]; - dst = (u32 *)buf; - - /* main copy loop from NAND-buffer to SDRAM memory */ - for (i = 0; i < CONFIG_SYS_NAND_PAGE_SIZE / 4; i++) { - writel(readl(src), dst); - src++; - dst++; - } - - return 0; -} - -static int is_badblock(int pagenumber) -{ - int page = pagenumber; - u32 badblock; - u32 *src; - - /* Check the first two pages for bad block markers */ - for (page = pagenumber; page < pagenumber + 2; page++) { - nfc_nand_read_page(page); - - src = (u32 *)&nfc->spare_area[0][0]; - - /* - * IMPORTANT NOTE: The nand flash controller uses a non- - * standard layout for large page devices. This can - * affect the position of the bad block marker. - */ - /* Get the bad block marker */ - badblock = readl(&src[CONFIG_SYS_NAND_BAD_BLOCK_POS / 4]); - badblock >>= 8 * (CONFIG_SYS_NAND_BAD_BLOCK_POS % 4); - badblock &= 0xff; - - /* bad block marker verify */ - if (badblock != 0xff) - return 1; /* potential bad block */ - } - - return 0; -} - -int nand_spl_load_image(uint32_t from, unsigned int size, void *buf) -{ - int i; - unsigned int page; - unsigned int maxpages = CONFIG_SYS_NAND_SIZE / - CONFIG_SYS_NAND_PAGE_SIZE; - - nfc_nand_init(); - - /* Convert to page number */ - page = from / CONFIG_SYS_NAND_PAGE_SIZE; - i = 0; - - size = roundup(size, CONFIG_SYS_NAND_PAGE_SIZE); - while (i < size / CONFIG_SYS_NAND_PAGE_SIZE) { - if (nfc_read_page(page, buf) < 0) - return -1; - - page++; - i++; - buf = buf + CONFIG_SYS_NAND_PAGE_SIZE; - - /* - * Check if we have crossed a block boundary, and if so - * check for bad block. - */ - if (!(page % CONFIG_SYS_NAND_PAGE_COUNT)) { - /* - * Yes, new block. See if this block is good. If not, - * loop until we find a good block. - */ - while (is_badblock(page)) { - page = page + CONFIG_SYS_NAND_PAGE_COUNT; - /* Check i we've reached the end of flash. */ - if (page >= maxpages) - return -1; - } - } - } - - return 0; -} - -#ifndef CONFIG_SPL_FRAMEWORK -/* - * The main entry for NAND booting. It's necessary that SDRAM is already - * configured and available since this code loads the main U-Boot image - * from NAND into SDRAM and starts it from there. - */ -void nand_boot(void) -{ - __attribute__((noreturn)) void (*uboot)(void); - - /* - * CONFIG_SYS_NAND_U_BOOT_OFFS and CONFIG_SYS_NAND_U_BOOT_SIZE must - * be aligned to full pages - */ - if (!nand_spl_load_image(CONFIG_SYS_NAND_U_BOOT_OFFS, - CONFIG_SYS_NAND_U_BOOT_SIZE, - (uchar *)CONFIG_SYS_NAND_U_BOOT_DST)) { - /* Copy from NAND successful, start U-boot */ - uboot = (void *)CONFIG_SYS_NAND_U_BOOT_START; - uboot(); - } else { - /* Unrecoverable error when copying from NAND */ - hang(); - } -} -#endif - -void nand_init(void) {} -void nand_deselect(void) {} diff --git a/qemu/roms/u-boot/drivers/mtd/nand/mxs_nand.c b/qemu/roms/u-boot/drivers/mtd/nand/mxs_nand.c deleted file mode 100644 index 036c113ad..000000000 --- a/qemu/roms/u-boot/drivers/mtd/nand/mxs_nand.c +++ /dev/null @@ -1,1179 +0,0 @@ -/* - * Freescale i.MX28 NAND flash driver - * - * Copyright (C) 2011 Marek Vasut <marek.vasut@gmail.com> - * on behalf of DENX Software Engineering GmbH - * - * Based on code from LTIB: - * Freescale GPMI NFC NAND Flash Driver - * - * Copyright (C) 2010 Freescale Semiconductor, Inc. - * Copyright (C) 2008 Embedded Alley Solutions, Inc. - * - * SPDX-License-Identifier: GPL-2.0+ - */ - -#include <common.h> -#include <linux/mtd/mtd.h> -#include <linux/mtd/nand.h> -#include <linux/types.h> -#include <malloc.h> -#include <asm/errno.h> -#include <asm/io.h> -#include <asm/arch/clock.h> -#include <asm/arch/imx-regs.h> -#include <asm/imx-common/regs-bch.h> -#include <asm/imx-common/regs-gpmi.h> -#include <asm/arch/sys_proto.h> -#include <asm/imx-common/dma.h> - -#define MXS_NAND_DMA_DESCRIPTOR_COUNT 4 - -#define MXS_NAND_CHUNK_DATA_CHUNK_SIZE 512 -#if defined(CONFIG_MX6) -#define MXS_NAND_CHUNK_DATA_CHUNK_SIZE_SHIFT 2 -#else -#define MXS_NAND_CHUNK_DATA_CHUNK_SIZE_SHIFT 0 -#endif -#define MXS_NAND_METADATA_SIZE 10 - -#define MXS_NAND_COMMAND_BUFFER_SIZE 32 - -#define MXS_NAND_BCH_TIMEOUT 10000 - -struct mxs_nand_info { - int cur_chip; - - uint32_t cmd_queue_len; - uint32_t data_buf_size; - - uint8_t *cmd_buf; - uint8_t *data_buf; - uint8_t *oob_buf; - - uint8_t marking_block_bad; - uint8_t raw_oob_mode; - - /* Functions with altered behaviour */ - int (*hooked_read_oob)(struct mtd_info *mtd, - loff_t from, struct mtd_oob_ops *ops); - int (*hooked_write_oob)(struct mtd_info *mtd, - loff_t to, struct mtd_oob_ops *ops); - int (*hooked_block_markbad)(struct mtd_info *mtd, - loff_t ofs); - - /* DMA descriptors */ - struct mxs_dma_desc **desc; - uint32_t desc_index; -}; - -struct nand_ecclayout fake_ecc_layout; - -/* - * Cache management functions - */ -#ifndef CONFIG_SYS_DCACHE_OFF -static void mxs_nand_flush_data_buf(struct mxs_nand_info *info) -{ - uint32_t addr = (uint32_t)info->data_buf; - - flush_dcache_range(addr, addr + info->data_buf_size); -} - -static void mxs_nand_inval_data_buf(struct mxs_nand_info *info) -{ - uint32_t addr = (uint32_t)info->data_buf; - - invalidate_dcache_range(addr, addr + info->data_buf_size); -} - -static void mxs_nand_flush_cmd_buf(struct mxs_nand_info *info) -{ - uint32_t addr = (uint32_t)info->cmd_buf; - - flush_dcache_range(addr, addr + MXS_NAND_COMMAND_BUFFER_SIZE); -} -#else -static inline void mxs_nand_flush_data_buf(struct mxs_nand_info *info) {} -static inline void mxs_nand_inval_data_buf(struct mxs_nand_info *info) {} -static inline void mxs_nand_flush_cmd_buf(struct mxs_nand_info *info) {} -#endif - -static struct mxs_dma_desc *mxs_nand_get_dma_desc(struct mxs_nand_info *info) -{ - struct mxs_dma_desc *desc; - - if (info->desc_index >= MXS_NAND_DMA_DESCRIPTOR_COUNT) { - printf("MXS NAND: Too many DMA descriptors requested\n"); - return NULL; - } - - desc = info->desc[info->desc_index]; - info->desc_index++; - - return desc; -} - -static void mxs_nand_return_dma_descs(struct mxs_nand_info *info) -{ - int i; - struct mxs_dma_desc *desc; - - for (i = 0; i < info->desc_index; i++) { - desc = info->desc[i]; - memset(desc, 0, sizeof(struct mxs_dma_desc)); - desc->address = (dma_addr_t)desc; - } - - info->desc_index = 0; -} - -static uint32_t mxs_nand_ecc_chunk_cnt(uint32_t page_data_size) -{ - return page_data_size / MXS_NAND_CHUNK_DATA_CHUNK_SIZE; -} - -static uint32_t mxs_nand_ecc_size_in_bits(uint32_t ecc_strength) -{ - return ecc_strength * 13; -} - -static uint32_t mxs_nand_aux_status_offset(void) -{ - return (MXS_NAND_METADATA_SIZE + 0x3) & ~0x3; -} - -static inline uint32_t mxs_nand_get_ecc_strength(uint32_t page_data_size, - uint32_t page_oob_size) -{ - if (page_data_size == 2048) - return 8; - - if (page_data_size == 4096) { - if (page_oob_size == 128) - return 8; - - if (page_oob_size == 218) - return 16; - - if (page_oob_size == 224) - return 16; - } - - return 0; -} - -static inline uint32_t mxs_nand_get_mark_offset(uint32_t page_data_size, - uint32_t ecc_strength) -{ - uint32_t chunk_data_size_in_bits; - uint32_t chunk_ecc_size_in_bits; - uint32_t chunk_total_size_in_bits; - uint32_t block_mark_chunk_number; - uint32_t block_mark_chunk_bit_offset; - uint32_t block_mark_bit_offset; - - chunk_data_size_in_bits = MXS_NAND_CHUNK_DATA_CHUNK_SIZE * 8; - chunk_ecc_size_in_bits = mxs_nand_ecc_size_in_bits(ecc_strength); - - chunk_total_size_in_bits = - chunk_data_size_in_bits + chunk_ecc_size_in_bits; - - /* Compute the bit offset of the block mark within the physical page. */ - block_mark_bit_offset = page_data_size * 8; - - /* Subtract the metadata bits. */ - block_mark_bit_offset -= MXS_NAND_METADATA_SIZE * 8; - - /* - * Compute the chunk number (starting at zero) in which the block mark - * appears. - */ - block_mark_chunk_number = - block_mark_bit_offset / chunk_total_size_in_bits; - - /* - * Compute the bit offset of the block mark within its chunk, and - * validate it. - */ - block_mark_chunk_bit_offset = block_mark_bit_offset - - (block_mark_chunk_number * chunk_total_size_in_bits); - - if (block_mark_chunk_bit_offset > chunk_data_size_in_bits) - return 1; - - /* - * Now that we know the chunk number in which the block mark appears, - * we can subtract all the ECC bits that appear before it. - */ - block_mark_bit_offset -= - block_mark_chunk_number * chunk_ecc_size_in_bits; - - return block_mark_bit_offset; -} - -static uint32_t mxs_nand_mark_byte_offset(struct mtd_info *mtd) -{ - uint32_t ecc_strength; - ecc_strength = mxs_nand_get_ecc_strength(mtd->writesize, mtd->oobsize); - return mxs_nand_get_mark_offset(mtd->writesize, ecc_strength) >> 3; -} - -static uint32_t mxs_nand_mark_bit_offset(struct mtd_info *mtd) -{ - uint32_t ecc_strength; - ecc_strength = mxs_nand_get_ecc_strength(mtd->writesize, mtd->oobsize); - return mxs_nand_get_mark_offset(mtd->writesize, ecc_strength) & 0x7; -} - -/* - * Wait for BCH complete IRQ and clear the IRQ - */ -static int mxs_nand_wait_for_bch_complete(void) -{ - struct mxs_bch_regs *bch_regs = (struct mxs_bch_regs *)MXS_BCH_BASE; - int timeout = MXS_NAND_BCH_TIMEOUT; - int ret; - - ret = mxs_wait_mask_set(&bch_regs->hw_bch_ctrl_reg, - BCH_CTRL_COMPLETE_IRQ, timeout); - - writel(BCH_CTRL_COMPLETE_IRQ, &bch_regs->hw_bch_ctrl_clr); - - return ret; -} - -/* - * This is the function that we install in the cmd_ctrl function pointer of the - * owning struct nand_chip. The only functions in the reference implementation - * that use these functions pointers are cmdfunc and select_chip. - * - * In this driver, we implement our own select_chip, so this function will only - * be called by the reference implementation's cmdfunc. For this reason, we can - * ignore the chip enable bit and concentrate only on sending bytes to the NAND - * Flash. - */ -static void mxs_nand_cmd_ctrl(struct mtd_info *mtd, int data, unsigned int ctrl) -{ - struct nand_chip *nand = mtd->priv; - struct mxs_nand_info *nand_info = nand->priv; - struct mxs_dma_desc *d; - uint32_t channel = MXS_DMA_CHANNEL_AHB_APBH_GPMI0 + nand_info->cur_chip; - int ret; - - /* - * If this condition is true, something is _VERY_ wrong in MTD - * subsystem! - */ - if (nand_info->cmd_queue_len == MXS_NAND_COMMAND_BUFFER_SIZE) { - printf("MXS NAND: Command queue too long\n"); - return; - } - - /* - * Every operation begins with a command byte and a series of zero or - * more address bytes. These are distinguished by either the Address - * Latch Enable (ALE) or Command Latch Enable (CLE) signals being - * asserted. When MTD is ready to execute the command, it will - * deasert both latch enables. - * - * Rather than run a separate DMA operation for every single byte, we - * queue them up and run a single DMA operation for the entire series - * of command and data bytes. - */ - if (ctrl & (NAND_ALE | NAND_CLE)) { - if (data != NAND_CMD_NONE) - nand_info->cmd_buf[nand_info->cmd_queue_len++] = data; - return; - } - - /* - * If control arrives here, MTD has deasserted both the ALE and CLE, - * which means it's ready to run an operation. Check if we have any - * bytes to send. - */ - if (nand_info->cmd_queue_len == 0) - return; - - /* Compile the DMA descriptor -- a descriptor that sends command. */ - d = mxs_nand_get_dma_desc(nand_info); - d->cmd.data = - MXS_DMA_DESC_COMMAND_DMA_READ | MXS_DMA_DESC_IRQ | - MXS_DMA_DESC_CHAIN | MXS_DMA_DESC_DEC_SEM | - MXS_DMA_DESC_WAIT4END | (3 << MXS_DMA_DESC_PIO_WORDS_OFFSET) | - (nand_info->cmd_queue_len << MXS_DMA_DESC_BYTES_OFFSET); - - d->cmd.address = (dma_addr_t)nand_info->cmd_buf; - - d->cmd.pio_words[0] = - GPMI_CTRL0_COMMAND_MODE_WRITE | - GPMI_CTRL0_WORD_LENGTH | - (nand_info->cur_chip << GPMI_CTRL0_CS_OFFSET) | - GPMI_CTRL0_ADDRESS_NAND_CLE | - GPMI_CTRL0_ADDRESS_INCREMENT | - nand_info->cmd_queue_len; - - mxs_dma_desc_append(channel, d); - - /* Flush caches */ - mxs_nand_flush_cmd_buf(nand_info); - - /* Execute the DMA chain. */ - ret = mxs_dma_go(channel); - if (ret) - printf("MXS NAND: Error sending command\n"); - - mxs_nand_return_dma_descs(nand_info); - - /* Reset the command queue. */ - nand_info->cmd_queue_len = 0; -} - -/* - * Test if the NAND flash is ready. - */ -static int mxs_nand_device_ready(struct mtd_info *mtd) -{ - struct nand_chip *chip = mtd->priv; - struct mxs_nand_info *nand_info = chip->priv; - struct mxs_gpmi_regs *gpmi_regs = - (struct mxs_gpmi_regs *)MXS_GPMI_BASE; - uint32_t tmp; - - tmp = readl(&gpmi_regs->hw_gpmi_stat); - tmp >>= (GPMI_STAT_READY_BUSY_OFFSET + nand_info->cur_chip); - - return tmp & 1; -} - -/* - * Select the NAND chip. - */ -static void mxs_nand_select_chip(struct mtd_info *mtd, int chip) -{ - struct nand_chip *nand = mtd->priv; - struct mxs_nand_info *nand_info = nand->priv; - - nand_info->cur_chip = chip; -} - -/* - * Handle block mark swapping. - * - * Note that, when this function is called, it doesn't know whether it's - * swapping the block mark, or swapping it *back* -- but it doesn't matter - * because the the operation is the same. - */ -static void mxs_nand_swap_block_mark(struct mtd_info *mtd, - uint8_t *data_buf, uint8_t *oob_buf) -{ - uint32_t bit_offset; - uint32_t buf_offset; - - uint32_t src; - uint32_t dst; - - bit_offset = mxs_nand_mark_bit_offset(mtd); - buf_offset = mxs_nand_mark_byte_offset(mtd); - - /* - * Get the byte from the data area that overlays the block mark. Since - * the ECC engine applies its own view to the bits in the page, the - * physical block mark won't (in general) appear on a byte boundary in - * the data. - */ - src = data_buf[buf_offset] >> bit_offset; - src |= data_buf[buf_offset + 1] << (8 - bit_offset); - - dst = oob_buf[0]; - - oob_buf[0] = src; - - data_buf[buf_offset] &= ~(0xff << bit_offset); - data_buf[buf_offset + 1] &= 0xff << bit_offset; - - data_buf[buf_offset] |= dst << bit_offset; - data_buf[buf_offset + 1] |= dst >> (8 - bit_offset); -} - -/* - * Read data from NAND. - */ -static void mxs_nand_read_buf(struct mtd_info *mtd, uint8_t *buf, int length) -{ - struct nand_chip *nand = mtd->priv; - struct mxs_nand_info *nand_info = nand->priv; - struct mxs_dma_desc *d; - uint32_t channel = MXS_DMA_CHANNEL_AHB_APBH_GPMI0 + nand_info->cur_chip; - int ret; - - if (length > NAND_MAX_PAGESIZE) { - printf("MXS NAND: DMA buffer too big\n"); - return; - } - - if (!buf) { - printf("MXS NAND: DMA buffer is NULL\n"); - return; - } - - /* Compile the DMA descriptor - a descriptor that reads data. */ - d = mxs_nand_get_dma_desc(nand_info); - d->cmd.data = - MXS_DMA_DESC_COMMAND_DMA_WRITE | MXS_DMA_DESC_IRQ | - MXS_DMA_DESC_DEC_SEM | MXS_DMA_DESC_WAIT4END | - (1 << MXS_DMA_DESC_PIO_WORDS_OFFSET) | - (length << MXS_DMA_DESC_BYTES_OFFSET); - - d->cmd.address = (dma_addr_t)nand_info->data_buf; - - d->cmd.pio_words[0] = - GPMI_CTRL0_COMMAND_MODE_READ | - GPMI_CTRL0_WORD_LENGTH | - (nand_info->cur_chip << GPMI_CTRL0_CS_OFFSET) | - GPMI_CTRL0_ADDRESS_NAND_DATA | - length; - - mxs_dma_desc_append(channel, d); - - /* - * A DMA descriptor that waits for the command to end and the chip to - * become ready. - * - * I think we actually should *not* be waiting for the chip to become - * ready because, after all, we don't care. I think the original code - * did that and no one has re-thought it yet. - */ - d = mxs_nand_get_dma_desc(nand_info); - d->cmd.data = - MXS_DMA_DESC_COMMAND_NO_DMAXFER | MXS_DMA_DESC_IRQ | - MXS_DMA_DESC_NAND_WAIT_4_READY | MXS_DMA_DESC_DEC_SEM | - MXS_DMA_DESC_WAIT4END | (4 << MXS_DMA_DESC_PIO_WORDS_OFFSET); - - d->cmd.address = 0; - - d->cmd.pio_words[0] = - GPMI_CTRL0_COMMAND_MODE_WAIT_FOR_READY | - GPMI_CTRL0_WORD_LENGTH | - (nand_info->cur_chip << GPMI_CTRL0_CS_OFFSET) | - GPMI_CTRL0_ADDRESS_NAND_DATA; - - mxs_dma_desc_append(channel, d); - - /* Execute the DMA chain. */ - ret = mxs_dma_go(channel); - if (ret) { - printf("MXS NAND: DMA read error\n"); - goto rtn; - } - - /* Invalidate caches */ - mxs_nand_inval_data_buf(nand_info); - - memcpy(buf, nand_info->data_buf, length); - -rtn: - mxs_nand_return_dma_descs(nand_info); -} - -/* - * Write data to NAND. - */ -static void mxs_nand_write_buf(struct mtd_info *mtd, const uint8_t *buf, - int length) -{ - struct nand_chip *nand = mtd->priv; - struct mxs_nand_info *nand_info = nand->priv; - struct mxs_dma_desc *d; - uint32_t channel = MXS_DMA_CHANNEL_AHB_APBH_GPMI0 + nand_info->cur_chip; - int ret; - - if (length > NAND_MAX_PAGESIZE) { - printf("MXS NAND: DMA buffer too big\n"); - return; - } - - if (!buf) { - printf("MXS NAND: DMA buffer is NULL\n"); - return; - } - - memcpy(nand_info->data_buf, buf, length); - - /* Compile the DMA descriptor - a descriptor that writes data. */ - d = mxs_nand_get_dma_desc(nand_info); - d->cmd.data = - MXS_DMA_DESC_COMMAND_DMA_READ | MXS_DMA_DESC_IRQ | - MXS_DMA_DESC_DEC_SEM | MXS_DMA_DESC_WAIT4END | - (4 << MXS_DMA_DESC_PIO_WORDS_OFFSET) | - (length << MXS_DMA_DESC_BYTES_OFFSET); - - d->cmd.address = (dma_addr_t)nand_info->data_buf; - - d->cmd.pio_words[0] = - GPMI_CTRL0_COMMAND_MODE_WRITE | - GPMI_CTRL0_WORD_LENGTH | - (nand_info->cur_chip << GPMI_CTRL0_CS_OFFSET) | - GPMI_CTRL0_ADDRESS_NAND_DATA | - length; - - mxs_dma_desc_append(channel, d); - - /* Flush caches */ - mxs_nand_flush_data_buf(nand_info); - - /* Execute the DMA chain. */ - ret = mxs_dma_go(channel); - if (ret) - printf("MXS NAND: DMA write error\n"); - - mxs_nand_return_dma_descs(nand_info); -} - -/* - * Read a single byte from NAND. - */ -static uint8_t mxs_nand_read_byte(struct mtd_info *mtd) -{ - uint8_t buf; - mxs_nand_read_buf(mtd, &buf, 1); - return buf; -} - -/* - * Read a page from NAND. - */ -static int mxs_nand_ecc_read_page(struct mtd_info *mtd, struct nand_chip *nand, - uint8_t *buf, int oob_required, - int page) -{ - struct mxs_nand_info *nand_info = nand->priv; - struct mxs_dma_desc *d; - uint32_t channel = MXS_DMA_CHANNEL_AHB_APBH_GPMI0 + nand_info->cur_chip; - uint32_t corrected = 0, failed = 0; - uint8_t *status; - int i, ret; - - /* Compile the DMA descriptor - wait for ready. */ - d = mxs_nand_get_dma_desc(nand_info); - d->cmd.data = - MXS_DMA_DESC_COMMAND_NO_DMAXFER | MXS_DMA_DESC_CHAIN | - MXS_DMA_DESC_NAND_WAIT_4_READY | MXS_DMA_DESC_WAIT4END | - (1 << MXS_DMA_DESC_PIO_WORDS_OFFSET); - - d->cmd.address = 0; - - d->cmd.pio_words[0] = - GPMI_CTRL0_COMMAND_MODE_WAIT_FOR_READY | - GPMI_CTRL0_WORD_LENGTH | - (nand_info->cur_chip << GPMI_CTRL0_CS_OFFSET) | - GPMI_CTRL0_ADDRESS_NAND_DATA; - - mxs_dma_desc_append(channel, d); - - /* Compile the DMA descriptor - enable the BCH block and read. */ - d = mxs_nand_get_dma_desc(nand_info); - d->cmd.data = - MXS_DMA_DESC_COMMAND_NO_DMAXFER | MXS_DMA_DESC_CHAIN | - MXS_DMA_DESC_WAIT4END | (6 << MXS_DMA_DESC_PIO_WORDS_OFFSET); - - d->cmd.address = 0; - - d->cmd.pio_words[0] = - GPMI_CTRL0_COMMAND_MODE_READ | - GPMI_CTRL0_WORD_LENGTH | - (nand_info->cur_chip << GPMI_CTRL0_CS_OFFSET) | - GPMI_CTRL0_ADDRESS_NAND_DATA | - (mtd->writesize + mtd->oobsize); - d->cmd.pio_words[1] = 0; - d->cmd.pio_words[2] = - GPMI_ECCCTRL_ENABLE_ECC | - GPMI_ECCCTRL_ECC_CMD_DECODE | - GPMI_ECCCTRL_BUFFER_MASK_BCH_PAGE; - d->cmd.pio_words[3] = mtd->writesize + mtd->oobsize; - d->cmd.pio_words[4] = (dma_addr_t)nand_info->data_buf; - d->cmd.pio_words[5] = (dma_addr_t)nand_info->oob_buf; - - mxs_dma_desc_append(channel, d); - - /* Compile the DMA descriptor - disable the BCH block. */ - d = mxs_nand_get_dma_desc(nand_info); - d->cmd.data = - MXS_DMA_DESC_COMMAND_NO_DMAXFER | MXS_DMA_DESC_CHAIN | - MXS_DMA_DESC_NAND_WAIT_4_READY | MXS_DMA_DESC_WAIT4END | - (3 << MXS_DMA_DESC_PIO_WORDS_OFFSET); - - d->cmd.address = 0; - - d->cmd.pio_words[0] = - GPMI_CTRL0_COMMAND_MODE_WAIT_FOR_READY | - GPMI_CTRL0_WORD_LENGTH | - (nand_info->cur_chip << GPMI_CTRL0_CS_OFFSET) | - GPMI_CTRL0_ADDRESS_NAND_DATA | - (mtd->writesize + mtd->oobsize); - d->cmd.pio_words[1] = 0; - d->cmd.pio_words[2] = 0; - - mxs_dma_desc_append(channel, d); - - /* Compile the DMA descriptor - deassert the NAND lock and interrupt. */ - d = mxs_nand_get_dma_desc(nand_info); - d->cmd.data = - MXS_DMA_DESC_COMMAND_NO_DMAXFER | MXS_DMA_DESC_IRQ | - MXS_DMA_DESC_DEC_SEM; - - d->cmd.address = 0; - - mxs_dma_desc_append(channel, d); - - /* Execute the DMA chain. */ - ret = mxs_dma_go(channel); - if (ret) { - printf("MXS NAND: DMA read error\n"); - goto rtn; - } - - ret = mxs_nand_wait_for_bch_complete(); - if (ret) { - printf("MXS NAND: BCH read timeout\n"); - goto rtn; - } - - /* Invalidate caches */ - mxs_nand_inval_data_buf(nand_info); - - /* Read DMA completed, now do the mark swapping. */ - mxs_nand_swap_block_mark(mtd, nand_info->data_buf, nand_info->oob_buf); - - /* Loop over status bytes, accumulating ECC status. */ - status = nand_info->oob_buf + mxs_nand_aux_status_offset(); - for (i = 0; i < mxs_nand_ecc_chunk_cnt(mtd->writesize); i++) { - if (status[i] == 0x00) - continue; - - if (status[i] == 0xff) - continue; - - if (status[i] == 0xfe) { - failed++; - continue; - } - - corrected += status[i]; - } - - /* Propagate ECC status to the owning MTD. */ - mtd->ecc_stats.failed += failed; - mtd->ecc_stats.corrected += corrected; - - /* - * It's time to deliver the OOB bytes. See mxs_nand_ecc_read_oob() for - * details about our policy for delivering the OOB. - * - * We fill the caller's buffer with set bits, and then copy the block - * mark to the caller's buffer. Note that, if block mark swapping was - * necessary, it has already been done, so we can rely on the first - * byte of the auxiliary buffer to contain the block mark. - */ - memset(nand->oob_poi, 0xff, mtd->oobsize); - - nand->oob_poi[0] = nand_info->oob_buf[0]; - - memcpy(buf, nand_info->data_buf, mtd->writesize); - -rtn: - mxs_nand_return_dma_descs(nand_info); - - return ret; -} - -/* - * Write a page to NAND. - */ -static int mxs_nand_ecc_write_page(struct mtd_info *mtd, - struct nand_chip *nand, const uint8_t *buf, - int oob_required) -{ - struct mxs_nand_info *nand_info = nand->priv; - struct mxs_dma_desc *d; - uint32_t channel = MXS_DMA_CHANNEL_AHB_APBH_GPMI0 + nand_info->cur_chip; - int ret; - - memcpy(nand_info->data_buf, buf, mtd->writesize); - memcpy(nand_info->oob_buf, nand->oob_poi, mtd->oobsize); - - /* Handle block mark swapping. */ - mxs_nand_swap_block_mark(mtd, nand_info->data_buf, nand_info->oob_buf); - - /* Compile the DMA descriptor - write data. */ - d = mxs_nand_get_dma_desc(nand_info); - d->cmd.data = - MXS_DMA_DESC_COMMAND_NO_DMAXFER | MXS_DMA_DESC_IRQ | - MXS_DMA_DESC_DEC_SEM | MXS_DMA_DESC_WAIT4END | - (6 << MXS_DMA_DESC_PIO_WORDS_OFFSET); - - d->cmd.address = 0; - - d->cmd.pio_words[0] = - GPMI_CTRL0_COMMAND_MODE_WRITE | - GPMI_CTRL0_WORD_LENGTH | - (nand_info->cur_chip << GPMI_CTRL0_CS_OFFSET) | - GPMI_CTRL0_ADDRESS_NAND_DATA; - d->cmd.pio_words[1] = 0; - d->cmd.pio_words[2] = - GPMI_ECCCTRL_ENABLE_ECC | - GPMI_ECCCTRL_ECC_CMD_ENCODE | - GPMI_ECCCTRL_BUFFER_MASK_BCH_PAGE; - d->cmd.pio_words[3] = (mtd->writesize + mtd->oobsize); - d->cmd.pio_words[4] = (dma_addr_t)nand_info->data_buf; - d->cmd.pio_words[5] = (dma_addr_t)nand_info->oob_buf; - - mxs_dma_desc_append(channel, d); - - /* Flush caches */ - mxs_nand_flush_data_buf(nand_info); - - /* Execute the DMA chain. */ - ret = mxs_dma_go(channel); - if (ret) { - printf("MXS NAND: DMA write error\n"); - goto rtn; - } - - ret = mxs_nand_wait_for_bch_complete(); - if (ret) { - printf("MXS NAND: BCH write timeout\n"); - goto rtn; - } - -rtn: - mxs_nand_return_dma_descs(nand_info); - return 0; -} - -/* - * Read OOB from NAND. - * - * This function is a veneer that replaces the function originally installed by - * the NAND Flash MTD code. - */ -static int mxs_nand_hook_read_oob(struct mtd_info *mtd, loff_t from, - struct mtd_oob_ops *ops) -{ - struct nand_chip *chip = mtd->priv; - struct mxs_nand_info *nand_info = chip->priv; - int ret; - - if (ops->mode == MTD_OPS_RAW) - nand_info->raw_oob_mode = 1; - else - nand_info->raw_oob_mode = 0; - - ret = nand_info->hooked_read_oob(mtd, from, ops); - - nand_info->raw_oob_mode = 0; - - return ret; -} - -/* - * Write OOB to NAND. - * - * This function is a veneer that replaces the function originally installed by - * the NAND Flash MTD code. - */ -static int mxs_nand_hook_write_oob(struct mtd_info *mtd, loff_t to, - struct mtd_oob_ops *ops) -{ - struct nand_chip *chip = mtd->priv; - struct mxs_nand_info *nand_info = chip->priv; - int ret; - - if (ops->mode == MTD_OPS_RAW) - nand_info->raw_oob_mode = 1; - else - nand_info->raw_oob_mode = 0; - - ret = nand_info->hooked_write_oob(mtd, to, ops); - - nand_info->raw_oob_mode = 0; - - return ret; -} - -/* - * Mark a block bad in NAND. - * - * This function is a veneer that replaces the function originally installed by - * the NAND Flash MTD code. - */ -static int mxs_nand_hook_block_markbad(struct mtd_info *mtd, loff_t ofs) -{ - struct nand_chip *chip = mtd->priv; - struct mxs_nand_info *nand_info = chip->priv; - int ret; - - nand_info->marking_block_bad = 1; - - ret = nand_info->hooked_block_markbad(mtd, ofs); - - nand_info->marking_block_bad = 0; - - return ret; -} - -/* - * There are several places in this driver where we have to handle the OOB and - * block marks. This is the function where things are the most complicated, so - * this is where we try to explain it all. All the other places refer back to - * here. - * - * These are the rules, in order of decreasing importance: - * - * 1) Nothing the caller does can be allowed to imperil the block mark, so all - * write operations take measures to protect it. - * - * 2) In read operations, the first byte of the OOB we return must reflect the - * true state of the block mark, no matter where that block mark appears in - * the physical page. - * - * 3) ECC-based read operations return an OOB full of set bits (since we never - * allow ECC-based writes to the OOB, it doesn't matter what ECC-based reads - * return). - * - * 4) "Raw" read operations return a direct view of the physical bytes in the - * page, using the conventional definition of which bytes are data and which - * are OOB. This gives the caller a way to see the actual, physical bytes - * in the page, without the distortions applied by our ECC engine. - * - * What we do for this specific read operation depends on whether we're doing - * "raw" read, or an ECC-based read. - * - * It turns out that knowing whether we want an "ECC-based" or "raw" read is not - * easy. When reading a page, for example, the NAND Flash MTD code calls our - * ecc.read_page or ecc.read_page_raw function. Thus, the fact that MTD wants an - * ECC-based or raw view of the page is implicit in which function it calls - * (there is a similar pair of ECC-based/raw functions for writing). - * - * Since MTD assumes the OOB is not covered by ECC, there is no pair of - * ECC-based/raw functions for reading or or writing the OOB. The fact that the - * caller wants an ECC-based or raw view of the page is not propagated down to - * this driver. - * - * Since our OOB *is* covered by ECC, we need this information. So, we hook the - * ecc.read_oob and ecc.write_oob function pointers in the owning - * struct mtd_info with our own functions. These hook functions set the - * raw_oob_mode field so that, when control finally arrives here, we'll know - * what to do. - */ -static int mxs_nand_ecc_read_oob(struct mtd_info *mtd, struct nand_chip *nand, - int page) -{ - struct mxs_nand_info *nand_info = nand->priv; - - /* - * First, fill in the OOB buffer. If we're doing a raw read, we need to - * get the bytes from the physical page. If we're not doing a raw read, - * we need to fill the buffer with set bits. - */ - if (nand_info->raw_oob_mode) { - /* - * If control arrives here, we're doing a "raw" read. Send the - * command to read the conventional OOB and read it. - */ - nand->cmdfunc(mtd, NAND_CMD_READ0, mtd->writesize, page); - nand->read_buf(mtd, nand->oob_poi, mtd->oobsize); - } else { - /* - * If control arrives here, we're not doing a "raw" read. Fill - * the OOB buffer with set bits and correct the block mark. - */ - memset(nand->oob_poi, 0xff, mtd->oobsize); - - nand->cmdfunc(mtd, NAND_CMD_READ0, mtd->writesize, page); - mxs_nand_read_buf(mtd, nand->oob_poi, 1); - } - - return 0; - -} - -/* - * Write OOB data to NAND. - */ -static int mxs_nand_ecc_write_oob(struct mtd_info *mtd, struct nand_chip *nand, - int page) -{ - struct mxs_nand_info *nand_info = nand->priv; - uint8_t block_mark = 0; - - /* - * There are fundamental incompatibilities between the i.MX GPMI NFC and - * the NAND Flash MTD model that make it essentially impossible to write - * the out-of-band bytes. - * - * We permit *ONE* exception. If the *intent* of writing the OOB is to - * mark a block bad, we can do that. - */ - - if (!nand_info->marking_block_bad) { - printf("NXS NAND: Writing OOB isn't supported\n"); - return -EIO; - } - - /* Write the block mark. */ - nand->cmdfunc(mtd, NAND_CMD_SEQIN, mtd->writesize, page); - nand->write_buf(mtd, &block_mark, 1); - nand->cmdfunc(mtd, NAND_CMD_PAGEPROG, -1, -1); - - /* Check if it worked. */ - if (nand->waitfunc(mtd, nand) & NAND_STATUS_FAIL) - return -EIO; - - return 0; -} - -/* - * Claims all blocks are good. - * - * In principle, this function is *only* called when the NAND Flash MTD system - * isn't allowed to keep an in-memory bad block table, so it is forced to ask - * the driver for bad block information. - * - * In fact, we permit the NAND Flash MTD system to have an in-memory BBT, so - * this function is *only* called when we take it away. - * - * Thus, this function is only called when we want *all* blocks to look good, - * so it *always* return success. - */ -static int mxs_nand_block_bad(struct mtd_info *mtd, loff_t ofs, int getchip) -{ - return 0; -} - -/* - * Nominally, the purpose of this function is to look for or create the bad - * block table. In fact, since the we call this function at the very end of - * the initialization process started by nand_scan(), and we doesn't have a - * more formal mechanism, we "hook" this function to continue init process. - * - * At this point, the physical NAND Flash chips have been identified and - * counted, so we know the physical geometry. This enables us to make some - * important configuration decisions. - * - * The return value of this function propogates directly back to this driver's - * call to nand_scan(). Anything other than zero will cause this driver to - * tear everything down and declare failure. - */ -static int mxs_nand_scan_bbt(struct mtd_info *mtd) -{ - struct nand_chip *nand = mtd->priv; - struct mxs_nand_info *nand_info = nand->priv; - struct mxs_bch_regs *bch_regs = (struct mxs_bch_regs *)MXS_BCH_BASE; - uint32_t tmp; - - /* Configure BCH and set NFC geometry */ - mxs_reset_block(&bch_regs->hw_bch_ctrl_reg); - - /* Configure layout 0 */ - tmp = (mxs_nand_ecc_chunk_cnt(mtd->writesize) - 1) - << BCH_FLASHLAYOUT0_NBLOCKS_OFFSET; - tmp |= MXS_NAND_METADATA_SIZE << BCH_FLASHLAYOUT0_META_SIZE_OFFSET; - tmp |= (mxs_nand_get_ecc_strength(mtd->writesize, mtd->oobsize) >> 1) - << BCH_FLASHLAYOUT0_ECC0_OFFSET; - tmp |= MXS_NAND_CHUNK_DATA_CHUNK_SIZE - >> MXS_NAND_CHUNK_DATA_CHUNK_SIZE_SHIFT; - writel(tmp, &bch_regs->hw_bch_flash0layout0); - - tmp = (mtd->writesize + mtd->oobsize) - << BCH_FLASHLAYOUT1_PAGE_SIZE_OFFSET; - tmp |= (mxs_nand_get_ecc_strength(mtd->writesize, mtd->oobsize) >> 1) - << BCH_FLASHLAYOUT1_ECCN_OFFSET; - tmp |= MXS_NAND_CHUNK_DATA_CHUNK_SIZE - >> MXS_NAND_CHUNK_DATA_CHUNK_SIZE_SHIFT; - writel(tmp, &bch_regs->hw_bch_flash0layout1); - - /* Set *all* chip selects to use layout 0 */ - writel(0, &bch_regs->hw_bch_layoutselect); - - /* Enable BCH complete interrupt */ - writel(BCH_CTRL_COMPLETE_IRQ_EN, &bch_regs->hw_bch_ctrl_set); - - /* Hook some operations at the MTD level. */ - if (mtd->_read_oob != mxs_nand_hook_read_oob) { - nand_info->hooked_read_oob = mtd->_read_oob; - mtd->_read_oob = mxs_nand_hook_read_oob; - } - - if (mtd->_write_oob != mxs_nand_hook_write_oob) { - nand_info->hooked_write_oob = mtd->_write_oob; - mtd->_write_oob = mxs_nand_hook_write_oob; - } - - if (mtd->_block_markbad != mxs_nand_hook_block_markbad) { - nand_info->hooked_block_markbad = mtd->_block_markbad; - mtd->_block_markbad = mxs_nand_hook_block_markbad; - } - - /* We use the reference implementation for bad block management. */ - return nand_default_bbt(mtd); -} - -/* - * Allocate DMA buffers - */ -int mxs_nand_alloc_buffers(struct mxs_nand_info *nand_info) -{ - uint8_t *buf; - const int size = NAND_MAX_PAGESIZE + NAND_MAX_OOBSIZE; - - nand_info->data_buf_size = roundup(size, MXS_DMA_ALIGNMENT); - - /* DMA buffers */ - buf = memalign(MXS_DMA_ALIGNMENT, nand_info->data_buf_size); - if (!buf) { - printf("MXS NAND: Error allocating DMA buffers\n"); - return -ENOMEM; - } - - memset(buf, 0, nand_info->data_buf_size); - - nand_info->data_buf = buf; - nand_info->oob_buf = buf + NAND_MAX_PAGESIZE; - /* Command buffers */ - nand_info->cmd_buf = memalign(MXS_DMA_ALIGNMENT, - MXS_NAND_COMMAND_BUFFER_SIZE); - if (!nand_info->cmd_buf) { - free(buf); - printf("MXS NAND: Error allocating command buffers\n"); - return -ENOMEM; - } - memset(nand_info->cmd_buf, 0, MXS_NAND_COMMAND_BUFFER_SIZE); - nand_info->cmd_queue_len = 0; - - return 0; -} - -/* - * Initializes the NFC hardware. - */ -int mxs_nand_init(struct mxs_nand_info *info) -{ - struct mxs_gpmi_regs *gpmi_regs = - (struct mxs_gpmi_regs *)MXS_GPMI_BASE; - struct mxs_bch_regs *bch_regs = - (struct mxs_bch_regs *)MXS_BCH_BASE; - int i = 0, j; - - info->desc = malloc(sizeof(struct mxs_dma_desc *) * - MXS_NAND_DMA_DESCRIPTOR_COUNT); - if (!info->desc) - goto err1; - - /* Allocate the DMA descriptors. */ - for (i = 0; i < MXS_NAND_DMA_DESCRIPTOR_COUNT; i++) { - info->desc[i] = mxs_dma_desc_alloc(); - if (!info->desc[i]) - goto err2; - } - - /* Init the DMA controller. */ - for (j = MXS_DMA_CHANNEL_AHB_APBH_GPMI0; - j <= MXS_DMA_CHANNEL_AHB_APBH_GPMI7; j++) { - if (mxs_dma_init_channel(j)) - goto err3; - } - - /* Reset the GPMI block. */ - mxs_reset_block(&gpmi_regs->hw_gpmi_ctrl0_reg); - mxs_reset_block(&bch_regs->hw_bch_ctrl_reg); - - /* - * Choose NAND mode, set IRQ polarity, disable write protection and - * select BCH ECC. - */ - clrsetbits_le32(&gpmi_regs->hw_gpmi_ctrl1, - GPMI_CTRL1_GPMI_MODE, - GPMI_CTRL1_ATA_IRQRDY_POLARITY | GPMI_CTRL1_DEV_RESET | - GPMI_CTRL1_BCH_MODE); - - return 0; - -err3: - for (--j; j >= 0; j--) - mxs_dma_release(j); -err2: - free(info->desc); -err1: - for (--i; i >= 0; i--) - mxs_dma_desc_free(info->desc[i]); - printf("MXS NAND: Unable to allocate DMA descriptors\n"); - return -ENOMEM; -} - -/*! - * This function is called during the driver binding process. - * - * @param pdev the device structure used to store device specific - * information that is used by the suspend, resume and - * remove functions - * - * @return The function always returns 0. - */ -int board_nand_init(struct nand_chip *nand) -{ - struct mxs_nand_info *nand_info; - int err; - - nand_info = malloc(sizeof(struct mxs_nand_info)); - if (!nand_info) { - printf("MXS NAND: Failed to allocate private data\n"); - return -ENOMEM; - } - memset(nand_info, 0, sizeof(struct mxs_nand_info)); - - err = mxs_nand_alloc_buffers(nand_info); - if (err) - goto err1; - - err = mxs_nand_init(nand_info); - if (err) - goto err2; - - memset(&fake_ecc_layout, 0, sizeof(fake_ecc_layout)); - - nand->priv = nand_info; - nand->options |= NAND_NO_SUBPAGE_WRITE; - - nand->cmd_ctrl = mxs_nand_cmd_ctrl; - - nand->dev_ready = mxs_nand_device_ready; - nand->select_chip = mxs_nand_select_chip; - nand->block_bad = mxs_nand_block_bad; - nand->scan_bbt = mxs_nand_scan_bbt; - - nand->read_byte = mxs_nand_read_byte; - - nand->read_buf = mxs_nand_read_buf; - nand->write_buf = mxs_nand_write_buf; - - nand->ecc.read_page = mxs_nand_ecc_read_page; - nand->ecc.write_page = mxs_nand_ecc_write_page; - nand->ecc.read_oob = mxs_nand_ecc_read_oob; - nand->ecc.write_oob = mxs_nand_ecc_write_oob; - - nand->ecc.layout = &fake_ecc_layout; - nand->ecc.mode = NAND_ECC_HW; - nand->ecc.bytes = 9; - nand->ecc.size = 512; - nand->ecc.strength = 8; - - return 0; - -err2: - free(nand_info->data_buf); - free(nand_info->cmd_buf); -err1: - free(nand_info); - return err; -} diff --git a/qemu/roms/u-boot/drivers/mtd/nand/nand.c b/qemu/roms/u-boot/drivers/mtd/nand/nand.c deleted file mode 100644 index 4cf4c1c70..000000000 --- a/qemu/roms/u-boot/drivers/mtd/nand/nand.c +++ /dev/null @@ -1,120 +0,0 @@ -/* - * (C) Copyright 2005 - * 2N Telekomunikace, a.s. <www.2n.cz> - * Ladislav Michl <michl@2n.cz> - * - * See file CREDITS for list of people who contributed to this - * project. - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * version 2 as published by the Free Software Foundation. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, - * MA 02111-1307 USA - */ - -#include <common.h> -#include <nand.h> -#include <errno.h> - -#ifndef CONFIG_SYS_NAND_BASE_LIST -#define CONFIG_SYS_NAND_BASE_LIST { CONFIG_SYS_NAND_BASE } -#endif - -DECLARE_GLOBAL_DATA_PTR; - -int nand_curr_device = -1; - - -nand_info_t nand_info[CONFIG_SYS_MAX_NAND_DEVICE]; - -#ifndef CONFIG_SYS_NAND_SELF_INIT -static struct nand_chip nand_chip[CONFIG_SYS_MAX_NAND_DEVICE]; -static ulong base_address[CONFIG_SYS_MAX_NAND_DEVICE] = CONFIG_SYS_NAND_BASE_LIST; -#endif - -static char dev_name[CONFIG_SYS_MAX_NAND_DEVICE][8]; - -static unsigned long total_nand_size; /* in kiB */ - -/* Register an initialized NAND mtd device with the U-Boot NAND command. */ -int nand_register(int devnum) -{ - struct mtd_info *mtd; - - if (devnum >= CONFIG_SYS_MAX_NAND_DEVICE) - return -EINVAL; - - mtd = &nand_info[devnum]; - - sprintf(dev_name[devnum], "nand%d", devnum); - mtd->name = dev_name[devnum]; - -#ifdef CONFIG_MTD_DEVICE - /* - * Add MTD device so that we can reference it later - * via the mtdcore infrastructure (e.g. ubi). - */ - add_mtd_device(mtd); -#endif - - total_nand_size += mtd->size / 1024; - - if (nand_curr_device == -1) - nand_curr_device = devnum; - - return 0; -} - -#ifndef CONFIG_SYS_NAND_SELF_INIT -static void nand_init_chip(int i) -{ - struct mtd_info *mtd = &nand_info[i]; - struct nand_chip *nand = &nand_chip[i]; - ulong base_addr = base_address[i]; - int maxchips = CONFIG_SYS_NAND_MAX_CHIPS; - - if (maxchips < 1) - maxchips = 1; - - mtd->priv = nand; - nand->IO_ADDR_R = nand->IO_ADDR_W = (void __iomem *)base_addr; - - if (board_nand_init(nand)) - return; - - if (nand_scan(mtd, maxchips)) - return; - - nand_register(i); -} -#endif - -void nand_init(void) -{ -#ifdef CONFIG_SYS_NAND_SELF_INIT - board_nand_init(); -#else - int i; - - for (i = 0; i < CONFIG_SYS_MAX_NAND_DEVICE; i++) - nand_init_chip(i); -#endif - - printf("%lu MiB\n", total_nand_size / 1024); - -#ifdef CONFIG_SYS_NAND_SELECT_DEVICE - /* - * Select the chip in the board/cpu specific driver - */ - board_nand_select_device(nand_info[nand_curr_device].priv, nand_curr_device); -#endif -} diff --git a/qemu/roms/u-boot/drivers/mtd/nand/nand_base.c b/qemu/roms/u-boot/drivers/mtd/nand/nand_base.c deleted file mode 100644 index 1ce55fde8..000000000 --- a/qemu/roms/u-boot/drivers/mtd/nand/nand_base.c +++ /dev/null @@ -1,3438 +0,0 @@ -/* - * drivers/mtd/nand.c - * - * Overview: - * This is the generic MTD driver for NAND flash devices. It should be - * capable of working with almost all NAND chips currently available. - * Basic support for AG-AND chips is provided. - * - * Additional technical information is available on - * http://www.linux-mtd.infradead.org/doc/nand.html - * - * Copyright (C) 2000 Steven J. Hill (sjhill@realitydiluted.com) - * 2002-2006 Thomas Gleixner (tglx@linutronix.de) - * - * Credits: - * David Woodhouse for adding multichip support - * - * Aleph One Ltd. and Toby Churchill Ltd. for supporting the - * rework for 2K page size chips - * - * TODO: - * Enable cached programming for 2k page size chips - * Check, if mtd->ecctype should be set to MTD_ECC_HW - * if we have HW ECC support. - * The AG-AND chips have nice features for speed improvement, - * which are not supported yet. Read / program 4 pages in one go. - * BBT table is not serialized, has to be fixed - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. - * - */ - -#include <common.h> - -#define ENOTSUPP 524 /* Operation is not supported */ - -#include <malloc.h> -#include <watchdog.h> -#include <linux/err.h> -#include <linux/compat.h> -#include <linux/mtd/mtd.h> -#include <linux/mtd/nand.h> -#include <linux/mtd/nand_ecc.h> -#include <linux/mtd/nand_bch.h> - -#ifdef CONFIG_MTD_PARTITIONS -#include <linux/mtd/partitions.h> -#endif - -#include <asm/io.h> -#include <asm/errno.h> - -/* - * CONFIG_SYS_NAND_RESET_CNT is used as a timeout mechanism when resetting - * a flash. NAND flash is initialized prior to interrupts so standard timers - * can't be used. CONFIG_SYS_NAND_RESET_CNT should be set to a value - * which is greater than (max NAND reset time / NAND status read time). - * A conservative default of 200000 (500 us / 25 ns) is used as a default. - */ -#ifndef CONFIG_SYS_NAND_RESET_CNT -#define CONFIG_SYS_NAND_RESET_CNT 200000 -#endif - -/* Define default oob placement schemes for large and small page devices */ -static struct nand_ecclayout nand_oob_8 = { - .eccbytes = 3, - .eccpos = {0, 1, 2}, - .oobfree = { - {.offset = 3, - .length = 2}, - {.offset = 6, - .length = 2} } -}; - -static struct nand_ecclayout nand_oob_16 = { - .eccbytes = 6, - .eccpos = {0, 1, 2, 3, 6, 7}, - .oobfree = { - {.offset = 8, - . length = 8} } -}; - -static struct nand_ecclayout nand_oob_64 = { - .eccbytes = 24, - .eccpos = { - 40, 41, 42, 43, 44, 45, 46, 47, - 48, 49, 50, 51, 52, 53, 54, 55, - 56, 57, 58, 59, 60, 61, 62, 63}, - .oobfree = { - {.offset = 2, - .length = 38} } -}; - -static struct nand_ecclayout nand_oob_128 = { - .eccbytes = 48, - .eccpos = { - 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}, - .oobfree = { - {.offset = 2, - .length = 78} } -}; - -static int nand_get_device(struct nand_chip *chip, struct mtd_info *mtd, - int new_state); - -static int nand_do_write_oob(struct mtd_info *mtd, loff_t to, - struct mtd_oob_ops *ops); - -static int nand_wait(struct mtd_info *mtd, struct nand_chip *this); - -static int check_offs_len(struct mtd_info *mtd, - loff_t ofs, uint64_t len) -{ - struct nand_chip *chip = mtd->priv; - int ret = 0; - - /* Start address must align on block boundary */ - if (ofs & ((1 << chip->phys_erase_shift) - 1)) { - MTDDEBUG(MTD_DEBUG_LEVEL0, "%s: Unaligned address\n", __func__); - ret = -EINVAL; - } - - /* Length must align on block boundary */ - if (len & ((1 << chip->phys_erase_shift) - 1)) { - MTDDEBUG(MTD_DEBUG_LEVEL0, "%s: Length not block aligned\n", - __func__); - ret = -EINVAL; - } - - return ret; -} - -/** - * nand_release_device - [GENERIC] release chip - * @mtd: MTD device structure - * - * Deselect, release chip lock and wake up anyone waiting on the device. - */ -static void nand_release_device(struct mtd_info *mtd) -{ - struct nand_chip *chip = mtd->priv; - - /* De-select the NAND device */ - chip->select_chip(mtd, -1); -} - -/** - * nand_read_byte - [DEFAULT] read one byte from the chip - * @mtd: MTD device structure - * - * Default read function for 8bit buswidth. - */ -uint8_t nand_read_byte(struct mtd_info *mtd) -{ - struct nand_chip *chip = mtd->priv; - return readb(chip->IO_ADDR_R); -} - -/** - * nand_read_byte16 - [DEFAULT] read one byte endianess aware from the chip - * nand_read_byte16 - [DEFAULT] read one byte endianness aware from the chip - * @mtd: MTD device structure - * - * Default read function for 16bit buswidth with endianness conversion. - * - */ -static uint8_t nand_read_byte16(struct mtd_info *mtd) -{ - struct nand_chip *chip = mtd->priv; - return (uint8_t) cpu_to_le16(readw(chip->IO_ADDR_R)); -} - -/** - * nand_read_word - [DEFAULT] read one word from the chip - * @mtd: MTD device structure - * - * Default read function for 16bit buswidth without endianness conversion. - */ -static u16 nand_read_word(struct mtd_info *mtd) -{ - struct nand_chip *chip = mtd->priv; - return readw(chip->IO_ADDR_R); -} - -/** - * nand_select_chip - [DEFAULT] control CE line - * @mtd: MTD device structure - * @chipnr: chipnumber to select, -1 for deselect - * - * Default select function for 1 chip devices. - */ -static void nand_select_chip(struct mtd_info *mtd, int chipnr) -{ - struct nand_chip *chip = mtd->priv; - - switch (chipnr) { - case -1: - chip->cmd_ctrl(mtd, NAND_CMD_NONE, 0 | NAND_CTRL_CHANGE); - break; - case 0: - break; - - default: - BUG(); - } -} - -/** - * nand_write_buf - [DEFAULT] write buffer to chip - * @mtd: MTD device structure - * @buf: data buffer - * @len: number of bytes to write - * - * Default write function for 8bit buswidth. - */ -void nand_write_buf(struct mtd_info *mtd, const uint8_t *buf, int len) -{ - int i; - struct nand_chip *chip = mtd->priv; - - for (i = 0; i < len; i++) - writeb(buf[i], chip->IO_ADDR_W); -} - -/** - * nand_read_buf - [DEFAULT] read chip data into buffer - * @mtd: MTD device structure - * @buf: buffer to store date - * @len: number of bytes to read - * - * Default read function for 8bit buswidth. - */ -void nand_read_buf(struct mtd_info *mtd, uint8_t *buf, int len) -{ - int i; - struct nand_chip *chip = mtd->priv; - - for (i = 0; i < len; i++) - buf[i] = readb(chip->IO_ADDR_R); -} - -/** - * nand_verify_buf - [DEFAULT] Verify chip data against buffer - * @mtd: MTD device structure - * @buf: buffer containing the data to compare - * @len: number of bytes to compare - * - * Default verify function for 8bit buswidth. - */ -static int nand_verify_buf(struct mtd_info *mtd, const uint8_t *buf, int len) -{ - int i; - struct nand_chip *chip = mtd->priv; - - for (i = 0; i < len; i++) - if (buf[i] != readb(chip->IO_ADDR_R)) - return -EFAULT; - return 0; -} - -/** - * nand_write_buf16 - [DEFAULT] write buffer to chip - * @mtd: MTD device structure - * @buf: data buffer - * @len: number of bytes to write - * - * Default write function for 16bit buswidth. - */ -void nand_write_buf16(struct mtd_info *mtd, const uint8_t *buf, int len) -{ - int i; - struct nand_chip *chip = mtd->priv; - u16 *p = (u16 *) buf; - len >>= 1; - - for (i = 0; i < len; i++) - writew(p[i], chip->IO_ADDR_W); - -} - -/** - * nand_read_buf16 - [DEFAULT] read chip data into buffer - * @mtd: MTD device structure - * @buf: buffer to store date - * @len: number of bytes to read - * - * Default read function for 16bit buswidth. - */ -void nand_read_buf16(struct mtd_info *mtd, uint8_t *buf, int len) -{ - int i; - struct nand_chip *chip = mtd->priv; - u16 *p = (u16 *) buf; - len >>= 1; - - for (i = 0; i < len; i++) - p[i] = readw(chip->IO_ADDR_R); -} - -/** - * nand_verify_buf16 - [DEFAULT] Verify chip data against buffer - * @mtd: MTD device structure - * @buf: buffer containing the data to compare - * @len: number of bytes to compare - * - * Default verify function for 16bit buswidth. - */ -static int nand_verify_buf16(struct mtd_info *mtd, const uint8_t *buf, int len) -{ - int i; - struct nand_chip *chip = mtd->priv; - u16 *p = (u16 *) buf; - len >>= 1; - - for (i = 0; i < len; i++) - if (p[i] != readw(chip->IO_ADDR_R)) - return -EFAULT; - - return 0; -} - -/** - * nand_block_bad - [DEFAULT] Read bad block marker from the chip - * @mtd: MTD device structure - * @ofs: offset from device start - * @getchip: 0, if the chip is already selected - * - * Check, if the block is bad. - */ -static int nand_block_bad(struct mtd_info *mtd, loff_t ofs, int getchip) -{ - int page, chipnr, res = 0, i = 0; - struct nand_chip *chip = mtd->priv; - u16 bad; - - if (chip->bbt_options & NAND_BBT_SCANLASTPAGE) - ofs += mtd->erasesize - mtd->writesize; - - page = (int)(ofs >> chip->page_shift) & chip->pagemask; - - if (getchip) { - chipnr = (int)(ofs >> chip->chip_shift); - - nand_get_device(chip, mtd, FL_READING); - - /* Select the NAND device */ - chip->select_chip(mtd, chipnr); - } - - do { - if (chip->options & NAND_BUSWIDTH_16) { - chip->cmdfunc(mtd, NAND_CMD_READOOB, - chip->badblockpos & 0xFE, page); - bad = cpu_to_le16(chip->read_word(mtd)); - if (chip->badblockpos & 0x1) - bad >>= 8; - else - bad &= 0xFF; - } else { - chip->cmdfunc(mtd, NAND_CMD_READOOB, chip->badblockpos, - page); - bad = chip->read_byte(mtd); - } - - if (likely(chip->badblockbits == 8)) - res = bad != 0xFF; - else - res = hweight8(bad) < chip->badblockbits; - ofs += mtd->writesize; - page = (int)(ofs >> chip->page_shift) & chip->pagemask; - i++; - } while (!res && i < 2 && (chip->bbt_options & NAND_BBT_SCAN2NDPAGE)); - - if (getchip) - nand_release_device(mtd); - - return res; -} - -/** - * nand_default_block_markbad - [DEFAULT] mark a block bad - * @mtd: MTD device structure - * @ofs: offset from device start - * - * This is the default implementation, which can be overridden by a hardware - * specific driver. We try operations in the following order, according to our - * bbt_options (NAND_BBT_NO_OOB_BBM and NAND_BBT_USE_FLASH): - * (1) erase the affected block, to allow OOB marker to be written cleanly - * (2) update in-memory BBT - * (3) write bad block marker to OOB area of affected block - * (4) update flash-based BBT - * Note that we retain the first error encountered in (3) or (4), finish the - * procedures, and dump the error in the end. -*/ -static int nand_default_block_markbad(struct mtd_info *mtd, loff_t ofs) -{ - struct nand_chip *chip = mtd->priv; - uint8_t buf[2] = { 0, 0 }; - int block, res, ret = 0, i = 0; - int write_oob = !(chip->bbt_options & NAND_BBT_NO_OOB_BBM); - - if (write_oob) { - struct erase_info einfo; - - /* Attempt erase before marking OOB */ - memset(&einfo, 0, sizeof(einfo)); - einfo.mtd = mtd; - einfo.addr = ofs; - einfo.len = 1 << chip->phys_erase_shift; - nand_erase_nand(mtd, &einfo, 0); - } - - /* Get block number */ - block = (int)(ofs >> chip->bbt_erase_shift); - /* Mark block bad in memory-based BBT */ - if (chip->bbt) - chip->bbt[block >> 2] |= 0x01 << ((block & 0x03) << 1); - - /* Write bad block marker to OOB */ - if (write_oob) { - struct mtd_oob_ops ops; - loff_t wr_ofs = ofs; - - nand_get_device(chip, mtd, FL_WRITING); - - ops.datbuf = NULL; - ops.oobbuf = buf; - ops.ooboffs = chip->badblockpos; - if (chip->options & NAND_BUSWIDTH_16) { - ops.ooboffs &= ~0x01; - ops.len = ops.ooblen = 2; - } else { - ops.len = ops.ooblen = 1; - } - ops.mode = MTD_OPS_PLACE_OOB; - - /* Write to first/last page(s) if necessary */ - if (chip->bbt_options & NAND_BBT_SCANLASTPAGE) - wr_ofs += mtd->erasesize - mtd->writesize; - do { - res = nand_do_write_oob(mtd, wr_ofs, &ops); - if (!ret) - ret = res; - - i++; - wr_ofs += mtd->writesize; - } while ((chip->bbt_options & NAND_BBT_SCAN2NDPAGE) && i < 2); - - nand_release_device(mtd); - } - - /* Update flash-based bad block table */ - if (chip->bbt_options & NAND_BBT_USE_FLASH) { - res = nand_update_bbt(mtd, ofs); - if (!ret) - ret = res; - } - - if (!ret) - mtd->ecc_stats.badblocks++; - - return ret; -} - -/** - * nand_check_wp - [GENERIC] check if the chip is write protected - * @mtd: MTD device structure - * - * Check, if the device is write protected. The function expects, that the - * device is already selected. - */ -static int nand_check_wp(struct mtd_info *mtd) -{ - struct nand_chip *chip = mtd->priv; - - /* Broken xD cards report WP despite being writable */ - if (chip->options & NAND_BROKEN_XD) - return 0; - - /* Check the WP bit */ - chip->cmdfunc(mtd, NAND_CMD_STATUS, -1, -1); - return (chip->read_byte(mtd) & NAND_STATUS_WP) ? 0 : 1; -} - -/** - * nand_block_checkbad - [GENERIC] Check if a block is marked bad - * @mtd: MTD device structure - * @ofs: offset from device start - * @getchip: 0, if the chip is already selected - * @allowbbt: 1, if its allowed to access the bbt area - * - * Check, if the block is bad. Either by reading the bad block table or - * calling of the scan function. - */ -static int nand_block_checkbad(struct mtd_info *mtd, loff_t ofs, int getchip, - int allowbbt) -{ - struct nand_chip *chip = mtd->priv; - - if (!(chip->options & NAND_BBT_SCANNED)) { - chip->options |= NAND_BBT_SCANNED; - chip->scan_bbt(mtd); - } - - if (!chip->bbt) - return chip->block_bad(mtd, ofs, getchip); - - /* Return info from the table */ - return nand_isbad_bbt(mtd, ofs, allowbbt); -} - -/* Wait for the ready pin, after a command. The timeout is caught later. */ -void nand_wait_ready(struct mtd_info *mtd) -{ - struct nand_chip *chip = mtd->priv; - u32 timeo = (CONFIG_SYS_HZ * 20) / 1000; - u32 time_start; - - time_start = get_timer(0); - - /* Wait until command is processed or timeout occurs */ - while (get_timer(time_start) < timeo) { - if (chip->dev_ready) - if (chip->dev_ready(mtd)) - break; - } -} - -/** - * nand_command - [DEFAULT] Send command to NAND device - * @mtd: MTD device structure - * @command: the command to be sent - * @column: the column address for this command, -1 if none - * @page_addr: the page address for this command, -1 if none - * - * Send command to NAND device. This function is used for small page devices - * (256/512 Bytes per page). - */ -static void nand_command(struct mtd_info *mtd, unsigned int command, - int column, int page_addr) -{ - register struct nand_chip *chip = mtd->priv; - int ctrl = NAND_CTRL_CLE | NAND_CTRL_CHANGE; - uint32_t rst_sts_cnt = CONFIG_SYS_NAND_RESET_CNT; - - /* Write out the command to the device */ - if (command == NAND_CMD_SEQIN) { - int readcmd; - - if (column >= mtd->writesize) { - /* OOB area */ - column -= mtd->writesize; - readcmd = NAND_CMD_READOOB; - } else if (column < 256) { - /* First 256 bytes --> READ0 */ - readcmd = NAND_CMD_READ0; - } else { - column -= 256; - readcmd = NAND_CMD_READ1; - } - chip->cmd_ctrl(mtd, readcmd, ctrl); - ctrl &= ~NAND_CTRL_CHANGE; - } - chip->cmd_ctrl(mtd, command, ctrl); - - /* Address cycle, when necessary */ - ctrl = NAND_CTRL_ALE | NAND_CTRL_CHANGE; - /* Serially input address */ - if (column != -1) { - /* Adjust columns for 16 bit buswidth */ - if (chip->options & NAND_BUSWIDTH_16) - column >>= 1; - chip->cmd_ctrl(mtd, column, ctrl); - ctrl &= ~NAND_CTRL_CHANGE; - } - if (page_addr != -1) { - chip->cmd_ctrl(mtd, page_addr, ctrl); - ctrl &= ~NAND_CTRL_CHANGE; - chip->cmd_ctrl(mtd, page_addr >> 8, ctrl); - /* One more address cycle for devices > 32MiB */ - if (chip->chipsize > (32 << 20)) - chip->cmd_ctrl(mtd, page_addr >> 16, ctrl); - } - chip->cmd_ctrl(mtd, NAND_CMD_NONE, NAND_NCE | NAND_CTRL_CHANGE); - - /* - * Program and erase have their own busy handlers status and sequential - * in needs no delay - */ - switch (command) { - - case NAND_CMD_PAGEPROG: - case NAND_CMD_ERASE1: - case NAND_CMD_ERASE2: - case NAND_CMD_SEQIN: - case NAND_CMD_STATUS: - return; - - case NAND_CMD_RESET: - if (chip->dev_ready) - break; - udelay(chip->chip_delay); - chip->cmd_ctrl(mtd, NAND_CMD_STATUS, - NAND_CTRL_CLE | NAND_CTRL_CHANGE); - chip->cmd_ctrl(mtd, - NAND_CMD_NONE, NAND_NCE | NAND_CTRL_CHANGE); - while (!(chip->read_byte(mtd) & NAND_STATUS_READY) && - (rst_sts_cnt--)); - return; - - /* This applies to read commands */ - default: - /* - * If we don't have access to the busy pin, we apply the given - * command delay - */ - if (!chip->dev_ready) { - udelay(chip->chip_delay); - return; - } - } - /* - * Apply this short delay always to ensure that we do wait tWB in - * any case on any machine. - */ - ndelay(100); - - nand_wait_ready(mtd); -} - -/** - * nand_command_lp - [DEFAULT] Send command to NAND large page device - * @mtd: MTD device structure - * @command: the command to be sent - * @column: the column address for this command, -1 if none - * @page_addr: the page address for this command, -1 if none - * - * Send command to NAND device. This is the version for the new large page - * devices. We don't have the separate regions as we have in the small page - * devices. We must emulate NAND_CMD_READOOB to keep the code compatible. - */ -static void nand_command_lp(struct mtd_info *mtd, unsigned int command, - int column, int page_addr) -{ - register struct nand_chip *chip = mtd->priv; - uint32_t rst_sts_cnt = CONFIG_SYS_NAND_RESET_CNT; - - /* Emulate NAND_CMD_READOOB */ - if (command == NAND_CMD_READOOB) { - column += mtd->writesize; - command = NAND_CMD_READ0; - } - - /* Command latch cycle */ - chip->cmd_ctrl(mtd, command & 0xff, - NAND_NCE | NAND_CLE | NAND_CTRL_CHANGE); - - if (column != -1 || page_addr != -1) { - int ctrl = NAND_CTRL_CHANGE | NAND_NCE | NAND_ALE; - - /* Serially input address */ - if (column != -1) { - /* Adjust columns for 16 bit buswidth */ - if (chip->options & NAND_BUSWIDTH_16) - column >>= 1; - chip->cmd_ctrl(mtd, column, ctrl); - ctrl &= ~NAND_CTRL_CHANGE; - chip->cmd_ctrl(mtd, column >> 8, ctrl); - } - if (page_addr != -1) { - chip->cmd_ctrl(mtd, page_addr, ctrl); - chip->cmd_ctrl(mtd, page_addr >> 8, - NAND_NCE | NAND_ALE); - /* One more address cycle for devices > 128MiB */ - if (chip->chipsize > (128 << 20)) - chip->cmd_ctrl(mtd, page_addr >> 16, - NAND_NCE | NAND_ALE); - } - } - chip->cmd_ctrl(mtd, NAND_CMD_NONE, NAND_NCE | NAND_CTRL_CHANGE); - - /* - * Program and erase have their own busy handlers status, sequential - * in, and deplete1 need no delay. - */ - switch (command) { - - case NAND_CMD_CACHEDPROG: - case NAND_CMD_PAGEPROG: - case NAND_CMD_ERASE1: - case NAND_CMD_ERASE2: - case NAND_CMD_SEQIN: - case NAND_CMD_RNDIN: - case NAND_CMD_STATUS: - case NAND_CMD_DEPLETE1: - return; - - case NAND_CMD_STATUS_ERROR: - case NAND_CMD_STATUS_ERROR0: - case NAND_CMD_STATUS_ERROR1: - case NAND_CMD_STATUS_ERROR2: - case NAND_CMD_STATUS_ERROR3: - /* Read error status commands require only a short delay */ - udelay(chip->chip_delay); - return; - - case NAND_CMD_RESET: - if (chip->dev_ready) - break; - udelay(chip->chip_delay); - chip->cmd_ctrl(mtd, NAND_CMD_STATUS, - NAND_NCE | NAND_CLE | NAND_CTRL_CHANGE); - chip->cmd_ctrl(mtd, NAND_CMD_NONE, - NAND_NCE | NAND_CTRL_CHANGE); - while (!(chip->read_byte(mtd) & NAND_STATUS_READY) && - (rst_sts_cnt--)); - return; - - case NAND_CMD_RNDOUT: - /* No ready / busy check necessary */ - chip->cmd_ctrl(mtd, NAND_CMD_RNDOUTSTART, - NAND_NCE | NAND_CLE | NAND_CTRL_CHANGE); - chip->cmd_ctrl(mtd, NAND_CMD_NONE, - NAND_NCE | NAND_CTRL_CHANGE); - return; - - case NAND_CMD_READ0: - chip->cmd_ctrl(mtd, NAND_CMD_READSTART, - NAND_NCE | NAND_CLE | NAND_CTRL_CHANGE); - chip->cmd_ctrl(mtd, NAND_CMD_NONE, - NAND_NCE | NAND_CTRL_CHANGE); - - /* This applies to read commands */ - default: - /* - * If we don't have access to the busy pin, we apply the given - * command delay. - */ - if (!chip->dev_ready) { - udelay(chip->chip_delay); - return; - } - } - - /* - * Apply this short delay always to ensure that we do wait tWB in - * any case on any machine. - */ - ndelay(100); - - nand_wait_ready(mtd); -} - -/** - * nand_get_device - [GENERIC] Get chip for selected access - * @chip: the nand chip descriptor - * @mtd: MTD device structure - * @new_state: the state which is requested - * - * Get the device and lock it for exclusive access - */ -static int -nand_get_device(struct nand_chip *chip, struct mtd_info *mtd, int new_state) -{ - chip->state = new_state; - return 0; -} - -/** - * nand_wait - [DEFAULT] wait until the command is done - * @mtd: MTD device structure - * @chip: NAND chip structure - * - * Wait for command done. This applies to erase and program only. Erase can - * take up to 400ms and program up to 20ms according to general NAND and - * SmartMedia specs. - */ -static int nand_wait(struct mtd_info *mtd, struct nand_chip *chip) -{ - unsigned long timeo; - int state = chip->state; - u32 time_start; - - if (state == FL_ERASING) - timeo = (CONFIG_SYS_HZ * 400) / 1000; - else - timeo = (CONFIG_SYS_HZ * 20) / 1000; - - if ((state == FL_ERASING) && (chip->options & NAND_IS_AND)) - chip->cmdfunc(mtd, NAND_CMD_STATUS_MULTI, -1, -1); - else - chip->cmdfunc(mtd, NAND_CMD_STATUS, -1, -1); - - time_start = get_timer(0); - - while (1) { - if (get_timer(time_start) > timeo) { - printf("Timeout!"); - return 0x01; - } - - if (chip->dev_ready) { - if (chip->dev_ready(mtd)) - break; - } else { - if (chip->read_byte(mtd) & NAND_STATUS_READY) - break; - } - } -#ifdef PPCHAMELON_NAND_TIMER_HACK - time_start = get_timer(0); - while (get_timer(time_start) < 10) - ; -#endif /* PPCHAMELON_NAND_TIMER_HACK */ - - return (int)chip->read_byte(mtd); -} - -/** - * nand_read_page_raw - [INTERN] read raw page data without ecc - * @mtd: mtd info structure - * @chip: nand chip info structure - * @buf: buffer to store read data - * @oob_required: caller requires OOB data read to chip->oob_poi - * @page: page number to read - * - * Not for syndrome calculating ECC controllers, which use a special oob layout. - */ -static int nand_read_page_raw(struct mtd_info *mtd, struct nand_chip *chip, - uint8_t *buf, int oob_required, int page) -{ - chip->read_buf(mtd, buf, mtd->writesize); - if (oob_required) - chip->read_buf(mtd, chip->oob_poi, mtd->oobsize); - return 0; -} - -/** - * nand_read_page_raw_syndrome - [INTERN] read raw page data without ecc - * @mtd: mtd info structure - * @chip: nand chip info structure - * @buf: buffer to store read data - * @oob_required: caller requires OOB data read to chip->oob_poi - * @page: page number to read - * - * We need a special oob layout and handling even when OOB isn't used. - */ -static int nand_read_page_raw_syndrome(struct mtd_info *mtd, - struct nand_chip *chip, uint8_t *buf, - int oob_required, int page) -{ - int eccsize = chip->ecc.size; - int eccbytes = chip->ecc.bytes; - uint8_t *oob = chip->oob_poi; - int steps, size; - - for (steps = chip->ecc.steps; steps > 0; steps--) { - chip->read_buf(mtd, buf, eccsize); - buf += eccsize; - - if (chip->ecc.prepad) { - chip->read_buf(mtd, oob, chip->ecc.prepad); - oob += chip->ecc.prepad; - } - - chip->read_buf(mtd, oob, eccbytes); - oob += eccbytes; - - if (chip->ecc.postpad) { - chip->read_buf(mtd, oob, chip->ecc.postpad); - oob += chip->ecc.postpad; - } - } - - size = mtd->oobsize - (oob - chip->oob_poi); - if (size) - chip->read_buf(mtd, oob, size); - - return 0; -} - -/** - * nand_read_page_swecc - [REPLACEABLE] software ECC based page read function - * @mtd: mtd info structure - * @chip: nand chip info structure - * @buf: buffer to store read data - * @oob_required: caller requires OOB data read to chip->oob_poi - * @page: page number to read - */ -static int nand_read_page_swecc(struct mtd_info *mtd, struct nand_chip *chip, - uint8_t *buf, int oob_required, int page) -{ - int i, eccsize = chip->ecc.size; - int eccbytes = chip->ecc.bytes; - int eccsteps = chip->ecc.steps; - uint8_t *p = buf; - uint8_t *ecc_calc = chip->buffers->ecccalc; - uint8_t *ecc_code = chip->buffers->ecccode; - uint32_t *eccpos = chip->ecc.layout->eccpos; - - chip->ecc.read_page_raw(mtd, chip, buf, 1, page); - - for (i = 0; eccsteps; eccsteps--, i += eccbytes, p += eccsize) - chip->ecc.calculate(mtd, p, &ecc_calc[i]); - - for (i = 0; i < chip->ecc.total; i++) - ecc_code[i] = chip->oob_poi[eccpos[i]]; - - eccsteps = chip->ecc.steps; - p = buf; - - for (i = 0 ; eccsteps; eccsteps--, i += eccbytes, p += eccsize) { - int stat; - - stat = chip->ecc.correct(mtd, p, &ecc_code[i], &ecc_calc[i]); - if (stat < 0) - mtd->ecc_stats.failed++; - else - mtd->ecc_stats.corrected += stat; - } - return 0; -} - -/** - * nand_read_subpage - [REPLACEABLE] software ECC based sub-page read function - * @mtd: mtd info structure - * @chip: nand chip info structure - * @data_offs: offset of requested data within the page - * @readlen: data length - * @bufpoi: buffer to store read data - */ -static int nand_read_subpage(struct mtd_info *mtd, struct nand_chip *chip, - uint32_t data_offs, uint32_t readlen, uint8_t *bufpoi) -{ - int start_step, end_step, num_steps; - uint32_t *eccpos = chip->ecc.layout->eccpos; - uint8_t *p; - int data_col_addr, i, gaps = 0; - int datafrag_len, eccfrag_len, aligned_len, aligned_pos; - int busw = (chip->options & NAND_BUSWIDTH_16) ? 2 : 1; - int index = 0; - - /* Column address within the page aligned to ECC size (256bytes) */ - start_step = data_offs / chip->ecc.size; - end_step = (data_offs + readlen - 1) / chip->ecc.size; - num_steps = end_step - start_step + 1; - - /* Data size aligned to ECC ecc.size */ - datafrag_len = num_steps * chip->ecc.size; - eccfrag_len = num_steps * chip->ecc.bytes; - - data_col_addr = start_step * chip->ecc.size; - /* If we read not a page aligned data */ - if (data_col_addr != 0) - chip->cmdfunc(mtd, NAND_CMD_RNDOUT, data_col_addr, -1); - - p = bufpoi + data_col_addr; - chip->read_buf(mtd, p, datafrag_len); - - /* Calculate ECC */ - for (i = 0; i < eccfrag_len ; i += chip->ecc.bytes, p += chip->ecc.size) - chip->ecc.calculate(mtd, p, &chip->buffers->ecccalc[i]); - - /* - * The performance is faster if we position offsets according to - * ecc.pos. Let's make sure that there are no gaps in ECC positions. - */ - for (i = 0; i < eccfrag_len - 1; i++) { - if (eccpos[i + start_step * chip->ecc.bytes] + 1 != - eccpos[i + start_step * chip->ecc.bytes + 1]) { - gaps = 1; - break; - } - } - if (gaps) { - chip->cmdfunc(mtd, NAND_CMD_RNDOUT, mtd->writesize, -1); - chip->read_buf(mtd, chip->oob_poi, mtd->oobsize); - } else { - /* - * Send the command to read the particular ECC bytes take care - * about buswidth alignment in read_buf. - */ - index = start_step * chip->ecc.bytes; - - aligned_pos = eccpos[index] & ~(busw - 1); - aligned_len = eccfrag_len; - if (eccpos[index] & (busw - 1)) - aligned_len++; - if (eccpos[index + (num_steps * chip->ecc.bytes)] & (busw - 1)) - aligned_len++; - - chip->cmdfunc(mtd, NAND_CMD_RNDOUT, - mtd->writesize + aligned_pos, -1); - chip->read_buf(mtd, &chip->oob_poi[aligned_pos], aligned_len); - } - - for (i = 0; i < eccfrag_len; i++) - chip->buffers->ecccode[i] = chip->oob_poi[eccpos[i + index]]; - - p = bufpoi + data_col_addr; - for (i = 0; i < eccfrag_len ; i += chip->ecc.bytes, p += chip->ecc.size) { - int stat; - - stat = chip->ecc.correct(mtd, p, - &chip->buffers->ecccode[i], &chip->buffers->ecccalc[i]); - if (stat < 0) - mtd->ecc_stats.failed++; - else - mtd->ecc_stats.corrected += stat; - } - return 0; -} - -/** - * nand_read_page_hwecc - [REPLACEABLE] hardware ECC based page read function - * @mtd: mtd info structure - * @chip: nand chip info structure - * @buf: buffer to store read data - * @oob_required: caller requires OOB data read to chip->oob_poi - * @page: page number to read - * - * Not for syndrome calculating ECC controllers which need a special oob layout. - */ -static int nand_read_page_hwecc(struct mtd_info *mtd, struct nand_chip *chip, - uint8_t *buf, int oob_required, int page) -{ - int i, eccsize = chip->ecc.size; - int eccbytes = chip->ecc.bytes; - int eccsteps = chip->ecc.steps; - uint8_t *p = buf; - uint8_t *ecc_calc = chip->buffers->ecccalc; - uint8_t *ecc_code = chip->buffers->ecccode; - uint32_t *eccpos = chip->ecc.layout->eccpos; - - for (i = 0; eccsteps; eccsteps--, i += eccbytes, p += eccsize) { - chip->ecc.hwctl(mtd, NAND_ECC_READ); - chip->read_buf(mtd, p, eccsize); - chip->ecc.calculate(mtd, p, &ecc_calc[i]); - } - chip->read_buf(mtd, chip->oob_poi, mtd->oobsize); - - for (i = 0; i < chip->ecc.total; i++) - ecc_code[i] = chip->oob_poi[eccpos[i]]; - - eccsteps = chip->ecc.steps; - p = buf; - - for (i = 0 ; eccsteps; eccsteps--, i += eccbytes, p += eccsize) { - int stat; - - stat = chip->ecc.correct(mtd, p, &ecc_code[i], &ecc_calc[i]); - if (stat < 0) - mtd->ecc_stats.failed++; - else - mtd->ecc_stats.corrected += stat; - } - return 0; -} - -/** - * nand_read_page_hwecc_oob_first - [REPLACEABLE] hw ecc, read oob first - * @mtd: mtd info structure - * @chip: nand chip info structure - * @buf: buffer to store read data - * @oob_required: caller requires OOB data read to chip->oob_poi - * @page: page number to read - * - * Hardware ECC for large page chips, require OOB to be read first. For this - * ECC mode, the write_page method is re-used from ECC_HW. These methods - * read/write ECC from the OOB area, unlike the ECC_HW_SYNDROME support with - * multiple ECC steps, follows the "infix ECC" scheme and reads/writes ECC from - * the data area, by overwriting the NAND manufacturer bad block markings. - */ -static int nand_read_page_hwecc_oob_first(struct mtd_info *mtd, - struct nand_chip *chip, uint8_t *buf, int oob_required, int page) -{ - int i, eccsize = chip->ecc.size; - int eccbytes = chip->ecc.bytes; - int eccsteps = chip->ecc.steps; - uint8_t *p = buf; - uint8_t *ecc_code = chip->buffers->ecccode; - uint32_t *eccpos = chip->ecc.layout->eccpos; - uint8_t *ecc_calc = chip->buffers->ecccalc; - - /* Read the OOB area first */ - chip->cmdfunc(mtd, NAND_CMD_READOOB, 0, page); - chip->read_buf(mtd, chip->oob_poi, mtd->oobsize); - chip->cmdfunc(mtd, NAND_CMD_READ0, 0, page); - - for (i = 0; i < chip->ecc.total; i++) - ecc_code[i] = chip->oob_poi[eccpos[i]]; - - for (i = 0; eccsteps; eccsteps--, i += eccbytes, p += eccsize) { - int stat; - - chip->ecc.hwctl(mtd, NAND_ECC_READ); - chip->read_buf(mtd, p, eccsize); - chip->ecc.calculate(mtd, p, &ecc_calc[i]); - - stat = chip->ecc.correct(mtd, p, &ecc_code[i], NULL); - if (stat < 0) - mtd->ecc_stats.failed++; - else - mtd->ecc_stats.corrected += stat; - } - return 0; -} - -/** - * nand_read_page_syndrome - [REPLACEABLE] hardware ECC syndrome based page read - * @mtd: mtd info structure - * @chip: nand chip info structure - * @buf: buffer to store read data - * @oob_required: caller requires OOB data read to chip->oob_poi - * @page: page number to read - * - * The hw generator calculates the error syndrome automatically. Therefore we - * need a special oob layout and handling. - */ -static int nand_read_page_syndrome(struct mtd_info *mtd, struct nand_chip *chip, - uint8_t *buf, int oob_required, int page) -{ - int i, eccsize = chip->ecc.size; - int eccbytes = chip->ecc.bytes; - int eccsteps = chip->ecc.steps; - uint8_t *p = buf; - uint8_t *oob = chip->oob_poi; - - for (i = 0; eccsteps; eccsteps--, i += eccbytes, p += eccsize) { - int stat; - - chip->ecc.hwctl(mtd, NAND_ECC_READ); - chip->read_buf(mtd, p, eccsize); - - if (chip->ecc.prepad) { - chip->read_buf(mtd, oob, chip->ecc.prepad); - oob += chip->ecc.prepad; - } - - chip->ecc.hwctl(mtd, NAND_ECC_READSYN); - chip->read_buf(mtd, oob, eccbytes); - stat = chip->ecc.correct(mtd, p, oob, NULL); - - if (stat < 0) - mtd->ecc_stats.failed++; - else - mtd->ecc_stats.corrected += stat; - - oob += eccbytes; - - if (chip->ecc.postpad) { - chip->read_buf(mtd, oob, chip->ecc.postpad); - oob += chip->ecc.postpad; - } - } - - /* Calculate remaining oob bytes */ - i = mtd->oobsize - (oob - chip->oob_poi); - if (i) - chip->read_buf(mtd, oob, i); - - return 0; -} - -/** - * nand_transfer_oob - [INTERN] Transfer oob to client buffer - * @chip: nand chip structure - * @oob: oob destination address - * @ops: oob ops structure - * @len: size of oob to transfer - */ -static uint8_t *nand_transfer_oob(struct nand_chip *chip, uint8_t *oob, - struct mtd_oob_ops *ops, size_t len) -{ - switch (ops->mode) { - - case MTD_OPS_PLACE_OOB: - case MTD_OPS_RAW: - memcpy(oob, chip->oob_poi + ops->ooboffs, len); - return oob + len; - - case MTD_OPS_AUTO_OOB: { - struct nand_oobfree *free = chip->ecc.layout->oobfree; - uint32_t boffs = 0, roffs = ops->ooboffs; - size_t bytes = 0; - - for (; free->length && len; free++, len -= bytes) { - /* Read request not from offset 0? */ - if (unlikely(roffs)) { - if (roffs >= free->length) { - roffs -= free->length; - continue; - } - boffs = free->offset + roffs; - bytes = min_t(size_t, len, - (free->length - roffs)); - roffs = 0; - } else { - bytes = min_t(size_t, len, free->length); - boffs = free->offset; - } - memcpy(oob, chip->oob_poi + boffs, bytes); - oob += bytes; - } - return oob; - } - default: - BUG(); - } - return NULL; -} - -/** - * nand_do_read_ops - [INTERN] Read data with ECC - * @mtd: MTD device structure - * @from: offset to read from - * @ops: oob ops structure - * - * Internal function. Called with chip held. - */ -static int nand_do_read_ops(struct mtd_info *mtd, loff_t from, - struct mtd_oob_ops *ops) -{ - int chipnr, page, realpage, col, bytes, aligned, oob_required; - struct nand_chip *chip = mtd->priv; - struct mtd_ecc_stats stats; - int ret = 0; - uint32_t readlen = ops->len; - uint32_t oobreadlen = ops->ooblen; - uint32_t max_oobsize = ops->mode == MTD_OPS_AUTO_OOB ? - mtd->oobavail : mtd->oobsize; - - uint8_t *bufpoi, *oob, *buf; - unsigned int max_bitflips = 0; - - stats = mtd->ecc_stats; - - chipnr = (int)(from >> chip->chip_shift); - chip->select_chip(mtd, chipnr); - - realpage = (int)(from >> chip->page_shift); - page = realpage & chip->pagemask; - - col = (int)(from & (mtd->writesize - 1)); - - buf = ops->datbuf; - oob = ops->oobbuf; - oob_required = oob ? 1 : 0; - - while (1) { - WATCHDOG_RESET(); - - bytes = min(mtd->writesize - col, readlen); - aligned = (bytes == mtd->writesize); - - /* Is the current page in the buffer? */ - if (realpage != chip->pagebuf || oob) { - bufpoi = aligned ? buf : chip->buffers->databuf; - - chip->cmdfunc(mtd, NAND_CMD_READ0, 0x00, page); - - /* - * Now read the page into the buffer. Absent an error, - * the read methods return max bitflips per ecc step. - */ - if (unlikely(ops->mode == MTD_OPS_RAW)) - ret = chip->ecc.read_page_raw(mtd, chip, bufpoi, - oob_required, - page); - else if (!aligned && NAND_HAS_SUBPAGE_READ(chip) && - !oob) - ret = chip->ecc.read_subpage(mtd, chip, - col, bytes, bufpoi); - else - ret = chip->ecc.read_page(mtd, chip, bufpoi, - oob_required, page); - if (ret < 0) { - if (!aligned) - /* Invalidate page cache */ - chip->pagebuf = -1; - break; - } - - max_bitflips = max_t(unsigned int, max_bitflips, ret); - - /* Transfer not aligned data */ - if (!aligned) { - if (!NAND_HAS_SUBPAGE_READ(chip) && !oob && - !(mtd->ecc_stats.failed - stats.failed) && - (ops->mode != MTD_OPS_RAW)) { - chip->pagebuf = realpage; - chip->pagebuf_bitflips = ret; - } else { - /* Invalidate page cache */ - chip->pagebuf = -1; - } - memcpy(buf, chip->buffers->databuf + col, bytes); - } - - buf += bytes; - - if (unlikely(oob)) { - int toread = min(oobreadlen, max_oobsize); - - if (toread) { - oob = nand_transfer_oob(chip, - oob, ops, toread); - oobreadlen -= toread; - } - } - } else { - memcpy(buf, chip->buffers->databuf + col, bytes); - buf += bytes; - max_bitflips = max_t(unsigned int, max_bitflips, - chip->pagebuf_bitflips); - } - - readlen -= bytes; - - if (!readlen) - break; - - /* For subsequent reads align to page boundary */ - col = 0; - /* Increment page address */ - realpage++; - - page = realpage & chip->pagemask; - /* Check, if we cross a chip boundary */ - if (!page) { - chipnr++; - chip->select_chip(mtd, -1); - chip->select_chip(mtd, chipnr); - } - } - - ops->retlen = ops->len - (size_t) readlen; - if (oob) - ops->oobretlen = ops->ooblen - oobreadlen; - - if (ret) - return ret; - - if (mtd->ecc_stats.failed - stats.failed) - return -EBADMSG; - - return max_bitflips; -} - -/** - * nand_read - [MTD Interface] MTD compatibility function for nand_do_read_ecc - * @mtd: MTD device structure - * @from: offset to read from - * @len: number of bytes to read - * @retlen: pointer to variable to store the number of read bytes - * @buf: the databuffer to put data - * - * Get hold of the chip and call nand_do_read. - */ -static int nand_read(struct mtd_info *mtd, loff_t from, size_t len, - size_t *retlen, uint8_t *buf) -{ - struct nand_chip *chip = mtd->priv; - struct mtd_oob_ops ops; - int ret; - - nand_get_device(chip, mtd, FL_READING); - ops.len = len; - ops.datbuf = buf; - ops.oobbuf = NULL; - ops.mode = MTD_OPS_PLACE_OOB; - ret = nand_do_read_ops(mtd, from, &ops); - *retlen = ops.retlen; - nand_release_device(mtd); - return ret; -} - -/** - * nand_read_oob_std - [REPLACEABLE] the most common OOB data read function - * @mtd: mtd info structure - * @chip: nand chip info structure - * @page: page number to read - */ -static int nand_read_oob_std(struct mtd_info *mtd, struct nand_chip *chip, - int page) -{ - chip->cmdfunc(mtd, NAND_CMD_READOOB, 0, page); - chip->read_buf(mtd, chip->oob_poi, mtd->oobsize); - return 0; -} - -/** - * nand_read_oob_syndrome - [REPLACEABLE] OOB data read function for HW ECC - * with syndromes - * @mtd: mtd info structure - * @chip: nand chip info structure - * @page: page number to read - */ -static int nand_read_oob_syndrome(struct mtd_info *mtd, struct nand_chip *chip, - int page) -{ - uint8_t *buf = chip->oob_poi; - int length = mtd->oobsize; - int chunk = chip->ecc.bytes + chip->ecc.prepad + chip->ecc.postpad; - int eccsize = chip->ecc.size; - uint8_t *bufpoi = buf; - int i, toread, sndrnd = 0, pos; - - chip->cmdfunc(mtd, NAND_CMD_READ0, chip->ecc.size, page); - for (i = 0; i < chip->ecc.steps; i++) { - if (sndrnd) { - pos = eccsize + i * (eccsize + chunk); - if (mtd->writesize > 512) - chip->cmdfunc(mtd, NAND_CMD_RNDOUT, pos, -1); - else - chip->cmdfunc(mtd, NAND_CMD_READ0, pos, page); - } else - sndrnd = 1; - toread = min_t(int, length, chunk); - chip->read_buf(mtd, bufpoi, toread); - bufpoi += toread; - length -= toread; - } - if (length > 0) - chip->read_buf(mtd, bufpoi, length); - - return 0; -} - -/** - * nand_write_oob_std - [REPLACEABLE] the most common OOB data write function - * @mtd: mtd info structure - * @chip: nand chip info structure - * @page: page number to write - */ -static int nand_write_oob_std(struct mtd_info *mtd, struct nand_chip *chip, - int page) -{ - int status = 0; - const uint8_t *buf = chip->oob_poi; - int length = mtd->oobsize; - - chip->cmdfunc(mtd, NAND_CMD_SEQIN, mtd->writesize, page); - chip->write_buf(mtd, buf, length); - /* Send command to program the OOB data */ - chip->cmdfunc(mtd, NAND_CMD_PAGEPROG, -1, -1); - - status = chip->waitfunc(mtd, chip); - - return status & NAND_STATUS_FAIL ? -EIO : 0; -} - -/** - * nand_write_oob_syndrome - [REPLACEABLE] OOB data write function for HW ECC - * with syndrome - only for large page flash - * @mtd: mtd info structure - * @chip: nand chip info structure - * @page: page number to write - */ -static int nand_write_oob_syndrome(struct mtd_info *mtd, - struct nand_chip *chip, int page) -{ - int chunk = chip->ecc.bytes + chip->ecc.prepad + chip->ecc.postpad; - int eccsize = chip->ecc.size, length = mtd->oobsize; - int i, len, pos, status = 0, sndcmd = 0, steps = chip->ecc.steps; - const uint8_t *bufpoi = chip->oob_poi; - - /* - * data-ecc-data-ecc ... ecc-oob - * or - * data-pad-ecc-pad-data-pad .... ecc-pad-oob - */ - if (!chip->ecc.prepad && !chip->ecc.postpad) { - pos = steps * (eccsize + chunk); - steps = 0; - } else - pos = eccsize; - - chip->cmdfunc(mtd, NAND_CMD_SEQIN, pos, page); - for (i = 0; i < steps; i++) { - if (sndcmd) { - if (mtd->writesize <= 512) { - uint32_t fill = 0xFFFFFFFF; - - len = eccsize; - while (len > 0) { - int num = min_t(int, len, 4); - chip->write_buf(mtd, (uint8_t *)&fill, - num); - len -= num; - } - } else { - pos = eccsize + i * (eccsize + chunk); - chip->cmdfunc(mtd, NAND_CMD_RNDIN, pos, -1); - } - } else - sndcmd = 1; - len = min_t(int, length, chunk); - chip->write_buf(mtd, bufpoi, len); - bufpoi += len; - length -= len; - } - if (length > 0) - chip->write_buf(mtd, bufpoi, length); - - chip->cmdfunc(mtd, NAND_CMD_PAGEPROG, -1, -1); - status = chip->waitfunc(mtd, chip); - - return status & NAND_STATUS_FAIL ? -EIO : 0; -} - -/** - * nand_do_read_oob - [INTERN] NAND read out-of-band - * @mtd: MTD device structure - * @from: offset to read from - * @ops: oob operations description structure - * - * NAND read out-of-band data from the spare area. - */ -static int nand_do_read_oob(struct mtd_info *mtd, loff_t from, - struct mtd_oob_ops *ops) -{ - int page, realpage, chipnr; - struct nand_chip *chip = mtd->priv; - struct mtd_ecc_stats stats; - int readlen = ops->ooblen; - int len; - uint8_t *buf = ops->oobbuf; - int ret = 0; - - MTDDEBUG(MTD_DEBUG_LEVEL3, "%s: from = 0x%08Lx, len = %i\n", - __func__, (unsigned long long)from, readlen); - - stats = mtd->ecc_stats; - - if (ops->mode == MTD_OPS_AUTO_OOB) - len = chip->ecc.layout->oobavail; - else - len = mtd->oobsize; - - if (unlikely(ops->ooboffs >= len)) { - MTDDEBUG(MTD_DEBUG_LEVEL0, "%s: Attempt to start read " - "outside oob\n", __func__); - return -EINVAL; - } - - /* Do not allow reads past end of device */ - if (unlikely(from >= mtd->size || - ops->ooboffs + readlen > ((mtd->size >> chip->page_shift) - - (from >> chip->page_shift)) * len)) { - MTDDEBUG(MTD_DEBUG_LEVEL0, "%s: Attempt read beyond end " - "of device\n", __func__); - return -EINVAL; - } - - chipnr = (int)(from >> chip->chip_shift); - chip->select_chip(mtd, chipnr); - - /* Shift to get page */ - realpage = (int)(from >> chip->page_shift); - page = realpage & chip->pagemask; - - while (1) { - WATCHDOG_RESET(); - if (ops->mode == MTD_OPS_RAW) - ret = chip->ecc.read_oob_raw(mtd, chip, page); - else - ret = chip->ecc.read_oob(mtd, chip, page); - - if (ret < 0) - break; - - len = min(len, readlen); - buf = nand_transfer_oob(chip, buf, ops, len); - - readlen -= len; - if (!readlen) - break; - - /* Increment page address */ - realpage++; - - page = realpage & chip->pagemask; - /* Check, if we cross a chip boundary */ - if (!page) { - chipnr++; - chip->select_chip(mtd, -1); - chip->select_chip(mtd, chipnr); - } - } - - ops->oobretlen = ops->ooblen - readlen; - - if (ret < 0) - return ret; - - if (mtd->ecc_stats.failed - stats.failed) - return -EBADMSG; - - return mtd->ecc_stats.corrected - stats.corrected ? -EUCLEAN : 0; -} - -/** - * nand_read_oob - [MTD Interface] NAND read data and/or out-of-band - * @mtd: MTD device structure - * @from: offset to read from - * @ops: oob operation description structure - * - * NAND read data and/or out-of-band data. - */ -static int nand_read_oob(struct mtd_info *mtd, loff_t from, - struct mtd_oob_ops *ops) -{ - struct nand_chip *chip = mtd->priv; - int ret = -ENOTSUPP; - - ops->retlen = 0; - - /* Do not allow reads past end of device */ - if (ops->datbuf && (from + ops->len) > mtd->size) { - MTDDEBUG(MTD_DEBUG_LEVEL0, "%s: Attempt read " - "beyond end of device\n", __func__); - return -EINVAL; - } - - nand_get_device(chip, mtd, FL_READING); - - switch (ops->mode) { - case MTD_OPS_PLACE_OOB: - case MTD_OPS_AUTO_OOB: - case MTD_OPS_RAW: - break; - - default: - goto out; - } - - if (!ops->datbuf) - ret = nand_do_read_oob(mtd, from, ops); - else - ret = nand_do_read_ops(mtd, from, ops); - -out: - nand_release_device(mtd); - return ret; -} - - -/** - * nand_write_page_raw - [INTERN] raw page write function - * @mtd: mtd info structure - * @chip: nand chip info structure - * @buf: data buffer - * @oob_required: must write chip->oob_poi to OOB - * - * Not for syndrome calculating ECC controllers, which use a special oob layout. - */ -static int nand_write_page_raw(struct mtd_info *mtd, struct nand_chip *chip, - const uint8_t *buf, int oob_required) -{ - chip->write_buf(mtd, buf, mtd->writesize); - if (oob_required) - chip->write_buf(mtd, chip->oob_poi, mtd->oobsize); - - return 0; -} - -/** - * nand_write_page_raw_syndrome - [INTERN] raw page write function - * @mtd: mtd info structure - * @chip: nand chip info structure - * @buf: data buffer - * @oob_required: must write chip->oob_poi to OOB - * - * We need a special oob layout and handling even when ECC isn't checked. - */ -static int nand_write_page_raw_syndrome(struct mtd_info *mtd, - struct nand_chip *chip, - const uint8_t *buf, int oob_required) -{ - int eccsize = chip->ecc.size; - int eccbytes = chip->ecc.bytes; - uint8_t *oob = chip->oob_poi; - int steps, size; - - for (steps = chip->ecc.steps; steps > 0; steps--) { - chip->write_buf(mtd, buf, eccsize); - buf += eccsize; - - if (chip->ecc.prepad) { - chip->write_buf(mtd, oob, chip->ecc.prepad); - oob += chip->ecc.prepad; - } - - chip->read_buf(mtd, oob, eccbytes); - oob += eccbytes; - - if (chip->ecc.postpad) { - chip->write_buf(mtd, oob, chip->ecc.postpad); - oob += chip->ecc.postpad; - } - } - - size = mtd->oobsize - (oob - chip->oob_poi); - if (size) - chip->write_buf(mtd, oob, size); - - return 0; -} -/** - * nand_write_page_swecc - [REPLACEABLE] software ECC based page write function - * @mtd: mtd info structure - * @chip: nand chip info structure - * @buf: data buffer - * @oob_required: must write chip->oob_poi to OOB - */ -static int nand_write_page_swecc(struct mtd_info *mtd, struct nand_chip *chip, - const uint8_t *buf, int oob_required) -{ - int i, eccsize = chip->ecc.size; - int eccbytes = chip->ecc.bytes; - int eccsteps = chip->ecc.steps; - uint8_t *ecc_calc = chip->buffers->ecccalc; - const uint8_t *p = buf; - uint32_t *eccpos = chip->ecc.layout->eccpos; - - /* Software ECC calculation */ - for (i = 0; eccsteps; eccsteps--, i += eccbytes, p += eccsize) - chip->ecc.calculate(mtd, p, &ecc_calc[i]); - - for (i = 0; i < chip->ecc.total; i++) - chip->oob_poi[eccpos[i]] = ecc_calc[i]; - - return chip->ecc.write_page_raw(mtd, chip, buf, 1); -} - -/** - * nand_write_page_hwecc - [REPLACEABLE] hardware ECC based page write function - * @mtd: mtd info structure - * @chip: nand chip info structure - * @buf: data buffer - * @oob_required: must write chip->oob_poi to OOB - */ -static int nand_write_page_hwecc(struct mtd_info *mtd, struct nand_chip *chip, - const uint8_t *buf, int oob_required) -{ - int i, eccsize = chip->ecc.size; - int eccbytes = chip->ecc.bytes; - int eccsteps = chip->ecc.steps; - uint8_t *ecc_calc = chip->buffers->ecccalc; - const uint8_t *p = buf; - uint32_t *eccpos = chip->ecc.layout->eccpos; - - for (i = 0; eccsteps; eccsteps--, i += eccbytes, p += eccsize) { - chip->ecc.hwctl(mtd, NAND_ECC_WRITE); - chip->write_buf(mtd, p, eccsize); - chip->ecc.calculate(mtd, p, &ecc_calc[i]); - } - - for (i = 0; i < chip->ecc.total; i++) - chip->oob_poi[eccpos[i]] = ecc_calc[i]; - - chip->write_buf(mtd, chip->oob_poi, mtd->oobsize); - - return 0; -} - -/** - * nand_write_page_syndrome - [REPLACEABLE] hardware ECC syndrome based page write - * @mtd: mtd info structure - * @chip: nand chip info structure - * @buf: data buffer - * @oob_required: must write chip->oob_poi to OOB - * - * The hw generator calculates the error syndrome automatically. Therefore we - * need a special oob layout and handling. - */ -static int nand_write_page_syndrome(struct mtd_info *mtd, - struct nand_chip *chip, - const uint8_t *buf, int oob_required) -{ - int i, eccsize = chip->ecc.size; - int eccbytes = chip->ecc.bytes; - int eccsteps = chip->ecc.steps; - const uint8_t *p = buf; - uint8_t *oob = chip->oob_poi; - - for (i = 0; eccsteps; eccsteps--, i += eccbytes, p += eccsize) { - - chip->ecc.hwctl(mtd, NAND_ECC_WRITE); - chip->write_buf(mtd, p, eccsize); - - if (chip->ecc.prepad) { - chip->write_buf(mtd, oob, chip->ecc.prepad); - oob += chip->ecc.prepad; - } - - chip->ecc.calculate(mtd, p, oob); - chip->write_buf(mtd, oob, eccbytes); - oob += eccbytes; - - if (chip->ecc.postpad) { - chip->write_buf(mtd, oob, chip->ecc.postpad); - oob += chip->ecc.postpad; - } - } - - /* Calculate remaining oob bytes */ - i = mtd->oobsize - (oob - chip->oob_poi); - if (i) - chip->write_buf(mtd, oob, i); - - return 0; -} - -/** - * nand_write_page - [REPLACEABLE] write one page - * @mtd: MTD device structure - * @chip: NAND chip descriptor - * @buf: the data to write - * @oob_required: must write chip->oob_poi to OOB - * @page: page number to write - * @cached: cached programming - * @raw: use _raw version of write_page - */ -static int nand_write_page(struct mtd_info *mtd, struct nand_chip *chip, - const uint8_t *buf, int oob_required, int page, - int cached, int raw) -{ - int status; - - chip->cmdfunc(mtd, NAND_CMD_SEQIN, 0x00, page); - - if (unlikely(raw)) - status = chip->ecc.write_page_raw(mtd, chip, buf, oob_required); - else - status = chip->ecc.write_page(mtd, chip, buf, oob_required); - - if (status < 0) - return status; - - /* - * Cached progamming disabled for now. Not sure if it's worth the - * trouble. The speed gain is not very impressive. (2.3->2.6Mib/s). - */ - cached = 0; - - if (!cached || !(chip->options & NAND_CACHEPRG)) { - - chip->cmdfunc(mtd, NAND_CMD_PAGEPROG, -1, -1); - status = chip->waitfunc(mtd, chip); - /* - * See if operation failed and additional status checks are - * available. - */ - if ((status & NAND_STATUS_FAIL) && (chip->errstat)) - status = chip->errstat(mtd, chip, FL_WRITING, status, - page); - - if (status & NAND_STATUS_FAIL) - return -EIO; - } else { - chip->cmdfunc(mtd, NAND_CMD_CACHEDPROG, -1, -1); - status = chip->waitfunc(mtd, chip); - } - -#ifdef CONFIG_MTD_NAND_VERIFY_WRITE - /* Send command to read back the data */ - chip->cmdfunc(mtd, NAND_CMD_READ0, 0, page); - - if (chip->verify_buf(mtd, buf, mtd->writesize)) - return -EIO; - - /* Make sure the next page prog is preceded by a status read */ - chip->cmdfunc(mtd, NAND_CMD_STATUS, -1, -1); -#endif - return 0; -} - -/** - * nand_fill_oob - [INTERN] Transfer client buffer to oob - * @mtd: MTD device structure - * @oob: oob data buffer - * @len: oob data write length - * @ops: oob ops structure - */ -static uint8_t *nand_fill_oob(struct mtd_info *mtd, uint8_t *oob, size_t len, - struct mtd_oob_ops *ops) -{ - struct nand_chip *chip = mtd->priv; - - /* - * Initialise to all 0xFF, to avoid the possibility of left over OOB - * data from a previous OOB read. - */ - memset(chip->oob_poi, 0xff, mtd->oobsize); - - switch (ops->mode) { - - case MTD_OPS_PLACE_OOB: - case MTD_OPS_RAW: - memcpy(chip->oob_poi + ops->ooboffs, oob, len); - return oob + len; - - case MTD_OPS_AUTO_OOB: { - struct nand_oobfree *free = chip->ecc.layout->oobfree; - uint32_t boffs = 0, woffs = ops->ooboffs; - size_t bytes = 0; - - for (; free->length && len; free++, len -= bytes) { - /* Write request not from offset 0? */ - if (unlikely(woffs)) { - if (woffs >= free->length) { - woffs -= free->length; - continue; - } - boffs = free->offset + woffs; - bytes = min_t(size_t, len, - (free->length - woffs)); - woffs = 0; - } else { - bytes = min_t(size_t, len, free->length); - boffs = free->offset; - } - memcpy(chip->oob_poi + boffs, oob, bytes); - oob += bytes; - } - return oob; - } - default: - BUG(); - } - return NULL; -} - -#define NOTALIGNED(x) ((x & (chip->subpagesize - 1)) != 0) - -/** - * nand_do_write_ops - [INTERN] NAND write with ECC - * @mtd: MTD device structure - * @to: offset to write to - * @ops: oob operations description structure - * - * NAND write with ECC. - */ -static int nand_do_write_ops(struct mtd_info *mtd, loff_t to, - struct mtd_oob_ops *ops) -{ - int chipnr, realpage, page, blockmask, column; - struct nand_chip *chip = mtd->priv; - uint32_t writelen = ops->len; - - uint32_t oobwritelen = ops->ooblen; - uint32_t oobmaxlen = ops->mode == MTD_OPS_AUTO_OOB ? - mtd->oobavail : mtd->oobsize; - - uint8_t *oob = ops->oobbuf; - uint8_t *buf = ops->datbuf; - int ret, subpage; - int oob_required = oob ? 1 : 0; - - ops->retlen = 0; - if (!writelen) - return 0; - - column = to & (mtd->writesize - 1); - subpage = column || (writelen & (mtd->writesize - 1)); - - if (subpage && oob) - return -EINVAL; - - chipnr = (int)(to >> chip->chip_shift); - chip->select_chip(mtd, chipnr); - - /* Check, if it is write protected */ - if (nand_check_wp(mtd)) { - printk (KERN_NOTICE "nand_do_write_ops: Device is write protected\n"); - return -EIO; - } - - realpage = (int)(to >> chip->page_shift); - page = realpage & chip->pagemask; - blockmask = (1 << (chip->phys_erase_shift - chip->page_shift)) - 1; - - /* Invalidate the page cache, when we write to the cached page */ - if (to <= (chip->pagebuf << chip->page_shift) && - (chip->pagebuf << chip->page_shift) < (to + ops->len)) - chip->pagebuf = -1; - - /* Don't allow multipage oob writes with offset */ - if (oob && ops->ooboffs && (ops->ooboffs + ops->ooblen > oobmaxlen)) - return -EINVAL; - - while (1) { - WATCHDOG_RESET(); - - int bytes = mtd->writesize; - int cached = writelen > bytes && page != blockmask; - uint8_t *wbuf = buf; - - /* Partial page write? */ - if (unlikely(column || writelen < mtd->writesize)) { - cached = 0; - bytes = min_t(int, bytes - column, (int) writelen); - chip->pagebuf = -1; - memset(chip->buffers->databuf, 0xff, mtd->writesize); - memcpy(&chip->buffers->databuf[column], buf, bytes); - wbuf = chip->buffers->databuf; - } - - if (unlikely(oob)) { - size_t len = min(oobwritelen, oobmaxlen); - oob = nand_fill_oob(mtd, oob, len, ops); - oobwritelen -= len; - } else { - /* We still need to erase leftover OOB data */ - memset(chip->oob_poi, 0xff, mtd->oobsize); - } - - ret = chip->write_page(mtd, chip, wbuf, oob_required, page, - cached, (ops->mode == MTD_OPS_RAW)); - if (ret) - break; - - writelen -= bytes; - if (!writelen) - break; - - column = 0; - buf += bytes; - realpage++; - - page = realpage & chip->pagemask; - /* Check, if we cross a chip boundary */ - if (!page) { - chipnr++; - chip->select_chip(mtd, -1); - chip->select_chip(mtd, chipnr); - } - } - - ops->retlen = ops->len - writelen; - if (unlikely(oob)) - ops->oobretlen = ops->ooblen; - return ret; -} - -/** - * nand_write - [MTD Interface] NAND write with ECC - * @mtd: MTD device structure - * @to: offset to write to - * @len: number of bytes to write - * @retlen: pointer to variable to store the number of written bytes - * @buf: the data to write - * - * NAND write with ECC. - */ -static int nand_write(struct mtd_info *mtd, loff_t to, size_t len, - size_t *retlen, const uint8_t *buf) -{ - struct nand_chip *chip = mtd->priv; - struct mtd_oob_ops ops; - int ret; - - nand_get_device(chip, mtd, FL_WRITING); - ops.len = len; - ops.datbuf = (uint8_t *)buf; - ops.oobbuf = NULL; - ops.mode = MTD_OPS_PLACE_OOB; - ret = nand_do_write_ops(mtd, to, &ops); - *retlen = ops.retlen; - nand_release_device(mtd); - return ret; -} - -/** - * nand_do_write_oob - [MTD Interface] NAND write out-of-band - * @mtd: MTD device structure - * @to: offset to write to - * @ops: oob operation description structure - * - * NAND write out-of-band. - */ -static int nand_do_write_oob(struct mtd_info *mtd, loff_t to, - struct mtd_oob_ops *ops) -{ - int chipnr, page, status, len; - struct nand_chip *chip = mtd->priv; - - MTDDEBUG(MTD_DEBUG_LEVEL3, "%s: to = 0x%08x, len = %i\n", - __func__, (unsigned int)to, (int)ops->ooblen); - - if (ops->mode == MTD_OPS_AUTO_OOB) - len = chip->ecc.layout->oobavail; - else - len = mtd->oobsize; - - /* Do not allow write past end of page */ - if ((ops->ooboffs + ops->ooblen) > len) { - MTDDEBUG(MTD_DEBUG_LEVEL0, "%s: Attempt to write " - "past end of page\n", __func__); - return -EINVAL; - } - - if (unlikely(ops->ooboffs >= len)) { - MTDDEBUG(MTD_DEBUG_LEVEL0, "%s: Attempt to start " - "write outside oob\n", __func__); - return -EINVAL; - } - - /* Do not allow write past end of device */ - if (unlikely(to >= mtd->size || - ops->ooboffs + ops->ooblen > - ((mtd->size >> chip->page_shift) - - (to >> chip->page_shift)) * len)) { - MTDDEBUG(MTD_DEBUG_LEVEL0, "%s: Attempt write beyond " - "end of device\n", __func__); - return -EINVAL; - } - - chipnr = (int)(to >> chip->chip_shift); - chip->select_chip(mtd, chipnr); - - /* Shift to get page */ - page = (int)(to >> chip->page_shift); - - /* - * Reset the chip. Some chips (like the Toshiba TC5832DC found in one - * of my DiskOnChip 2000 test units) will clear the whole data page too - * if we don't do this. I have no clue why, but I seem to have 'fixed' - * it in the doc2000 driver in August 1999. dwmw2. - */ - chip->cmdfunc(mtd, NAND_CMD_RESET, -1, -1); - - /* Check, if it is write protected */ - if (nand_check_wp(mtd)) - return -EROFS; - - /* Invalidate the page cache, if we write to the cached page */ - if (page == chip->pagebuf) - chip->pagebuf = -1; - - nand_fill_oob(mtd, ops->oobbuf, ops->ooblen, ops); - - if (ops->mode == MTD_OPS_RAW) - status = chip->ecc.write_oob_raw(mtd, chip, page & chip->pagemask); - else - status = chip->ecc.write_oob(mtd, chip, page & chip->pagemask); - - if (status) - return status; - - ops->oobretlen = ops->ooblen; - - return 0; -} - -/** - * nand_write_oob - [MTD Interface] NAND write data and/or out-of-band - * @mtd: MTD device structure - * @to: offset to write to - * @ops: oob operation description structure - */ -static int nand_write_oob(struct mtd_info *mtd, loff_t to, - struct mtd_oob_ops *ops) -{ - struct nand_chip *chip = mtd->priv; - int ret = -ENOTSUPP; - - ops->retlen = 0; - - /* Do not allow writes past end of device */ - if (ops->datbuf && (to + ops->len) > mtd->size) { - MTDDEBUG(MTD_DEBUG_LEVEL0, "%s: Attempt write beyond " - "end of device\n", __func__); - return -EINVAL; - } - - nand_get_device(chip, mtd, FL_WRITING); - - switch (ops->mode) { - case MTD_OPS_PLACE_OOB: - case MTD_OPS_AUTO_OOB: - case MTD_OPS_RAW: - break; - - default: - goto out; - } - - if (!ops->datbuf) - ret = nand_do_write_oob(mtd, to, ops); - else - ret = nand_do_write_ops(mtd, to, ops); - -out: - nand_release_device(mtd); - return ret; -} - -/** - * single_erase_cmd - [GENERIC] NAND standard block erase command function - * @mtd: MTD device structure - * @page: the page address of the block which will be erased - * - * Standard erase command for NAND chips. - */ -static void single_erase_cmd(struct mtd_info *mtd, int page) -{ - struct nand_chip *chip = mtd->priv; - /* Send commands to erase a block */ - chip->cmdfunc(mtd, NAND_CMD_ERASE1, -1, page); - chip->cmdfunc(mtd, NAND_CMD_ERASE2, -1, -1); -} - -/** - * multi_erase_cmd - [GENERIC] AND specific block erase command function - * @mtd: MTD device structure - * @page: the page address of the block which will be erased - * - * AND multi block erase command function. Erase 4 consecutive blocks. - */ -static void multi_erase_cmd(struct mtd_info *mtd, int page) -{ - struct nand_chip *chip = mtd->priv; - /* Send commands to erase a block */ - chip->cmdfunc(mtd, NAND_CMD_ERASE1, -1, page++); - chip->cmdfunc(mtd, NAND_CMD_ERASE1, -1, page++); - chip->cmdfunc(mtd, NAND_CMD_ERASE1, -1, page++); - chip->cmdfunc(mtd, NAND_CMD_ERASE1, -1, page); - chip->cmdfunc(mtd, NAND_CMD_ERASE2, -1, -1); -} - -/** - * nand_erase - [MTD Interface] erase block(s) - * @mtd: MTD device structure - * @instr: erase instruction - * - * Erase one ore more blocks. - */ -static int nand_erase(struct mtd_info *mtd, struct erase_info *instr) -{ - return nand_erase_nand(mtd, instr, 0); -} - -#define BBT_PAGE_MASK 0xffffff3f -/** - * nand_erase_nand - [INTERN] erase block(s) - * @mtd: MTD device structure - * @instr: erase instruction - * @allowbbt: allow erasing the bbt area - * - * Erase one ore more blocks. - */ -int nand_erase_nand(struct mtd_info *mtd, struct erase_info *instr, - int allowbbt) -{ - int page, status, pages_per_block, ret, chipnr; - struct nand_chip *chip = mtd->priv; - loff_t rewrite_bbt[CONFIG_SYS_NAND_MAX_CHIPS] = {0}; - unsigned int bbt_masked_page = 0xffffffff; - loff_t len; - - MTDDEBUG(MTD_DEBUG_LEVEL3, "%s: start = 0x%012llx, len = %llu\n", - __func__, (unsigned long long)instr->addr, - (unsigned long long)instr->len); - - if (check_offs_len(mtd, instr->addr, instr->len)) - return -EINVAL; - - /* Grab the lock and see if the device is available */ - nand_get_device(chip, mtd, FL_ERASING); - - /* Shift to get first page */ - page = (int)(instr->addr >> chip->page_shift); - chipnr = (int)(instr->addr >> chip->chip_shift); - - /* Calculate pages in each block */ - pages_per_block = 1 << (chip->phys_erase_shift - chip->page_shift); - - /* Select the NAND device */ - chip->select_chip(mtd, chipnr); - - /* Check, if it is write protected */ - if (nand_check_wp(mtd)) { - MTDDEBUG(MTD_DEBUG_LEVEL0, "%s: Device is write protected!!!\n", - __func__); - instr->state = MTD_ERASE_FAILED; - goto erase_exit; - } - - /* - * If BBT requires refresh, set the BBT page mask to see if the BBT - * should be rewritten. Otherwise the mask is set to 0xffffffff which - * can not be matched. This is also done when the bbt is actually - * erased to avoid recursive updates. - */ - if (chip->options & BBT_AUTO_REFRESH && !allowbbt) - bbt_masked_page = chip->bbt_td->pages[chipnr] & BBT_PAGE_MASK; - - /* Loop through the pages */ - len = instr->len; - - instr->state = MTD_ERASING; - - while (len) { - WATCHDOG_RESET(); - /* Check if we have a bad block, we do not erase bad blocks! */ - if (!instr->scrub && nand_block_checkbad(mtd, ((loff_t) page) << - chip->page_shift, 0, allowbbt)) { - pr_warn("%s: attempt to erase a bad block at page 0x%08x\n", - __func__, page); - instr->state = MTD_ERASE_FAILED; - goto erase_exit; - } - - /* - * Invalidate the page cache, if we erase the block which - * contains the current cached page. - */ - if (page <= chip->pagebuf && chip->pagebuf < - (page + pages_per_block)) - chip->pagebuf = -1; - - chip->erase_cmd(mtd, page & chip->pagemask); - - status = chip->waitfunc(mtd, chip); - - /* - * See if operation failed and additional status checks are - * available - */ - if ((status & NAND_STATUS_FAIL) && (chip->errstat)) - status = chip->errstat(mtd, chip, FL_ERASING, - status, page); - - /* See if block erase succeeded */ - if (status & NAND_STATUS_FAIL) { - MTDDEBUG(MTD_DEBUG_LEVEL0, "%s: Failed erase, " - "page 0x%08x\n", __func__, page); - instr->state = MTD_ERASE_FAILED; - instr->fail_addr = - ((loff_t)page << chip->page_shift); - goto erase_exit; - } - - /* - * If BBT requires refresh, set the BBT rewrite flag to the - * page being erased. - */ - if (bbt_masked_page != 0xffffffff && - (page & BBT_PAGE_MASK) == bbt_masked_page) - rewrite_bbt[chipnr] = - ((loff_t)page << chip->page_shift); - - /* Increment page address and decrement length */ - len -= (1 << chip->phys_erase_shift); - page += pages_per_block; - - /* Check, if we cross a chip boundary */ - if (len && !(page & chip->pagemask)) { - chipnr++; - chip->select_chip(mtd, -1); - chip->select_chip(mtd, chipnr); - - /* - * If BBT requires refresh and BBT-PERCHIP, set the BBT - * page mask to see if this BBT should be rewritten. - */ - if (bbt_masked_page != 0xffffffff && - (chip->bbt_td->options & NAND_BBT_PERCHIP)) - bbt_masked_page = chip->bbt_td->pages[chipnr] & - BBT_PAGE_MASK; - } - } - instr->state = MTD_ERASE_DONE; - -erase_exit: - - ret = instr->state == MTD_ERASE_DONE ? 0 : -EIO; - - /* Deselect and wake up anyone waiting on the device */ - nand_release_device(mtd); - - /* Do call back function */ - if (!ret) - mtd_erase_callback(instr); - - /* - * If BBT requires refresh and erase was successful, rewrite any - * selected bad block tables. - */ - if (bbt_masked_page == 0xffffffff || ret) - return ret; - - for (chipnr = 0; chipnr < chip->numchips; chipnr++) { - if (!rewrite_bbt[chipnr]) - continue; - /* Update the BBT for chip */ - MTDDEBUG(MTD_DEBUG_LEVEL0, "%s: nand_update_bbt " - "(%d:0x%0llx 0x%0x)\n", __func__, chipnr, - rewrite_bbt[chipnr], chip->bbt_td->pages[chipnr]); - nand_update_bbt(mtd, rewrite_bbt[chipnr]); - } - - /* Return more or less happy */ - return ret; -} - -/** - * nand_sync - [MTD Interface] sync - * @mtd: MTD device structure - * - * Sync is actually a wait for chip ready function. - */ -static void nand_sync(struct mtd_info *mtd) -{ - struct nand_chip *chip = mtd->priv; - - MTDDEBUG(MTD_DEBUG_LEVEL3, "%s: called\n", __func__); - - /* Grab the lock and see if the device is available */ - nand_get_device(chip, mtd, FL_SYNCING); - /* Release it and go back */ - nand_release_device(mtd); -} - -/** - * nand_block_isbad - [MTD Interface] Check if block at offset is bad - * @mtd: MTD device structure - * @offs: offset relative to mtd start - */ -static int nand_block_isbad(struct mtd_info *mtd, loff_t offs) -{ - return nand_block_checkbad(mtd, offs, 1, 0); -} - -/** - * nand_block_markbad - [MTD Interface] Mark block at the given offset as bad - * @mtd: MTD device structure - * @ofs: offset relative to mtd start - */ -static int nand_block_markbad(struct mtd_info *mtd, loff_t ofs) -{ - struct nand_chip *chip = mtd->priv; - int ret; - - ret = nand_block_isbad(mtd, ofs); - if (ret) { - /* If it was bad already, return success and do nothing */ - if (ret > 0) - return 0; - return ret; - } - - return chip->block_markbad(mtd, ofs); -} - - /** - * nand_onfi_set_features- [REPLACEABLE] set features for ONFI nand - * @mtd: MTD device structure - * @chip: nand chip info structure - * @addr: feature address. - * @subfeature_param: the subfeature parameters, a four bytes array. - */ -static int nand_onfi_set_features(struct mtd_info *mtd, struct nand_chip *chip, - int addr, uint8_t *subfeature_param) -{ - int status; - - if (!chip->onfi_version) - return -EINVAL; - - chip->cmdfunc(mtd, NAND_CMD_SET_FEATURES, addr, -1); - chip->write_buf(mtd, subfeature_param, ONFI_SUBFEATURE_PARAM_LEN); - status = chip->waitfunc(mtd, chip); - if (status & NAND_STATUS_FAIL) - return -EIO; - return 0; -} - -/** - * nand_onfi_get_features- [REPLACEABLE] get features for ONFI nand - * @mtd: MTD device structure - * @chip: nand chip info structure - * @addr: feature address. - * @subfeature_param: the subfeature parameters, a four bytes array. - */ -static int nand_onfi_get_features(struct mtd_info *mtd, struct nand_chip *chip, - int addr, uint8_t *subfeature_param) -{ - if (!chip->onfi_version) - return -EINVAL; - - /* clear the sub feature parameters */ - memset(subfeature_param, 0, ONFI_SUBFEATURE_PARAM_LEN); - - chip->cmdfunc(mtd, NAND_CMD_GET_FEATURES, addr, -1); - chip->read_buf(mtd, subfeature_param, ONFI_SUBFEATURE_PARAM_LEN); - return 0; -} - -/* Set default functions */ -static void nand_set_defaults(struct nand_chip *chip, int busw) -{ - /* check for proper chip_delay setup, set 20us if not */ - if (!chip->chip_delay) - chip->chip_delay = 20; - - /* check, if a user supplied command function given */ - if (chip->cmdfunc == NULL) - chip->cmdfunc = nand_command; - - /* check, if a user supplied wait function given */ - if (chip->waitfunc == NULL) - chip->waitfunc = nand_wait; - - if (!chip->select_chip) - chip->select_chip = nand_select_chip; - if (!chip->read_byte) - chip->read_byte = busw ? nand_read_byte16 : nand_read_byte; - if (!chip->read_word) - chip->read_word = nand_read_word; - if (!chip->block_bad) - chip->block_bad = nand_block_bad; - if (!chip->block_markbad) - chip->block_markbad = nand_default_block_markbad; - if (!chip->write_buf) - chip->write_buf = busw ? nand_write_buf16 : nand_write_buf; - if (!chip->read_buf) - chip->read_buf = busw ? nand_read_buf16 : nand_read_buf; - if (!chip->verify_buf) - chip->verify_buf = busw ? nand_verify_buf16 : nand_verify_buf; - if (!chip->scan_bbt) - chip->scan_bbt = nand_default_bbt; - if (!chip->controller) - chip->controller = &chip->hwcontrol; -} - -#ifdef CONFIG_SYS_NAND_ONFI_DETECTION -/* Sanitize ONFI strings so we can safely print them */ -static void sanitize_string(char *s, size_t len) -{ - ssize_t i; - - /* Null terminate */ - s[len - 1] = 0; - - /* Remove non printable chars */ - for (i = 0; i < len - 1; i++) { - if (s[i] < ' ' || s[i] > 127) - s[i] = '?'; - } - - /* Remove trailing spaces */ - strim(s); -} - -static u16 onfi_crc16(u16 crc, u8 const *p, size_t len) -{ - int i; - while (len--) { - crc ^= *p++ << 8; - for (i = 0; i < 8; i++) - crc = (crc << 1) ^ ((crc & 0x8000) ? 0x8005 : 0); - } - - return crc; -} - -/* - * Check if the NAND chip is ONFI compliant, returns 1 if it is, 0 otherwise. - */ -static int nand_flash_detect_onfi(struct mtd_info *mtd, struct nand_chip *chip, - int *busw) -{ - struct nand_onfi_params *p = &chip->onfi_params; - int i; - int val; - - /* 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; - - 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) - return 0; - - /* Check version */ - val = le16_to_cpu(p->revision); - if (val & (1 << 5)) - chip->onfi_version = 23; - else if (val & (1 << 4)) - chip->onfi_version = 22; - else if (val & (1 << 3)) - chip->onfi_version = 21; - else if (val & (1 << 2)) - chip->onfi_version = 20; - else if (val & (1 << 1)) - chip->onfi_version = 10; - else - chip->onfi_version = 0; - - if (!chip->onfi_version) { - pr_info("%s: unsupported ONFI version: %d\n", __func__, val); - return 0; - } - - sanitize_string(p->manufacturer, sizeof(p->manufacturer)); - 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; - mtd->oobsize = le16_to_cpu(p->spare_bytes_per_page); - chip->chipsize = le32_to_cpu(p->blocks_per_lun); - chip->chipsize *= (uint64_t)mtd->erasesize * p->lun_count; - *busw = 0; - if (le16_to_cpu(p->features) & 1) - *busw = NAND_BUSWIDTH_16; - - pr_info("ONFI flash detected\n"); - return 1; -} -#else -static inline int nand_flash_detect_onfi(struct mtd_info *mtd, - struct nand_chip *chip, - int *busw) -{ - return 0; -} -#endif - -/* - * nand_id_has_period - Check if an ID string has a given wraparound period - * @id_data: the ID string - * @arrlen: the length of the @id_data array - * @period: the period of repitition - * - * Check if an ID string is repeated within a given sequence of bytes at - * specific repetition interval period (e.g., {0x20,0x01,0x7F,0x20} has a - * period of 2). This is a helper function for nand_id_len(). Returns non-zero - * if the repetition has a period of @period; otherwise, returns zero. - */ -static int nand_id_has_period(u8 *id_data, int arrlen, int period) -{ - int i, j; - for (i = 0; i < period; i++) - for (j = i + period; j < arrlen; j += period) - if (id_data[i] != id_data[j]) - return 0; - return 1; -} - -/* - * nand_id_len - Get the length of an ID string returned by CMD_READID - * @id_data: the ID string - * @arrlen: the length of the @id_data array - - * Returns the length of the ID string, according to known wraparound/trailing - * zero patterns. If no pattern exists, returns the length of the array. - */ -static int nand_id_len(u8 *id_data, int arrlen) -{ - int last_nonzero, period; - - /* Find last non-zero byte */ - for (last_nonzero = arrlen - 1; last_nonzero >= 0; last_nonzero--) - if (id_data[last_nonzero]) - break; - - /* All zeros */ - if (last_nonzero < 0) - return 0; - - /* Calculate wraparound period */ - for (period = 1; period < arrlen; period++) - if (nand_id_has_period(id_data, arrlen, period)) - break; - - /* There's a repeated pattern */ - if (period < arrlen) - return period; - - /* There are trailing zeros */ - if (last_nonzero < arrlen - 1) - return last_nonzero + 1; - - /* No pattern detected */ - return arrlen; -} - -/* - * 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 - * manufacturer-specific "extended ID" decoding patterns. - */ -static void nand_decode_ext_id(struct mtd_info *mtd, struct nand_chip *chip, - u8 id_data[8], int *busw) -{ - int extid, id_len; - /* The 3rd id byte holds MLC / multichip data */ - chip->cellinfo = id_data[2]; - /* The 4th id byte is the important one */ - extid = id_data[3]; - - id_len = nand_id_len(id_data, 8); - - /* - * Field definitions are in the following datasheets: - * Old style (4,5 byte ID): Samsung K9GAG08U0M (p.32) - * New Samsung (6 byte ID): Samsung K9GAG08U0F (p.44) - * Hynix MLC (6 byte ID): Hynix H27UBG8T2B (p.22) - * - * Check for ID length, non-zero 6th byte, cell type, and Hynix/Samsung - * 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) { - /* Calc pagesize */ - mtd->writesize = 2048 << (extid & 0x03); - extid >>= 2; - /* Calc oobsize */ - switch (((extid >> 2) & 0x04) | (extid & 0x03)) { - case 1: - mtd->oobsize = 128; - break; - case 2: - mtd->oobsize = 218; - break; - case 3: - mtd->oobsize = 400; - break; - case 4: - mtd->oobsize = 436; - break; - case 5: - mtd->oobsize = 512; - break; - case 6: - default: /* Other cases are "reserved" (unknown) */ - mtd->oobsize = 640; - break; - } - extid >>= 2; - /* Calc blocksize */ - mtd->erasesize = (128 * 1024) << - (((extid >> 1) & 0x04) | (extid & 0x03)); - *busw = 0; - } else if (id_len == 6 && id_data[0] == NAND_MFR_HYNIX && - (chip->cellinfo & NAND_CI_CELLTYPE_MSK)) { - unsigned int tmp; - - /* Calc pagesize */ - mtd->writesize = 2048 << (extid & 0x03); - extid >>= 2; - /* Calc oobsize */ - switch (((extid >> 2) & 0x04) | (extid & 0x03)) { - case 0: - mtd->oobsize = 128; - break; - case 1: - mtd->oobsize = 224; - break; - case 2: - mtd->oobsize = 448; - break; - case 3: - mtd->oobsize = 64; - break; - case 4: - mtd->oobsize = 32; - break; - case 5: - mtd->oobsize = 16; - break; - default: - mtd->oobsize = 640; - break; - } - extid >>= 2; - /* Calc blocksize */ - tmp = ((extid >> 1) & 0x04) | (extid & 0x03); - if (tmp < 0x03) - mtd->erasesize = (128 * 1024) << tmp; - else if (tmp == 0x03) - mtd->erasesize = 768 * 1024; - else - mtd->erasesize = (64 * 1024) << tmp; - *busw = 0; - } else { - /* Calc pagesize */ - mtd->writesize = 1024 << (extid & 0x03); - extid >>= 2; - /* Calc oobsize */ - mtd->oobsize = (8 << (extid & 0x01)) * - (mtd->writesize >> 9); - extid >>= 2; - /* Calc blocksize. Blocksize is multiples of 64KiB */ - mtd->erasesize = (64 * 1024) << (extid & 0x03); - extid >>= 2; - /* Get buswidth information */ - *busw = (extid & 0x01) ? NAND_BUSWIDTH_16 : 0; - } -} - - /* - * Old devices have chip data hardcoded in the device ID table. nand_decode_id - * decodes a matching ID table entry and assigns the MTD size parameters for - * the chip. - */ -static void nand_decode_id(struct mtd_info *mtd, struct nand_chip *chip, - const struct nand_flash_dev *type, u8 id_data[8], - int *busw) -{ - int maf_id = id_data[0]; - - mtd->erasesize = type->erasesize; - mtd->writesize = type->pagesize; - mtd->oobsize = mtd->writesize / 32; - *busw = type->options & NAND_BUSWIDTH_16; - - /* - * Check for Spansion/AMD ID + repeating 5th, 6th byte since - * some Spansion chips have erasesize that conflicts with size - * listed in nand_ids table. - * Data sheet (5 byte ID): Spansion S30ML-P ORNAND (p.39) - */ - if (maf_id == NAND_MFR_AMD && id_data[4] != 0x00 && id_data[5] == 0x00 - && id_data[6] == 0x00 && id_data[7] == 0x00 - && mtd->writesize == 512) { - mtd->erasesize = 128 * 1024; - mtd->erasesize <<= ((id_data[3] & 0x03) << 1); - } -} - - /* - * Set the bad block marker/indicator (BBM/BBI) patterns according to some - * heuristic patterns using various detected parameters (e.g., manufacturer, - * page size, cell-type information). - */ -static void nand_decode_bbm_options(struct mtd_info *mtd, - struct nand_chip *chip, u8 id_data[8]) -{ - int maf_id = id_data[0]; - - /* Set the bad block position */ - if (mtd->writesize > 512 || (chip->options & NAND_BUSWIDTH_16)) - chip->badblockpos = NAND_LARGE_BADBLOCK_POS; - else - chip->badblockpos = NAND_SMALL_BADBLOCK_POS; - - /* - * Bad block marker is stored in the last page of each block on Samsung - * and Hynix MLC devices; stored in first two pages of each block on - * 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) && - (maf_id == NAND_MFR_SAMSUNG || - maf_id == NAND_MFR_HYNIX)) - chip->bbt_options |= NAND_BBT_SCANLASTPAGE; - else if ((!(chip->cellinfo & NAND_CI_CELLTYPE_MSK) && - (maf_id == NAND_MFR_SAMSUNG || - maf_id == NAND_MFR_HYNIX || - maf_id == NAND_MFR_TOSHIBA || - maf_id == NAND_MFR_AMD || - maf_id == NAND_MFR_MACRONIX)) || - (mtd->writesize == 2048 && - maf_id == NAND_MFR_MICRON)) - chip->bbt_options |= NAND_BBT_SCAN2NDPAGE; -} - -/* - * Get the flash and manufacturer id and lookup if the type is supported. - */ -static const struct nand_flash_dev *nand_get_flash_type(struct mtd_info *mtd, - struct nand_chip *chip, - int busw, - int *maf_id, int *dev_id, - const struct nand_flash_dev *type) -{ - const char *name; - int i, maf_idx; - u8 id_data[8]; - - /* Select the device */ - chip->select_chip(mtd, 0); - - /* - * Reset the chip, required by some chips (e.g. Micron MT29FxGxxxxx) - * after power-up. - */ - chip->cmdfunc(mtd, NAND_CMD_RESET, -1, -1); - - /* Send the command for reading device ID */ - chip->cmdfunc(mtd, NAND_CMD_READID, 0x00, -1); - - /* Read manufacturer and device IDs */ - *maf_id = chip->read_byte(mtd); - *dev_id = chip->read_byte(mtd); - - /* - * Try again to make sure, as some systems the bus-hold or other - * interface concerns can cause random data which looks like a - * possibly credible NAND flash to appear. If the two results do - * not match, ignore the device completely. - */ - - chip->cmdfunc(mtd, NAND_CMD_READID, 0x00, -1); - - /* Read entire ID string */ - for (i = 0; i < 8; i++) - id_data[i] = chip->read_byte(mtd); - - if (id_data[0] != *maf_id || id_data[1] != *dev_id) { - pr_info("%s: second ID read did not match " - "%02x,%02x against %02x,%02x\n", __func__, - *maf_id, *dev_id, id_data[0], id_data[1]); - return ERR_PTR(-ENODEV); - } - - if (!type) - type = nand_flash_ids; - - for (; type->name != NULL; type++) - if (*dev_id == type->id) - break; - - chip->onfi_version = 0; - if (!type->name || !type->pagesize) { - /* Check is chip is ONFI compliant */ - if (nand_flash_detect_onfi(mtd, chip, &busw)) - goto ident_done; - } - - if (!type->name) - return ERR_PTR(-ENODEV); - - if (!mtd->name) - mtd->name = type->name; - - chip->chipsize = (uint64_t)type->chipsize << 20; - - if (!type->pagesize && chip->init_size) { - /* Set the pagesize, oobsize, erasesize by the driver */ - busw = chip->init_size(mtd, chip, id_data); - } else if (!type->pagesize) { - /* Decode parameters from extended ID */ - nand_decode_ext_id(mtd, chip, id_data, &busw); - } else { - nand_decode_id(mtd, chip, type, id_data, &busw); - } - /* Get chip options, preserve non chip based options */ - chip->options |= type->options; - - /* - * Check if chip is not a Samsung device. Do not clear the - * options for chips which do not have an extended id. - */ - if (*maf_id != NAND_MFR_SAMSUNG && !type->pagesize) - chip->options &= ~NAND_SAMSUNG_LP_OPTIONS; -ident_done: - - /* Try to identify manufacturer */ - for (maf_idx = 0; nand_manuf_ids[maf_idx].id != 0x0; maf_idx++) { - if (nand_manuf_ids[maf_idx].id == *maf_id) - break; - } - - /* - * Check, if buswidth is correct. Hardware drivers should set - * chip correct! - */ - if (busw != (chip->options & NAND_BUSWIDTH_16)) { - 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, mtd->name); - pr_warn("NAND bus width %d instead %d bit\n", - (chip->options & NAND_BUSWIDTH_16) ? 16 : 8, - busw ? 16 : 8); - return ERR_PTR(-EINVAL); - } - - nand_decode_bbm_options(mtd, chip, id_data); - - /* Calculate the address shift from the page size */ - chip->page_shift = ffs(mtd->writesize) - 1; - /* Convert chipsize to number of pages per chip -1 */ - chip->pagemask = (chip->chipsize >> chip->page_shift) - 1; - - chip->bbt_erase_shift = chip->phys_erase_shift = - ffs(mtd->erasesize) - 1; - if (chip->chipsize & 0xffffffff) - chip->chip_shift = ffs((unsigned)chip->chipsize) - 1; - else { - chip->chip_shift = ffs((unsigned)(chip->chipsize >> 32)); - chip->chip_shift += 32 - 1; - } - - chip->badblockbits = 8; - - /* Check for AND chips with 4 page planes */ - if (chip->options & NAND_4PAGE_ARRAY) - chip->erase_cmd = multi_erase_cmd; - else - chip->erase_cmd = single_erase_cmd; - - /* Do not replace user supplied command function! */ - if (mtd->writesize > 512 && chip->cmdfunc == nand_command) - chip->cmdfunc = nand_command_lp; - - name = type->name; -#ifdef CONFIG_SYS_NAND_ONFI_DETECTION - if (chip->onfi_version) - name = chip->onfi_params.model; -#endif - pr_info("NAND device: Manufacturer ID: 0x%02x, Chip ID: 0x%02x (%s %s)," - " page size: %d, OOB size: %d\n", - *maf_id, *dev_id, nand_manuf_ids[maf_idx].name, - name, - mtd->writesize, mtd->oobsize); - - return type; -} - -/** - * nand_scan_ident - [NAND Interface] Scan for the NAND device - * @mtd: MTD device structure - * @maxchips: number of chips to scan for - * @table: alternative NAND ID table - * - * This is the first phase of the normal nand_scan() function. It reads the - * flash ID and sets up MTD fields accordingly. - * - * The mtd->owner field must be set to the module of the caller. - */ -int nand_scan_ident(struct mtd_info *mtd, int maxchips, - const struct nand_flash_dev *table) -{ - int i, busw, nand_maf_id, nand_dev_id; - struct nand_chip *chip = mtd->priv; - const struct nand_flash_dev *type; - - /* Get buswidth to select the correct functions */ - busw = chip->options & NAND_BUSWIDTH_16; - /* Set the default functions */ - nand_set_defaults(chip, busw); - - /* Read the flash type */ - type = nand_get_flash_type(mtd, chip, busw, - &nand_maf_id, &nand_dev_id, table); - - if (IS_ERR(type)) { -#ifndef CONFIG_SYS_NAND_QUIET_TEST - pr_warn("No NAND device found\n"); -#endif - chip->select_chip(mtd, -1); - return PTR_ERR(type); - } - - /* Check for a chip array */ - for (i = 1; i < maxchips; i++) { - chip->select_chip(mtd, i); - /* See comment in nand_get_flash_type for reset */ - chip->cmdfunc(mtd, NAND_CMD_RESET, -1, -1); - /* Send the command for reading device ID */ - chip->cmdfunc(mtd, NAND_CMD_READID, 0x00, -1); - /* Read manufacturer and device IDs */ - if (nand_maf_id != chip->read_byte(mtd) || - nand_dev_id != chip->read_byte(mtd)) - break; - } -#ifdef DEBUG - if (i > 1) - pr_info("%d NAND chips detected\n", i); -#endif - - /* Store the number of chips and calc total size for mtd */ - chip->numchips = i; - mtd->size = i * chip->chipsize; - - return 0; -} - - -/** - * nand_scan_tail - [NAND Interface] Scan for the NAND device - * @mtd: MTD device structure - * - * This is the second phase of the normal nand_scan() function. It fills out - * all the uninitialized function pointers with the defaults and scans for a - * bad block table if appropriate. - */ -int nand_scan_tail(struct mtd_info *mtd) -{ - int i; - struct nand_chip *chip = mtd->priv; - - /* New bad blocks should be marked in OOB, flash-based BBT, or both */ - BUG_ON((chip->bbt_options & NAND_BBT_NO_OOB_BBM) && - !(chip->bbt_options & NAND_BBT_USE_FLASH)); - - if (!(chip->options & NAND_OWN_BUFFERS)) - chip->buffers = memalign(ARCH_DMA_MINALIGN, - sizeof(*chip->buffers)); - if (!chip->buffers) - return -ENOMEM; - - /* Set the internal oob buffer location, just after the page data */ - chip->oob_poi = chip->buffers->databuf + mtd->writesize; - - /* - * If no default placement scheme is given, select an appropriate one. - */ - if (!chip->ecc.layout && (chip->ecc.mode != NAND_ECC_SOFT_BCH)) { - switch (mtd->oobsize) { - case 8: - chip->ecc.layout = &nand_oob_8; - break; - case 16: - chip->ecc.layout = &nand_oob_16; - break; - case 64: - chip->ecc.layout = &nand_oob_64; - break; - case 128: - chip->ecc.layout = &nand_oob_128; - break; - default: - pr_warn("No oob scheme defined for oobsize %d\n", - mtd->oobsize); - } - } - - if (!chip->write_page) - chip->write_page = nand_write_page; - - /* set for ONFI nand */ - if (!chip->onfi_set_features) - chip->onfi_set_features = nand_onfi_set_features; - if (!chip->onfi_get_features) - chip->onfi_get_features = nand_onfi_get_features; - - /* - * Check ECC mode, default to software if 3byte/512byte hardware ECC is - * selected and we have 256 byte pagesize fallback to software ECC - */ - - switch (chip->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) { - 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; - - 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; - - 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)) { - 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 (mtd->writesize >= chip->ecc.size) { - if (!chip->ecc.strength) { - pr_warn("Driver must set ecc.strength when using hardware ECC\n"); - BUG(); - } - break; - } - 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; - - 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; - break; - - case NAND_ECC_SOFT_BCH: - if (!mtd_nand_has_bch()) { - pr_warn("CONFIG_MTD_ECC_BCH not enabled\n"); - return -EINVAL; - } - 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; - /* - * 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; - } - chip->ecc.priv = nand_bch_init(mtd, - chip->ecc.size, - chip->ecc.bytes, - &chip->ecc.layout); - if (!chip->ecc.priv) - pr_warn("BCH ECC initialization failed!\n"); - chip->ecc.strength = - chip->ecc.bytes * 8 / fls(8 * chip->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; - break; - - default: - pr_warn("Invalid NAND_ECC_MODE %d\n", chip->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; - - /* - * 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; - - /* - * 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) { - pr_warn("Invalid ECC parameters\n"); - BUG(); - } - chip->ecc.total = chip->ecc.steps * chip->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) { - case 2: - mtd->subpage_sft = 1; - break; - case 4: - case 8: - case 16: - mtd->subpage_sft = 2; - break; - } - } - chip->subpagesize = mtd->writesize >> mtd->subpage_sft; - - /* Initialize state */ - chip->state = FL_READY; - - /* De-select the device */ - chip->select_chip(mtd, -1); - - /* Invalidate the pagebuffer reference */ - chip->pagebuf = -1; - - /* Large page NAND with SOFT_ECC should support subpage reads */ - if ((chip->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->flags = (chip->options & NAND_ROM) ? MTD_CAP_ROM : - MTD_CAP_NANDFLASH; - mtd->_erase = nand_erase; - mtd->_point = NULL; - mtd->_unpoint = NULL; - mtd->_read = nand_read; - mtd->_write = nand_write; - mtd->_read_oob = nand_read_oob; - mtd->_write_oob = nand_write_oob; - mtd->_sync = nand_sync; - mtd->_lock = NULL; - mtd->_unlock = NULL; - mtd->_block_isbad = nand_block_isbad; - mtd->_block_markbad = nand_block_markbad; - - /* propagate ecc info to mtd_info */ - mtd->ecclayout = chip->ecc.layout; - mtd->ecc_strength = chip->ecc.strength; - /* - * Initialize bitflip_threshold to its default prior scan_bbt() call. - * scan_bbt() might invoke mtd_read(), thus bitflip_threshold must be - * properly set. - */ - if (!mtd->bitflip_threshold) - mtd->bitflip_threshold = mtd->ecc_strength; - - /* Check, if we should skip the bad block table scan */ - if (chip->options & NAND_SKIP_BBTSCAN) - chip->options |= NAND_BBT_SCANNED; - - return 0; -} - -/** - * nand_scan - [NAND Interface] Scan for the NAND device - * @mtd: MTD device structure - * @maxchips: number of chips to scan for - * - * This fills out all the uninitialized function pointers with the defaults. - * The flash ID is read and the mtd/chip structures are filled with the - * appropriate values. The mtd->owner field must be set to the module of the - * caller. - */ -int nand_scan(struct mtd_info *mtd, int maxchips) -{ - int ret; - - ret = nand_scan_ident(mtd, maxchips, NULL); - if (!ret) - ret = nand_scan_tail(mtd); - return ret; -} - -/** - * nand_release - [NAND Interface] Free resources held by the NAND device - * @mtd: MTD device structure - */ -void nand_release(struct mtd_info *mtd) -{ - struct nand_chip *chip = mtd->priv; - - if (chip->ecc.mode == NAND_ECC_SOFT_BCH) - nand_bch_free((struct nand_bch_control *)chip->ecc.priv); - -#ifdef CONFIG_MTD_PARTITIONS - /* Deregister partitions */ - del_mtd_partitions(mtd); -#endif - - /* Free bad block table memory */ - kfree(chip->bbt); - if (!(chip->options & NAND_OWN_BUFFERS)) - kfree(chip->buffers); - - /* Free bad block descriptor memory */ - if (chip->badblock_pattern && chip->badblock_pattern->options - & NAND_BBT_DYNAMICSTRUCT) - kfree(chip->badblock_pattern); -} diff --git a/qemu/roms/u-boot/drivers/mtd/nand/nand_bbt.c b/qemu/roms/u-boot/drivers/mtd/nand/nand_bbt.c deleted file mode 100644 index 8ef58451d..000000000 --- a/qemu/roms/u-boot/drivers/mtd/nand/nand_bbt.c +++ /dev/null @@ -1,1397 +0,0 @@ -/* - * drivers/mtd/nand_bbt.c - * - * Overview: - * Bad block table support for the NAND driver - * - * Copyright © 2004 Thomas Gleixner (tglx@linutronix.de) - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. - * - * Description: - * - * When nand_scan_bbt is called, then it tries to find the bad block table - * depending on the options in the BBT descriptor(s). If no flash based BBT - * (NAND_BBT_USE_FLASH) is specified then the device is scanned for factory - * marked good / bad blocks. This information is used to create a memory BBT. - * Once a new bad block is discovered then the "factory" information is updated - * on the device. - * If a flash based BBT is specified then the function first tries to find the - * BBT on flash. If a BBT is found then the contents are read and the memory - * based BBT is created. If a mirrored BBT is selected then the mirror is - * searched too and the versions are compared. If the mirror has a greater - * version number, then the mirror BBT is used to build the memory based BBT. - * If the tables are not versioned, then we "or" the bad block information. - * If one of the BBTs is out of date or does not exist it is (re)created. - * If no BBT exists at all then the device is scanned for factory marked - * good / bad blocks and the bad block tables are created. - * - * For manufacturer created BBTs like the one found on M-SYS DOC devices - * the BBT is searched and read but never created - * - * The auto generated bad block table is located in the last good blocks - * of the device. The table is mirrored, so it can be updated eventually. - * The table is marked in the OOB area with an ident pattern and a version - * number which indicates which of both tables is more up to date. If the NAND - * controller needs the complete OOB area for the ECC information then the - * option NAND_BBT_NO_OOB should be used (along with NAND_BBT_USE_FLASH, of - * course): it moves the ident pattern and the version byte into the data area - * and the OOB area will remain untouched. - * - * The table uses 2 bits per block - * 11b: block is good - * 00b: block is factory marked bad - * 01b, 10b: block is marked bad due to wear - * - * The memory bad block table uses the following scheme: - * 00b: block is good - * 01b: block is marked bad due to wear - * 10b: block is reserved (to protect the bbt area) - * 11b: block is factory marked bad - * - * Multichip devices like DOC store the bad block info per floor. - * - * Following assumptions are made: - * - bbts start at a page boundary, if autolocated on a block boundary - * - the space necessary for a bbt in FLASH does not exceed a block boundary - * - */ - -#include <common.h> -#include <malloc.h> -#include <linux/compat.h> -#include <linux/mtd/mtd.h> -#include <linux/mtd/bbm.h> -#include <linux/mtd/nand.h> -#include <linux/mtd/nand_ecc.h> -#include <linux/bitops.h> -#include <linux/string.h> - -#include <asm/errno.h> - -static int check_pattern_no_oob(uint8_t *buf, struct nand_bbt_descr *td) -{ - if (memcmp(buf, td->pattern, td->len)) - return -1; - return 0; -} - -/** - * check_pattern - [GENERIC] check if a pattern is in the buffer - * @buf: the buffer to search - * @len: the length of buffer to search - * @paglen: the pagelength - * @td: search pattern descriptor - * - * Check for a pattern at the given place. Used to search bad block tables and - * good / bad block identifiers. If the SCAN_EMPTY option is set then check, if - * all bytes except the pattern area contain 0xff. - */ -static int check_pattern(uint8_t *buf, int len, int paglen, struct nand_bbt_descr *td) -{ - int end = 0; - uint8_t *p = buf; - - if (td->options & NAND_BBT_NO_OOB) - return check_pattern_no_oob(buf, td); - - end = paglen + td->offs; - if (td->options & NAND_BBT_SCANEMPTY) - if (memchr_inv(p, 0xff, end)) - return -1; - p += end; - - /* Compare the pattern */ - if (memcmp(p, td->pattern, td->len)) - return -1; - - if (td->options & NAND_BBT_SCANEMPTY) { - p += td->len; - end += td->len; - if (memchr_inv(p, 0xff, len - end)) - return -1; - } - return 0; -} - -/** - * check_short_pattern - [GENERIC] check if a pattern is in the buffer - * @buf: the buffer to search - * @td: search pattern descriptor - * - * Check for a pattern at the given place. Used to search bad block tables and - * good / bad block identifiers. Same as check_pattern, but no optional empty - * check. - */ -static int check_short_pattern(uint8_t *buf, struct nand_bbt_descr *td) -{ - /* Compare the pattern */ - if (memcmp(buf + td->offs, td->pattern, td->len)) - return -1; - return 0; -} - -/** - * add_marker_len - compute the length of the marker in data area - * @td: BBT descriptor used for computation - * - * The length will be 0 if the marker is located in OOB area. - */ -static u32 add_marker_len(struct nand_bbt_descr *td) -{ - u32 len; - - if (!(td->options & NAND_BBT_NO_OOB)) - return 0; - - len = td->len; - if (td->options & NAND_BBT_VERSION) - len++; - return len; -} - -/** - * read_bbt - [GENERIC] Read the bad block table starting from page - * @mtd: MTD device structure - * @buf: temporary buffer - * @page: the starting page - * @num: the number of bbt descriptors to read - * @td: the bbt describtion table - * @offs: offset in the memory table - * - * Read the bad block table starting from page. - */ -static int read_bbt(struct mtd_info *mtd, uint8_t *buf, int page, int num, - struct nand_bbt_descr *td, int offs) -{ - int res, ret = 0, i, j, act = 0; - struct nand_chip *this = mtd->priv; - size_t retlen, len, totlen; - loff_t from; - int bits = td->options & NAND_BBT_NRBITS_MSK; - uint8_t msk = (uint8_t)((1 << bits) - 1); - u32 marker_len; - int reserved_block_code = td->reserved_block_code; - - totlen = (num * bits) >> 3; - marker_len = add_marker_len(td); - from = ((loff_t)page) << this->page_shift; - - while (totlen) { - len = min(totlen, (size_t)(1 << this->bbt_erase_shift)); - if (marker_len) { - /* - * In case the BBT marker is not in the OOB area it - * will be just in the first page. - */ - len -= marker_len; - from += marker_len; - marker_len = 0; - } - res = mtd_read(mtd, from, len, &retlen, buf); - if (res < 0) { - if (mtd_is_eccerr(res)) { - pr_info("nand_bbt: ECC error in BBT at " - "0x%012llx\n", from & ~mtd->writesize); - return res; - } else if (mtd_is_bitflip(res)) { - pr_info("nand_bbt: corrected error in BBT at " - "0x%012llx\n", from & ~mtd->writesize); - ret = res; - } else { - pr_info("nand_bbt: error reading BBT\n"); - return res; - } - } - - /* Analyse data */ - for (i = 0; i < len; i++) { - uint8_t dat = buf[i]; - for (j = 0; j < 8; j += bits, act += 2) { - uint8_t tmp = (dat >> j) & msk; - if (tmp == msk) - continue; - if (reserved_block_code && (tmp == reserved_block_code)) { - pr_info("nand_read_bbt: reserved block at 0x%012llx\n", - (loff_t)((offs << 2) + (act >> 1)) << this->bbt_erase_shift); - this->bbt[offs + (act >> 3)] |= 0x2 << (act & 0x06); - mtd->ecc_stats.bbtblocks++; - continue; - } - pr_info("nand_read_bbt: Bad block at 0x%012llx\n", - (loff_t)((offs << 2) + (act >> 1)) - << this->bbt_erase_shift); - /* Factory marked bad or worn out? */ - if (tmp == 0) - this->bbt[offs + (act >> 3)] |= 0x3 << (act & 0x06); - else - this->bbt[offs + (act >> 3)] |= 0x1 << (act & 0x06); - mtd->ecc_stats.badblocks++; - } - } - totlen -= len; - from += len; - } - return ret; -} - -/** - * read_abs_bbt - [GENERIC] Read the bad block table starting at a given page - * @mtd: MTD device structure - * @buf: temporary buffer - * @td: descriptor for the bad block table - * @chip: read the table for a specific chip, -1 read all chips; applies only if - * NAND_BBT_PERCHIP option is set - * - * Read the bad block table for all chips starting at a given page. We assume - * that the bbt bits are in consecutive order. - */ -static int read_abs_bbt(struct mtd_info *mtd, uint8_t *buf, struct nand_bbt_descr *td, int chip) -{ - struct nand_chip *this = mtd->priv; - int res = 0, i; - - if (td->options & NAND_BBT_PERCHIP) { - int offs = 0; - for (i = 0; i < this->numchips; i++) { - if (chip == -1 || chip == i) - res = read_bbt(mtd, buf, td->pages[i], - this->chipsize >> this->bbt_erase_shift, - td, offs); - if (res) - return res; - offs += this->chipsize >> (this->bbt_erase_shift + 2); - } - } else { - res = read_bbt(mtd, buf, td->pages[0], - mtd->size >> this->bbt_erase_shift, td, 0); - if (res) - return res; - } - return 0; -} - -/* BBT marker is in the first page, no OOB */ -static int scan_read_data(struct mtd_info *mtd, uint8_t *buf, loff_t offs, - struct nand_bbt_descr *td) -{ - size_t retlen; - size_t len; - - len = td->len; - if (td->options & NAND_BBT_VERSION) - len++; - - return mtd_read(mtd, offs, len, &retlen, buf); -} - -/** - * scan_read_oob - [GENERIC] Scan data+OOB region to buffer - * @mtd: MTD device structure - * @buf: temporary buffer - * @offs: offset at which to scan - * @len: length of data region to read - * - * Scan read data from data+OOB. May traverse multiple pages, interleaving - * page,OOB,page,OOB,... in buf. Completes transfer and returns the "strongest" - * ECC condition (error or bitflip). May quit on the first (non-ECC) error. - */ -static int scan_read_oob(struct mtd_info *mtd, uint8_t *buf, loff_t offs, - size_t len) -{ - struct mtd_oob_ops ops; - int res, ret = 0; - - ops.mode = MTD_OPS_PLACE_OOB; - ops.ooboffs = 0; - ops.ooblen = mtd->oobsize; - - while (len > 0) { - ops.datbuf = buf; - ops.len = min(len, (size_t)mtd->writesize); - ops.oobbuf = buf + ops.len; - - res = mtd_read_oob(mtd, offs, &ops); - if (res) { - if (!mtd_is_bitflip_or_eccerr(res)) - return res; - else if (mtd_is_eccerr(res) || !ret) - ret = res; - } - - buf += mtd->oobsize + mtd->writesize; - len -= mtd->writesize; - offs += mtd->writesize; - } - return ret; -} - -static int scan_read(struct mtd_info *mtd, uint8_t *buf, loff_t offs, - size_t len, struct nand_bbt_descr *td) -{ - if (td->options & NAND_BBT_NO_OOB) - return scan_read_data(mtd, buf, offs, td); - else - return scan_read_oob(mtd, buf, offs, len); -} - -/* Scan write data with oob to flash */ -static int scan_write_bbt(struct mtd_info *mtd, loff_t offs, size_t len, - uint8_t *buf, uint8_t *oob) -{ - struct mtd_oob_ops ops; - - ops.mode = MTD_OPS_PLACE_OOB; - ops.ooboffs = 0; - ops.ooblen = mtd->oobsize; - ops.datbuf = buf; - ops.oobbuf = oob; - ops.len = len; - - return mtd_write_oob(mtd, offs, &ops); -} - -static u32 bbt_get_ver_offs(struct mtd_info *mtd, struct nand_bbt_descr *td) -{ - u32 ver_offs = td->veroffs; - - if (!(td->options & NAND_BBT_NO_OOB)) - ver_offs += mtd->writesize; - return ver_offs; -} - -/** - * read_abs_bbts - [GENERIC] Read the bad block table(s) for all chips starting at a given page - * @mtd: MTD device structure - * @buf: temporary buffer - * @td: descriptor for the bad block table - * @md: descriptor for the bad block table mirror - * - * Read the bad block table(s) for all chips starting at a given page. We - * assume that the bbt bits are in consecutive order. - */ -static void read_abs_bbts(struct mtd_info *mtd, uint8_t *buf, - struct nand_bbt_descr *td, struct nand_bbt_descr *md) -{ - struct nand_chip *this = mtd->priv; - - /* Read the primary version, if available */ - if (td->options & NAND_BBT_VERSION) { - scan_read(mtd, buf, (loff_t)td->pages[0] << this->page_shift, - mtd->writesize, td); - td->version[0] = buf[bbt_get_ver_offs(mtd, td)]; - pr_info("Bad block table at page %d, version 0x%02X\n", - td->pages[0], td->version[0]); - } - - /* Read the mirror version, if available */ - if (md && (md->options & NAND_BBT_VERSION)) { - scan_read(mtd, buf, (loff_t)md->pages[0] << this->page_shift, - mtd->writesize, md); - md->version[0] = buf[bbt_get_ver_offs(mtd, md)]; - pr_info("Bad block table at page %d, version 0x%02X\n", - md->pages[0], md->version[0]); - } -} - -/* 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) -{ - struct mtd_oob_ops ops; - int j, ret; - - ops.ooblen = mtd->oobsize; - ops.oobbuf = buf; - ops.ooboffs = 0; - ops.datbuf = NULL; - ops.mode = MTD_OPS_PLACE_OOB; - - for (j = 0; j < numpages; j++) { - /* - * Read the full oob until read_oob is fixed to handle single - * byte reads for 16 bit buswidth. - */ - ret = mtd_read_oob(mtd, offs, &ops); - /* Ignore ECC errors when checking for BBM */ - if (ret && !mtd_is_bitflip_or_eccerr(ret)) - return ret; - - if (check_short_pattern(buf, bd)) - return 1; - - offs += mtd->writesize; - } - return 0; -} - -/** - * create_bbt - [GENERIC] Create a bad block table by scanning the device - * @mtd: MTD device structure - * @buf: temporary buffer - * @bd: descriptor for the good/bad block search pattern - * @chip: create the table for a specific chip, -1 read all chips; applies only - * if NAND_BBT_PERCHIP option is set - * - * Create a bad block table by scanning the device for the given good/bad block - * identify pattern. - */ -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 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) - numpages = 2; - else - numpages = 1; - - if (!(bd->options & NAND_BBT_SCANEMPTY)) { - /* We need only read few bytes from the OOB area */ - scanlen = 0; - readlen = bd->len; - } else { - /* Full page content should be read */ - scanlen = mtd->writesize + mtd->oobsize; - readlen = numpages * mtd->writesize; - } - - if (chip == -1) { - /* - * Note that numblocks is 2 * (real numblocks) here, see i+=2 - * below as it makes shifting and masking less painful - */ - numblocks = mtd->size >> (this->bbt_erase_shift - 1); - startblock = 0; - from = 0; - } else { - if (chip >= this->numchips) { - pr_warn("create_bbt(): chipnr (%d) > available chips (%d)\n", - chip + 1, this->numchips); - return -EINVAL; - } - numblocks = this->chipsize >> (this->bbt_erase_shift - 1); - startblock = chip * numblocks; - numblocks += startblock; - from = (loff_t)startblock << (this->bbt_erase_shift - 1); - } - - if (this->bbt_options & NAND_BBT_SCANLASTPAGE) - from += mtd->erasesize - (mtd->writesize * numpages); - - for (i = startblock; i < numblocks;) { - int ret; - - 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); - - if (ret < 0) - return ret; - - if (ret) { - this->bbt[i >> 3] |= 0x03 << (i & 0x6); - pr_warn("Bad eraseblock %d at 0x%012llx\n", - i >> 1, (unsigned long long)from); - mtd->ecc_stats.badblocks++; - } - - i += 2; - from += (1 << this->bbt_erase_shift); - } - return 0; -} - -/** - * search_bbt - [GENERIC] scan the device for a specific bad block table - * @mtd: MTD device structure - * @buf: temporary buffer - * @td: descriptor for the bad block table - * - * Read the bad block table by searching for a given ident pattern. Search is - * preformed either from the beginning up or from the end of the device - * downwards. The search starts always at the start of a block. If the option - * NAND_BBT_PERCHIP is given, each chip is searched for a bbt, which contains - * the bad block information of this chip. This is necessary to provide support - * for certain DOC devices. - * - * The bbt ident pattern resides in the oob area of the first page in a block. - */ -static int search_bbt(struct mtd_info *mtd, uint8_t *buf, struct nand_bbt_descr *td) -{ - struct nand_chip *this = mtd->priv; - int i, chips; - int startblock, block, dir; - int scanlen = mtd->writesize + mtd->oobsize; - int bbtblocks; - int blocktopage = this->bbt_erase_shift - this->page_shift; - - /* Search direction top -> down? */ - if (td->options & NAND_BBT_LASTBLOCK) { - startblock = (mtd->size >> this->bbt_erase_shift) - 1; - dir = -1; - } else { - startblock = 0; - dir = 1; - } - - /* Do we have a bbt per chip? */ - if (td->options & NAND_BBT_PERCHIP) { - chips = this->numchips; - bbtblocks = this->chipsize >> this->bbt_erase_shift; - startblock &= bbtblocks - 1; - } else { - chips = 1; - bbtblocks = mtd->size >> this->bbt_erase_shift; - } - - for (i = 0; i < chips; i++) { - /* Reset version information */ - td->version[i] = 0; - td->pages[i] = -1; - /* Scan the maximum number of blocks */ - for (block = 0; block < td->maxblocks; block++) { - - int actblock = startblock + dir * block; - loff_t offs = (loff_t)actblock << this->bbt_erase_shift; - - /* Read first page */ - scan_read(mtd, buf, offs, mtd->writesize, td); - if (!check_pattern(buf, scanlen, mtd->writesize, td)) { - td->pages[i] = actblock << blocktopage; - if (td->options & NAND_BBT_VERSION) { - offs = bbt_get_ver_offs(mtd, td); - td->version[i] = buf[offs]; - } - break; - } - } - startblock += this->chipsize >> this->bbt_erase_shift; - } - /* Check, if we found a bbt for each requested chip */ - for (i = 0; i < chips; i++) { - if (td->pages[i] == -1) - pr_warn("Bad block table not found for chip %d\n", i); - else - pr_info("Bad block table found at page %d, version 0x%02X\n", td->pages[i], - td->version[i]); - } - return 0; -} - -/** - * search_read_bbts - [GENERIC] scan the device for bad block table(s) - * @mtd: MTD device structure - * @buf: temporary buffer - * @td: descriptor for the bad block table - * @md: descriptor for the bad block table mirror - * - * Search and read the bad block table(s). - */ -static void search_read_bbts(struct mtd_info *mtd, uint8_t *buf, - struct nand_bbt_descr *td, - struct nand_bbt_descr *md) -{ - /* Search the primary table */ - search_bbt(mtd, buf, td); - - /* Search the mirror table */ - if (md) - search_bbt(mtd, buf, md); -} - -/** - * write_bbt - [GENERIC] (Re)write the bad block table - * @mtd: MTD device structure - * @buf: temporary buffer - * @td: descriptor for the bad block table - * @md: descriptor for the bad block table mirror - * @chipsel: selector for a specific chip, -1 for all - * - * (Re)write the bad block table. - */ -static int write_bbt(struct mtd_info *mtd, uint8_t *buf, - struct nand_bbt_descr *td, struct nand_bbt_descr *md, - int chipsel) -{ - struct nand_chip *this = mtd->priv; - struct erase_info einfo; - int i, j, res, chip = 0; - int bits, startblock, dir, page, offs, numblocks, sft, sftmsk; - int nrchips, bbtoffs, pageoffs, ooboffs; - uint8_t msk[4]; - uint8_t rcode = td->reserved_block_code; - size_t retlen, len = 0; - loff_t to; - struct mtd_oob_ops ops; - - ops.ooblen = mtd->oobsize; - ops.ooboffs = 0; - ops.datbuf = NULL; - ops.mode = MTD_OPS_PLACE_OOB; - - if (!rcode) - rcode = 0xff; - /* Write bad block table per chip rather than per device? */ - if (td->options & NAND_BBT_PERCHIP) { - numblocks = (int)(this->chipsize >> this->bbt_erase_shift); - /* Full device write or specific chip? */ - if (chipsel == -1) { - nrchips = this->numchips; - } else { - nrchips = chipsel + 1; - chip = chipsel; - } - } else { - numblocks = (int)(mtd->size >> this->bbt_erase_shift); - nrchips = 1; - } - - /* 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; - } - - /* - * 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 ((this->bbt[block >> 2] >> - (2 * (block & 0x03))) & 0x03) { - case 0x01: - case 0x03: - 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: - - /* Set up shift count and masks for the flash table */ - bits = td->options & NAND_BBT_NRBITS_MSK; - msk[2] = ~rcode; - switch (bits) { - case 1: sft = 3; sftmsk = 0x07; msk[0] = 0x00; msk[1] = 0x01; - msk[3] = 0x01; - break; - case 2: sft = 2; sftmsk = 0x06; msk[0] = 0x00; msk[1] = 0x01; - msk[3] = 0x03; - break; - case 4: sft = 1; sftmsk = 0x04; msk[0] = 0x00; msk[1] = 0x0C; - msk[3] = 0x0f; - break; - case 8: sft = 0; sftmsk = 0x00; msk[0] = 0x00; msk[1] = 0x0F; - msk[3] = 0xff; - break; - default: return -EINVAL; - } - - bbtoffs = chip * (numblocks >> 2); - - to = ((loff_t)page) << this->page_shift; - - /* Must we save the block contents? */ - if (td->options & NAND_BBT_SAVECONTENT) { - /* Make it block aligned */ - to &= ~((loff_t)((1 << this->bbt_erase_shift) - 1)); - len = 1 << this->bbt_erase_shift; - res = mtd_read(mtd, to, len, &retlen, buf); - if (res < 0) { - if (retlen != len) { - pr_info("nand_bbt: error reading block " - "for writing the bad block table\n"); - return res; - } - pr_warn("nand_bbt: ECC error while reading " - "block for writing bad block table\n"); - } - /* Read oob data */ - ops.ooblen = (len >> this->page_shift) * mtd->oobsize; - ops.oobbuf = &buf[len]; - res = mtd_read_oob(mtd, to + mtd->writesize, &ops); - if (res < 0 || ops.oobretlen != ops.ooblen) - goto outerr; - - /* Calc the byte offset in the buffer */ - pageoffs = page - (int)(to >> this->page_shift); - offs = pageoffs << this->page_shift; - /* Preset the bbt area with 0xff */ - memset(&buf[offs], 0xff, (size_t)(numblocks >> sft)); - ooboffs = len + (pageoffs * mtd->oobsize); - - } else if (td->options & NAND_BBT_NO_OOB) { - ooboffs = 0; - offs = td->len; - /* The version byte */ - if (td->options & NAND_BBT_VERSION) - offs++; - /* Calc length */ - len = (size_t)(numblocks >> sft); - len += offs; - /* Make it page aligned! */ - len = ALIGN(len, mtd->writesize); - /* Preset the buffer with 0xff */ - memset(buf, 0xff, len); - /* Pattern is located at the begin of first page */ - memcpy(buf, td->pattern, td->len); - } else { - /* Calc length */ - len = (size_t)(numblocks >> sft); - /* Make it page aligned! */ - len = ALIGN(len, mtd->writesize); - /* Preset the buffer with 0xff */ - memset(buf, 0xff, len + - (len >> this->page_shift)* mtd->oobsize); - offs = 0; - ooboffs = len; - /* Pattern is located in oob area of first page */ - memcpy(&buf[ooboffs + td->offs], td->pattern, td->len); - } - - if (td->options & NAND_BBT_VERSION) - buf[ooboffs + td->veroffs] = td->version[chip]; - - /* Walk through the memory table */ - for (i = 0; i < numblocks;) { - uint8_t dat; - dat = this->bbt[bbtoffs + (i >> 2)]; - for (j = 0; j < 4; j++, i++) { - int sftcnt = (i << (3 - sft)) & sftmsk; - /* Do not store the reserved bbt blocks! */ - buf[offs + (i >> sft)] &= - ~(msk[dat & 0x03] << sftcnt); - dat >>= 2; - } - } - - memset(&einfo, 0, sizeof(einfo)); - einfo.mtd = mtd; - einfo.addr = to; - einfo.len = 1 << this->bbt_erase_shift; - res = nand_erase_nand(mtd, &einfo, 1); - if (res < 0) - goto outerr; - - res = scan_write_bbt(mtd, to, len, buf, - td->options & NAND_BBT_NO_OOB ? NULL : - &buf[len]); - if (res < 0) - goto outerr; - - 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; - } - return 0; - - outerr: - pr_warn("nand_bbt: error while writing bad block table %d\n", res); - return res; -} - -/** - * nand_memory_bbt - [GENERIC] create a memory based bad block table - * @mtd: MTD device structure - * @bd: descriptor for the good/bad block search pattern - * - * The function creates a memory based bbt by scanning the device for - * manufacturer / software marked good / bad blocks. - */ -static inline int nand_memory_bbt(struct mtd_info *mtd, struct nand_bbt_descr *bd) -{ - struct nand_chip *this = mtd->priv; - - bd->options &= ~NAND_BBT_SCANEMPTY; - return create_bbt(mtd, this->buffers->databuf, bd, -1); -} - -/** - * check_create - [GENERIC] create and write bbt(s) if necessary - * @mtd: MTD device structure - * @buf: temporary buffer - * @bd: descriptor for the good/bad block search pattern - * - * The function checks the results of the previous call to read_bbt and creates - * / updates the bbt(s) if necessary. Creation is necessary if no bbt was found - * for the chip/device. Update is necessary if one of the tables is missing or - * the version nr. of one table is less than the other. - */ -static int check_create(struct mtd_info *mtd, uint8_t *buf, struct nand_bbt_descr *bd) -{ - int i, chips, writeops, create, chipsel, res, res2; - struct nand_chip *this = mtd->priv; - struct nand_bbt_descr *td = this->bbt_td; - struct nand_bbt_descr *md = this->bbt_md; - struct nand_bbt_descr *rd, *rd2; - - /* Do we have a bbt per chip? */ - if (td->options & NAND_BBT_PERCHIP) - chips = this->numchips; - else - chips = 1; - - for (i = 0; i < chips; i++) { - writeops = 0; - create = 0; - rd = NULL; - rd2 = NULL; - res = res2 = 0; - /* Per chip or per device? */ - chipsel = (td->options & NAND_BBT_PERCHIP) ? i : -1; - /* Mirrored table available? */ - if (md) { - if (td->pages[i] == -1 && md->pages[i] == -1) { - create = 1; - writeops = 0x03; - } else if (td->pages[i] == -1) { - rd = md; - writeops = 0x01; - } else if (md->pages[i] == -1) { - rd = td; - writeops = 0x02; - } else if (td->version[i] == md->version[i]) { - rd = td; - if (!(td->options & NAND_BBT_VERSION)) - rd2 = md; - } else if (((int8_t)(td->version[i] - md->version[i])) > 0) { - rd = td; - writeops = 0x02; - } else { - rd = md; - writeops = 0x01; - } - } else { - if (td->pages[i] == -1) { - create = 1; - writeops = 0x01; - } else { - rd = td; - } - } - - if (create) { - /* Create the bad block table by scanning the device? */ - if (!(td->options & NAND_BBT_CREATE)) - continue; - - /* Create the table in memory by scanning the chip(s) */ - if (!(this->bbt_options & NAND_BBT_CREATE_EMPTY)) - create_bbt(mtd, buf, bd, chipsel); - - td->version[i] = 1; - if (md) - md->version[i] = 1; - } - - /* Read back first? */ - if (rd) { - res = read_abs_bbt(mtd, buf, rd, chipsel); - if (mtd_is_eccerr(res)) { - /* Mark table as invalid */ - rd->pages[i] = -1; - rd->version[i] = 0; - i--; - continue; - } - } - /* If they weren't versioned, read both */ - if (rd2) { - res2 = read_abs_bbt(mtd, buf, rd2, chipsel); - if (mtd_is_eccerr(res2)) { - /* Mark table as invalid */ - rd2->pages[i] = -1; - rd2->version[i] = 0; - i--; - continue; - } - } - - /* Scrub the flash table(s)? */ - if (mtd_is_bitflip(res) || mtd_is_bitflip(res2)) - writeops = 0x03; - - /* Update version numbers before writing */ - if (md) { - td->version[i] = max(td->version[i], md->version[i]); - md->version[i] = td->version[i]; - } - - /* Write the bad block table to the device? */ - if ((writeops & 0x01) && (td->options & NAND_BBT_WRITE)) { - res = write_bbt(mtd, buf, td, md, chipsel); - if (res < 0) - return res; - } - - /* Write the mirror bad block table to the device? */ - if ((writeops & 0x02) && md && (md->options & NAND_BBT_WRITE)) { - res = write_bbt(mtd, buf, md, td, chipsel); - if (res < 0) - return res; - } - } - return 0; -} - -/** - * mark_bbt_regions - [GENERIC] mark the bad block table regions - * @mtd: MTD device structure - * @td: bad block table descriptor - * - * The bad block table regions are marked as "bad" to prevent accidental - * erasures / writes. The regions are identified by the mark 0x02. - */ -static void mark_bbt_region(struct mtd_info *mtd, struct nand_bbt_descr *td) -{ - struct nand_chip *this = mtd->priv; - int i, j, chips, block, nrblocks, update; - uint8_t oldval, newval; - - /* Do we have a bbt per chip? */ - if (td->options & NAND_BBT_PERCHIP) { - chips = this->numchips; - nrblocks = (int)(this->chipsize >> this->bbt_erase_shift); - } else { - chips = 1; - nrblocks = (int)(mtd->size >> this->bbt_erase_shift); - } - - for (i = 0; i < chips; i++) { - if ((td->options & NAND_BBT_ABSPAGE) || - !(td->options & NAND_BBT_WRITE)) { - if (td->pages[i] == -1) - continue; - block = td->pages[i] >> (this->bbt_erase_shift - this->page_shift); - block <<= 1; - oldval = this->bbt[(block >> 3)]; - newval = oldval | (0x2 << (block & 0x06)); - this->bbt[(block >> 3)] = newval; - if ((oldval != newval) && td->reserved_block_code) - nand_update_bbt(mtd, (loff_t)block << (this->bbt_erase_shift - 1)); - continue; - } - update = 0; - if (td->options & NAND_BBT_LASTBLOCK) - block = ((i + 1) * nrblocks) - td->maxblocks; - else - block = i * nrblocks; - block <<= 1; - for (j = 0; j < td->maxblocks; j++) { - oldval = this->bbt[(block >> 3)]; - newval = oldval | (0x2 << (block & 0x06)); - this->bbt[(block >> 3)] = newval; - if (oldval != newval) - update = 1; - block += 2; - } - /* - * If we want reserved blocks to be recorded to flash, and some - * new ones have been marked, then we need to update the stored - * bbts. This should only happen once. - */ - if (update && td->reserved_block_code) - nand_update_bbt(mtd, (loff_t)(block - 2) << (this->bbt_erase_shift - 1)); - } -} - -/** - * verify_bbt_descr - verify the bad block description - * @mtd: MTD device structure - * @bd: the table to verify - * - * This functions performs a few sanity checks on the bad block description - * table. - */ -static void verify_bbt_descr(struct mtd_info *mtd, struct nand_bbt_descr *bd) -{ - struct nand_chip *this = mtd->priv; - u32 pattern_len; - u32 bits; - u32 table_size; - - if (!bd) - return; - - pattern_len = bd->len; - bits = bd->options & NAND_BBT_NRBITS_MSK; - - BUG_ON((this->bbt_options & NAND_BBT_NO_OOB) && - !(this->bbt_options & NAND_BBT_USE_FLASH)); - BUG_ON(!bits); - - if (bd->options & NAND_BBT_VERSION) - pattern_len++; - - if (bd->options & NAND_BBT_NO_OOB) { - BUG_ON(!(this->bbt_options & NAND_BBT_USE_FLASH)); - BUG_ON(!(this->bbt_options & NAND_BBT_NO_OOB)); - BUG_ON(bd->offs); - if (bd->options & NAND_BBT_VERSION) - BUG_ON(bd->veroffs != bd->len); - BUG_ON(bd->options & NAND_BBT_SAVECONTENT); - } - - if (bd->options & NAND_BBT_PERCHIP) - table_size = this->chipsize >> this->bbt_erase_shift; - else - table_size = mtd->size >> this->bbt_erase_shift; - table_size >>= 3; - table_size *= bits; - if (bd->options & NAND_BBT_NO_OOB) - table_size += pattern_len; - BUG_ON(table_size > (1 << this->bbt_erase_shift)); -} - -/** - * nand_scan_bbt - [NAND Interface] scan, find, read and maybe create bad block table(s) - * @mtd: MTD device structure - * @bd: descriptor for the good/bad block search pattern - * - * The function checks, if a bad block table(s) is/are already available. If - * not it scans the device for manufacturer marked good / bad blocks and writes - * the bad block table(s) to the selected place. - * - * The bad block table memory is allocated here. It must be freed by calling - * the nand_free_bbt function. - */ -int nand_scan_bbt(struct mtd_info *mtd, struct nand_bbt_descr *bd) -{ - struct nand_chip *this = mtd->priv; - int len, res = 0; - uint8_t *buf; - struct nand_bbt_descr *td = this->bbt_td; - struct nand_bbt_descr *md = this->bbt_md; - - len = mtd->size >> (this->bbt_erase_shift + 2); - /* - * Allocate memory (2bit per block) and clear the memory bad block - * table. - */ - this->bbt = kzalloc(len, GFP_KERNEL); - if (!this->bbt) - return -ENOMEM; - - /* - * If no primary table decriptor is given, scan the device to build a - * memory based bad block table. - */ - if (!td) { - if ((res = nand_memory_bbt(mtd, bd))) { - pr_err("nand_bbt: can't scan flash and build the RAM-based BBT\n"); - kfree(this->bbt); - this->bbt = NULL; - } - return res; - } - verify_bbt_descr(mtd, td); - verify_bbt_descr(mtd, md); - - /* Allocate a temporary buffer for one eraseblock incl. oob */ - len = (1 << this->bbt_erase_shift); - len += (len >> this->page_shift) * mtd->oobsize; - buf = vmalloc(len); - if (!buf) { - kfree(this->bbt); - this->bbt = NULL; - return -ENOMEM; - } - - /* Is the bbt at a given page? */ - if (td->options & NAND_BBT_ABSPAGE) { - read_abs_bbts(mtd, buf, td, md); - } else { - /* Search the bad block table using a pattern in oob */ - search_read_bbts(mtd, buf, td, md); - } - - res = check_create(mtd, buf, bd); - - /* Prevent the bbt regions from erasing / writing */ - mark_bbt_region(mtd, td); - if (md) - mark_bbt_region(mtd, md); - - vfree(buf); - return res; -} - -/** - * nand_update_bbt - [NAND Interface] update bad block table(s) - * @mtd: MTD device structure - * @offs: the offset of the newly marked block - * - * The function updates the bad block table(s). - */ -int nand_update_bbt(struct mtd_info *mtd, loff_t offs) -{ - struct nand_chip *this = mtd->priv; - int len, res = 0; - int chip, chipsel; - uint8_t *buf; - struct nand_bbt_descr *td = this->bbt_td; - struct nand_bbt_descr *md = this->bbt_md; - - if (!this->bbt || !td) - return -EINVAL; - - /* Allocate a temporary buffer for one eraseblock incl. oob */ - len = (1 << this->bbt_erase_shift); - len += (len >> this->page_shift) * mtd->oobsize; - buf = kmalloc(len, GFP_KERNEL); - if (!buf) - return -ENOMEM; - - /* Do we have a bbt per chip? */ - if (td->options & NAND_BBT_PERCHIP) { - chip = (int)(offs >> this->chip_shift); - chipsel = chip; - } else { - chip = 0; - chipsel = -1; - } - - td->version[chip]++; - if (md) - md->version[chip]++; - - /* Write the bad block table to the device? */ - if (td->options & NAND_BBT_WRITE) { - res = write_bbt(mtd, buf, td, md, chipsel); - if (res < 0) - goto out; - } - /* Write the mirror bad block table to the device? */ - if (md && (md->options & NAND_BBT_WRITE)) { - res = write_bbt(mtd, buf, md, td, chipsel); - } - - out: - kfree(buf); - return res; -} - -/* - * 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, 0xff }; - -static uint8_t scan_agand_pattern[] = { 0x1C, 0x71, 0xC7, 0x1C, 0x71, 0xC7 }; - -static struct nand_bbt_descr agand_flashbased = { - .options = NAND_BBT_SCANEMPTY | NAND_BBT_SCANALLPAGES, - .offs = 0x20, - .len = 6, - .pattern = scan_agand_pattern -}; - -/* Generic flash bbt descriptors */ -static uint8_t bbt_pattern[] = {'B', 'b', 't', '0' }; -static uint8_t mirror_pattern[] = {'1', 't', 'b', 'B' }; - -static struct nand_bbt_descr bbt_main_descr = { - .options = NAND_BBT_LASTBLOCK | NAND_BBT_CREATE | NAND_BBT_WRITE - | NAND_BBT_2BIT | NAND_BBT_VERSION | NAND_BBT_PERCHIP, - .offs = 8, - .len = 4, - .veroffs = 12, - .maxblocks = NAND_BBT_SCAN_MAXBLOCKS, - .pattern = bbt_pattern -}; - -static struct nand_bbt_descr bbt_mirror_descr = { - .options = NAND_BBT_LASTBLOCK | NAND_BBT_CREATE | NAND_BBT_WRITE - | NAND_BBT_2BIT | NAND_BBT_VERSION | NAND_BBT_PERCHIP, - .offs = 8, - .len = 4, - .veroffs = 12, - .maxblocks = NAND_BBT_SCAN_MAXBLOCKS, - .pattern = mirror_pattern -}; - -static struct nand_bbt_descr bbt_main_no_oob_descr = { - .options = NAND_BBT_LASTBLOCK | NAND_BBT_CREATE | NAND_BBT_WRITE - | NAND_BBT_2BIT | NAND_BBT_VERSION | NAND_BBT_PERCHIP - | NAND_BBT_NO_OOB, - .len = 4, - .veroffs = 4, - .maxblocks = NAND_BBT_SCAN_MAXBLOCKS, - .pattern = bbt_pattern -}; - -static struct nand_bbt_descr bbt_mirror_no_oob_descr = { - .options = NAND_BBT_LASTBLOCK | NAND_BBT_CREATE | NAND_BBT_WRITE - | NAND_BBT_2BIT | NAND_BBT_VERSION | NAND_BBT_PERCHIP - | NAND_BBT_NO_OOB, - .len = 4, - .veroffs = 4, - .maxblocks = NAND_BBT_SCAN_MAXBLOCKS, - .pattern = mirror_pattern -}; - -#define BADBLOCK_SCAN_MASK (~NAND_BBT_NO_OOB) -/** - * nand_create_badblock_pattern - [INTERN] Creates a BBT descriptor structure - * @this: NAND chip to create descriptor for - * - * This function allocates and initializes a nand_bbt_descr for BBM detection - * based on the properties of @this. The new descriptor is stored in - * this->badblock_pattern. Thus, this->badblock_pattern should be NULL when - * passed to this function. - */ -static int nand_create_badblock_pattern(struct nand_chip *this) -{ - struct nand_bbt_descr *bd; - if (this->badblock_pattern) { - pr_warn("Bad block pattern already allocated; not replacing\n"); - return -EINVAL; - } - bd = kzalloc(sizeof(*bd), GFP_KERNEL); - if (!bd) - return -ENOMEM; - bd->options = this->bbt_options & BADBLOCK_SCAN_MASK; - bd->offs = this->badblockpos; - bd->len = (this->options & NAND_BUSWIDTH_16) ? 2 : 1; - bd->pattern = scan_ff_pattern; - bd->options |= NAND_BBT_DYNAMICSTRUCT; - this->badblock_pattern = bd; - return 0; -} - -/** - * nand_default_bbt - [NAND Interface] Select a default bad block table for the device - * @mtd: MTD device structure - * - * This function selects the default bad block table support for the device and - * calls the nand_scan_bbt function. - */ -int nand_default_bbt(struct mtd_info *mtd) -{ - struct nand_chip *this = mtd->priv; - - /* - * Default for AG-AND. We must use a flash based bad block table as the - * devices have factory marked _good_ blocks. Erasing those blocks - * leads to loss of the good / bad information, so we _must_ store this - * information in a good / bad table during startup. - */ - if (this->options & NAND_IS_AND) { - /* Use the default pattern descriptors */ - if (!this->bbt_td) { - this->bbt_td = &bbt_main_descr; - this->bbt_md = &bbt_mirror_descr; - } - this->bbt_options |= NAND_BBT_USE_FLASH; - return nand_scan_bbt(mtd, &agand_flashbased); - } - - /* Is a flash based bad block table requested? */ - if (this->bbt_options & NAND_BBT_USE_FLASH) { - /* Use the default pattern descriptors */ - if (!this->bbt_td) { - if (this->bbt_options & NAND_BBT_NO_OOB) { - this->bbt_td = &bbt_main_no_oob_descr; - this->bbt_md = &bbt_mirror_no_oob_descr; - } else { - this->bbt_td = &bbt_main_descr; - this->bbt_md = &bbt_mirror_descr; - } - } - } else { - this->bbt_td = NULL; - this->bbt_md = NULL; - } - - if (!this->badblock_pattern) - nand_create_badblock_pattern(this); - - return nand_scan_bbt(mtd, this->badblock_pattern); -} - -/** - * nand_isbad_bbt - [NAND Interface] Check if a block is bad - * @mtd: MTD device structure - * @offs: offset in the device - * @allowbbt: allow access to bad block table region - */ -int nand_isbad_bbt(struct mtd_info *mtd, loff_t offs, int allowbbt) -{ - struct nand_chip *this = mtd->priv; - int block; - uint8_t res; - - /* Get block number * 2 */ - block = (int)(offs >> (this->bbt_erase_shift - 1)); - res = (this->bbt[block >> 3] >> (block & 0x06)) & 0x03; - - MTDDEBUG(MTD_DEBUG_LEVEL2, "nand_isbad_bbt(): bbt info for offs 0x%08x: (block %d) 0x%02x\n", - (unsigned int)offs, block >> 1, res); - - switch ((int)res) { - case 0x00: - return 0; - case 0x01: - return 1; - case 0x02: - return allowbbt ? 0 : 1; - } - return 1; -} diff --git a/qemu/roms/u-boot/drivers/mtd/nand/nand_bch.c b/qemu/roms/u-boot/drivers/mtd/nand/nand_bch.c deleted file mode 100644 index 35d2140da..000000000 --- a/qemu/roms/u-boot/drivers/mtd/nand/nand_bch.c +++ /dev/null @@ -1,224 +0,0 @@ -/* - * This file provides ECC correction for more than 1 bit per block of data, - * using binary BCH codes. It relies on the generic BCH library lib/bch.c. - * - * Copyright © 2011 Ivan Djelic <ivan.djelic@parrot.com> - * - * SPDX-License-Identifier: GPL-2.0+ - */ - -#include <common.h> -/*#include <asm/io.h>*/ -#include <linux/types.h> - -#include <linux/bitops.h> -#include <linux/mtd/mtd.h> -#include <linux/mtd/nand.h> -#include <linux/mtd/nand_bch.h> -#include <linux/bch.h> -#include <malloc.h> - -/** - * struct nand_bch_control - private NAND BCH control structure - * @bch: BCH control structure - * @ecclayout: private ecc layout for this BCH configuration - * @errloc: error location array - * @eccmask: XOR ecc mask, allows erased pages to be decoded as valid - */ -struct nand_bch_control { - struct bch_control *bch; - struct nand_ecclayout ecclayout; - unsigned int *errloc; - unsigned char *eccmask; -}; - -/** - * nand_bch_calculate_ecc - [NAND Interface] Calculate ECC for data block - * @mtd: MTD block structure - * @buf: input buffer with raw data - * @code: output buffer with ECC - */ -int nand_bch_calculate_ecc(struct mtd_info *mtd, const unsigned char *buf, - unsigned char *code) -{ - const struct nand_chip *chip = mtd->priv; - struct nand_bch_control *nbc = chip->ecc.priv; - unsigned int i; - - memset(code, 0, chip->ecc.bytes); - encode_bch(nbc->bch, buf, chip->ecc.size, code); - - /* apply mask so that an erased page is a valid codeword */ - for (i = 0; i < chip->ecc.bytes; i++) - code[i] ^= nbc->eccmask[i]; - - return 0; -} - -/** - * nand_bch_correct_data - [NAND Interface] Detect and correct bit error(s) - * @mtd: MTD block structure - * @buf: raw data read from the chip - * @read_ecc: ECC from the chip - * @calc_ecc: the ECC calculated from raw data - * - * Detect and correct bit errors for a data byte block - */ -int nand_bch_correct_data(struct mtd_info *mtd, unsigned char *buf, - unsigned char *read_ecc, unsigned char *calc_ecc) -{ - const struct nand_chip *chip = mtd->priv; - struct nand_bch_control *nbc = chip->ecc.priv; - unsigned int *errloc = nbc->errloc; - int i, count; - - count = decode_bch(nbc->bch, NULL, chip->ecc.size, read_ecc, calc_ecc, - NULL, errloc); - if (count > 0) { - for (i = 0; i < count; i++) { - if (errloc[i] < (chip->ecc.size*8)) - /* error is located in data, correct it */ - buf[errloc[i] >> 3] ^= (1 << (errloc[i] & 7)); - /* else error in ecc, no action needed */ - - MTDDEBUG(MTD_DEBUG_LEVEL0, "%s: corrected bitflip %u\n", - __func__, errloc[i]); - } - } else if (count < 0) { - printk(KERN_ERR "ecc unrecoverable error\n"); - count = -1; - } - return count; -} - -/** - * nand_bch_init - [NAND Interface] Initialize NAND BCH error correction - * @mtd: MTD block structure - * @eccsize: ecc block size in bytes - * @eccbytes: ecc length in bytes - * @ecclayout: output default layout - * - * Returns: - * a pointer to a new NAND BCH control structure, or NULL upon failure - * - * Initialize NAND BCH error correction. Parameters @eccsize and @eccbytes - * are used to compute BCH parameters m (Galois field order) and t (error - * correction capability). @eccbytes should be equal to the number of bytes - * required to store m*t bits, where m is such that 2^m-1 > @eccsize*8. - * - * Example: to configure 4 bit correction per 512 bytes, you should pass - * @eccsize = 512 (thus, m=13 is the smallest integer such that 2^m-1 > 512*8) - * @eccbytes = 7 (7 bytes are required to store m*t = 13*4 = 52 bits) - */ -struct nand_bch_control * -nand_bch_init(struct mtd_info *mtd, unsigned int eccsize, unsigned int eccbytes, - struct nand_ecclayout **ecclayout) -{ - unsigned int m, t, eccsteps, i; - struct nand_ecclayout *layout; - struct nand_bch_control *nbc = NULL; - unsigned char *erased_page; - - if (!eccsize || !eccbytes) { - printk(KERN_WARNING "ecc parameters not supplied\n"); - goto fail; - } - - m = fls(1+8*eccsize); - t = (eccbytes*8)/m; - - nbc = kzalloc(sizeof(*nbc), GFP_KERNEL); - if (!nbc) - goto fail; - - nbc->bch = init_bch(m, t, 0); - if (!nbc->bch) - goto fail; - - /* verify that eccbytes has the expected value */ - if (nbc->bch->ecc_bytes != eccbytes) { - printk(KERN_WARNING "invalid eccbytes %u, should be %u\n", - eccbytes, nbc->bch->ecc_bytes); - goto fail; - } - - eccsteps = mtd->writesize/eccsize; - - /* if no ecc placement scheme was provided, build one */ - if (!*ecclayout) { - - /* handle large page devices only */ - if (mtd->oobsize < 64) { - printk(KERN_WARNING "must provide an oob scheme for " - "oobsize %d\n", mtd->oobsize); - goto fail; - } - - layout = &nbc->ecclayout; - layout->eccbytes = eccsteps*eccbytes; - - /* reserve 2 bytes for bad block marker */ - if (layout->eccbytes+2 > mtd->oobsize) { - printk(KERN_WARNING "no suitable oob scheme available " - "for oobsize %d eccbytes %u\n", mtd->oobsize, - eccbytes); - goto fail; - } - /* put ecc bytes at oob tail */ - for (i = 0; i < layout->eccbytes; i++) - layout->eccpos[i] = mtd->oobsize-layout->eccbytes+i; - - layout->oobfree[0].offset = 2; - layout->oobfree[0].length = mtd->oobsize-2-layout->eccbytes; - - *ecclayout = layout; - } - - /* sanity checks */ - if (8*(eccsize+eccbytes) >= (1 << m)) { - printk(KERN_WARNING "eccsize %u is too large\n", eccsize); - goto fail; - } - if ((*ecclayout)->eccbytes != (eccsteps*eccbytes)) { - printk(KERN_WARNING "invalid ecc layout\n"); - goto fail; - } - - nbc->eccmask = kmalloc(eccbytes, GFP_KERNEL); - nbc->errloc = kmalloc(t*sizeof(*nbc->errloc), GFP_KERNEL); - if (!nbc->eccmask || !nbc->errloc) - goto fail; - /* - * compute and store the inverted ecc of an erased ecc block - */ - erased_page = kmalloc(eccsize, GFP_KERNEL); - if (!erased_page) - goto fail; - - memset(erased_page, 0xff, eccsize); - memset(nbc->eccmask, 0, eccbytes); - encode_bch(nbc->bch, erased_page, eccsize, nbc->eccmask); - kfree(erased_page); - - for (i = 0; i < eccbytes; i++) - nbc->eccmask[i] ^= 0xff; - - return nbc; -fail: - nand_bch_free(nbc); - return NULL; -} - -/** - * nand_bch_free - [NAND Interface] Release NAND BCH ECC resources - * @nbc: NAND BCH control structure - */ -void nand_bch_free(struct nand_bch_control *nbc) -{ - if (nbc) { - free_bch(nbc->bch); - kfree(nbc->errloc); - kfree(nbc->eccmask); - kfree(nbc); - } -} diff --git a/qemu/roms/u-boot/drivers/mtd/nand/nand_ecc.c b/qemu/roms/u-boot/drivers/mtd/nand/nand_ecc.c deleted file mode 100644 index 083e0e99e..000000000 --- a/qemu/roms/u-boot/drivers/mtd/nand/nand_ecc.c +++ /dev/null @@ -1,191 +0,0 @@ -/* - * This file contains an ECC algorithm from Toshiba that detects and - * corrects 1 bit errors in a 256 byte block of data. - * - * drivers/mtd/nand/nand_ecc.c - * - * Copyright (C) 2000-2004 Steven J. Hill (sjhill@realitydiluted.com) - * Toshiba America Electronics Components, Inc. - * - * Copyright (C) 2006 Thomas Gleixner <tglx@linutronix.de> - * - * SPDX-License-Identifier: GPL-2.0+ - * - * As a special exception, if other files instantiate templates or use - * macros or inline functions from these files, or you compile these - * files and link them with other works to produce a work based on these - * files, these files do not by themselves cause the resulting work to be - * covered by the GNU General Public License. However the source code for - * these files must still be made available in accordance with section (3) - * of the GNU General Public License. - * - * This exception does not invalidate any other reasons why a work based on - * this file might be covered by the GNU General Public License. - */ - -#include <common.h> - -#include <asm/errno.h> -#include <linux/mtd/mtd.h> -#include <linux/mtd/nand_ecc.h> - -/* The PPC4xx NDFC uses Smart Media (SMC) bytes order */ -#ifdef CONFIG_NAND_NDFC -#define CONFIG_MTD_NAND_ECC_SMC -#endif - -/* - * NAND-SPL has no sofware ECC for now, so don't include nand_calculate_ecc(), - * only nand_correct_data() is needed - */ - -#if !defined(CONFIG_NAND_SPL) || defined(CONFIG_SPL_NAND_SOFTECC) -/* - * Pre-calculated 256-way 1 byte column parity - */ -static const u_char nand_ecc_precalc_table[] = { - 0x00, 0x55, 0x56, 0x03, 0x59, 0x0c, 0x0f, 0x5a, 0x5a, 0x0f, 0x0c, 0x59, 0x03, 0x56, 0x55, 0x00, - 0x65, 0x30, 0x33, 0x66, 0x3c, 0x69, 0x6a, 0x3f, 0x3f, 0x6a, 0x69, 0x3c, 0x66, 0x33, 0x30, 0x65, - 0x66, 0x33, 0x30, 0x65, 0x3f, 0x6a, 0x69, 0x3c, 0x3c, 0x69, 0x6a, 0x3f, 0x65, 0x30, 0x33, 0x66, - 0x03, 0x56, 0x55, 0x00, 0x5a, 0x0f, 0x0c, 0x59, 0x59, 0x0c, 0x0f, 0x5a, 0x00, 0x55, 0x56, 0x03, - 0x69, 0x3c, 0x3f, 0x6a, 0x30, 0x65, 0x66, 0x33, 0x33, 0x66, 0x65, 0x30, 0x6a, 0x3f, 0x3c, 0x69, - 0x0c, 0x59, 0x5a, 0x0f, 0x55, 0x00, 0x03, 0x56, 0x56, 0x03, 0x00, 0x55, 0x0f, 0x5a, 0x59, 0x0c, - 0x0f, 0x5a, 0x59, 0x0c, 0x56, 0x03, 0x00, 0x55, 0x55, 0x00, 0x03, 0x56, 0x0c, 0x59, 0x5a, 0x0f, - 0x6a, 0x3f, 0x3c, 0x69, 0x33, 0x66, 0x65, 0x30, 0x30, 0x65, 0x66, 0x33, 0x69, 0x3c, 0x3f, 0x6a, - 0x6a, 0x3f, 0x3c, 0x69, 0x33, 0x66, 0x65, 0x30, 0x30, 0x65, 0x66, 0x33, 0x69, 0x3c, 0x3f, 0x6a, - 0x0f, 0x5a, 0x59, 0x0c, 0x56, 0x03, 0x00, 0x55, 0x55, 0x00, 0x03, 0x56, 0x0c, 0x59, 0x5a, 0x0f, - 0x0c, 0x59, 0x5a, 0x0f, 0x55, 0x00, 0x03, 0x56, 0x56, 0x03, 0x00, 0x55, 0x0f, 0x5a, 0x59, 0x0c, - 0x69, 0x3c, 0x3f, 0x6a, 0x30, 0x65, 0x66, 0x33, 0x33, 0x66, 0x65, 0x30, 0x6a, 0x3f, 0x3c, 0x69, - 0x03, 0x56, 0x55, 0x00, 0x5a, 0x0f, 0x0c, 0x59, 0x59, 0x0c, 0x0f, 0x5a, 0x00, 0x55, 0x56, 0x03, - 0x66, 0x33, 0x30, 0x65, 0x3f, 0x6a, 0x69, 0x3c, 0x3c, 0x69, 0x6a, 0x3f, 0x65, 0x30, 0x33, 0x66, - 0x65, 0x30, 0x33, 0x66, 0x3c, 0x69, 0x6a, 0x3f, 0x3f, 0x6a, 0x69, 0x3c, 0x66, 0x33, 0x30, 0x65, - 0x00, 0x55, 0x56, 0x03, 0x59, 0x0c, 0x0f, 0x5a, 0x5a, 0x0f, 0x0c, 0x59, 0x03, 0x56, 0x55, 0x00 -}; - -/** - * nand_calculate_ecc - [NAND Interface] Calculate 3-byte ECC for 256-byte block - * @mtd: MTD block structure - * @dat: raw data - * @ecc_code: buffer for ECC - */ -int nand_calculate_ecc(struct mtd_info *mtd, const u_char *dat, - u_char *ecc_code) -{ - uint8_t idx, reg1, reg2, reg3, tmp1, tmp2; - int i; - - /* Initialize variables */ - reg1 = reg2 = reg3 = 0; - - /* Build up column parity */ - for(i = 0; i < 256; i++) { - /* Get CP0 - CP5 from table */ - idx = nand_ecc_precalc_table[*dat++]; - reg1 ^= (idx & 0x3f); - - /* All bit XOR = 1 ? */ - if (idx & 0x40) { - reg3 ^= (uint8_t) i; - reg2 ^= ~((uint8_t) i); - } - } - - /* Create non-inverted ECC code from line parity */ - tmp1 = (reg3 & 0x80) >> 0; /* B7 -> B7 */ - tmp1 |= (reg2 & 0x80) >> 1; /* B7 -> B6 */ - tmp1 |= (reg3 & 0x40) >> 1; /* B6 -> B5 */ - tmp1 |= (reg2 & 0x40) >> 2; /* B6 -> B4 */ - tmp1 |= (reg3 & 0x20) >> 2; /* B5 -> B3 */ - tmp1 |= (reg2 & 0x20) >> 3; /* B5 -> B2 */ - tmp1 |= (reg3 & 0x10) >> 3; /* B4 -> B1 */ - tmp1 |= (reg2 & 0x10) >> 4; /* B4 -> B0 */ - - tmp2 = (reg3 & 0x08) << 4; /* B3 -> B7 */ - tmp2 |= (reg2 & 0x08) << 3; /* B3 -> B6 */ - tmp2 |= (reg3 & 0x04) << 3; /* B2 -> B5 */ - tmp2 |= (reg2 & 0x04) << 2; /* B2 -> B4 */ - tmp2 |= (reg3 & 0x02) << 2; /* B1 -> B3 */ - tmp2 |= (reg2 & 0x02) << 1; /* B1 -> B2 */ - tmp2 |= (reg3 & 0x01) << 1; /* B0 -> B1 */ - tmp2 |= (reg2 & 0x01) << 0; /* B7 -> B0 */ - - /* Calculate final ECC code */ -#ifdef CONFIG_MTD_NAND_ECC_SMC - ecc_code[0] = ~tmp2; - ecc_code[1] = ~tmp1; -#else - ecc_code[0] = ~tmp1; - ecc_code[1] = ~tmp2; -#endif - ecc_code[2] = ((~reg1) << 2) | 0x03; - - return 0; -} -#endif /* CONFIG_NAND_SPL */ - -static inline int countbits(uint32_t byte) -{ - int res = 0; - - for (;byte; byte >>= 1) - res += byte & 0x01; - return res; -} - -/** - * nand_correct_data - [NAND Interface] Detect and correct bit error(s) - * @mtd: MTD block structure - * @dat: raw data read from the chip - * @read_ecc: ECC from the chip - * @calc_ecc: the ECC calculated from raw data - * - * Detect and correct a 1 bit error for 256 byte block - */ -int nand_correct_data(struct mtd_info *mtd, u_char *dat, - u_char *read_ecc, u_char *calc_ecc) -{ - uint8_t s0, s1, s2; - -#ifdef CONFIG_MTD_NAND_ECC_SMC - s0 = calc_ecc[0] ^ read_ecc[0]; - s1 = calc_ecc[1] ^ read_ecc[1]; - s2 = calc_ecc[2] ^ read_ecc[2]; -#else - s1 = calc_ecc[0] ^ read_ecc[0]; - s0 = calc_ecc[1] ^ read_ecc[1]; - s2 = calc_ecc[2] ^ read_ecc[2]; -#endif - if ((s0 | s1 | s2) == 0) - return 0; - - /* Check for a single bit error */ - if( ((s0 ^ (s0 >> 1)) & 0x55) == 0x55 && - ((s1 ^ (s1 >> 1)) & 0x55) == 0x55 && - ((s2 ^ (s2 >> 1)) & 0x54) == 0x54) { - - uint32_t byteoffs, bitnum; - - byteoffs = (s1 << 0) & 0x80; - byteoffs |= (s1 << 1) & 0x40; - byteoffs |= (s1 << 2) & 0x20; - byteoffs |= (s1 << 3) & 0x10; - - byteoffs |= (s0 >> 4) & 0x08; - byteoffs |= (s0 >> 3) & 0x04; - byteoffs |= (s0 >> 2) & 0x02; - byteoffs |= (s0 >> 1) & 0x01; - - bitnum = (s2 >> 5) & 0x04; - bitnum |= (s2 >> 4) & 0x02; - bitnum |= (s2 >> 3) & 0x01; - - dat[byteoffs] ^= (1 << bitnum); - - return 1; - } - - if(countbits(s0 | ((uint32_t)s1 << 8) | ((uint32_t)s2 <<16)) == 1) - return 1; - - return -EBADMSG; -} diff --git a/qemu/roms/u-boot/drivers/mtd/nand/nand_ids.c b/qemu/roms/u-boot/drivers/mtd/nand/nand_ids.c deleted file mode 100644 index f3f0cb676..000000000 --- a/qemu/roms/u-boot/drivers/mtd/nand/nand_ids.c +++ /dev/null @@ -1,182 +0,0 @@ -/* - * drivers/mtd/nandids.c - * - * Copyright (C) 2002 Thomas Gleixner (tglx@linutronix.de) - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. - * - */ - -#include <common.h> -#include <linux/mtd/nand.h> -/* -* Chip ID list -* -* Name. ID code, pagesize, chipsize in MegaByte, eraseblock size, -* options -* -* Pagesize; 0, 256, 512 -* 0 get this information from the extended chip ID -+ 256 256 Byte page size -* 512 512 Byte page size -*/ -const struct nand_flash_dev nand_flash_ids[] = { - -#ifdef CONFIG_MTD_NAND_MUSEUM_IDS - {"NAND 1MiB 5V 8-bit", 0x6e, 256, 1, 0x1000, 0}, - {"NAND 2MiB 5V 8-bit", 0x64, 256, 2, 0x1000, 0}, - {"NAND 4MiB 5V 8-bit", 0x6b, 512, 4, 0x2000, 0}, - {"NAND 1MiB 3,3V 8-bit", 0xe8, 256, 1, 0x1000, 0}, - {"NAND 1MiB 3,3V 8-bit", 0xec, 256, 1, 0x1000, 0}, - {"NAND 2MiB 3,3V 8-bit", 0xea, 256, 2, 0x1000, 0}, - {"NAND 4MiB 3,3V 8-bit", 0xd5, 512, 4, 0x2000, 0}, - {"NAND 4MiB 3,3V 8-bit", 0xe3, 512, 4, 0x2000, 0}, - {"NAND 4MiB 3,3V 8-bit", 0xe5, 512, 4, 0x2000, 0}, - {"NAND 8MiB 3,3V 8-bit", 0xd6, 512, 8, 0x2000, 0}, - - {"NAND 8MiB 1,8V 8-bit", 0x39, 512, 8, 0x2000, 0}, - {"NAND 8MiB 3,3V 8-bit", 0xe6, 512, 8, 0x2000, 0}, - {"NAND 8MiB 1,8V 16-bit", 0x49, 512, 8, 0x2000, NAND_BUSWIDTH_16}, - {"NAND 8MiB 3,3V 16-bit", 0x59, 512, 8, 0x2000, NAND_BUSWIDTH_16}, -#endif - - {"NAND 16MiB 1,8V 8-bit", 0x33, 512, 16, 0x4000, 0}, - {"NAND 16MiB 3,3V 8-bit", 0x73, 512, 16, 0x4000, 0}, - {"NAND 16MiB 1,8V 16-bit", 0x43, 512, 16, 0x4000, NAND_BUSWIDTH_16}, - {"NAND 16MiB 3,3V 16-bit", 0x53, 512, 16, 0x4000, NAND_BUSWIDTH_16}, - - {"NAND 32MiB 1,8V 8-bit", 0x35, 512, 32, 0x4000, 0}, - {"NAND 32MiB 3,3V 8-bit", 0x75, 512, 32, 0x4000, 0}, - {"NAND 32MiB 1,8V 16-bit", 0x45, 512, 32, 0x4000, NAND_BUSWIDTH_16}, - {"NAND 32MiB 3,3V 16-bit", 0x55, 512, 32, 0x4000, NAND_BUSWIDTH_16}, - - {"NAND 64MiB 1,8V 8-bit", 0x36, 512, 64, 0x4000, 0}, - {"NAND 64MiB 3,3V 8-bit", 0x76, 512, 64, 0x4000, 0}, - {"NAND 64MiB 1,8V 16-bit", 0x46, 512, 64, 0x4000, NAND_BUSWIDTH_16}, - {"NAND 64MiB 3,3V 16-bit", 0x56, 512, 64, 0x4000, NAND_BUSWIDTH_16}, - - {"NAND 128MiB 1,8V 8-bit", 0x78, 512, 128, 0x4000, 0}, - {"NAND 128MiB 1,8V 8-bit", 0x39, 512, 128, 0x4000, 0}, - {"NAND 128MiB 3,3V 8-bit", 0x79, 512, 128, 0x4000, 0}, - {"NAND 128MiB 1,8V 16-bit", 0x72, 512, 128, 0x4000, NAND_BUSWIDTH_16}, - {"NAND 128MiB 1,8V 16-bit", 0x49, 512, 128, 0x4000, NAND_BUSWIDTH_16}, - {"NAND 128MiB 3,3V 16-bit", 0x74, 512, 128, 0x4000, NAND_BUSWIDTH_16}, - {"NAND 128MiB 3,3V 16-bit", 0x59, 512, 128, 0x4000, NAND_BUSWIDTH_16}, - - {"NAND 256MiB 3,3V 8-bit", 0x71, 512, 256, 0x4000, 0}, - - /* - * These are the new chips with large page size. The pagesize and the - * erasesize is determined from the extended id bytes - */ -#define LP_OPTIONS NAND_SAMSUNG_LP_OPTIONS -#define LP_OPTIONS16 (LP_OPTIONS | NAND_BUSWIDTH_16) - - /* 512 Megabit */ - {"NAND 64MiB 1,8V 8-bit", 0xA2, 0, 64, 0, LP_OPTIONS}, - {"NAND 64MiB 1,8V 8-bit", 0xA0, 0, 64, 0, LP_OPTIONS}, - {"NAND 64MiB 3,3V 8-bit", 0xF2, 0, 64, 0, LP_OPTIONS}, - {"NAND 64MiB 3,3V 8-bit", 0xD0, 0, 64, 0, LP_OPTIONS}, - {"NAND 64MiB 3,3V 8-bit", 0xF0, 0, 64, 0, LP_OPTIONS}, - {"NAND 64MiB 1,8V 16-bit", 0xB2, 0, 64, 0, LP_OPTIONS16}, - {"NAND 64MiB 1,8V 16-bit", 0xB0, 0, 64, 0, LP_OPTIONS16}, - {"NAND 64MiB 3,3V 16-bit", 0xC2, 0, 64, 0, LP_OPTIONS16}, - {"NAND 64MiB 3,3V 16-bit", 0xC0, 0, 64, 0, LP_OPTIONS16}, - - /* 1 Gigabit */ - {"NAND 128MiB 1,8V 8-bit", 0xA1, 0, 128, 0, LP_OPTIONS}, - {"NAND 128MiB 3,3V 8-bit", 0xF1, 0, 128, 0, LP_OPTIONS}, - {"NAND 128MiB 3,3V 8-bit", 0xD1, 0, 128, 0, LP_OPTIONS}, - {"NAND 128MiB 1,8V 16-bit", 0xB1, 0, 128, 0, LP_OPTIONS16}, - {"NAND 128MiB 3,3V 16-bit", 0xC1, 0, 128, 0, LP_OPTIONS16}, - {"NAND 128MiB 1,8V 16-bit", 0xAD, 0, 128, 0, LP_OPTIONS16}, - - /* 2 Gigabit */ - {"NAND 256MiB 1,8V 8-bit", 0xAA, 0, 256, 0, LP_OPTIONS}, - {"NAND 256MiB 3,3V 8-bit", 0xDA, 0, 256, 0, LP_OPTIONS}, - {"NAND 256MiB 1,8V 16-bit", 0xBA, 0, 256, 0, LP_OPTIONS16}, - {"NAND 256MiB 3,3V 16-bit", 0xCA, 0, 256, 0, LP_OPTIONS16}, - - /* 4 Gigabit */ - {"NAND 512MiB 1,8V 8-bit", 0xAC, 0, 512, 0, LP_OPTIONS}, - {"NAND 512MiB 3,3V 8-bit", 0xDC, 0, 512, 0, LP_OPTIONS}, - {"NAND 512MiB 1,8V 16-bit", 0xBC, 0, 512, 0, LP_OPTIONS16}, - {"NAND 512MiB 3,3V 16-bit", 0xCC, 0, 512, 0, LP_OPTIONS16}, - - /* 8 Gigabit */ - {"NAND 1GiB 1,8V 8-bit", 0xA3, 0, 1024, 0, LP_OPTIONS}, - {"NAND 1GiB 3,3V 8-bit", 0xD3, 0, 1024, 0, LP_OPTIONS}, - {"NAND 1GiB 1,8V 16-bit", 0xB3, 0, 1024, 0, LP_OPTIONS16}, - {"NAND 1GiB 3,3V 16-bit", 0xC3, 0, 1024, 0, LP_OPTIONS16}, - - /* 16 Gigabit */ - {"NAND 2GiB 1,8V 8-bit", 0xA5, 0, 2048, 0, LP_OPTIONS}, - {"NAND 2GiB 3,3V 8-bit", 0xD5, 0, 2048, 0, LP_OPTIONS}, - {"NAND 2GiB 1,8V 16-bit", 0xB5, 0, 2048, 0, LP_OPTIONS16}, - {"NAND 2GiB 3,3V 16-bit", 0xC5, 0, 2048, 0, LP_OPTIONS16}, - - /* 32 Gigabit */ - {"NAND 4GiB 1,8V 8-bit", 0xA7, 0, 4096, 0, LP_OPTIONS}, - {"NAND 4GiB 3,3V 8-bit", 0xD7, 0, 4096, 0, LP_OPTIONS}, - {"NAND 4GiB 1,8V 16-bit", 0xB7, 0, 4096, 0, LP_OPTIONS16}, - {"NAND 4GiB 3,3V 16-bit", 0xC7, 0, 4096, 0, LP_OPTIONS16}, - - /* 64 Gigabit */ - {"NAND 8GiB 1,8V 8-bit", 0xAE, 0, 8192, 0, LP_OPTIONS}, - {"NAND 8GiB 3,3V 8-bit", 0xDE, 0, 8192, 0, LP_OPTIONS}, - {"NAND 8GiB 1,8V 16-bit", 0xBE, 0, 8192, 0, LP_OPTIONS16}, - {"NAND 8GiB 3,3V 16-bit", 0xCE, 0, 8192, 0, LP_OPTIONS16}, - - /* 128 Gigabit */ - {"NAND 16GiB 1,8V 8-bit", 0x1A, 0, 16384, 0, LP_OPTIONS}, - {"NAND 16GiB 3,3V 8-bit", 0x3A, 0, 16384, 0, LP_OPTIONS}, - {"NAND 16GiB 1,8V 16-bit", 0x2A, 0, 16384, 0, LP_OPTIONS16}, - {"NAND 16GiB 3,3V 16-bit", 0x4A, 0, 16384, 0, LP_OPTIONS16}, - - /* 256 Gigabit */ - {"NAND 32GiB 1,8V 8-bit", 0x1C, 0, 32768, 0, LP_OPTIONS}, - {"NAND 32GiB 3,3V 8-bit", 0x3C, 0, 32768, 0, LP_OPTIONS}, - {"NAND 32GiB 1,8V 16-bit", 0x2C, 0, 32768, 0, LP_OPTIONS16}, - {"NAND 32GiB 3,3V 16-bit", 0x4C, 0, 32768, 0, LP_OPTIONS16}, - - /* 512 Gigabit */ - {"NAND 64GiB 1,8V 8-bit", 0x1E, 0, 65536, 0, LP_OPTIONS}, - {"NAND 64GiB 3,3V 8-bit", 0x3E, 0, 65536, 0, LP_OPTIONS}, - {"NAND 64GiB 1,8V 16-bit", 0x2E, 0, 65536, 0, LP_OPTIONS16}, - {"NAND 64GiB 3,3V 16-bit", 0x4E, 0, 65536, 0, LP_OPTIONS16}, - - /* - * Renesas AND 1 Gigabit. Those chips do not support extended id and - * have a strange page/block layout ! The chosen minimum erasesize is - * 4 * 2 * 2048 = 16384 Byte, as those chips have an array of 4 page - * planes 1 block = 2 pages, but due to plane arrangement the blocks - * 0-3 consists of page 0 + 4,1 + 5, 2 + 6, 3 + 7 Anyway JFFS2 would - * increase the eraseblock size so we chose a combined one which can be - * erased in one go There are more speed improvements for reads and - * writes possible, but not implemented now - */ - {"AND 128MiB 3,3V 8-bit", 0x01, 2048, 128, 0x4000, - NAND_IS_AND | NAND_4PAGE_ARRAY | BBT_AUTO_REFRESH}, - - {NULL,} -}; - -/* -* Manufacturer ID list -*/ -const struct nand_manufacturers nand_manuf_ids[] = { - {NAND_MFR_TOSHIBA, "Toshiba"}, - {NAND_MFR_SAMSUNG, "Samsung"}, - {NAND_MFR_FUJITSU, "Fujitsu"}, - {NAND_MFR_NATIONAL, "National"}, - {NAND_MFR_RENESAS, "Renesas"}, - {NAND_MFR_STMICRO, "ST Micro"}, - {NAND_MFR_HYNIX, "Hynix"}, - {NAND_MFR_MICRON, "Micron"}, - {NAND_MFR_AMD, "AMD/Spansion"}, - {NAND_MFR_MACRONIX, "Macronix"}, - {NAND_MFR_EON, "Eon"}, - {0x0, "Unknown"} -}; diff --git a/qemu/roms/u-boot/drivers/mtd/nand/nand_plat.c b/qemu/roms/u-boot/drivers/mtd/nand/nand_plat.c deleted file mode 100644 index 37a0206ad..000000000 --- a/qemu/roms/u-boot/drivers/mtd/nand/nand_plat.c +++ /dev/null @@ -1,64 +0,0 @@ -/* - * Genericish driver for memory mapped NAND devices - * - * Copyright (c) 2006-2009 Analog Devices Inc. - * Licensed under the GPL-2 or later. - */ - -/* Your board must implement the following macros: - * NAND_PLAT_WRITE_CMD(chip, cmd) - * NAND_PLAT_WRITE_ADR(chip, cmd) - * NAND_PLAT_INIT() - * - * It may also implement the following: - * NAND_PLAT_DEV_READY(chip) - */ - -#include <common.h> -#include <asm/io.h> -#ifdef NAND_PLAT_GPIO_DEV_READY -# include <asm/gpio.h> -# define NAND_PLAT_DEV_READY(chip) gpio_get_value(NAND_PLAT_GPIO_DEV_READY) -#endif - -#include <nand.h> - -static void plat_cmd_ctrl(struct mtd_info *mtd, int cmd, unsigned int ctrl) -{ - struct nand_chip *this = mtd->priv; - - if (cmd == NAND_CMD_NONE) - return; - - if (ctrl & NAND_CLE) - NAND_PLAT_WRITE_CMD(this, cmd); - else - NAND_PLAT_WRITE_ADR(this, cmd); -} - -#ifdef NAND_PLAT_DEV_READY -static int plat_dev_ready(struct mtd_info *mtd) -{ - return NAND_PLAT_DEV_READY((struct nand_chip *)mtd->priv); -} -#else -# define plat_dev_ready NULL -#endif - -int board_nand_init(struct nand_chip *nand) -{ -#ifdef NAND_PLAT_GPIO_DEV_READY - gpio_request(NAND_PLAT_GPIO_DEV_READY, "nand-plat"); - gpio_direction_input(NAND_PLAT_GPIO_DEV_READY); -#endif - -#ifdef NAND_PLAT_INIT - NAND_PLAT_INIT(); -#endif - - nand->cmd_ctrl = plat_cmd_ctrl; - nand->dev_ready = plat_dev_ready; - nand->ecc.mode = NAND_ECC_SOFT; - - return 0; -} diff --git a/qemu/roms/u-boot/drivers/mtd/nand/nand_spl_load.c b/qemu/roms/u-boot/drivers/mtd/nand/nand_spl_load.c deleted file mode 100644 index 5a2564464..000000000 --- a/qemu/roms/u-boot/drivers/mtd/nand/nand_spl_load.c +++ /dev/null @@ -1,42 +0,0 @@ -/* - * Copyright (C) 2011 - * Heiko Schocher, DENX Software Engineering, hs@denx.de. - * - * SPDX-License-Identifier: GPL-2.0+ - */ - -#include <common.h> -#include <nand.h> - -/* - * The main entry for NAND booting. It's necessary that SDRAM is already - * configured and available since this code loads the main U-Boot image - * from NAND into SDRAM and starts it from there. - */ -void nand_boot(void) -{ - __attribute__((noreturn)) void (*uboot)(void); - - /* - * Load U-Boot image from NAND into RAM - */ - nand_spl_load_image(CONFIG_SYS_NAND_U_BOOT_OFFS, - CONFIG_SYS_NAND_U_BOOT_SIZE, - (void *)CONFIG_SYS_NAND_U_BOOT_DST); - -#ifdef CONFIG_NAND_ENV_DST - nand_spl_load_image(CONFIG_ENV_OFFSET, CONFIG_ENV_SIZE, - (void *)CONFIG_NAND_ENV_DST); - -#ifdef CONFIG_ENV_OFFSET_REDUND - nand_spl_load_image(CONFIG_ENV_OFFSET_REDUND, CONFIG_ENV_SIZE, - (void *)CONFIG_NAND_ENV_DST + CONFIG_ENV_SIZE); -#endif -#endif - - /* - * Jump to U-Boot image - */ - uboot = (void *)CONFIG_SYS_NAND_U_BOOT_START; - (*uboot)(); -} diff --git a/qemu/roms/u-boot/drivers/mtd/nand/nand_spl_simple.c b/qemu/roms/u-boot/drivers/mtd/nand/nand_spl_simple.c deleted file mode 100644 index cead4b506..000000000 --- a/qemu/roms/u-boot/drivers/mtd/nand/nand_spl_simple.c +++ /dev/null @@ -1,270 +0,0 @@ -/* - * (C) Copyright 2006-2008 - * Stefan Roese, DENX Software Engineering, sr@denx.de. - * - * SPDX-License-Identifier: GPL-2.0+ - */ - -#include <common.h> -#include <nand.h> -#include <asm/io.h> -#include <linux/mtd/nand_ecc.h> - -static int nand_ecc_pos[] = CONFIG_SYS_NAND_ECCPOS; -static nand_info_t mtd; -static struct nand_chip nand_chip; - -#define ECCSTEPS (CONFIG_SYS_NAND_PAGE_SIZE / \ - CONFIG_SYS_NAND_ECCSIZE) -#define ECCTOTAL (ECCSTEPS * CONFIG_SYS_NAND_ECCBYTES) - - -#if (CONFIG_SYS_NAND_PAGE_SIZE <= 512) -/* - * NAND command for small page NAND devices (512) - */ -static int nand_command(int block, int page, uint32_t offs, - u8 cmd) -{ - struct nand_chip *this = mtd.priv; - int page_addr = page + block * CONFIG_SYS_NAND_PAGE_COUNT; - - while (!this->dev_ready(&mtd)) - ; - - /* Begin command latch cycle */ - this->cmd_ctrl(&mtd, cmd, NAND_CTRL_CLE | NAND_CTRL_CHANGE); - /* Set ALE and clear CLE to start address cycle */ - /* Column address */ - this->cmd_ctrl(&mtd, offs, NAND_CTRL_ALE | NAND_CTRL_CHANGE); - this->cmd_ctrl(&mtd, page_addr & 0xff, NAND_CTRL_ALE); /* A[16:9] */ - this->cmd_ctrl(&mtd, (page_addr >> 8) & 0xff, - NAND_CTRL_ALE); /* A[24:17] */ -#ifdef CONFIG_SYS_NAND_4_ADDR_CYCLE - /* One more address cycle for devices > 32MiB */ - this->cmd_ctrl(&mtd, (page_addr >> 16) & 0x0f, - NAND_CTRL_ALE); /* A[28:25] */ -#endif - /* Latch in address */ - this->cmd_ctrl(&mtd, NAND_CMD_NONE, NAND_NCE | NAND_CTRL_CHANGE); - - /* - * Wait a while for the data to be ready - */ - while (!this->dev_ready(&mtd)) - ; - - return 0; -} -#else -/* - * NAND command for large page NAND devices (2k) - */ -static int nand_command(int block, int page, uint32_t offs, - u8 cmd) -{ - struct nand_chip *this = mtd.priv; - int page_addr = page + block * CONFIG_SYS_NAND_PAGE_COUNT; - void (*hwctrl)(struct mtd_info *mtd, int cmd, - unsigned int ctrl) = this->cmd_ctrl; - - while (!this->dev_ready(&mtd)) - ; - - /* Emulate NAND_CMD_READOOB */ - if (cmd == NAND_CMD_READOOB) { - offs += CONFIG_SYS_NAND_PAGE_SIZE; - cmd = NAND_CMD_READ0; - } - - /* Shift the offset from byte addressing to word addressing. */ - if (this->options & NAND_BUSWIDTH_16) - offs >>= 1; - - /* Begin command latch cycle */ - hwctrl(&mtd, cmd, NAND_CTRL_CLE | NAND_CTRL_CHANGE); - /* Set ALE and clear CLE to start address cycle */ - /* Column address */ - hwctrl(&mtd, offs & 0xff, - NAND_CTRL_ALE | NAND_CTRL_CHANGE); /* A[7:0] */ - hwctrl(&mtd, (offs >> 8) & 0xff, NAND_CTRL_ALE); /* A[11:9] */ - /* Row address */ - hwctrl(&mtd, (page_addr & 0xff), NAND_CTRL_ALE); /* A[19:12] */ - hwctrl(&mtd, ((page_addr >> 8) & 0xff), - NAND_CTRL_ALE); /* A[27:20] */ -#ifdef CONFIG_SYS_NAND_5_ADDR_CYCLE - /* One more address cycle for devices > 128MiB */ - hwctrl(&mtd, (page_addr >> 16) & 0x0f, - NAND_CTRL_ALE); /* A[31:28] */ -#endif - /* Latch in address */ - hwctrl(&mtd, NAND_CMD_READSTART, - NAND_CTRL_CLE | NAND_CTRL_CHANGE); - hwctrl(&mtd, NAND_CMD_NONE, NAND_NCE | NAND_CTRL_CHANGE); - - /* - * Wait a while for the data to be ready - */ - while (!this->dev_ready(&mtd)) - ; - - return 0; -} -#endif - -static int nand_is_bad_block(int block) -{ - struct nand_chip *this = mtd.priv; - - nand_command(block, 0, CONFIG_SYS_NAND_BAD_BLOCK_POS, - NAND_CMD_READOOB); - - /* - * Read one byte (or two if it's a 16 bit chip). - */ - if (this->options & NAND_BUSWIDTH_16) { - if (readw(this->IO_ADDR_R) != 0xffff) - return 1; - } else { - if (readb(this->IO_ADDR_R) != 0xff) - return 1; - } - - return 0; -} - -#if defined(CONFIG_SYS_NAND_HW_ECC_OOBFIRST) -static int nand_read_page(int block, int page, uchar *dst) -{ - struct nand_chip *this = mtd.priv; - u_char ecc_calc[ECCTOTAL]; - u_char ecc_code[ECCTOTAL]; - u_char oob_data[CONFIG_SYS_NAND_OOBSIZE]; - int i; - int eccsize = CONFIG_SYS_NAND_ECCSIZE; - int eccbytes = CONFIG_SYS_NAND_ECCBYTES; - int eccsteps = ECCSTEPS; - uint8_t *p = dst; - - nand_command(block, page, 0, NAND_CMD_READOOB); - this->read_buf(&mtd, oob_data, CONFIG_SYS_NAND_OOBSIZE); - nand_command(block, page, 0, NAND_CMD_READ0); - - /* Pick the ECC bytes out of the oob data */ - for (i = 0; i < ECCTOTAL; i++) - ecc_code[i] = oob_data[nand_ecc_pos[i]]; - - - for (i = 0; eccsteps; eccsteps--, i += eccbytes, p += eccsize) { - this->ecc.hwctl(&mtd, NAND_ECC_READ); - this->read_buf(&mtd, p, eccsize); - this->ecc.calculate(&mtd, p, &ecc_calc[i]); - this->ecc.correct(&mtd, p, &ecc_code[i], &ecc_calc[i]); - } - - return 0; -} -#else -static int nand_read_page(int block, int page, void *dst) -{ - struct nand_chip *this = mtd.priv; - u_char ecc_calc[ECCTOTAL]; - u_char ecc_code[ECCTOTAL]; - u_char oob_data[CONFIG_SYS_NAND_OOBSIZE]; - int i; - int eccsize = CONFIG_SYS_NAND_ECCSIZE; - int eccbytes = CONFIG_SYS_NAND_ECCBYTES; - int eccsteps = ECCSTEPS; - uint8_t *p = dst; - - nand_command(block, page, 0, NAND_CMD_READ0); - - for (i = 0; eccsteps; eccsteps--, i += eccbytes, p += eccsize) { - if (this->ecc.mode != NAND_ECC_SOFT) - this->ecc.hwctl(&mtd, NAND_ECC_READ); - this->read_buf(&mtd, p, eccsize); - this->ecc.calculate(&mtd, p, &ecc_calc[i]); - } - this->read_buf(&mtd, oob_data, CONFIG_SYS_NAND_OOBSIZE); - - /* Pick the ECC bytes out of the oob data */ - for (i = 0; i < ECCTOTAL; i++) - ecc_code[i] = oob_data[nand_ecc_pos[i]]; - - eccsteps = ECCSTEPS; - p = dst; - - for (i = 0 ; eccsteps; eccsteps--, i += eccbytes, p += eccsize) { - /* No chance to do something with the possible error message - * from correct_data(). We just hope that all possible errors - * are corrected by this routine. - */ - this->ecc.correct(&mtd, p, &ecc_code[i], &ecc_calc[i]); - } - - return 0; -} -#endif - -int nand_spl_load_image(uint32_t offs, unsigned int size, void *dst) -{ - unsigned int block, lastblock; - unsigned int page; - - /* - * offs has to be aligned to a page address! - */ - block = offs / CONFIG_SYS_NAND_BLOCK_SIZE; - lastblock = (offs + size - 1) / CONFIG_SYS_NAND_BLOCK_SIZE; - page = (offs % CONFIG_SYS_NAND_BLOCK_SIZE) / CONFIG_SYS_NAND_PAGE_SIZE; - - while (block <= lastblock) { - if (!nand_is_bad_block(block)) { - /* - * Skip bad blocks - */ - while (page < CONFIG_SYS_NAND_PAGE_COUNT) { - nand_read_page(block, page, dst); - dst += CONFIG_SYS_NAND_PAGE_SIZE; - page++; - } - - page = 0; - } else { - lastblock++; - } - - block++; - } - - return 0; -} - -/* nand_init() - initialize data to make nand usable by SPL */ -void nand_init(void) -{ - /* - * Init board specific nand support - */ - mtd.priv = &nand_chip; - nand_chip.IO_ADDR_R = nand_chip.IO_ADDR_W = - (void __iomem *)CONFIG_SYS_NAND_BASE; - board_nand_init(&nand_chip); - -#ifdef CONFIG_SPL_NAND_SOFTECC - if (nand_chip.ecc.mode == NAND_ECC_SOFT) { - nand_chip.ecc.calculate = nand_calculate_ecc; - nand_chip.ecc.correct = nand_correct_data; - } -#endif - - if (nand_chip.select_chip) - nand_chip.select_chip(&mtd, 0); -} - -/* Unselect after operation */ -void nand_deselect(void) -{ - if (nand_chip.select_chip) - nand_chip.select_chip(&mtd, -1); -} diff --git a/qemu/roms/u-boot/drivers/mtd/nand/nand_util.c b/qemu/roms/u-boot/drivers/mtd/nand/nand_util.c deleted file mode 100644 index b29282603..000000000 --- a/qemu/roms/u-boot/drivers/mtd/nand/nand_util.c +++ /dev/null @@ -1,861 +0,0 @@ -/* - * drivers/mtd/nand/nand_util.c - * - * Copyright (C) 2006 by Weiss-Electronic GmbH. - * All rights reserved. - * - * @author: Guido Classen <clagix@gmail.com> - * @descr: NAND Flash support - * @references: borrowed heavily from Linux mtd-utils code: - * flash_eraseall.c by Arcom Control System Ltd - * nandwrite.c by Steven J. Hill (sjhill@realitydiluted.com) - * and Thomas Gleixner (tglx@linutronix.de) - * - * Copyright (C) 2008 Nokia Corporation: drop_ffs() function by - * Artem Bityutskiy <dedekind1@gmail.com> from mtd-utils - * - * Copyright 2010 Freescale Semiconductor - * - * SPDX-License-Identifier: GPL-2.0 - */ - -#include <common.h> -#include <command.h> -#include <watchdog.h> -#include <malloc.h> -#include <div64.h> - -#include <asm/errno.h> -#include <linux/mtd/mtd.h> -#include <nand.h> -#include <jffs2/jffs2.h> - -typedef struct erase_info erase_info_t; -typedef struct mtd_info mtd_info_t; - -/* support only for native endian JFFS2 */ -#define cpu_to_je16(x) (x) -#define cpu_to_je32(x) (x) - -/** - * nand_erase_opts: - erase NAND flash with support for various options - * (jffs2 formatting) - * - * @param meminfo NAND device to erase - * @param opts options, @see struct nand_erase_options - * @return 0 in case of success - * - * This code is ported from flash_eraseall.c from Linux mtd utils by - * Arcom Control System Ltd. - */ -int nand_erase_opts(nand_info_t *meminfo, const nand_erase_options_t *opts) -{ - struct jffs2_unknown_node cleanmarker; - erase_info_t erase; - unsigned long erase_length, erased_length; /* in blocks */ - int result; - int percent_complete = -1; - const char *mtd_device = meminfo->name; - struct mtd_oob_ops oob_opts; - struct nand_chip *chip = meminfo->priv; - - if ((opts->offset & (meminfo->erasesize - 1)) != 0) { - printf("Attempt to erase non block-aligned data\n"); - return -1; - } - - memset(&erase, 0, sizeof(erase)); - memset(&oob_opts, 0, sizeof(oob_opts)); - - erase.mtd = meminfo; - erase.len = meminfo->erasesize; - erase.addr = opts->offset; - erase_length = lldiv(opts->length + meminfo->erasesize - 1, - meminfo->erasesize); - - cleanmarker.magic = cpu_to_je16(JFFS2_MAGIC_BITMASK); - cleanmarker.nodetype = cpu_to_je16(JFFS2_NODETYPE_CLEANMARKER); - cleanmarker.totlen = cpu_to_je32(8); - - /* scrub option allows to erase badblock. To prevent internal - * check from erase() method, set block check method to dummy - * and disable bad block table while erasing. - */ - if (opts->scrub) { - erase.scrub = opts->scrub; - /* - * We don't need the bad block table anymore... - * after scrub, there are no bad blocks left! - */ - if (chip->bbt) { - kfree(chip->bbt); - } - chip->bbt = NULL; - } - - for (erased_length = 0; - erased_length < erase_length; - erase.addr += meminfo->erasesize) { - - WATCHDOG_RESET(); - - if (opts->lim && (erase.addr >= (opts->offset + opts->lim))) { - puts("Size of erase exceeds limit\n"); - return -EFBIG; - } - if (!opts->scrub) { - int ret = mtd_block_isbad(meminfo, erase.addr); - if (ret > 0) { - if (!opts->quiet) - printf("\rSkipping bad block at " - "0x%08llx " - " \n", - erase.addr); - - if (!opts->spread) - erased_length++; - - continue; - - } else if (ret < 0) { - printf("\n%s: MTD get bad block failed: %d\n", - mtd_device, - ret); - return -1; - } - } - - erased_length++; - - result = mtd_erase(meminfo, &erase); - if (result != 0) { - printf("\n%s: MTD Erase failure: %d\n", - mtd_device, result); - continue; - } - - /* format for JFFS2 ? */ - if (opts->jffs2 && chip->ecc.layout->oobavail >= 8) { - struct mtd_oob_ops ops; - ops.ooblen = 8; - ops.datbuf = NULL; - ops.oobbuf = (uint8_t *)&cleanmarker; - ops.ooboffs = 0; - ops.mode = MTD_OPS_AUTO_OOB; - - result = mtd_write_oob(meminfo, - erase.addr, - &ops); - if (result != 0) { - printf("\n%s: MTD writeoob failure: %d\n", - mtd_device, result); - continue; - } - } - - if (!opts->quiet) { - unsigned long long n = erased_length * 100ULL; - int percent; - - do_div(n, erase_length); - percent = (int)n; - - /* output progress message only at whole percent - * steps to reduce the number of messages printed - * on (slow) serial consoles - */ - if (percent != percent_complete) { - percent_complete = percent; - - printf("\rErasing at 0x%llx -- %3d%% complete.", - erase.addr, percent); - - if (opts->jffs2 && result == 0) - printf(" Cleanmarker written at 0x%llx.", - erase.addr); - } - } - } - if (!opts->quiet) - printf("\n"); - - if (opts->scrub) - chip->scan_bbt(meminfo); - - return 0; -} - -#ifdef CONFIG_CMD_NAND_LOCK_UNLOCK - -/****************************************************************************** - * Support for locking / unlocking operations of some NAND devices - *****************************************************************************/ - -/** - * nand_lock: Set all pages of NAND flash chip to the LOCK or LOCK-TIGHT - * state - * - * @param mtd nand mtd instance - * @param tight bring device in lock tight mode - * - * @return 0 on success, -1 in case of error - * - * The lock / lock-tight command only applies to the whole chip. To get some - * parts of the chip lock and others unlocked use the following sequence: - * - * - Lock all pages of the chip using nand_lock(mtd, 0) (or the lockpre pin) - * - Call nand_unlock() once for each consecutive area to be unlocked - * - If desired: Bring the chip to the lock-tight state using nand_lock(mtd, 1) - * - * If the device is in lock-tight state software can't change the - * current active lock/unlock state of all pages. nand_lock() / nand_unlock() - * calls will fail. It is only posible to leave lock-tight state by - * an hardware signal (low pulse on _WP pin) or by power down. - */ -int nand_lock(struct mtd_info *mtd, int tight) -{ - int ret = 0; - int status; - struct nand_chip *chip = mtd->priv; - - /* select the NAND device */ - chip->select_chip(mtd, 0); - - /* check the Lock Tight Status */ - chip->cmdfunc(mtd, NAND_CMD_LOCK_STATUS, -1, 0); - if (chip->read_byte(mtd) & NAND_LOCK_STATUS_TIGHT) { - printf("nand_lock: Device is locked tight!\n"); - ret = -1; - goto out; - } - - chip->cmdfunc(mtd, - (tight ? NAND_CMD_LOCK_TIGHT : NAND_CMD_LOCK), - -1, -1); - - /* call wait ready function */ - status = chip->waitfunc(mtd, chip); - - /* see if device thinks it succeeded */ - if (status & 0x01) { - ret = -1; - } - - out: - /* de-select the NAND device */ - chip->select_chip(mtd, -1); - return ret; -} - -/** - * nand_get_lock_status: - query current lock state from one page of NAND - * flash - * - * @param mtd nand mtd instance - * @param offset page address to query (must be page-aligned!) - * - * @return -1 in case of error - * >0 lock status: - * bitfield with the following combinations: - * NAND_LOCK_STATUS_TIGHT: page in tight state - * NAND_LOCK_STATUS_UNLOCK: page unlocked - * - */ -int nand_get_lock_status(struct mtd_info *mtd, loff_t offset) -{ - int ret = 0; - int chipnr; - int page; - struct nand_chip *chip = mtd->priv; - - /* select the NAND device */ - chipnr = (int)(offset >> chip->chip_shift); - chip->select_chip(mtd, chipnr); - - - if ((offset & (mtd->writesize - 1)) != 0) { - printf("nand_get_lock_status: " - "Start address must be beginning of " - "nand page!\n"); - ret = -1; - goto out; - } - - /* check the Lock Status */ - page = (int)(offset >> chip->page_shift); - chip->cmdfunc(mtd, NAND_CMD_LOCK_STATUS, -1, page & chip->pagemask); - - ret = chip->read_byte(mtd) & (NAND_LOCK_STATUS_TIGHT - | NAND_LOCK_STATUS_UNLOCK); - - out: - /* de-select the NAND device */ - chip->select_chip(mtd, -1); - return ret; -} - -/** - * nand_unlock: - Unlock area of NAND pages - * only one consecutive area can be unlocked at one time! - * - * @param mtd nand mtd instance - * @param start start byte address - * @param length number of bytes to unlock (must be a multiple of - * page size nand->writesize) - * @param allexcept if set, unlock everything not selected - * - * @return 0 on success, -1 in case of error - */ -int nand_unlock(struct mtd_info *mtd, loff_t start, size_t length, - int allexcept) -{ - int ret = 0; - int chipnr; - int status; - int page; - struct nand_chip *chip = mtd->priv; - - debug("nand_unlock%s: start: %08llx, length: %zd!\n", - allexcept ? " (allexcept)" : "", start, length); - - /* select the NAND device */ - chipnr = (int)(start >> chip->chip_shift); - chip->select_chip(mtd, chipnr); - - /* check the WP bit */ - chip->cmdfunc(mtd, NAND_CMD_STATUS, -1, -1); - if (!(chip->read_byte(mtd) & NAND_STATUS_WP)) { - printf("nand_unlock: Device is write protected!\n"); - ret = -1; - goto out; - } - - /* check the Lock Tight Status */ - page = (int)(start >> chip->page_shift); - chip->cmdfunc(mtd, NAND_CMD_LOCK_STATUS, -1, page & chip->pagemask); - if (chip->read_byte(mtd) & NAND_LOCK_STATUS_TIGHT) { - printf("nand_unlock: Device is locked tight!\n"); - ret = -1; - goto out; - } - - if ((start & (mtd->erasesize - 1)) != 0) { - printf("nand_unlock: Start address must be beginning of " - "nand block!\n"); - ret = -1; - goto out; - } - - if (length == 0 || (length & (mtd->erasesize - 1)) != 0) { - printf("nand_unlock: Length must be a multiple of nand block " - "size %08x!\n", mtd->erasesize); - ret = -1; - goto out; - } - - /* - * Set length so that the last address is set to the - * starting address of the last block - */ - length -= mtd->erasesize; - - /* submit address of first page to unlock */ - chip->cmdfunc(mtd, NAND_CMD_UNLOCK1, -1, page & chip->pagemask); - - /* submit ADDRESS of LAST page to unlock */ - page += (int)(length >> chip->page_shift); - - /* - * Page addresses for unlocking are supposed to be block-aligned. - * At least some NAND chips use the low bit to indicate that the - * page range should be inverted. - */ - if (allexcept) - page |= 1; - - chip->cmdfunc(mtd, NAND_CMD_UNLOCK2, -1, page & chip->pagemask); - - /* call wait ready function */ - status = chip->waitfunc(mtd, chip); - /* see if device thinks it succeeded */ - if (status & 0x01) { - /* there was an error */ - ret = -1; - goto out; - } - - out: - /* de-select the NAND device */ - chip->select_chip(mtd, -1); - return ret; -} -#endif - -/** - * check_skip_len - * - * Check if there are any bad blocks, and whether length including bad - * blocks fits into device - * - * @param nand NAND device - * @param offset offset in flash - * @param length image length - * @param used length of flash needed for the requested length - * @return 0 if the image fits and there are no bad blocks - * 1 if the image fits, but there are bad blocks - * -1 if the image does not fit - */ -static int check_skip_len(nand_info_t *nand, loff_t offset, size_t length, - size_t *used) -{ - size_t len_excl_bad = 0; - int ret = 0; - - while (len_excl_bad < length) { - size_t block_len, block_off; - loff_t block_start; - - if (offset >= nand->size) - return -1; - - block_start = offset & ~(loff_t)(nand->erasesize - 1); - block_off = offset & (nand->erasesize - 1); - block_len = nand->erasesize - block_off; - - if (!nand_block_isbad(nand, block_start)) - len_excl_bad += block_len; - else - ret = 1; - - offset += block_len; - *used += block_len; - } - - /* If the length is not a multiple of block_len, adjust. */ - if (len_excl_bad > length) - *used -= (len_excl_bad - length); - - return ret; -} - -#ifdef CONFIG_CMD_NAND_TRIMFFS -static size_t drop_ffs(const nand_info_t *nand, const u_char *buf, - const size_t *len) -{ - size_t l = *len; - ssize_t i; - - for (i = l - 1; i >= 0; i--) - if (buf[i] != 0xFF) - break; - - /* The resulting length must be aligned to the minimum flash I/O size */ - l = i + 1; - l = (l + nand->writesize - 1) / nand->writesize; - l *= nand->writesize; - - /* - * since the input length may be unaligned, prevent access past the end - * of the buffer - */ - return min(l, *len); -} -#endif - -/** - * nand_write_skip_bad: - * - * Write image to NAND flash. - * Blocks that are marked bad are skipped and the is written to the next - * block instead as long as the image is short enough to fit even after - * skipping the bad blocks. Due to bad blocks we may not be able to - * perform the requested write. In the case where the write would - * extend beyond the end of the NAND device, both length and actual (if - * not NULL) are set to 0. In the case where the write would extend - * beyond the limit we are passed, length is set to 0 and actual is set - * to the required length. - * - * @param nand NAND device - * @param offset offset in flash - * @param length buffer length - * @param actual set to size required to write length worth of - * buffer or 0 on error, if not NULL - * @param lim maximum size that actual may be in order to not - * exceed the buffer - * @param buffer buffer to read from - * @param flags flags modifying the behaviour of the write to NAND - * @return 0 in case of success - */ -int nand_write_skip_bad(nand_info_t *nand, loff_t offset, size_t *length, - size_t *actual, loff_t lim, u_char *buffer, int flags) -{ - int rval = 0, blocksize; - size_t left_to_write = *length; - size_t used_for_write = 0; - u_char *p_buffer = buffer; - int need_skip; - - if (actual) - *actual = 0; - -#ifdef CONFIG_CMD_NAND_YAFFS - if (flags & WITH_YAFFS_OOB) { - if (flags & ~WITH_YAFFS_OOB) - return -EINVAL; - - int pages; - pages = nand->erasesize / nand->writesize; - blocksize = (pages * nand->oobsize) + nand->erasesize; - if (*length % (nand->writesize + nand->oobsize)) { - printf("Attempt to write incomplete page" - " in yaffs mode\n"); - return -EINVAL; - } - } else -#endif - { - blocksize = nand->erasesize; - } - - /* - * nand_write() handles unaligned, partial page writes. - * - * We allow length to be unaligned, for convenience in - * using the $filesize variable. - * - * However, starting at an unaligned offset makes the - * semantics of bad block skipping ambiguous (really, - * you should only start a block skipping access at a - * partition boundary). So don't try to handle that. - */ - if ((offset & (nand->writesize - 1)) != 0) { - printf("Attempt to write non page-aligned data\n"); - *length = 0; - return -EINVAL; - } - - need_skip = check_skip_len(nand, offset, *length, &used_for_write); - - if (actual) - *actual = used_for_write; - - if (need_skip < 0) { - printf("Attempt to write outside the flash area\n"); - *length = 0; - return -EINVAL; - } - - if (used_for_write > lim) { - puts("Size of write exceeds partition or device limit\n"); - *length = 0; - return -EFBIG; - } - - if (!need_skip && !(flags & WITH_DROP_FFS)) { - rval = nand_write(nand, offset, length, buffer); - if (rval == 0) - return 0; - - *length = 0; - printf("NAND write to offset %llx failed %d\n", - offset, rval); - return rval; - } - - while (left_to_write > 0) { - size_t block_offset = offset & (nand->erasesize - 1); - size_t write_size, truncated_write_size; - - WATCHDOG_RESET(); - - if (nand_block_isbad(nand, offset & ~(nand->erasesize - 1))) { - printf("Skip bad block 0x%08llx\n", - offset & ~(nand->erasesize - 1)); - offset += nand->erasesize - block_offset; - continue; - } - - if (left_to_write < (blocksize - block_offset)) - write_size = left_to_write; - else - write_size = blocksize - block_offset; - -#ifdef CONFIG_CMD_NAND_YAFFS - if (flags & WITH_YAFFS_OOB) { - int page, pages; - size_t pagesize = nand->writesize; - size_t pagesize_oob = pagesize + nand->oobsize; - struct mtd_oob_ops ops; - - ops.len = pagesize; - ops.ooblen = nand->oobsize; - ops.mode = MTD_OPS_AUTO_OOB; - ops.ooboffs = 0; - - pages = write_size / pagesize_oob; - for (page = 0; page < pages; page++) { - WATCHDOG_RESET(); - - ops.datbuf = p_buffer; - ops.oobbuf = ops.datbuf + pagesize; - - rval = mtd_write_oob(nand, offset, &ops); - if (rval != 0) - break; - - offset += pagesize; - p_buffer += pagesize_oob; - } - } - else -#endif - { - truncated_write_size = write_size; -#ifdef CONFIG_CMD_NAND_TRIMFFS - if (flags & WITH_DROP_FFS) - truncated_write_size = drop_ffs(nand, p_buffer, - &write_size); -#endif - - rval = nand_write(nand, offset, &truncated_write_size, - p_buffer); - offset += write_size; - p_buffer += write_size; - } - - if (rval != 0) { - printf("NAND write to offset %llx failed %d\n", - offset, rval); - *length -= left_to_write; - return rval; - } - - left_to_write -= write_size; - } - - return 0; -} - -/** - * nand_read_skip_bad: - * - * Read image from NAND flash. - * Blocks that are marked bad are skipped and the next block is read - * instead as long as the image is short enough to fit even after - * skipping the bad blocks. Due to bad blocks we may not be able to - * perform the requested read. In the case where the read would extend - * beyond the end of the NAND device, both length and actual (if not - * NULL) are set to 0. In the case where the read would extend beyond - * the limit we are passed, length is set to 0 and actual is set to the - * required length. - * - * @param nand NAND device - * @param offset offset in flash - * @param length buffer length, on return holds number of read bytes - * @param actual set to size required to read length worth of buffer or 0 - * on error, if not NULL - * @param lim maximum size that actual may be in order to not exceed the - * buffer - * @param buffer buffer to write to - * @return 0 in case of success - */ -int nand_read_skip_bad(nand_info_t *nand, loff_t offset, size_t *length, - size_t *actual, loff_t lim, u_char *buffer) -{ - int rval; - size_t left_to_read = *length; - size_t used_for_read = 0; - u_char *p_buffer = buffer; - int need_skip; - - if ((offset & (nand->writesize - 1)) != 0) { - printf("Attempt to read non page-aligned data\n"); - *length = 0; - if (actual) - *actual = 0; - return -EINVAL; - } - - need_skip = check_skip_len(nand, offset, *length, &used_for_read); - - if (actual) - *actual = used_for_read; - - if (need_skip < 0) { - printf("Attempt to read outside the flash area\n"); - *length = 0; - return -EINVAL; - } - - if (used_for_read > lim) { - puts("Size of read exceeds partition or device limit\n"); - *length = 0; - return -EFBIG; - } - - if (!need_skip) { - rval = nand_read(nand, offset, length, buffer); - if (!rval || rval == -EUCLEAN) - return 0; - - *length = 0; - printf("NAND read from offset %llx failed %d\n", - offset, rval); - return rval; - } - - while (left_to_read > 0) { - size_t block_offset = offset & (nand->erasesize - 1); - size_t read_length; - - WATCHDOG_RESET(); - - if (nand_block_isbad(nand, offset & ~(nand->erasesize - 1))) { - printf("Skipping bad block 0x%08llx\n", - offset & ~(nand->erasesize - 1)); - offset += nand->erasesize - block_offset; - continue; - } - - if (left_to_read < (nand->erasesize - block_offset)) - read_length = left_to_read; - else - read_length = nand->erasesize - block_offset; - - rval = nand_read(nand, offset, &read_length, p_buffer); - if (rval && rval != -EUCLEAN) { - printf("NAND read from offset %llx failed %d\n", - offset, rval); - *length -= left_to_read; - return rval; - } - - left_to_read -= read_length; - offset += read_length; - p_buffer += read_length; - } - - return 0; -} - -#ifdef CONFIG_CMD_NAND_TORTURE - -/** - * check_pattern: - * - * Check if buffer contains only a certain byte pattern. - * - * @param buf buffer to check - * @param patt the pattern to check - * @param size buffer size in bytes - * @return 1 if there are only patt bytes in buf - * 0 if something else was found - */ -static int check_pattern(const u_char *buf, u_char patt, int size) -{ - int i; - - for (i = 0; i < size; i++) - if (buf[i] != patt) - return 0; - return 1; -} - -/** - * nand_torture: - * - * Torture a block of NAND flash. - * This is useful to determine if a block that caused a write error is still - * good or should be marked as bad. - * - * @param nand NAND device - * @param offset offset in flash - * @return 0 if the block is still good - */ -int nand_torture(nand_info_t *nand, loff_t offset) -{ - u_char patterns[] = {0xa5, 0x5a, 0x00}; - struct erase_info instr = { - .mtd = nand, - .addr = offset, - .len = nand->erasesize, - }; - size_t retlen; - int err, ret = -1, i, patt_count; - u_char *buf; - - if ((offset & (nand->erasesize - 1)) != 0) { - puts("Attempt to torture a block at a non block-aligned offset\n"); - return -EINVAL; - } - - if (offset + nand->erasesize > nand->size) { - puts("Attempt to torture a block outside the flash area\n"); - return -EINVAL; - } - - patt_count = ARRAY_SIZE(patterns); - - buf = malloc(nand->erasesize); - if (buf == NULL) { - puts("Out of memory for erase block buffer\n"); - return -ENOMEM; - } - - for (i = 0; i < patt_count; i++) { - err = nand->erase(nand, &instr); - if (err) { - printf("%s: erase() failed for block at 0x%llx: %d\n", - nand->name, instr.addr, err); - goto out; - } - - /* Make sure the block contains only 0xff bytes */ - err = nand->read(nand, offset, nand->erasesize, &retlen, buf); - if ((err && err != -EUCLEAN) || retlen != nand->erasesize) { - printf("%s: read() failed for block at 0x%llx: %d\n", - nand->name, instr.addr, err); - goto out; - } - - err = check_pattern(buf, 0xff, nand->erasesize); - if (!err) { - printf("Erased block at 0x%llx, but a non-0xff byte was found\n", - offset); - ret = -EIO; - goto out; - } - - /* Write a pattern and check it */ - memset(buf, patterns[i], nand->erasesize); - err = nand->write(nand, offset, nand->erasesize, &retlen, buf); - if (err || retlen != nand->erasesize) { - printf("%s: write() failed for block at 0x%llx: %d\n", - nand->name, instr.addr, err); - goto out; - } - - err = nand->read(nand, offset, nand->erasesize, &retlen, buf); - if ((err && err != -EUCLEAN) || retlen != nand->erasesize) { - printf("%s: read() failed for block at 0x%llx: %d\n", - nand->name, instr.addr, err); - goto out; - } - - err = check_pattern(buf, patterns[i], nand->erasesize); - if (!err) { - printf("Pattern 0x%.2x checking failed for block at " - "0x%llx\n", patterns[i], offset); - ret = -EIO; - goto out; - } - } - - ret = 0; - -out: - free(buf); - return ret; -} - -#endif diff --git a/qemu/roms/u-boot/drivers/mtd/nand/ndfc.c b/qemu/roms/u-boot/drivers/mtd/nand/ndfc.c deleted file mode 100644 index 5510b13c0..000000000 --- a/qemu/roms/u-boot/drivers/mtd/nand/ndfc.c +++ /dev/null @@ -1,214 +0,0 @@ -/* - * Overview: - * Platform independend driver for NDFC (NanD Flash Controller) - * integrated into IBM/AMCC PPC4xx cores - * - * (C) Copyright 2006-2009 - * Stefan Roese, DENX Software Engineering, sr@denx.de. - * - * Based on original work by - * Thomas Gleixner - * Copyright 2006 IBM - * - * SPDX-License-Identifier: GPL-2.0+ - */ - -#include <common.h> -#include <nand.h> -#include <linux/mtd/ndfc.h> -#include <linux/mtd/nand_ecc.h> -#include <asm/processor.h> -#include <asm/io.h> -#include <asm/ppc4xx.h> - -#ifndef CONFIG_SYS_NAND_BCR -#define CONFIG_SYS_NAND_BCR 0x80002222 -#endif -#ifndef CONFIG_SYS_NDFC_EBC0_CFG -#define CONFIG_SYS_NDFC_EBC0_CFG 0xb8400000 -#endif - -/* - * We need to store the info, which chip-select (CS) is used for the - * chip number. For example on Sequoia NAND chip #0 uses - * CS #3. - */ -static int ndfc_cs[NDFC_MAX_BANKS]; - -static void ndfc_hwcontrol(struct mtd_info *mtd, int cmd, unsigned int ctrl) -{ - struct nand_chip *this = mtd->priv; - ulong base = (ulong) this->IO_ADDR_W & 0xffffff00; - - if (cmd == NAND_CMD_NONE) - return; - - if (ctrl & NAND_CLE) - out_8((u8 *)(base + NDFC_CMD), cmd & 0xFF); - else - out_8((u8 *)(base + NDFC_ALE), cmd & 0xFF); -} - -static int ndfc_dev_ready(struct mtd_info *mtdinfo) -{ - struct nand_chip *this = mtdinfo->priv; - ulong base = (ulong) this->IO_ADDR_W & 0xffffff00; - - return (in_be32((u32 *)(base + NDFC_STAT)) & NDFC_STAT_IS_READY); -} - -static void ndfc_enable_hwecc(struct mtd_info *mtdinfo, int mode) -{ - struct nand_chip *this = mtdinfo->priv; - ulong base = (ulong) this->IO_ADDR_W & 0xffffff00; - u32 ccr; - - ccr = in_be32((u32 *)(base + NDFC_CCR)); - ccr |= NDFC_CCR_RESET_ECC; - out_be32((u32 *)(base + NDFC_CCR), ccr); -} - -static int ndfc_calculate_ecc(struct mtd_info *mtdinfo, - const u_char *dat, u_char *ecc_code) -{ - struct nand_chip *this = mtdinfo->priv; - ulong base = (ulong) this->IO_ADDR_W & 0xffffff00; - u32 ecc; - u8 *p = (u8 *)&ecc; - - ecc = in_be32((u32 *)(base + NDFC_ECC)); - - /* The NDFC uses Smart Media (SMC) bytes order - */ - ecc_code[0] = p[1]; - ecc_code[1] = p[2]; - ecc_code[2] = p[3]; - - return 0; -} - -/* - * Speedups for buffer read/write/verify - * - * NDFC allows 32bit read/write of data. So we can speed up the buffer - * functions. No further checking, as nand_base will always read/write - * page aligned. - */ -static void ndfc_read_buf(struct mtd_info *mtdinfo, uint8_t *buf, int len) -{ - struct nand_chip *this = mtdinfo->priv; - ulong base = (ulong) this->IO_ADDR_W & 0xffffff00; - uint32_t *p = (uint32_t *) buf; - - for (;len > 0; len -= 4) - *p++ = in_be32((u32 *)(base + NDFC_DATA)); -} - -/* - * Don't use these speedup functions in NAND boot image, since the image - * has to fit into 4kByte. - */ -static void ndfc_write_buf(struct mtd_info *mtdinfo, const uint8_t *buf, int len) -{ - struct nand_chip *this = mtdinfo->priv; - ulong base = (ulong) this->IO_ADDR_W & 0xffffff00; - uint32_t *p = (uint32_t *) buf; - - for (; len > 0; len -= 4) - out_be32((u32 *)(base + NDFC_DATA), *p++); -} - -static int ndfc_verify_buf(struct mtd_info *mtdinfo, const uint8_t *buf, int len) -{ - struct nand_chip *this = mtdinfo->priv; - ulong base = (ulong) this->IO_ADDR_W & 0xffffff00; - uint32_t *p = (uint32_t *) buf; - - for (; len > 0; len -= 4) - if (*p++ != in_be32((u32 *)(base + NDFC_DATA))) - return -1; - - return 0; -} - -/* - * Read a byte from the NDFC. - */ -static uint8_t ndfc_read_byte(struct mtd_info *mtd) -{ - - struct nand_chip *chip = mtd->priv; - -#ifdef CONFIG_SYS_NAND_BUSWIDTH_16BIT - return (uint8_t) readw(chip->IO_ADDR_R); -#else - return readb(chip->IO_ADDR_R); -#endif - -} - -void board_nand_select_device(struct nand_chip *nand, int chip) -{ - /* - * Don't use "chip" to address the NAND device, - * generate the cs from the address where it is encoded. - */ - ulong base = (ulong)nand->IO_ADDR_W & 0xffffff00; - int cs = ndfc_cs[chip]; - - /* Set NandFlash Core Configuration Register */ - /* 1 col x 2 rows */ - out_be32((u32 *)(base + NDFC_CCR), 0x00000000 | (cs << 24)); - out_be32((u32 *)(base + NDFC_BCFG0 + (cs << 2)), CONFIG_SYS_NAND_BCR); -} - -static void ndfc_select_chip(struct mtd_info *mtd, int chip) -{ - /* - * Nothing to do here! - */ -} - -int board_nand_init(struct nand_chip *nand) -{ - int cs = (ulong)nand->IO_ADDR_W & 0x00000003; - ulong base = (ulong)nand->IO_ADDR_W & 0xffffff00; - static int chip = 0; - - /* - * Save chip-select for this chip # - */ - ndfc_cs[chip] = cs; - - /* - * Select required NAND chip in NDFC - */ - board_nand_select_device(nand, chip); - - nand->IO_ADDR_R = (void __iomem *)(base + NDFC_DATA); - nand->IO_ADDR_W = (void __iomem *)(base + NDFC_DATA); - nand->cmd_ctrl = ndfc_hwcontrol; - nand->chip_delay = 50; - nand->read_buf = ndfc_read_buf; - nand->dev_ready = ndfc_dev_ready; - nand->ecc.correct = nand_correct_data; - nand->ecc.hwctl = ndfc_enable_hwecc; - nand->ecc.calculate = ndfc_calculate_ecc; - nand->ecc.mode = NAND_ECC_HW; - nand->ecc.size = 256; - nand->ecc.bytes = 3; - nand->ecc.strength = 1; - nand->select_chip = ndfc_select_chip; - -#ifdef CONFIG_SYS_NAND_BUSWIDTH_16BIT - nand->options |= NAND_BUSWIDTH_16; -#endif - - nand->write_buf = ndfc_write_buf; - nand->verify_buf = ndfc_verify_buf; - nand->read_byte = ndfc_read_byte; - - chip++; - - return 0; -} diff --git a/qemu/roms/u-boot/drivers/mtd/nand/nomadik.c b/qemu/roms/u-boot/drivers/mtd/nand/nomadik.c deleted file mode 100644 index a7cee5138..000000000 --- a/qemu/roms/u-boot/drivers/mtd/nand/nomadik.c +++ /dev/null @@ -1,206 +0,0 @@ -/* - * (C) Copyright 2007 STMicroelectronics, <www.st.com> - * (C) Copyright 2009 Alessandro Rubini <rubini@unipv.it> - * - * SPDX-License-Identifier: GPL-2.0+ - */ - -#include <common.h> -#include <nand.h> -#include <asm/io.h> - -static inline int parity(int b) /* b is really a byte; returns 0 or ~0 */ -{ - __asm__ __volatile__( - "eor %0, %0, %0, lsr #4\n\t" - "eor %0, %0, %0, lsr #2\n\t" - "eor %0, %0, %0, lsr #1\n\t" - "ands %0, %0, #1\n\t" - "subne %0, %0, #2\t" - : "=r" (b) : "0" (b)); - return b; -} - -/* - * This is the ECC routine used in hardware, according to the manual. - * HW claims to make the calculation but not the correction; so we must - * recalculate the bytes for a comparison. - */ -static int ecc512(const unsigned char *data, unsigned char *ecc) -{ - int gpar = 0; - int i, val, par; - int pbits = 0; /* P8, P16, ... P2048 */ - int pprime = 0; /* P8', P16', ... P2048' */ - int lowbits; /* P1, P2, P4 and primes */ - - for (i = 0; i < 512; i++) { - par = parity((val = data[i])); - gpar ^= val; - pbits ^= (i & par); - } - /* - * Ok, now gpar is global parity (xor of all bytes) - * pbits are all the parity bits (non-prime ones) - */ - par = parity(gpar); - pprime = pbits ^ par; - /* Put low bits in the right position for ecc[2] (bits 7..2) */ - lowbits = 0 - | (parity(gpar & 0xf0) & 0x80) /* P4 */ - | (parity(gpar & 0x0f) & 0x40) /* P4' */ - | (parity(gpar & 0xcc) & 0x20) /* P2 */ - | (parity(gpar & 0x33) & 0x10) /* P2' */ - | (parity(gpar & 0xaa) & 0x08) /* P1 */ - | (parity(gpar & 0x55) & 0x04); /* P1' */ - - ecc[2] = ~(lowbits | ((pbits & 0x100) >> 7) | ((pprime & 0x100) >> 8)); - /* now intermix bits for ecc[1] (P1024..P128') and ecc[0] (P64..P8') */ - ecc[1] = ~( (pbits & 0x80) >> 0 | ((pprime & 0x80) >> 1) - | ((pbits & 0x40) >> 1) | ((pprime & 0x40) >> 2) - | ((pbits & 0x20) >> 2) | ((pprime & 0x20) >> 3) - | ((pbits & 0x10) >> 3) | ((pprime & 0x10) >> 4)); - - ecc[0] = ~( (pbits & 0x8) << 4 | ((pprime & 0x8) << 3) - | ((pbits & 0x4) << 3) | ((pprime & 0x4) << 2) - | ((pbits & 0x2) << 2) | ((pprime & 0x2) << 1) - | ((pbits & 0x1) << 1) | ((pprime & 0x1) << 0)); - return 0; -} - -/* This is the method in the chip->ecc field */ -static int nomadik_ecc_calculate(struct mtd_info *mtd, const uint8_t *dat, - uint8_t *ecc_code) -{ - return ecc512(dat, ecc_code); -} - -static int nomadik_ecc_correct(struct mtd_info *mtd, uint8_t *dat, - uint8_t *r_ecc, uint8_t *c_ecc) -{ - struct nand_chip *chip = mtd->priv; - uint32_t r, c, d, diff; /*read, calculated, xor of them */ - - if (!memcmp(r_ecc, c_ecc, chip->ecc.bytes)) - return 0; - - /* Reorder the bytes into ascending-order 24 bits -- see manual */ - r = r_ecc[2] << 22 | r_ecc[1] << 14 | r_ecc[0] << 6 | r_ecc[2] >> 2; - c = c_ecc[2] << 22 | c_ecc[1] << 14 | c_ecc[0] << 6 | c_ecc[2] >> 2; - diff = (r ^ c) & ((1<<24)-1); /* use 24 bits only */ - - /* If 12 bits are different, one per pair, it's correctable */ - if (((diff | (diff>>1)) & 0x555555) == 0x555555) { - int bit = ((diff & 2) >> 1) - | ((diff & 0x8) >> 2) | ((diff & 0x20) >> 3); - int byte; - - d = diff >> 6; /* remove bit-order info */ - byte = ((d & 2) >> 1) - | ((d & 0x8) >> 2) | ((d & 0x20) >> 3) - | ((d & 0x80) >> 4) | ((d & 0x200) >> 5) - | ((d & 0x800) >> 6) | ((d & 0x2000) >> 7) - | ((d & 0x8000) >> 8) | ((d & 0x20000) >> 9); - /* correct the single bit */ - dat[byte] ^= 1<<bit; - return 0; - } - /* If 1 bit only differs, it's one bit error in ECC, ignore */ - if ((diff ^ (1 << (ffs(diff) - 1))) == 0) - return 0; - /* Otherwise, uncorrectable */ - return -1; -} - -static void nomadik_ecc_hwctl(struct mtd_info *mtd, int mode) -{ /* mandatory in the structure but not used here */ } - - -/* This is the layout used by older installations, we keep compatible */ -struct nand_ecclayout nomadik_ecc_layout = { - .eccbytes = 3 * 4, - .eccpos = { /* each subpage has 16 bytes: pos 2,3,4 hosts ECC */ - 0x02, 0x03, 0x04, - 0x12, 0x13, 0x14, - 0x22, 0x23, 0x24, - 0x32, 0x33, 0x34}, - .oobfree = { {0x08, 0x08}, {0x18, 0x08}, {0x28, 0x08}, {0x38, 0x08} }, -}; - -#define MASK_ALE (1 << 24) /* our ALE is AD21 */ -#define MASK_CLE (1 << 23) /* our CLE is AD22 */ - -/* This is copied from the AT91SAM9 devices (Stelian Pop, Lead Tech Design) */ -static void nomadik_nand_hwcontrol(struct mtd_info *mtd, - int cmd, unsigned int ctrl) -{ - struct nand_chip *this = mtd->priv; - u32 pcr0 = readl(REG_FSMC_PCR0); - - if (ctrl & NAND_CTRL_CHANGE) { - ulong IO_ADDR_W = (ulong) this->IO_ADDR_W; - IO_ADDR_W &= ~(MASK_ALE | MASK_CLE); - - if (ctrl & NAND_CLE) - IO_ADDR_W |= MASK_CLE; - if (ctrl & NAND_ALE) - IO_ADDR_W |= MASK_ALE; - - if (ctrl & NAND_NCE) - writel(pcr0 | 0x4, REG_FSMC_PCR0); - else - writel(pcr0 & ~0x4, REG_FSMC_PCR0); - - this->IO_ADDR_W = (void *) IO_ADDR_W; - this->IO_ADDR_R = (void *) IO_ADDR_W; - } - - if (cmd != NAND_CMD_NONE) - writeb(cmd, this->IO_ADDR_W); -} - -/* Returns 1 when ready; upper layers timeout at 20ms with timer routines */ -static int nomadik_nand_ready(struct mtd_info *mtd) -{ - return 1; /* The ready bit is handled in hardware */ -} - -/* Copy a buffer 32bits at a time: faster than defualt method which is 8bit */ -static void nomadik_nand_read_buf(struct mtd_info *mtd, uint8_t *buf, int len) -{ - int i; - struct nand_chip *chip = mtd->priv; - u32 *p = (u32 *) buf; - - len >>= 2; - writel(0, REG_FSMC_ECCR0); - for (i = 0; i < len; i++) - p[i] = readl(chip->IO_ADDR_R); -} - -int board_nand_init(struct nand_chip *chip) -{ - /* Set up the FSMC_PCR0 for nand access*/ - writel(0x0000004a, REG_FSMC_PCR0); - /* Set up FSMC_PMEM0, FSMC_PATT0 with timing data for access */ - writel(0x00020401, REG_FSMC_PMEM0); - writel(0x00020404, REG_FSMC_PATT0); - - chip->options = NAND_COPYBACK | NAND_CACHEPRG | NAND_NO_PADDING; - chip->cmd_ctrl = nomadik_nand_hwcontrol; - chip->dev_ready = nomadik_nand_ready; - /* The chip allows 32bit reads, so avoid the default 8bit copy */ - chip->read_buf = nomadik_nand_read_buf; - - /* ECC: follow the hardware-defined rulse, but do it in sw */ - chip->ecc.mode = NAND_ECC_HW; - chip->ecc.bytes = 3; - chip->ecc.size = 512; - chip->ecc.strength = 1; - chip->ecc.layout = &nomadik_ecc_layout; - chip->ecc.calculate = nomadik_ecc_calculate; - chip->ecc.hwctl = nomadik_ecc_hwctl; - chip->ecc.correct = nomadik_ecc_correct; - - return 0; -} diff --git a/qemu/roms/u-boot/drivers/mtd/nand/omap_elm.c b/qemu/roms/u-boot/drivers/mtd/nand/omap_elm.c deleted file mode 100644 index 47b1f1bfe..000000000 --- a/qemu/roms/u-boot/drivers/mtd/nand/omap_elm.c +++ /dev/null @@ -1,196 +0,0 @@ -/* - * (C) Copyright 2010-2011 Texas Instruments, <www.ti.com> - * Mansoor Ahamed <mansoor.ahamed@ti.com> - * - * BCH Error Location Module (ELM) support. - * - * NOTE: - * 1. Supports only continuous mode. Dont see need for page mode in uboot - * 2. Supports only syndrome polynomial 0. i.e. poly local variable is - * always set to ELM_DEFAULT_POLY. Dont see need for other polynomial - * sets in uboot - * - * SPDX-License-Identifier: GPL-2.0+ - */ - -#include <common.h> -#include <asm/io.h> -#include <asm/errno.h> -#include <linux/mtd/omap_gpmc.h> -#include <linux/mtd/omap_elm.h> -#include <asm/arch/hardware.h> - -#define ELM_DEFAULT_POLY (0) - -struct elm *elm_cfg; - -/** - * elm_load_syndromes - Load BCH syndromes based on nibble selection - * @syndrome: BCH syndrome - * @nibbles: - * @poly: Syndrome Polynomial set to use - * - * Load BCH syndromes based on nibble selection - */ -static void elm_load_syndromes(u8 *syndrome, u32 nibbles, u8 poly) -{ - u32 *ptr; - u32 val; - - /* reg 0 */ - ptr = &elm_cfg->syndrome_fragments[poly].syndrome_fragment_x[0]; - val = syndrome[0] | (syndrome[1] << 8) | (syndrome[2] << 16) | - (syndrome[3] << 24); - writel(val, ptr); - /* reg 1 */ - ptr = &elm_cfg->syndrome_fragments[poly].syndrome_fragment_x[1]; - val = syndrome[4] | (syndrome[5] << 8) | (syndrome[6] << 16) | - (syndrome[7] << 24); - writel(val, ptr); - - /* BCH 8-bit with 26 nibbles (4*8=32) */ - if (nibbles > 13) { - /* reg 2 */ - ptr = &elm_cfg->syndrome_fragments[poly].syndrome_fragment_x[2]; - val = syndrome[8] | (syndrome[9] << 8) | (syndrome[10] << 16) | - (syndrome[11] << 24); - writel(val, ptr); - /* reg 3 */ - ptr = &elm_cfg->syndrome_fragments[poly].syndrome_fragment_x[3]; - val = syndrome[12] | (syndrome[13] << 8) | - (syndrome[14] << 16) | (syndrome[15] << 24); - writel(val, ptr); - } - - /* BCH 16-bit with 52 nibbles (7*8=56) */ - if (nibbles > 26) { - /* reg 4 */ - ptr = &elm_cfg->syndrome_fragments[poly].syndrome_fragment_x[4]; - val = syndrome[16] | (syndrome[17] << 8) | - (syndrome[18] << 16) | (syndrome[19] << 24); - writel(val, ptr); - - /* reg 5 */ - ptr = &elm_cfg->syndrome_fragments[poly].syndrome_fragment_x[5]; - val = syndrome[20] | (syndrome[21] << 8) | - (syndrome[22] << 16) | (syndrome[23] << 24); - writel(val, ptr); - - /* reg 6 */ - ptr = &elm_cfg->syndrome_fragments[poly].syndrome_fragment_x[6]; - val = syndrome[24] | (syndrome[25] << 8) | - (syndrome[26] << 16) | (syndrome[27] << 24); - writel(val, ptr); - } -} - -/** - * elm_check_errors - Check for BCH errors and return error locations - * @syndrome: BCH syndrome - * @nibbles: - * @error_count: Returns number of errrors in the syndrome - * @error_locations: Returns error locations (in decimal) in this array - * - * Check the provided syndrome for BCH errors and return error count - * and locations in the array passed. Returns -1 if error is not correctable, - * else returns 0 - */ -int elm_check_error(u8 *syndrome, u32 nibbles, u32 *error_count, - u32 *error_locations) -{ - u8 poly = ELM_DEFAULT_POLY; - s8 i; - u32 location_status; - - elm_load_syndromes(syndrome, nibbles, poly); - - /* start processing */ - writel((readl(&elm_cfg->syndrome_fragments[poly].syndrome_fragment_x[6]) - | ELM_SYNDROME_FRAGMENT_6_SYNDROME_VALID), - &elm_cfg->syndrome_fragments[poly].syndrome_fragment_x[6]); - - /* wait for processing to complete */ - while ((readl(&elm_cfg->irqstatus) & (0x1 << poly)) != 0x1) - ; - /* clear status */ - writel((readl(&elm_cfg->irqstatus) | (0x1 << poly)), - &elm_cfg->irqstatus); - - /* check if correctable */ - location_status = readl(&elm_cfg->error_location[poly].location_status); - if (!(location_status & ELM_LOCATION_STATUS_ECC_CORRECTABLE_MASK)) - return -1; - - /* get error count */ - *error_count = readl(&elm_cfg->error_location[poly].location_status) & - ELM_LOCATION_STATUS_ECC_NB_ERRORS_MASK; - - for (i = 0; i < *error_count; i++) { - error_locations[i] = - readl(&elm_cfg->error_location[poly].error_location_x[i]); - } - - return 0; -} - - -/** - * elm_config - Configure ELM module - * @level: 4 / 8 / 16 bit BCH - * - * Configure ELM module based on BCH level. - * Set mode as continuous mode. - * Currently we are using only syndrome 0 and syndromes 1 to 6 are not used. - * Also, the mode is set only for syndrome 0 - */ -int elm_config(enum bch_level level) -{ - u32 val; - u8 poly = ELM_DEFAULT_POLY; - u32 buffer_size = 0x7FF; - - /* config size and level */ - val = (u32)(level) & ELM_LOCATION_CONFIG_ECC_BCH_LEVEL_MASK; - val |= ((buffer_size << ELM_LOCATION_CONFIG_ECC_SIZE_POS) & - ELM_LOCATION_CONFIG_ECC_SIZE_MASK); - writel(val, &elm_cfg->location_config); - - /* config continous mode */ - /* enable interrupt generation for syndrome polynomial set */ - writel((readl(&elm_cfg->irqenable) | (0x1 << poly)), - &elm_cfg->irqenable); - /* set continuous mode for the syndrome polynomial set */ - writel((readl(&elm_cfg->page_ctrl) & ~(0x1 << poly)), - &elm_cfg->page_ctrl); - - return 0; -} - -/** - * elm_reset - Do a soft reset of ELM - * - * Perform a soft reset of ELM and return after reset is done. - */ -void elm_reset(void) -{ - /* initiate reset */ - writel((readl(&elm_cfg->sysconfig) | ELM_SYSCONFIG_SOFTRESET), - &elm_cfg->sysconfig); - - /* wait for reset complete and normal operation */ - while ((readl(&elm_cfg->sysstatus) & ELM_SYSSTATUS_RESETDONE) != - ELM_SYSSTATUS_RESETDONE) - ; -} - -/** - * elm_init - Initialize ELM module - * - * Initialize ELM support. Currently it does only base address init - * and ELM reset. - */ -void elm_init(void) -{ - elm_cfg = (struct elm *)ELM_BASE; - elm_reset(); -} diff --git a/qemu/roms/u-boot/drivers/mtd/nand/omap_gpmc.c b/qemu/roms/u-boot/drivers/mtd/nand/omap_gpmc.c deleted file mode 100644 index 881a63618..000000000 --- a/qemu/roms/u-boot/drivers/mtd/nand/omap_gpmc.c +++ /dev/null @@ -1,836 +0,0 @@ -/* - * (C) Copyright 2004-2008 Texas Instruments, <www.ti.com> - * Rohit Choraria <rohitkc@ti.com> - * - * SPDX-License-Identifier: GPL-2.0+ - */ - -#include <common.h> -#include <asm/io.h> -#include <asm/errno.h> -#include <asm/arch/mem.h> -#include <linux/mtd/omap_gpmc.h> -#include <linux/mtd/nand_ecc.h> -#include <linux/bch.h> -#include <linux/compiler.h> -#include <nand.h> -#include <linux/mtd/omap_elm.h> - -#define BADBLOCK_MARKER_LENGTH 2 -#define SECTOR_BYTES 512 -#define ECCCLEAR (0x1 << 8) -#define ECCRESULTREG1 (0x1 << 0) -/* 4 bit padding to make byte aligned, 56 = 52 + 4 */ -#define BCH4_BIT_PAD 4 - -#ifdef CONFIG_BCH -static u8 bch8_polynomial[] = {0xef, 0x51, 0x2e, 0x09, 0xed, 0x93, 0x9a, 0xc2, - 0x97, 0x79, 0xe5, 0x24, 0xb5}; -#endif -static uint8_t cs; -static __maybe_unused struct nand_ecclayout omap_ecclayout; - -/* - * omap_nand_hwcontrol - Set the address pointers corretly for the - * following address/data/command operation - */ -static void omap_nand_hwcontrol(struct mtd_info *mtd, int32_t cmd, - uint32_t ctrl) -{ - register struct nand_chip *this = mtd->priv; - - /* - * Point the IO_ADDR to DATA and ADDRESS registers instead - * of chip address - */ - switch (ctrl) { - case NAND_CTRL_CHANGE | NAND_CTRL_CLE: - this->IO_ADDR_W = (void __iomem *)&gpmc_cfg->cs[cs].nand_cmd; - break; - case NAND_CTRL_CHANGE | NAND_CTRL_ALE: - this->IO_ADDR_W = (void __iomem *)&gpmc_cfg->cs[cs].nand_adr; - break; - case NAND_CTRL_CHANGE | NAND_NCE: - this->IO_ADDR_W = (void __iomem *)&gpmc_cfg->cs[cs].nand_dat; - break; - } - - if (cmd != NAND_CMD_NONE) - writeb(cmd, this->IO_ADDR_W); -} - -#ifdef CONFIG_SPL_BUILD -/* Check wait pin as dev ready indicator */ -int omap_spl_dev_ready(struct mtd_info *mtd) -{ - return gpmc_cfg->status & (1 << 8); -} -#endif - - -/* - * gen_true_ecc - This function will generate true ECC value, which - * can be used when correcting data read from NAND flash memory core - * - * @ecc_buf: buffer to store ecc code - * - * @return: re-formatted ECC value - */ -static uint32_t gen_true_ecc(uint8_t *ecc_buf) -{ - return ecc_buf[0] | (ecc_buf[1] << 16) | ((ecc_buf[2] & 0xF0) << 20) | - ((ecc_buf[2] & 0x0F) << 8); -} - -/* - * omap_correct_data - Compares the ecc read from nand spare area with ECC - * registers values and corrects one bit error if it has occured - * Further details can be had from OMAP TRM and the following selected links: - * http://en.wikipedia.org/wiki/Hamming_code - * http://www.cs.utexas.edu/users/plaxton/c/337/05f/slides/ErrorCorrection-4.pdf - * - * @mtd: MTD device structure - * @dat: page data - * @read_ecc: ecc read from nand flash - * @calc_ecc: ecc read from ECC registers - * - * @return 0 if data is OK or corrected, else returns -1 - */ -static int __maybe_unused omap_correct_data(struct mtd_info *mtd, uint8_t *dat, - uint8_t *read_ecc, uint8_t *calc_ecc) -{ - uint32_t orig_ecc, new_ecc, res, hm; - uint16_t parity_bits, byte; - uint8_t bit; - - /* Regenerate the orginal ECC */ - orig_ecc = gen_true_ecc(read_ecc); - new_ecc = gen_true_ecc(calc_ecc); - /* Get the XOR of real ecc */ - res = orig_ecc ^ new_ecc; - if (res) { - /* Get the hamming width */ - hm = hweight32(res); - /* Single bit errors can be corrected! */ - if (hm == 12) { - /* Correctable data! */ - parity_bits = res >> 16; - bit = (parity_bits & 0x7); - byte = (parity_bits >> 3) & 0x1FF; - /* Flip the bit to correct */ - dat[byte] ^= (0x1 << bit); - } else if (hm == 1) { - printf("Error: Ecc is wrong\n"); - /* ECC itself is corrupted */ - return 2; - } else { - /* - * hm distance != parity pairs OR one, could mean 2 bit - * error OR potentially be on a blank page.. - * orig_ecc: contains spare area data from nand flash. - * new_ecc: generated ecc while reading data area. - * Note: if the ecc = 0, all data bits from which it was - * generated are 0xFF. - * The 3 byte(24 bits) ecc is generated per 512byte - * chunk of a page. If orig_ecc(from spare area) - * is 0xFF && new_ecc(computed now from data area)=0x0, - * this means that data area is 0xFF and spare area is - * 0xFF. A sure sign of a erased page! - */ - if ((orig_ecc == 0x0FFF0FFF) && (new_ecc == 0x00000000)) - return 0; - printf("Error: Bad compare! failed\n"); - /* detected 2 bit error */ - return -1; - } - } - return 0; -} - -/* - * Generic BCH interface - */ -struct nand_bch_priv { - uint8_t mode; - uint8_t type; - uint8_t nibbles; - struct bch_control *control; - enum omap_ecc ecc_scheme; -}; - -/* bch types */ -#define ECC_BCH4 0 -#define ECC_BCH8 1 -#define ECC_BCH16 2 - -/* BCH nibbles for diff bch levels */ -#define ECC_BCH4_NIBBLES 13 -#define ECC_BCH8_NIBBLES 26 -#define ECC_BCH16_NIBBLES 52 - -/* - * This can be a single instance cause all current users have only one NAND - * with nearly the same setup (BCH8, some with ELM and others with sw BCH - * library). - * When some users with other BCH strength will exists this have to change! - */ -static __maybe_unused struct nand_bch_priv bch_priv = { - .type = ECC_BCH8, - .nibbles = ECC_BCH8_NIBBLES, - .control = NULL -}; - -/* - * omap_reverse_list - re-orders list elements in reverse order [internal] - * @list: pointer to start of list - * @length: length of list -*/ -void omap_reverse_list(u8 *list, unsigned int length) -{ - unsigned int i, j; - unsigned int half_length = length / 2; - u8 tmp; - for (i = 0, j = length - 1; i < half_length; i++, j--) { - tmp = list[i]; - list[i] = list[j]; - list[j] = tmp; - } -} - -/* - * omap_enable_hwecc - configures GPMC as per ECC scheme before read/write - * @mtd: MTD device structure - * @mode: Read/Write mode - */ -__maybe_unused -static void omap_enable_hwecc(struct mtd_info *mtd, int32_t mode) -{ - struct nand_chip *nand = mtd->priv; - struct nand_bch_priv *bch = nand->priv; - unsigned int dev_width = (nand->options & NAND_BUSWIDTH_16) ? 1 : 0; - unsigned int ecc_algo = 0; - unsigned int bch_type = 0; - unsigned int eccsize1 = 0x00, eccsize0 = 0x00, bch_wrapmode = 0x00; - u32 ecc_size_config_val = 0; - u32 ecc_config_val = 0; - - /* configure GPMC for specific ecc-scheme */ - switch (bch->ecc_scheme) { - case OMAP_ECC_HAM1_CODE_SW: - return; - case OMAP_ECC_HAM1_CODE_HW: - ecc_algo = 0x0; - bch_type = 0x0; - bch_wrapmode = 0x00; - eccsize0 = 0xFF; - eccsize1 = 0xFF; - break; - case OMAP_ECC_BCH8_CODE_HW_DETECTION_SW: - case OMAP_ECC_BCH8_CODE_HW: - ecc_algo = 0x1; - bch_type = 0x1; - if (mode == NAND_ECC_WRITE) { - bch_wrapmode = 0x01; - eccsize0 = 0; /* extra bits in nibbles per sector */ - eccsize1 = 28; /* OOB bits in nibbles per sector */ - } else { - bch_wrapmode = 0x01; - eccsize0 = 26; /* ECC bits in nibbles per sector */ - eccsize1 = 2; /* non-ECC bits in nibbles per sector */ - } - break; - default: - return; - } - /* Clear ecc and enable bits */ - writel(ECCCLEAR | ECCRESULTREG1, &gpmc_cfg->ecc_control); - /* Configure ecc size for BCH */ - ecc_size_config_val = (eccsize1 << 22) | (eccsize0 << 12); - writel(ecc_size_config_val, &gpmc_cfg->ecc_size_config); - - /* Configure device details for BCH engine */ - ecc_config_val = ((ecc_algo << 16) | /* HAM1 | BCHx */ - (bch_type << 12) | /* BCH4/BCH8/BCH16 */ - (bch_wrapmode << 8) | /* wrap mode */ - (dev_width << 7) | /* bus width */ - (0x0 << 4) | /* number of sectors */ - (cs << 1) | /* ECC CS */ - (0x1)); /* enable ECC */ - writel(ecc_config_val, &gpmc_cfg->ecc_config); -} - -/* - * omap_calculate_ecc - Read ECC result - * @mtd: MTD structure - * @dat: unused - * @ecc_code: ecc_code buffer - * Using noninverted ECC can be considered ugly since writing a blank - * page ie. padding will clear the ECC bytes. This is no problem as - * long nobody is trying to write data on the seemingly unused page. - * Reading an erased page will produce an ECC mismatch between - * generated and read ECC bytes that has to be dealt with separately. - * E.g. if page is 0xFF (fresh erased), and if HW ECC engine within GPMC - * is used, the result of read will be 0x0 while the ECC offsets of the - * spare area will be 0xFF which will result in an ECC mismatch. - */ -static int omap_calculate_ecc(struct mtd_info *mtd, const uint8_t *dat, - uint8_t *ecc_code) -{ - struct nand_chip *chip = mtd->priv; - struct nand_bch_priv *bch = chip->priv; - uint32_t *ptr, val = 0; - int8_t i = 0, j; - - switch (bch->ecc_scheme) { - case OMAP_ECC_HAM1_CODE_HW: - val = readl(&gpmc_cfg->ecc1_result); - ecc_code[0] = val & 0xFF; - ecc_code[1] = (val >> 16) & 0xFF; - ecc_code[2] = ((val >> 8) & 0x0F) | ((val >> 20) & 0xF0); - break; -#ifdef CONFIG_BCH - case OMAP_ECC_BCH8_CODE_HW_DETECTION_SW: -#endif - case OMAP_ECC_BCH8_CODE_HW: - ptr = &gpmc_cfg->bch_result_0_3[0].bch_result_x[3]; - val = readl(ptr); - ecc_code[i++] = (val >> 0) & 0xFF; - ptr--; - for (j = 0; j < 3; j++) { - val = readl(ptr); - ecc_code[i++] = (val >> 24) & 0xFF; - ecc_code[i++] = (val >> 16) & 0xFF; - ecc_code[i++] = (val >> 8) & 0xFF; - ecc_code[i++] = (val >> 0) & 0xFF; - ptr--; - } - break; - default: - return -EINVAL; - } - /* ECC scheme specific syndrome customizations */ - switch (bch->ecc_scheme) { - case OMAP_ECC_HAM1_CODE_HW: - break; -#ifdef CONFIG_BCH - case OMAP_ECC_BCH8_CODE_HW_DETECTION_SW: - - for (i = 0; i < chip->ecc.bytes; i++) - *(ecc_code + i) = *(ecc_code + i) ^ - bch8_polynomial[i]; - break; -#endif - case OMAP_ECC_BCH8_CODE_HW: - ecc_code[chip->ecc.bytes - 1] = 0x00; - break; - default: - return -EINVAL; - } - return 0; -} - -#ifdef CONFIG_NAND_OMAP_ELM -/* - * omap_correct_data_bch - Compares the ecc read from nand spare area - * with ECC registers values and corrects one bit error if it has occured - * - * @mtd: MTD device structure - * @dat: page data - * @read_ecc: ecc read from nand flash (ignored) - * @calc_ecc: ecc read from ECC registers - * - * @return 0 if data is OK or corrected, else returns -1 - */ -static int omap_correct_data_bch(struct mtd_info *mtd, uint8_t *dat, - uint8_t *read_ecc, uint8_t *calc_ecc) -{ - struct nand_chip *chip = mtd->priv; - struct nand_bch_priv *bch = chip->priv; - uint32_t eccbytes = chip->ecc.bytes; - uint32_t error_count = 0, error_max; - uint32_t error_loc[8]; - uint32_t i, ecc_flag = 0; - uint8_t count, err = 0; - uint32_t byte_pos, bit_pos; - - /* check calculated ecc */ - for (i = 0; i < chip->ecc.bytes && !ecc_flag; i++) { - if (calc_ecc[i] != 0x00) - ecc_flag = 1; - } - if (!ecc_flag) - return 0; - - /* check for whether its a erased-page */ - ecc_flag = 0; - for (i = 0; i < chip->ecc.bytes && !ecc_flag; i++) { - if (read_ecc[i] != 0xff) - ecc_flag = 1; - } - if (!ecc_flag) - return 0; - - /* - * while reading ECC result we read it in big endian. - * Hence while loading to ELM we have rotate to get the right endian. - */ - switch (bch->ecc_scheme) { - case OMAP_ECC_BCH8_CODE_HW: - omap_reverse_list(calc_ecc, eccbytes - 1); - break; - default: - return -EINVAL; - } - /* use elm module to check for errors */ - elm_config((enum bch_level)(bch->type)); - if (elm_check_error(calc_ecc, bch->nibbles, &error_count, error_loc)) { - printf("nand: error: uncorrectable ECC errors\n"); - return -EINVAL; - } - /* correct bch error */ - for (count = 0; count < error_count; count++) { - switch (bch->type) { - case ECC_BCH8: - /* 14th byte in ECC is reserved to match ROM layout */ - error_max = SECTOR_BYTES + (eccbytes - 1); - break; - default: - return -EINVAL; - } - byte_pos = error_max - (error_loc[count] / 8) - 1; - bit_pos = error_loc[count] % 8; - if (byte_pos < SECTOR_BYTES) { - dat[byte_pos] ^= 1 << bit_pos; - printf("nand: bit-flip corrected @data=%d\n", byte_pos); - } else if (byte_pos < error_max) { - read_ecc[byte_pos - SECTOR_BYTES] = 1 << bit_pos; - printf("nand: bit-flip corrected @oob=%d\n", byte_pos - - SECTOR_BYTES); - } else { - err = -EBADMSG; - printf("nand: error: invalid bit-flip location\n"); - } - } - return (err) ? err : error_count; -} - -/** - * omap_read_page_bch - hardware ecc based page read function - * @mtd: mtd info structure - * @chip: nand chip info structure - * @buf: buffer to store read data - * @oob_required: caller expects OOB data read to chip->oob_poi - * @page: page number to read - * - */ -static int omap_read_page_bch(struct mtd_info *mtd, struct nand_chip *chip, - uint8_t *buf, int oob_required, int page) -{ - int i, eccsize = chip->ecc.size; - int eccbytes = chip->ecc.bytes; - int eccsteps = chip->ecc.steps; - uint8_t *p = buf; - uint8_t *ecc_calc = chip->buffers->ecccalc; - uint8_t *ecc_code = chip->buffers->ecccode; - uint32_t *eccpos = chip->ecc.layout->eccpos; - uint8_t *oob = chip->oob_poi; - uint32_t data_pos; - uint32_t oob_pos; - - data_pos = 0; - /* oob area start */ - oob_pos = (eccsize * eccsteps) + chip->ecc.layout->eccpos[0]; - oob += chip->ecc.layout->eccpos[0]; - - for (i = 0; eccsteps; eccsteps--, i += eccbytes, p += eccsize, - oob += eccbytes) { - chip->ecc.hwctl(mtd, NAND_ECC_READ); - /* read data */ - chip->cmdfunc(mtd, NAND_CMD_RNDOUT, data_pos, page); - chip->read_buf(mtd, p, eccsize); - - /* read respective ecc from oob area */ - chip->cmdfunc(mtd, NAND_CMD_RNDOUT, oob_pos, page); - chip->read_buf(mtd, oob, eccbytes); - /* read syndrome */ - chip->ecc.calculate(mtd, p, &ecc_calc[i]); - - data_pos += eccsize; - oob_pos += eccbytes; - } - - for (i = 0; i < chip->ecc.total; i++) - ecc_code[i] = chip->oob_poi[eccpos[i]]; - - eccsteps = chip->ecc.steps; - p = buf; - - for (i = 0 ; eccsteps; eccsteps--, i += eccbytes, p += eccsize) { - int stat; - - stat = chip->ecc.correct(mtd, p, &ecc_code[i], &ecc_calc[i]); - if (stat < 0) - mtd->ecc_stats.failed++; - else - mtd->ecc_stats.corrected += stat; - } - return 0; -} -#endif /* CONFIG_NAND_OMAP_ELM */ - -/* - * OMAP3 BCH8 support (with BCH library) - */ -#ifdef CONFIG_BCH -/** - * omap_correct_data_bch_sw - 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 omap_correct_data_bch_sw(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 nand_chip *chip = mtd->priv; - struct nand_bch_priv *chip_priv = chip->priv; - struct bch_control *bch = chip_priv->control; - - count = decode_bch(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); - printf("corrected bitflip %u\n", errloc[i]); -#ifdef DEBUG - puts("read_ecc: "); - /* - * BCH8 have 13 bytes of ECC; BCH4 needs adoption - * here! - */ - for (i = 0; i < 13; i++) - printf("%02x ", read_ecc[i]); - puts("\n"); - puts("calc_ecc: "); - for (i = 0; i < 13; i++) - printf("%02x ", calc_ecc[i]); - puts("\n"); -#endif - } - } else if (count < 0) { - puts("ecc unrecoverable error\n"); - } - return count; -} - -/** - * omap_free_bch - Release BCH ecc resources - * @mtd: MTD device structure - */ -static void __maybe_unused omap_free_bch(struct mtd_info *mtd) -{ - struct nand_chip *chip = mtd->priv; - struct nand_bch_priv *chip_priv = chip->priv; - struct bch_control *bch = NULL; - - if (chip_priv) - bch = chip_priv->control; - - if (bch) { - free_bch(bch); - chip_priv->control = NULL; - } -} -#endif /* CONFIG_BCH */ - -/** - * omap_select_ecc_scheme - configures driver for particular ecc-scheme - * @nand: NAND chip device structure - * @ecc_scheme: ecc scheme to configure - * @pagesize: number of main-area bytes per page of NAND device - * @oobsize: number of OOB/spare bytes per page of NAND device - */ -static int omap_select_ecc_scheme(struct nand_chip *nand, - enum omap_ecc ecc_scheme, unsigned int pagesize, unsigned int oobsize) { - struct nand_bch_priv *bch = nand->priv; - struct nand_ecclayout *ecclayout = &omap_ecclayout; - int eccsteps = pagesize / SECTOR_BYTES; - int i; - - switch (ecc_scheme) { - case OMAP_ECC_HAM1_CODE_SW: - debug("nand: selected OMAP_ECC_HAM1_CODE_SW\n"); - /* For this ecc-scheme, ecc.bytes, ecc.layout, ... are - * initialized in nand_scan_tail(), so just set ecc.mode */ - bch_priv.control = NULL; - bch_priv.type = 0; - nand->ecc.mode = NAND_ECC_SOFT; - nand->ecc.layout = NULL; - nand->ecc.size = 0; - bch->ecc_scheme = OMAP_ECC_HAM1_CODE_SW; - break; - - case OMAP_ECC_HAM1_CODE_HW: - debug("nand: selected OMAP_ECC_HAM1_CODE_HW\n"); - /* check ecc-scheme requirements before updating ecc info */ - if ((3 * eccsteps) + BADBLOCK_MARKER_LENGTH > oobsize) { - printf("nand: error: insufficient OOB: require=%d\n", ( - (3 * eccsteps) + BADBLOCK_MARKER_LENGTH)); - return -EINVAL; - } - bch_priv.control = NULL; - bch_priv.type = 0; - /* populate ecc specific fields */ - memset(&nand->ecc, 0, sizeof(struct nand_ecc_ctrl)); - nand->ecc.mode = NAND_ECC_HW; - nand->ecc.strength = 1; - nand->ecc.size = SECTOR_BYTES; - nand->ecc.bytes = 3; - nand->ecc.hwctl = omap_enable_hwecc; - nand->ecc.correct = omap_correct_data; - nand->ecc.calculate = omap_calculate_ecc; - /* define ecc-layout */ - ecclayout->eccbytes = nand->ecc.bytes * eccsteps; - for (i = 0; i < ecclayout->eccbytes; i++) { - if (nand->options & NAND_BUSWIDTH_16) - ecclayout->eccpos[i] = i + 2; - else - ecclayout->eccpos[i] = i + 1; - } - ecclayout->oobfree[0].offset = i + BADBLOCK_MARKER_LENGTH; - ecclayout->oobfree[0].length = oobsize - ecclayout->eccbytes - - BADBLOCK_MARKER_LENGTH; - bch->ecc_scheme = OMAP_ECC_HAM1_CODE_HW; - break; - - case OMAP_ECC_BCH8_CODE_HW_DETECTION_SW: -#ifdef CONFIG_BCH - debug("nand: selected OMAP_ECC_BCH8_CODE_HW_DETECTION_SW\n"); - /* check ecc-scheme requirements before updating ecc info */ - if ((13 * eccsteps) + BADBLOCK_MARKER_LENGTH > oobsize) { - printf("nand: error: insufficient OOB: require=%d\n", ( - (13 * eccsteps) + BADBLOCK_MARKER_LENGTH)); - return -EINVAL; - } - /* check if BCH S/W library can be used for error detection */ - bch_priv.control = init_bch(13, 8, 0x201b); - if (!bch_priv.control) { - printf("nand: error: could not init_bch()\n"); - return -ENODEV; - } - bch_priv.type = ECC_BCH8; - /* populate ecc specific fields */ - memset(&nand->ecc, 0, sizeof(struct nand_ecc_ctrl)); - nand->ecc.mode = NAND_ECC_HW; - nand->ecc.strength = 8; - nand->ecc.size = SECTOR_BYTES; - nand->ecc.bytes = 13; - nand->ecc.hwctl = omap_enable_hwecc; - nand->ecc.correct = omap_correct_data_bch_sw; - nand->ecc.calculate = omap_calculate_ecc; - /* define ecc-layout */ - ecclayout->eccbytes = nand->ecc.bytes * eccsteps; - ecclayout->eccpos[0] = BADBLOCK_MARKER_LENGTH; - for (i = 1; i < ecclayout->eccbytes; i++) { - if (i % nand->ecc.bytes) - ecclayout->eccpos[i] = - ecclayout->eccpos[i - 1] + 1; - else - ecclayout->eccpos[i] = - ecclayout->eccpos[i - 1] + 2; - } - ecclayout->oobfree[0].offset = i + BADBLOCK_MARKER_LENGTH; - ecclayout->oobfree[0].length = oobsize - ecclayout->eccbytes - - BADBLOCK_MARKER_LENGTH; - bch->ecc_scheme = OMAP_ECC_BCH8_CODE_HW_DETECTION_SW; - break; -#else - printf("nand: error: CONFIG_BCH required for ECC\n"); - return -EINVAL; -#endif - - case OMAP_ECC_BCH8_CODE_HW: -#ifdef CONFIG_NAND_OMAP_ELM - debug("nand: selected OMAP_ECC_BCH8_CODE_HW\n"); - /* check ecc-scheme requirements before updating ecc info */ - if ((14 * eccsteps) + BADBLOCK_MARKER_LENGTH > oobsize) { - printf("nand: error: insufficient OOB: require=%d\n", ( - (14 * eccsteps) + BADBLOCK_MARKER_LENGTH)); - return -EINVAL; - } - /* intialize ELM for ECC error detection */ - elm_init(); - bch_priv.type = ECC_BCH8; - /* populate ecc specific fields */ - memset(&nand->ecc, 0, sizeof(struct nand_ecc_ctrl)); - nand->ecc.mode = NAND_ECC_HW; - nand->ecc.strength = 8; - nand->ecc.size = SECTOR_BYTES; - nand->ecc.bytes = 14; - nand->ecc.hwctl = omap_enable_hwecc; - nand->ecc.correct = omap_correct_data_bch; - nand->ecc.calculate = omap_calculate_ecc; - nand->ecc.read_page = omap_read_page_bch; - /* define ecc-layout */ - ecclayout->eccbytes = nand->ecc.bytes * eccsteps; - for (i = 0; i < ecclayout->eccbytes; i++) - ecclayout->eccpos[i] = i + BADBLOCK_MARKER_LENGTH; - ecclayout->oobfree[0].offset = i + BADBLOCK_MARKER_LENGTH; - ecclayout->oobfree[0].length = oobsize - ecclayout->eccbytes - - BADBLOCK_MARKER_LENGTH; - bch->ecc_scheme = OMAP_ECC_BCH8_CODE_HW; - break; -#else - printf("nand: error: CONFIG_NAND_OMAP_ELM required for ECC\n"); - return -EINVAL; -#endif - - default: - debug("nand: error: ecc scheme not enabled or supported\n"); - return -EINVAL; - } - - /* nand_scan_tail() sets ham1 sw ecc; hw ecc layout is set by driver */ - if (ecc_scheme != OMAP_ECC_HAM1_CODE_SW) - nand->ecc.layout = ecclayout; - - return 0; -} - -#ifndef CONFIG_SPL_BUILD -/* - * omap_nand_switch_ecc - switch the ECC operation between different engines - * (h/w and s/w) and different algorithms (hamming and BCHx) - * - * @hardware - true if one of the HW engines should be used - * @eccstrength - the number of bits that could be corrected - * (1 - hamming, 4 - BCH4, 8 - BCH8, 16 - BCH16) - */ -int __maybe_unused omap_nand_switch_ecc(uint32_t hardware, uint32_t eccstrength) -{ - struct nand_chip *nand; - struct mtd_info *mtd; - int err = 0; - - if (nand_curr_device < 0 || - nand_curr_device >= CONFIG_SYS_MAX_NAND_DEVICE || - !nand_info[nand_curr_device].name) { - printf("nand: error: no NAND devices found\n"); - return -ENODEV; - } - - mtd = &nand_info[nand_curr_device]; - nand = mtd->priv; - nand->options |= NAND_OWN_BUFFERS; - nand->options &= ~NAND_SUBPAGE_READ; - /* Setup the ecc configurations again */ - if (hardware) { - if (eccstrength == 1) { - err = omap_select_ecc_scheme(nand, - OMAP_ECC_HAM1_CODE_HW, - mtd->writesize, mtd->oobsize); - } else if (eccstrength == 8) { - err = omap_select_ecc_scheme(nand, - OMAP_ECC_BCH8_CODE_HW, - mtd->writesize, mtd->oobsize); - } else { - printf("nand: error: unsupported ECC scheme\n"); - return -EINVAL; - } - } else { - err = omap_select_ecc_scheme(nand, OMAP_ECC_HAM1_CODE_SW, - mtd->writesize, mtd->oobsize); - } - - /* Update NAND handling after ECC mode switch */ - if (!err) - err = nand_scan_tail(mtd); - return err; -} -#endif /* CONFIG_SPL_BUILD */ - -/* - * Board-specific NAND initialization. The following members of the - * argument are board-specific: - * - IO_ADDR_R: address to read the 8 I/O lines of the flash device - * - IO_ADDR_W: address to write the 8 I/O lines of the flash device - * - cmd_ctrl: hardwarespecific function for accesing control-lines - * - waitfunc: hardwarespecific function for accesing device ready/busy line - * - ecc.hwctl: function to enable (reset) hardware ecc generator - * - ecc.mode: mode of ecc, see defines - * - chip_delay: chip dependent delay for transfering data from array to - * read regs (tR) - * - options: various chip options. They can partly be set to inform - * nand_scan about special functionality. See the defines for further - * explanation - */ -int board_nand_init(struct nand_chip *nand) -{ - int32_t gpmc_config = 0; - cs = 0; - int err = 0; - /* - * xloader/Uboot's gpmc configuration would have configured GPMC for - * nand type of memory. The following logic scans and latches on to the - * first CS with NAND type memory. - * TBD: need to make this logic generic to handle multiple CS NAND - * devices. - */ - while (cs < GPMC_MAX_CS) { - /* Check if NAND type is set */ - if ((readl(&gpmc_cfg->cs[cs].config1) & 0xC00) == 0x800) { - /* Found it!! */ - break; - } - cs++; - } - if (cs >= GPMC_MAX_CS) { - printf("nand: error: Unable to find NAND settings in " - "GPMC Configuration - quitting\n"); - return -ENODEV; - } - - gpmc_config = readl(&gpmc_cfg->config); - /* Disable Write protect */ - gpmc_config |= 0x10; - writel(gpmc_config, &gpmc_cfg->config); - - nand->IO_ADDR_R = (void __iomem *)&gpmc_cfg->cs[cs].nand_dat; - nand->IO_ADDR_W = (void __iomem *)&gpmc_cfg->cs[cs].nand_cmd; - nand->priv = &bch_priv; - nand->cmd_ctrl = omap_nand_hwcontrol; - nand->options |= NAND_NO_PADDING | NAND_CACHEPRG; - /* If we are 16 bit dev, our gpmc config tells us that */ - if ((readl(&gpmc_cfg->cs[cs].config1) & 0x3000) == 0x1000) - nand->options |= NAND_BUSWIDTH_16; - - nand->chip_delay = 100; - nand->ecc.layout = &omap_ecclayout; - - /* select ECC scheme */ -#if defined(CONFIG_NAND_OMAP_ECCSCHEME) - err = omap_select_ecc_scheme(nand, CONFIG_NAND_OMAP_ECCSCHEME, - CONFIG_SYS_NAND_PAGE_SIZE, CONFIG_SYS_NAND_OOBSIZE); -#else - /* pagesize and oobsize are not required to configure sw ecc-scheme */ - err = omap_select_ecc_scheme(nand, OMAP_ECC_HAM1_CODE_SW, - 0, 0); -#endif - if (err) - return err; - -#ifdef CONFIG_SPL_BUILD - if (nand->options & NAND_BUSWIDTH_16) - nand->read_buf = nand_read_buf16; - else - nand->read_buf = nand_read_buf; - nand->dev_ready = omap_spl_dev_ready; -#endif - - return 0; -} diff --git a/qemu/roms/u-boot/drivers/mtd/nand/s3c2410_nand.c b/qemu/roms/u-boot/drivers/mtd/nand/s3c2410_nand.c deleted file mode 100644 index db87d0726..000000000 --- a/qemu/roms/u-boot/drivers/mtd/nand/s3c2410_nand.c +++ /dev/null @@ -1,175 +0,0 @@ -/* - * (C) Copyright 2006 OpenMoko, Inc. - * Author: Harald Welte <laforge@openmoko.org> - * - * SPDX-License-Identifier: GPL-2.0+ - */ - -#include <common.h> - -#include <nand.h> -#include <asm/arch/s3c24x0_cpu.h> -#include <asm/io.h> - -#define S3C2410_NFCONF_EN (1<<15) -#define S3C2410_NFCONF_512BYTE (1<<14) -#define S3C2410_NFCONF_4STEP (1<<13) -#define S3C2410_NFCONF_INITECC (1<<12) -#define S3C2410_NFCONF_nFCE (1<<11) -#define S3C2410_NFCONF_TACLS(x) ((x)<<8) -#define S3C2410_NFCONF_TWRPH0(x) ((x)<<4) -#define S3C2410_NFCONF_TWRPH1(x) ((x)<<0) - -#define S3C2410_ADDR_NALE 4 -#define S3C2410_ADDR_NCLE 8 - -#ifdef CONFIG_NAND_SPL - -/* in the early stage of NAND flash booting, printf() is not available */ -#define printf(fmt, args...) - -static void nand_read_buf(struct mtd_info *mtd, u_char *buf, int len) -{ - int i; - struct nand_chip *this = mtd->priv; - - for (i = 0; i < len; i++) - buf[i] = readb(this->IO_ADDR_R); -} -#endif - -static void s3c2410_hwcontrol(struct mtd_info *mtd, int cmd, unsigned int ctrl) -{ - struct nand_chip *chip = mtd->priv; - struct s3c2410_nand *nand = s3c2410_get_base_nand(); - - debug("hwcontrol(): 0x%02x 0x%02x\n", cmd, ctrl); - - if (ctrl & NAND_CTRL_CHANGE) { - ulong IO_ADDR_W = (ulong)nand; - - if (!(ctrl & NAND_CLE)) - IO_ADDR_W |= S3C2410_ADDR_NCLE; - if (!(ctrl & NAND_ALE)) - IO_ADDR_W |= S3C2410_ADDR_NALE; - - chip->IO_ADDR_W = (void *)IO_ADDR_W; - - if (ctrl & NAND_NCE) - writel(readl(&nand->nfconf) & ~S3C2410_NFCONF_nFCE, - &nand->nfconf); - else - writel(readl(&nand->nfconf) | S3C2410_NFCONF_nFCE, - &nand->nfconf); - } - - if (cmd != NAND_CMD_NONE) - writeb(cmd, chip->IO_ADDR_W); -} - -static int s3c2410_dev_ready(struct mtd_info *mtd) -{ - struct s3c2410_nand *nand = s3c2410_get_base_nand(); - debug("dev_ready\n"); - return readl(&nand->nfstat) & 0x01; -} - -#ifdef CONFIG_S3C2410_NAND_HWECC -void s3c2410_nand_enable_hwecc(struct mtd_info *mtd, int mode) -{ - struct s3c2410_nand *nand = s3c2410_get_base_nand(); - debug("s3c2410_nand_enable_hwecc(%p, %d)\n", mtd, mode); - writel(readl(&nand->nfconf) | S3C2410_NFCONF_INITECC, &nand->nfconf); -} - -static int s3c2410_nand_calculate_ecc(struct mtd_info *mtd, const u_char *dat, - u_char *ecc_code) -{ - struct s3c2410_nand *nand = s3c2410_get_base_nand(); - ecc_code[0] = readb(&nand->nfecc); - ecc_code[1] = readb(&nand->nfecc + 1); - ecc_code[2] = readb(&nand->nfecc + 2); - debug("s3c2410_nand_calculate_hwecc(%p,): 0x%02x 0x%02x 0x%02x\n", - mtd , ecc_code[0], ecc_code[1], ecc_code[2]); - - return 0; -} - -static int s3c2410_nand_correct_data(struct mtd_info *mtd, u_char *dat, - u_char *read_ecc, u_char *calc_ecc) -{ - if (read_ecc[0] == calc_ecc[0] && - read_ecc[1] == calc_ecc[1] && - read_ecc[2] == calc_ecc[2]) - return 0; - - printf("s3c2410_nand_correct_data: not implemented\n"); - return -1; -} -#endif - -int board_nand_init(struct nand_chip *nand) -{ - u_int32_t cfg; - u_int8_t tacls, twrph0, twrph1; - struct s3c24x0_clock_power *clk_power = s3c24x0_get_base_clock_power(); - struct s3c2410_nand *nand_reg = s3c2410_get_base_nand(); - - debug("board_nand_init()\n"); - - writel(readl(&clk_power->clkcon) | (1 << 4), &clk_power->clkcon); - - /* initialize hardware */ -#if defined(CONFIG_S3C24XX_CUSTOM_NAND_TIMING) - tacls = CONFIG_S3C24XX_TACLS; - twrph0 = CONFIG_S3C24XX_TWRPH0; - twrph1 = CONFIG_S3C24XX_TWRPH1; -#else - tacls = 4; - twrph0 = 8; - twrph1 = 8; -#endif - - cfg = S3C2410_NFCONF_EN; - cfg |= S3C2410_NFCONF_TACLS(tacls - 1); - cfg |= S3C2410_NFCONF_TWRPH0(twrph0 - 1); - cfg |= S3C2410_NFCONF_TWRPH1(twrph1 - 1); - writel(cfg, &nand_reg->nfconf); - - /* initialize nand_chip data structure */ - nand->IO_ADDR_R = (void *)&nand_reg->nfdata; - nand->IO_ADDR_W = (void *)&nand_reg->nfdata; - - nand->select_chip = NULL; - - /* read_buf and write_buf are default */ - /* read_byte and write_byte are default */ -#ifdef CONFIG_NAND_SPL - nand->read_buf = nand_read_buf; -#endif - - /* hwcontrol always must be implemented */ - nand->cmd_ctrl = s3c2410_hwcontrol; - - nand->dev_ready = s3c2410_dev_ready; - -#ifdef CONFIG_S3C2410_NAND_HWECC - nand->ecc.hwctl = s3c2410_nand_enable_hwecc; - nand->ecc.calculate = s3c2410_nand_calculate_ecc; - nand->ecc.correct = s3c2410_nand_correct_data; - nand->ecc.mode = NAND_ECC_HW; - nand->ecc.size = CONFIG_SYS_NAND_ECCSIZE; - nand->ecc.bytes = CONFIG_SYS_NAND_ECCBYTES; - nand->ecc.strength = 1; -#else - nand->ecc.mode = NAND_ECC_SOFT; -#endif - -#ifdef CONFIG_S3C2410_NAND_BBT - nand->bbt_options |= NAND_BBT_USE_FLASH; -#endif - - debug("end of nand_init\n"); - - return 0; -} diff --git a/qemu/roms/u-boot/drivers/mtd/nand/tegra_nand.c b/qemu/roms/u-boot/drivers/mtd/nand/tegra_nand.c deleted file mode 100644 index 163cf29a3..000000000 --- a/qemu/roms/u-boot/drivers/mtd/nand/tegra_nand.c +++ /dev/null @@ -1,1041 +0,0 @@ -/* - * Copyright (c) 2011 The Chromium OS Authors. - * (C) Copyright 2011 NVIDIA Corporation <www.nvidia.com> - * (C) Copyright 2006 Detlev Zundel, dzu@denx.de - * (C) Copyright 2006 DENX Software Engineering - * - * SPDX-License-Identifier: GPL-2.0+ - */ - -#include <common.h> -#include <asm/io.h> -#include <nand.h> -#include <asm/arch/clock.h> -#include <asm/arch/funcmux.h> -#include <asm/arch-tegra/clk_rst.h> -#include <asm/errno.h> -#include <asm/gpio.h> -#include <fdtdec.h> -#include "tegra_nand.h" - -DECLARE_GLOBAL_DATA_PTR; - -#define NAND_CMD_TIMEOUT_MS 10 - -#define SKIPPED_SPARE_BYTES 4 - -/* ECC bytes to be generated for tag data */ -#define TAG_ECC_BYTES 4 - -/* 64 byte oob block info for large page (== 2KB) device - * - * OOB flash layout for Tegra with Reed-Solomon 4 symbol correct ECC: - * Skipped bytes(4) - * Main area Ecc(36) - * Tag data(20) - * Tag data Ecc(4) - * - * Yaffs2 will use 16 tag bytes. - */ -static struct nand_ecclayout eccoob = { - .eccbytes = 36, - .eccpos = { - 4, 5, 6, 7, 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, - }, - .oobavail = 20, - .oobfree = { - { - .offset = 40, - .length = 20, - }, - } -}; - -enum { - ECC_OK, - ECC_TAG_ERROR = 1 << 0, - ECC_DATA_ERROR = 1 << 1 -}; - -/* Timing parameters */ -enum { - FDT_NAND_MAX_TRP_TREA, - FDT_NAND_TWB, - FDT_NAND_MAX_TCR_TAR_TRR, - FDT_NAND_TWHR, - FDT_NAND_MAX_TCS_TCH_TALS_TALH, - FDT_NAND_TWH, - FDT_NAND_TWP, - FDT_NAND_TRH, - FDT_NAND_TADL, - - FDT_NAND_TIMING_COUNT -}; - -/* Information about an attached NAND chip */ -struct fdt_nand { - struct nand_ctlr *reg; - int enabled; /* 1 to enable, 0 to disable */ - struct fdt_gpio_state wp_gpio; /* write-protect GPIO */ - s32 width; /* bit width, normally 8 */ - u32 timing[FDT_NAND_TIMING_COUNT]; -}; - -struct nand_drv { - struct nand_ctlr *reg; - - /* - * When running in PIO mode to get READ ID bytes from register - * RESP_0, we need this variable as an index to know which byte in - * register RESP_0 should be read. - * Because common code in nand_base.c invokes read_byte function two - * times for NAND_CMD_READID. - * And our controller returns 4 bytes at once in register RESP_0. - */ - int pio_byte_index; - struct fdt_nand config; -}; - -static struct nand_drv nand_ctrl; -static struct mtd_info *our_mtd; -static struct nand_chip nand_chip[CONFIG_SYS_MAX_NAND_DEVICE]; - -#ifdef CONFIG_SYS_DCACHE_OFF -static inline void dma_prepare(void *start, unsigned long length, - int is_writing) -{ -} -#else -/** - * Prepare for a DMA transaction - * - * For a write we flush out our data. For a read we invalidate, since we - * need to do this before we read from the buffer after the DMA has - * completed, so may as well do it now. - * - * @param start Start address for DMA buffer (should be cache-aligned) - * @param length Length of DMA buffer in bytes - * @param is_writing 0 if reading, non-zero if writing - */ -static void dma_prepare(void *start, unsigned long length, int is_writing) -{ - unsigned long addr = (unsigned long)start; - - length = ALIGN(length, ARCH_DMA_MINALIGN); - if (is_writing) - flush_dcache_range(addr, addr + length); - else - invalidate_dcache_range(addr, addr + length); -} -#endif - -/** - * Wait for command completion - * - * @param reg nand_ctlr structure - * @return - * 1 - Command completed - * 0 - Timeout - */ -static int nand_waitfor_cmd_completion(struct nand_ctlr *reg) -{ - u32 reg_val; - int running; - int i; - - for (i = 0; i < NAND_CMD_TIMEOUT_MS * 1000; i++) { - if ((readl(®->command) & CMD_GO) || - !(readl(®->status) & STATUS_RBSY0) || - !(readl(®->isr) & ISR_IS_CMD_DONE)) { - udelay(1); - continue; - } - reg_val = readl(®->dma_mst_ctrl); - /* - * If DMA_MST_CTRL_EN_A_ENABLE or DMA_MST_CTRL_EN_B_ENABLE - * is set, that means DMA engine is running. - * - * Then we have to wait until DMA_MST_CTRL_IS_DMA_DONE - * is cleared, indicating DMA transfer completion. - */ - running = reg_val & (DMA_MST_CTRL_EN_A_ENABLE | - DMA_MST_CTRL_EN_B_ENABLE); - if (!running || (reg_val & DMA_MST_CTRL_IS_DMA_DONE)) - return 1; - udelay(1); - } - return 0; -} - -/** - * Read one byte from the chip - * - * @param mtd MTD device structure - * @return data byte - * - * Read function for 8bit bus-width - */ -static uint8_t read_byte(struct mtd_info *mtd) -{ - struct nand_chip *chip = mtd->priv; - u32 dword_read; - struct nand_drv *info; - - info = (struct nand_drv *)chip->priv; - - /* In PIO mode, only 4 bytes can be transferred with single CMD_GO. */ - if (info->pio_byte_index > 3) { - info->pio_byte_index = 0; - writel(CMD_GO | CMD_PIO - | CMD_RX | CMD_CE0, - &info->reg->command); - if (!nand_waitfor_cmd_completion(info->reg)) - printf("Command timeout\n"); - } - - dword_read = readl(&info->reg->resp); - dword_read = dword_read >> (8 * info->pio_byte_index); - info->pio_byte_index++; - return (uint8_t)dword_read; -} - -/** - * Read len bytes from the chip into a buffer - * - * @param mtd MTD device structure - * @param buf buffer to store data to - * @param len number of bytes to read - * - * Read function for 8bit bus-width - */ -static void read_buf(struct mtd_info *mtd, uint8_t *buf, int len) -{ - int i, s; - unsigned int reg; - struct nand_chip *chip = mtd->priv; - struct nand_drv *info = (struct nand_drv *)chip->priv; - - for (i = 0; i < len; i += 4) { - s = (len - i) > 4 ? 4 : len - i; - writel(CMD_PIO | CMD_RX | CMD_A_VALID | CMD_CE0 | - ((s - 1) << CMD_TRANS_SIZE_SHIFT) | CMD_GO, - &info->reg->command); - if (!nand_waitfor_cmd_completion(info->reg)) - puts("Command timeout during read_buf\n"); - reg = readl(&info->reg->resp); - memcpy(buf + i, ®, s); - } -} - -/** - * Check NAND status to see if it is ready or not - * - * @param mtd MTD device structure - * @return - * 1 - ready - * 0 - not ready - */ -static int nand_dev_ready(struct mtd_info *mtd) -{ - struct nand_chip *chip = mtd->priv; - int reg_val; - struct nand_drv *info; - - info = (struct nand_drv *)chip->priv; - - reg_val = readl(&info->reg->status); - if (reg_val & STATUS_RBSY0) - return 1; - else - return 0; -} - -/* Dummy implementation: we don't support multiple chips */ -static void nand_select_chip(struct mtd_info *mtd, int chipnr) -{ - switch (chipnr) { - case -1: - case 0: - break; - - default: - BUG(); - } -} - -/** - * Clear all interrupt status bits - * - * @param reg nand_ctlr structure - */ -static void nand_clear_interrupt_status(struct nand_ctlr *reg) -{ - u32 reg_val; - - /* Clear interrupt status */ - reg_val = readl(®->isr); - writel(reg_val, ®->isr); -} - -/** - * Send command to NAND device - * - * @param mtd MTD device structure - * @param command the command to be sent - * @param column the column address for this command, -1 if none - * @param page_addr the page address for this command, -1 if none - */ -static void nand_command(struct mtd_info *mtd, unsigned int command, - int column, int page_addr) -{ - struct nand_chip *chip = mtd->priv; - struct nand_drv *info; - - info = (struct nand_drv *)chip->priv; - - /* - * Write out the command to the device. - * - * Only command NAND_CMD_RESET or NAND_CMD_READID will come - * here before mtd->writesize is initialized. - */ - - /* Emulate NAND_CMD_READOOB */ - if (command == NAND_CMD_READOOB) { - assert(mtd->writesize != 0); - column += mtd->writesize; - command = NAND_CMD_READ0; - } - - /* Adjust columns for 16 bit bus-width */ - if (column != -1 && (chip->options & NAND_BUSWIDTH_16)) - column >>= 1; - - nand_clear_interrupt_status(info->reg); - - /* Stop DMA engine, clear DMA completion status */ - writel(DMA_MST_CTRL_EN_A_DISABLE - | DMA_MST_CTRL_EN_B_DISABLE - | DMA_MST_CTRL_IS_DMA_DONE, - &info->reg->dma_mst_ctrl); - - /* - * Program and erase have their own busy handlers - * status and sequential in needs no delay - */ - switch (command) { - case NAND_CMD_READID: - writel(NAND_CMD_READID, &info->reg->cmd_reg1); - writel(column & 0xFF, &info->reg->addr_reg1); - writel(CMD_GO | CMD_CLE | CMD_ALE | CMD_PIO - | CMD_RX | - ((4 - 1) << CMD_TRANS_SIZE_SHIFT) - | CMD_CE0, - &info->reg->command); - info->pio_byte_index = 0; - break; - case NAND_CMD_PARAM: - writel(NAND_CMD_PARAM, &info->reg->cmd_reg1); - writel(column & 0xFF, &info->reg->addr_reg1); - writel(CMD_GO | CMD_CLE | CMD_ALE | CMD_CE0, - &info->reg->command); - break; - case NAND_CMD_READ0: - writel(NAND_CMD_READ0, &info->reg->cmd_reg1); - writel(NAND_CMD_READSTART, &info->reg->cmd_reg2); - writel((page_addr << 16) | (column & 0xFFFF), - &info->reg->addr_reg1); - writel(page_addr >> 16, &info->reg->addr_reg2); - return; - case NAND_CMD_SEQIN: - writel(NAND_CMD_SEQIN, &info->reg->cmd_reg1); - writel(NAND_CMD_PAGEPROG, &info->reg->cmd_reg2); - writel((page_addr << 16) | (column & 0xFFFF), - &info->reg->addr_reg1); - writel(page_addr >> 16, - &info->reg->addr_reg2); - return; - case NAND_CMD_PAGEPROG: - return; - case NAND_CMD_ERASE1: - writel(NAND_CMD_ERASE1, &info->reg->cmd_reg1); - writel(NAND_CMD_ERASE2, &info->reg->cmd_reg2); - writel(page_addr, &info->reg->addr_reg1); - writel(CMD_GO | CMD_CLE | CMD_ALE | - CMD_SEC_CMD | CMD_CE0 | CMD_ALE_BYTES3, - &info->reg->command); - break; - case NAND_CMD_ERASE2: - return; - case NAND_CMD_STATUS: - writel(NAND_CMD_STATUS, &info->reg->cmd_reg1); - writel(CMD_GO | CMD_CLE | CMD_PIO | CMD_RX - | ((1 - 0) << CMD_TRANS_SIZE_SHIFT) - | CMD_CE0, - &info->reg->command); - info->pio_byte_index = 0; - break; - case NAND_CMD_RESET: - writel(NAND_CMD_RESET, &info->reg->cmd_reg1); - writel(CMD_GO | CMD_CLE | CMD_CE0, - &info->reg->command); - break; - case NAND_CMD_RNDOUT: - default: - printf("%s: Unsupported command %d\n", __func__, command); - return; - } - if (!nand_waitfor_cmd_completion(info->reg)) - printf("Command 0x%02X timeout\n", command); -} - -/** - * Check whether the pointed buffer are all 0xff (blank). - * - * @param buf data buffer for blank check - * @param len length of the buffer in byte - * @return - * 1 - blank - * 0 - non-blank - */ -static int blank_check(u8 *buf, int len) -{ - int i; - - for (i = 0; i < len; i++) - if (buf[i] != 0xFF) - return 0; - return 1; -} - -/** - * After a DMA transfer for read, we call this function to see whether there - * is any uncorrectable error on the pointed data buffer or oob buffer. - * - * @param reg nand_ctlr structure - * @param databuf data buffer - * @param a_len data buffer length - * @param oobbuf oob buffer - * @param b_len oob buffer length - * @return - * ECC_OK - no ECC error or correctable ECC error - * ECC_TAG_ERROR - uncorrectable tag ECC error - * ECC_DATA_ERROR - uncorrectable data ECC error - * ECC_DATA_ERROR + ECC_TAG_ERROR - uncorrectable data+tag ECC error - */ -static int check_ecc_error(struct nand_ctlr *reg, u8 *databuf, - int a_len, u8 *oobbuf, int b_len) -{ - int return_val = ECC_OK; - u32 reg_val; - - if (!(readl(®->isr) & ISR_IS_ECC_ERR)) - return ECC_OK; - - /* - * Area A is used for the data block (databuf). Area B is used for - * the spare block (oobbuf) - */ - reg_val = readl(®->dec_status); - if ((reg_val & DEC_STATUS_A_ECC_FAIL) && databuf) { - reg_val = readl(®->bch_dec_status_buf); - /* - * If uncorrectable error occurs on data area, then see whether - * they are all FF. If all are FF, it's a blank page. - * Not error. - */ - if ((reg_val & BCH_DEC_STATUS_FAIL_SEC_FLAG_MASK) && - !blank_check(databuf, a_len)) - return_val |= ECC_DATA_ERROR; - } - - if ((reg_val & DEC_STATUS_B_ECC_FAIL) && oobbuf) { - reg_val = readl(®->bch_dec_status_buf); - /* - * If uncorrectable error occurs on tag area, then see whether - * they are all FF. If all are FF, it's a blank page. - * Not error. - */ - if ((reg_val & BCH_DEC_STATUS_FAIL_TAG_MASK) && - !blank_check(oobbuf, b_len)) - return_val |= ECC_TAG_ERROR; - } - - return return_val; -} - -/** - * Set GO bit to send command to device - * - * @param reg nand_ctlr structure - */ -static void start_command(struct nand_ctlr *reg) -{ - u32 reg_val; - - reg_val = readl(®->command); - reg_val |= CMD_GO; - writel(reg_val, ®->command); -} - -/** - * Clear command GO bit, DMA GO bit, and DMA completion status - * - * @param reg nand_ctlr structure - */ -static void stop_command(struct nand_ctlr *reg) -{ - /* Stop command */ - writel(0, ®->command); - - /* Stop DMA engine and clear DMA completion status */ - writel(DMA_MST_CTRL_GO_DISABLE - | DMA_MST_CTRL_IS_DMA_DONE, - ®->dma_mst_ctrl); -} - -/** - * Set up NAND bus width and page size - * - * @param info nand_info structure - * @param *reg_val address of reg_val - * @return 0 if ok, -1 on error - */ -static int set_bus_width_page_size(struct fdt_nand *config, - u32 *reg_val) -{ - if (config->width == 8) - *reg_val = CFG_BUS_WIDTH_8BIT; - else if (config->width == 16) - *reg_val = CFG_BUS_WIDTH_16BIT; - else { - debug("%s: Unsupported bus width %d\n", __func__, - config->width); - return -1; - } - - if (our_mtd->writesize == 512) - *reg_val |= CFG_PAGE_SIZE_512; - else if (our_mtd->writesize == 2048) - *reg_val |= CFG_PAGE_SIZE_2048; - else if (our_mtd->writesize == 4096) - *reg_val |= CFG_PAGE_SIZE_4096; - else { - debug("%s: Unsupported page size %d\n", __func__, - our_mtd->writesize); - return -1; - } - - return 0; -} - -/** - * Page read/write function - * - * @param mtd mtd info structure - * @param chip nand chip info structure - * @param buf data buffer - * @param page page number - * @param with_ecc 1 to enable ECC, 0 to disable ECC - * @param is_writing 0 for read, 1 for write - * @return 0 when successfully completed - * -EIO when command timeout - */ -static int nand_rw_page(struct mtd_info *mtd, struct nand_chip *chip, - uint8_t *buf, int page, int with_ecc, int is_writing) -{ - u32 reg_val; - int tag_size; - struct nand_oobfree *free = chip->ecc.layout->oobfree; - /* 4*128=512 (byte) is the value that our HW can support. */ - ALLOC_CACHE_ALIGN_BUFFER(u32, tag_buf, 128); - char *tag_ptr; - struct nand_drv *info; - struct fdt_nand *config; - - if ((uintptr_t)buf & 0x03) { - printf("buf %p has to be 4-byte aligned\n", buf); - return -EINVAL; - } - - info = (struct nand_drv *)chip->priv; - config = &info->config; - if (set_bus_width_page_size(config, ®_val)) - return -EINVAL; - - /* Need to be 4-byte aligned */ - tag_ptr = (char *)tag_buf; - - stop_command(info->reg); - - writel((1 << chip->page_shift) - 1, &info->reg->dma_cfg_a); - writel(virt_to_phys(buf), &info->reg->data_block_ptr); - - if (with_ecc) { - writel(virt_to_phys(tag_ptr), &info->reg->tag_ptr); - if (is_writing) - memcpy(tag_ptr, chip->oob_poi + free->offset, - chip->ecc.layout->oobavail + - TAG_ECC_BYTES); - } else { - writel(virt_to_phys(chip->oob_poi), &info->reg->tag_ptr); - } - - /* Set ECC selection, configure ECC settings */ - if (with_ecc) { - tag_size = chip->ecc.layout->oobavail + TAG_ECC_BYTES; - reg_val |= (CFG_SKIP_SPARE_SEL_4 - | CFG_SKIP_SPARE_ENABLE - | CFG_HW_ECC_CORRECTION_ENABLE - | CFG_ECC_EN_TAG_DISABLE - | CFG_HW_ECC_SEL_RS - | CFG_HW_ECC_ENABLE - | CFG_TVAL4 - | (tag_size - 1)); - - if (!is_writing) - tag_size += SKIPPED_SPARE_BYTES; - dma_prepare(tag_ptr, tag_size, is_writing); - } else { - tag_size = mtd->oobsize; - reg_val |= (CFG_SKIP_SPARE_DISABLE - | CFG_HW_ECC_CORRECTION_DISABLE - | CFG_ECC_EN_TAG_DISABLE - | CFG_HW_ECC_DISABLE - | (tag_size - 1)); - dma_prepare(chip->oob_poi, tag_size, is_writing); - } - writel(reg_val, &info->reg->config); - - dma_prepare(buf, 1 << chip->page_shift, is_writing); - - writel(BCH_CONFIG_BCH_ECC_DISABLE, &info->reg->bch_config); - - writel(tag_size - 1, &info->reg->dma_cfg_b); - - nand_clear_interrupt_status(info->reg); - - reg_val = CMD_CLE | CMD_ALE - | CMD_SEC_CMD - | (CMD_ALE_BYTES5 << CMD_ALE_BYTE_SIZE_SHIFT) - | CMD_A_VALID - | CMD_B_VALID - | (CMD_TRANS_SIZE_PAGE << CMD_TRANS_SIZE_SHIFT) - | CMD_CE0; - if (!is_writing) - reg_val |= (CMD_AFT_DAT_DISABLE | CMD_RX); - else - reg_val |= (CMD_AFT_DAT_ENABLE | CMD_TX); - writel(reg_val, &info->reg->command); - - /* Setup DMA engine */ - reg_val = DMA_MST_CTRL_GO_ENABLE - | DMA_MST_CTRL_BURST_8WORDS - | DMA_MST_CTRL_EN_A_ENABLE - | DMA_MST_CTRL_EN_B_ENABLE; - - if (!is_writing) - reg_val |= DMA_MST_CTRL_DIR_READ; - else - reg_val |= DMA_MST_CTRL_DIR_WRITE; - - writel(reg_val, &info->reg->dma_mst_ctrl); - - start_command(info->reg); - - if (!nand_waitfor_cmd_completion(info->reg)) { - if (!is_writing) - printf("Read Page 0x%X timeout ", page); - else - printf("Write Page 0x%X timeout ", page); - if (with_ecc) - printf("with ECC"); - else - printf("without ECC"); - printf("\n"); - return -EIO; - } - - if (with_ecc && !is_writing) { - memcpy(chip->oob_poi, tag_ptr, - SKIPPED_SPARE_BYTES); - memcpy(chip->oob_poi + free->offset, - tag_ptr + SKIPPED_SPARE_BYTES, - chip->ecc.layout->oobavail); - reg_val = (u32)check_ecc_error(info->reg, (u8 *)buf, - 1 << chip->page_shift, - (u8 *)(tag_ptr + SKIPPED_SPARE_BYTES), - chip->ecc.layout->oobavail); - if (reg_val & ECC_TAG_ERROR) - printf("Read Page 0x%X tag ECC error\n", page); - if (reg_val & ECC_DATA_ERROR) - printf("Read Page 0x%X data ECC error\n", - page); - if (reg_val & (ECC_DATA_ERROR | ECC_TAG_ERROR)) - return -EIO; - } - return 0; -} - -/** - * Hardware ecc based page read function - * - * @param mtd mtd info structure - * @param chip nand chip info structure - * @param buf buffer to store read data - * @param page page number to read - * @return 0 when successfully completed - * -EIO when command timeout - */ -static int nand_read_page_hwecc(struct mtd_info *mtd, - struct nand_chip *chip, uint8_t *buf, int oob_required, int page) -{ - return nand_rw_page(mtd, chip, buf, page, 1, 0); -} - -/** - * Hardware ecc based page write function - * - * @param mtd mtd info structure - * @param chip nand chip info structure - * @param buf data buffer - */ -static int nand_write_page_hwecc(struct mtd_info *mtd, - struct nand_chip *chip, const uint8_t *buf, int oob_required) -{ - int page; - struct nand_drv *info; - - info = (struct nand_drv *)chip->priv; - - page = (readl(&info->reg->addr_reg1) >> 16) | - (readl(&info->reg->addr_reg2) << 16); - - nand_rw_page(mtd, chip, (uint8_t *)buf, page, 1, 1); - return 0; -} - - -/** - * Read raw page data without ecc - * - * @param mtd mtd info structure - * @param chip nand chip info structure - * @param buf buffer to store read data - * @param page page number to read - * @return 0 when successfully completed - * -EINVAL when chip->oob_poi is not double-word aligned - * -EIO when command timeout - */ -static int nand_read_page_raw(struct mtd_info *mtd, - struct nand_chip *chip, uint8_t *buf, int oob_required, int page) -{ - return nand_rw_page(mtd, chip, buf, page, 0, 0); -} - -/** - * Raw page write function - * - * @param mtd mtd info structure - * @param chip nand chip info structure - * @param buf data buffer - */ -static int nand_write_page_raw(struct mtd_info *mtd, - struct nand_chip *chip, const uint8_t *buf, int oob_required) -{ - int page; - struct nand_drv *info; - - info = (struct nand_drv *)chip->priv; - page = (readl(&info->reg->addr_reg1) >> 16) | - (readl(&info->reg->addr_reg2) << 16); - - nand_rw_page(mtd, chip, (uint8_t *)buf, page, 0, 1); - return 0; -} - -/** - * OOB data read/write function - * - * @param mtd mtd info structure - * @param chip nand chip info structure - * @param page page number to read - * @param with_ecc 1 to enable ECC, 0 to disable ECC - * @param is_writing 0 for read, 1 for write - * @return 0 when successfully completed - * -EINVAL when chip->oob_poi is not double-word aligned - * -EIO when command timeout - */ -static int nand_rw_oob(struct mtd_info *mtd, struct nand_chip *chip, - int page, int with_ecc, int is_writing) -{ - u32 reg_val; - int tag_size; - struct nand_oobfree *free = chip->ecc.layout->oobfree; - struct nand_drv *info; - - if (((int)chip->oob_poi) & 0x03) - return -EINVAL; - info = (struct nand_drv *)chip->priv; - if (set_bus_width_page_size(&info->config, ®_val)) - return -EINVAL; - - stop_command(info->reg); - - writel(virt_to_phys(chip->oob_poi), &info->reg->tag_ptr); - - /* Set ECC selection */ - tag_size = mtd->oobsize; - if (with_ecc) - reg_val |= CFG_ECC_EN_TAG_ENABLE; - else - reg_val |= (CFG_ECC_EN_TAG_DISABLE); - - reg_val |= ((tag_size - 1) | - CFG_SKIP_SPARE_DISABLE | - CFG_HW_ECC_CORRECTION_DISABLE | - CFG_HW_ECC_DISABLE); - writel(reg_val, &info->reg->config); - - dma_prepare(chip->oob_poi, tag_size, is_writing); - - writel(BCH_CONFIG_BCH_ECC_DISABLE, &info->reg->bch_config); - - if (is_writing && with_ecc) - tag_size -= TAG_ECC_BYTES; - - writel(tag_size - 1, &info->reg->dma_cfg_b); - - nand_clear_interrupt_status(info->reg); - - reg_val = CMD_CLE | CMD_ALE - | CMD_SEC_CMD - | (CMD_ALE_BYTES5 << CMD_ALE_BYTE_SIZE_SHIFT) - | CMD_B_VALID - | CMD_CE0; - if (!is_writing) - reg_val |= (CMD_AFT_DAT_DISABLE | CMD_RX); - else - reg_val |= (CMD_AFT_DAT_ENABLE | CMD_TX); - writel(reg_val, &info->reg->command); - - /* Setup DMA engine */ - reg_val = DMA_MST_CTRL_GO_ENABLE - | DMA_MST_CTRL_BURST_8WORDS - | DMA_MST_CTRL_EN_B_ENABLE; - if (!is_writing) - reg_val |= DMA_MST_CTRL_DIR_READ; - else - reg_val |= DMA_MST_CTRL_DIR_WRITE; - - writel(reg_val, &info->reg->dma_mst_ctrl); - - start_command(info->reg); - - if (!nand_waitfor_cmd_completion(info->reg)) { - if (!is_writing) - printf("Read OOB of Page 0x%X timeout\n", page); - else - printf("Write OOB of Page 0x%X timeout\n", page); - return -EIO; - } - - if (with_ecc && !is_writing) { - reg_val = (u32)check_ecc_error(info->reg, 0, 0, - (u8 *)(chip->oob_poi + free->offset), - chip->ecc.layout->oobavail); - if (reg_val & ECC_TAG_ERROR) - printf("Read OOB of Page 0x%X tag ECC error\n", page); - } - return 0; -} - -/** - * OOB data read function - * - * @param mtd mtd info structure - * @param chip nand chip info structure - * @param page page number to read - */ -static int nand_read_oob(struct mtd_info *mtd, struct nand_chip *chip, - int page) -{ - chip->cmdfunc(mtd, NAND_CMD_READOOB, 0, page); - nand_rw_oob(mtd, chip, page, 0, 0); - return 0; -} - -/** - * OOB data write function - * - * @param mtd mtd info structure - * @param chip nand chip info structure - * @param page page number to write - * @return 0 when successfully completed - * -EINVAL when chip->oob_poi is not double-word aligned - * -EIO when command timeout - */ -static int nand_write_oob(struct mtd_info *mtd, struct nand_chip *chip, - int page) -{ - chip->cmdfunc(mtd, NAND_CMD_SEQIN, mtd->writesize, page); - - return nand_rw_oob(mtd, chip, page, 0, 1); -} - -/** - * Set up NAND memory timings according to the provided parameters - * - * @param timing Timing parameters - * @param reg NAND controller register address - */ -static void setup_timing(unsigned timing[FDT_NAND_TIMING_COUNT], - struct nand_ctlr *reg) -{ - u32 reg_val, clk_rate, clk_period, time_val; - - clk_rate = (u32)clock_get_periph_rate(PERIPH_ID_NDFLASH, - CLOCK_ID_PERIPH) / 1000000; - clk_period = 1000 / clk_rate; - reg_val = ((timing[FDT_NAND_MAX_TRP_TREA] / clk_period) << - TIMING_TRP_RESP_CNT_SHIFT) & TIMING_TRP_RESP_CNT_MASK; - reg_val |= ((timing[FDT_NAND_TWB] / clk_period) << - TIMING_TWB_CNT_SHIFT) & TIMING_TWB_CNT_MASK; - time_val = timing[FDT_NAND_MAX_TCR_TAR_TRR] / clk_period; - if (time_val > 2) - reg_val |= ((time_val - 2) << TIMING_TCR_TAR_TRR_CNT_SHIFT) & - TIMING_TCR_TAR_TRR_CNT_MASK; - reg_val |= ((timing[FDT_NAND_TWHR] / clk_period) << - TIMING_TWHR_CNT_SHIFT) & TIMING_TWHR_CNT_MASK; - time_val = timing[FDT_NAND_MAX_TCS_TCH_TALS_TALH] / clk_period; - if (time_val > 1) - reg_val |= ((time_val - 1) << TIMING_TCS_CNT_SHIFT) & - TIMING_TCS_CNT_MASK; - reg_val |= ((timing[FDT_NAND_TWH] / clk_period) << - TIMING_TWH_CNT_SHIFT) & TIMING_TWH_CNT_MASK; - reg_val |= ((timing[FDT_NAND_TWP] / clk_period) << - TIMING_TWP_CNT_SHIFT) & TIMING_TWP_CNT_MASK; - reg_val |= ((timing[FDT_NAND_TRH] / clk_period) << - TIMING_TRH_CNT_SHIFT) & TIMING_TRH_CNT_MASK; - reg_val |= ((timing[FDT_NAND_MAX_TRP_TREA] / clk_period) << - TIMING_TRP_CNT_SHIFT) & TIMING_TRP_CNT_MASK; - writel(reg_val, ®->timing); - - reg_val = 0; - time_val = timing[FDT_NAND_TADL] / clk_period; - if (time_val > 2) - reg_val = (time_val - 2) & TIMING2_TADL_CNT_MASK; - writel(reg_val, ®->timing2); -} - -/** - * Decode NAND parameters from the device tree - * - * @param blob Device tree blob - * @param node Node containing "nand-flash" compatble node - * @return 0 if ok, -ve on error (FDT_ERR_...) - */ -static int fdt_decode_nand(const void *blob, int node, struct fdt_nand *config) -{ - int err; - - config->reg = (struct nand_ctlr *)fdtdec_get_addr(blob, node, "reg"); - config->enabled = fdtdec_get_is_enabled(blob, node); - config->width = fdtdec_get_int(blob, node, "nvidia,nand-width", 8); - err = fdtdec_decode_gpio(blob, node, "nvidia,wp-gpios", - &config->wp_gpio); - if (err) - return err; - err = fdtdec_get_int_array(blob, node, "nvidia,timing", - config->timing, FDT_NAND_TIMING_COUNT); - if (err < 0) - return err; - - /* Now look up the controller and decode that */ - node = fdt_next_node(blob, node, NULL); - if (node < 0) - return node; - - return 0; -} - -/** - * Board-specific NAND initialization - * - * @param nand nand chip info structure - * @return 0, after initialized, -1 on error - */ -int tegra_nand_init(struct nand_chip *nand, int devnum) -{ - struct nand_drv *info = &nand_ctrl; - struct fdt_nand *config = &info->config; - int node, ret; - - node = fdtdec_next_compatible(gd->fdt_blob, 0, - COMPAT_NVIDIA_TEGRA20_NAND); - if (node < 0) - return -1; - if (fdt_decode_nand(gd->fdt_blob, node, config)) { - printf("Could not decode nand-flash in device tree\n"); - return -1; - } - if (!config->enabled) - return -1; - info->reg = config->reg; - nand->ecc.mode = NAND_ECC_HW; - nand->ecc.layout = &eccoob; - - nand->options = LP_OPTIONS; - nand->cmdfunc = nand_command; - nand->read_byte = read_byte; - nand->read_buf = read_buf; - nand->ecc.read_page = nand_read_page_hwecc; - nand->ecc.write_page = nand_write_page_hwecc; - nand->ecc.read_page_raw = nand_read_page_raw; - nand->ecc.write_page_raw = nand_write_page_raw; - nand->ecc.read_oob = nand_read_oob; - nand->ecc.write_oob = nand_write_oob; - nand->ecc.strength = 1; - nand->select_chip = nand_select_chip; - nand->dev_ready = nand_dev_ready; - nand->priv = &nand_ctrl; - - /* Adjust controller clock rate */ - clock_start_periph_pll(PERIPH_ID_NDFLASH, CLOCK_ID_PERIPH, 52000000); - - /* Adjust timing for NAND device */ - setup_timing(config->timing, info->reg); - - fdtdec_setup_gpio(&config->wp_gpio); - gpio_direction_output(config->wp_gpio.gpio, 1); - - our_mtd = &nand_info[devnum]; - our_mtd->priv = nand; - ret = nand_scan_ident(our_mtd, CONFIG_SYS_NAND_MAX_CHIPS, NULL); - if (ret) - return ret; - - nand->ecc.size = our_mtd->writesize; - nand->ecc.bytes = our_mtd->oobsize; - - ret = nand_scan_tail(our_mtd); - if (ret) - return ret; - - ret = nand_register(devnum); - if (ret) - return ret; - - return 0; -} - -void board_nand_init(void) -{ - struct nand_chip *nand = &nand_chip[0]; - - if (tegra_nand_init(nand, 0)) - puts("Tegra NAND init failed\n"); -} diff --git a/qemu/roms/u-boot/drivers/mtd/nand/tegra_nand.h b/qemu/roms/u-boot/drivers/mtd/nand/tegra_nand.h deleted file mode 100644 index ded9d7104..000000000 --- a/qemu/roms/u-boot/drivers/mtd/nand/tegra_nand.h +++ /dev/null @@ -1,241 +0,0 @@ -/* - * (C) Copyright 2011 NVIDIA Corporation <www.nvidia.com> - * - * SPDX-License-Identifier: GPL-2.0+ - */ - -/* register offset */ -#define COMMAND_0 0x00 -#define CMD_GO (1 << 31) -#define CMD_CLE (1 << 30) -#define CMD_ALE (1 << 29) -#define CMD_PIO (1 << 28) -#define CMD_TX (1 << 27) -#define CMD_RX (1 << 26) -#define CMD_SEC_CMD (1 << 25) -#define CMD_AFT_DAT_MASK (1 << 24) -#define CMD_AFT_DAT_DISABLE 0 -#define CMD_AFT_DAT_ENABLE (1 << 24) -#define CMD_TRANS_SIZE_SHIFT 20 -#define CMD_TRANS_SIZE_PAGE 8 -#define CMD_A_VALID (1 << 19) -#define CMD_B_VALID (1 << 18) -#define CMD_RD_STATUS_CHK (1 << 17) -#define CMD_R_BSY_CHK (1 << 16) -#define CMD_CE7 (1 << 15) -#define CMD_CE6 (1 << 14) -#define CMD_CE5 (1 << 13) -#define CMD_CE4 (1 << 12) -#define CMD_CE3 (1 << 11) -#define CMD_CE2 (1 << 10) -#define CMD_CE1 (1 << 9) -#define CMD_CE0 (1 << 8) -#define CMD_CLE_BYTE_SIZE_SHIFT 4 -enum { - CMD_CLE_BYTES1 = 0, - CMD_CLE_BYTES2, - CMD_CLE_BYTES3, - CMD_CLE_BYTES4, -}; -#define CMD_ALE_BYTE_SIZE_SHIFT 0 -enum { - CMD_ALE_BYTES1 = 0, - CMD_ALE_BYTES2, - CMD_ALE_BYTES3, - CMD_ALE_BYTES4, - CMD_ALE_BYTES5, - CMD_ALE_BYTES6, - CMD_ALE_BYTES7, - CMD_ALE_BYTES8 -}; - -#define STATUS_0 0x04 -#define STATUS_RBSY0 (1 << 8) - -#define ISR_0 0x08 -#define ISR_IS_CMD_DONE (1 << 5) -#define ISR_IS_ECC_ERR (1 << 4) - -#define IER_0 0x0C - -#define CFG_0 0x10 -#define CFG_HW_ECC_MASK (1 << 31) -#define CFG_HW_ECC_DISABLE 0 -#define CFG_HW_ECC_ENABLE (1 << 31) -#define CFG_HW_ECC_SEL_MASK (1 << 30) -#define CFG_HW_ECC_SEL_HAMMING 0 -#define CFG_HW_ECC_SEL_RS (1 << 30) -#define CFG_HW_ECC_CORRECTION_MASK (1 << 29) -#define CFG_HW_ECC_CORRECTION_DISABLE 0 -#define CFG_HW_ECC_CORRECTION_ENABLE (1 << 29) -#define CFG_PIPELINE_EN_MASK (1 << 28) -#define CFG_PIPELINE_EN_DISABLE 0 -#define CFG_PIPELINE_EN_ENABLE (1 << 28) -#define CFG_ECC_EN_TAG_MASK (1 << 27) -#define CFG_ECC_EN_TAG_DISABLE 0 -#define CFG_ECC_EN_TAG_ENABLE (1 << 27) -#define CFG_TVALUE_MASK (3 << 24) -enum { - CFG_TVAL4 = 0 << 24, - CFG_TVAL6 = 1 << 24, - CFG_TVAL8 = 2 << 24 -}; -#define CFG_SKIP_SPARE_MASK (1 << 23) -#define CFG_SKIP_SPARE_DISABLE 0 -#define CFG_SKIP_SPARE_ENABLE (1 << 23) -#define CFG_COM_BSY_MASK (1 << 22) -#define CFG_COM_BSY_DISABLE 0 -#define CFG_COM_BSY_ENABLE (1 << 22) -#define CFG_BUS_WIDTH_MASK (1 << 21) -#define CFG_BUS_WIDTH_8BIT 0 -#define CFG_BUS_WIDTH_16BIT (1 << 21) -#define CFG_LPDDR1_MODE_MASK (1 << 20) -#define CFG_LPDDR1_MODE_DISABLE 0 -#define CFG_LPDDR1_MODE_ENABLE (1 << 20) -#define CFG_EDO_MODE_MASK (1 << 19) -#define CFG_EDO_MODE_DISABLE 0 -#define CFG_EDO_MODE_ENABLE (1 << 19) -#define CFG_PAGE_SIZE_SEL_MASK (7 << 16) -enum { - CFG_PAGE_SIZE_256 = 0 << 16, - CFG_PAGE_SIZE_512 = 1 << 16, - CFG_PAGE_SIZE_1024 = 2 << 16, - CFG_PAGE_SIZE_2048 = 3 << 16, - CFG_PAGE_SIZE_4096 = 4 << 16 -}; -#define CFG_SKIP_SPARE_SEL_MASK (3 << 14) -enum { - CFG_SKIP_SPARE_SEL_4 = 0 << 14, - CFG_SKIP_SPARE_SEL_8 = 1 << 14, - CFG_SKIP_SPARE_SEL_12 = 2 << 14, - CFG_SKIP_SPARE_SEL_16 = 3 << 14 -}; -#define CFG_TAG_BYTE_SIZE_MASK 0x1FF - -#define TIMING_0 0x14 -#define TIMING_TRP_RESP_CNT_SHIFT 28 -#define TIMING_TRP_RESP_CNT_MASK (0xf << TIMING_TRP_RESP_CNT_SHIFT) -#define TIMING_TWB_CNT_SHIFT 24 -#define TIMING_TWB_CNT_MASK (0xf << TIMING_TWB_CNT_SHIFT) -#define TIMING_TCR_TAR_TRR_CNT_SHIFT 20 -#define TIMING_TCR_TAR_TRR_CNT_MASK (0xf << TIMING_TCR_TAR_TRR_CNT_SHIFT) -#define TIMING_TWHR_CNT_SHIFT 16 -#define TIMING_TWHR_CNT_MASK (0xf << TIMING_TWHR_CNT_SHIFT) -#define TIMING_TCS_CNT_SHIFT 14 -#define TIMING_TCS_CNT_MASK (3 << TIMING_TCS_CNT_SHIFT) -#define TIMING_TWH_CNT_SHIFT 12 -#define TIMING_TWH_CNT_MASK (3 << TIMING_TWH_CNT_SHIFT) -#define TIMING_TWP_CNT_SHIFT 8 -#define TIMING_TWP_CNT_MASK (0xf << TIMING_TWP_CNT_SHIFT) -#define TIMING_TRH_CNT_SHIFT 4 -#define TIMING_TRH_CNT_MASK (3 << TIMING_TRH_CNT_SHIFT) -#define TIMING_TRP_CNT_SHIFT 0 -#define TIMING_TRP_CNT_MASK (0xf << TIMING_TRP_CNT_SHIFT) - -#define RESP_0 0x18 - -#define TIMING2_0 0x1C -#define TIMING2_TADL_CNT_SHIFT 0 -#define TIMING2_TADL_CNT_MASK (0xf << TIMING2_TADL_CNT_SHIFT) - -#define CMD_REG1_0 0x20 -#define CMD_REG2_0 0x24 -#define ADDR_REG1_0 0x28 -#define ADDR_REG2_0 0x2C - -#define DMA_MST_CTRL_0 0x30 -#define DMA_MST_CTRL_GO_MASK (1 << 31) -#define DMA_MST_CTRL_GO_DISABLE 0 -#define DMA_MST_CTRL_GO_ENABLE (1 << 31) -#define DMA_MST_CTRL_DIR_MASK (1 << 30) -#define DMA_MST_CTRL_DIR_READ 0 -#define DMA_MST_CTRL_DIR_WRITE (1 << 30) -#define DMA_MST_CTRL_PERF_EN_MASK (1 << 29) -#define DMA_MST_CTRL_PERF_EN_DISABLE 0 -#define DMA_MST_CTRL_PERF_EN_ENABLE (1 << 29) -#define DMA_MST_CTRL_REUSE_BUFFER_MASK (1 << 27) -#define DMA_MST_CTRL_REUSE_BUFFER_DISABLE 0 -#define DMA_MST_CTRL_REUSE_BUFFER_ENABLE (1 << 27) -#define DMA_MST_CTRL_BURST_SIZE_SHIFT 24 -#define DMA_MST_CTRL_BURST_SIZE_MASK (7 << DMA_MST_CTRL_BURST_SIZE_SHIFT) -enum { - DMA_MST_CTRL_BURST_1WORDS = 2 << DMA_MST_CTRL_BURST_SIZE_SHIFT, - DMA_MST_CTRL_BURST_4WORDS = 3 << DMA_MST_CTRL_BURST_SIZE_SHIFT, - DMA_MST_CTRL_BURST_8WORDS = 4 << DMA_MST_CTRL_BURST_SIZE_SHIFT, - DMA_MST_CTRL_BURST_16WORDS = 5 << DMA_MST_CTRL_BURST_SIZE_SHIFT -}; -#define DMA_MST_CTRL_IS_DMA_DONE (1 << 20) -#define DMA_MST_CTRL_EN_A_MASK (1 << 2) -#define DMA_MST_CTRL_EN_A_DISABLE 0 -#define DMA_MST_CTRL_EN_A_ENABLE (1 << 2) -#define DMA_MST_CTRL_EN_B_MASK (1 << 1) -#define DMA_MST_CTRL_EN_B_DISABLE 0 -#define DMA_MST_CTRL_EN_B_ENABLE (1 << 1) - -#define DMA_CFG_A_0 0x34 -#define DMA_CFG_B_0 0x38 -#define FIFO_CTRL_0 0x3C -#define DATA_BLOCK_PTR_0 0x40 -#define TAG_PTR_0 0x44 -#define ECC_PTR_0 0x48 - -#define DEC_STATUS_0 0x4C -#define DEC_STATUS_A_ECC_FAIL (1 << 1) -#define DEC_STATUS_B_ECC_FAIL (1 << 0) - -#define BCH_CONFIG_0 0xCC -#define BCH_CONFIG_BCH_TVALUE_SHIFT 4 -#define BCH_CONFIG_BCH_TVALUE_MASK (3 << BCH_CONFIG_BCH_TVALUE_SHIFT) -enum { - BCH_CONFIG_BCH_TVAL4 = 0 << BCH_CONFIG_BCH_TVALUE_SHIFT, - BCH_CONFIG_BCH_TVAL8 = 1 << BCH_CONFIG_BCH_TVALUE_SHIFT, - BCH_CONFIG_BCH_TVAL14 = 2 << BCH_CONFIG_BCH_TVALUE_SHIFT, - BCH_CONFIG_BCH_TVAL16 = 3 << BCH_CONFIG_BCH_TVALUE_SHIFT -}; -#define BCH_CONFIG_BCH_ECC_MASK (1 << 0) -#define BCH_CONFIG_BCH_ECC_DISABLE 0 -#define BCH_CONFIG_BCH_ECC_ENABLE (1 << 0) - -#define BCH_DEC_RESULT_0 0xD0 -#define BCH_DEC_RESULT_CORRFAIL_ERR_MASK (1 << 8) -#define BCH_DEC_RESULT_PAGE_COUNT_MASK 0xFF - -#define BCH_DEC_STATUS_BUF_0 0xD4 -#define BCH_DEC_STATUS_FAIL_SEC_FLAG_MASK 0xFF000000 -#define BCH_DEC_STATUS_CORR_SEC_FLAG_MASK 0x00FF0000 -#define BCH_DEC_STATUS_FAIL_TAG_MASK (1 << 14) -#define BCH_DEC_STATUS_CORR_TAG_MASK (1 << 13) -#define BCH_DEC_STATUS_MAX_CORR_CNT_MASK (0x1f << 8) -#define BCH_DEC_STATUS_PAGE_NUMBER_MASK 0xFF - -#define LP_OPTIONS 0 - -struct nand_ctlr { - u32 command; /* offset 00h */ - u32 status; /* offset 04h */ - u32 isr; /* offset 08h */ - u32 ier; /* offset 0Ch */ - u32 config; /* offset 10h */ - u32 timing; /* offset 14h */ - u32 resp; /* offset 18h */ - u32 timing2; /* offset 1Ch */ - u32 cmd_reg1; /* offset 20h */ - u32 cmd_reg2; /* offset 24h */ - u32 addr_reg1; /* offset 28h */ - u32 addr_reg2; /* offset 2Ch */ - u32 dma_mst_ctrl; /* offset 30h */ - u32 dma_cfg_a; /* offset 34h */ - u32 dma_cfg_b; /* offset 38h */ - u32 fifo_ctrl; /* offset 3Ch */ - u32 data_block_ptr; /* offset 40h */ - u32 tag_ptr; /* offset 44h */ - u32 resv1; /* offset 48h */ - u32 dec_status; /* offset 4Ch */ - u32 hwstatus_cmd; /* offset 50h */ - u32 hwstatus_mask; /* offset 54h */ - u32 resv2[29]; - u32 bch_config; /* offset CCh */ - u32 bch_dec_result; /* offset D0h */ - u32 bch_dec_status_buf; - /* offset D4h */ -}; |