X-Git-Url: https://git.librecmc.org/?a=blobdiff_plain;f=drivers%2Fmtd%2Fnand%2Fatmel_nand.c;h=0d4f327ed71e2196b01e88eeaab1486f7ae0229f;hb=8ea1fbf75c56cb9ac0e9d96173068703d4ee8fdd;hp=9114a86da2bb0ee379739693e19308937516b44e;hpb=2a8c9c86b92a9ccee3c27286de317e19bb0530b3;p=oweals%2Fu-boot.git diff --git a/drivers/mtd/nand/atmel_nand.c b/drivers/mtd/nand/atmel_nand.c index 9114a86da2..0d4f327ed7 100644 --- a/drivers/mtd/nand/atmel_nand.c +++ b/drivers/mtd/nand/atmel_nand.c @@ -18,6 +18,7 @@ #include #include #include +#include #ifdef CONFIG_ATMEL_NAND_HWECC @@ -43,6 +44,7 @@ struct atmel_nand_host { u8 pmecc_corr_cap; u16 pmecc_sector_size; u32 pmecc_index_table_offset; + u32 pmecc_version; int pmecc_bytes_per_sector; int pmecc_sector_number; @@ -485,6 +487,10 @@ static int pmecc_correction(struct mtd_info *mtd, u32 pmecc_stat, uint8_t *buf, int i, err_nbr, eccbytes; uint8_t *buf_pos; + /* SAMA5D4 PMECC IP can correct errors for all 0xff page */ + if (host->pmecc_version >= PMECC_VERSION_SAMA5D4) + goto normal_check; + eccbytes = nand_chip->ecc.bytes; for (i = 0; i < eccbytes; i++) if (ecc[i] != 0xff) @@ -762,6 +768,62 @@ static int pmecc_choose_ecc(struct atmel_nand_host *host, } #endif +#if defined(NO_GALOIS_TABLE_IN_ROM) +static uint16_t *pmecc_galois_table; +static inline int deg(unsigned int poly) +{ + /* polynomial degree is the most-significant bit index */ + return fls(poly) - 1; +} + +static int build_gf_tables(int mm, unsigned int poly, + int16_t *index_of, int16_t *alpha_to) +{ + unsigned int i, x = 1; + const unsigned int k = 1 << deg(poly); + unsigned int nn = (1 << mm) - 1; + + /* primitive polynomial must be of degree m */ + if (k != (1u << mm)) + return -EINVAL; + + for (i = 0; i < nn; i++) { + alpha_to[i] = x; + index_of[x] = i; + if (i && (x == 1)) + /* polynomial is not primitive (a^i=1 with 0pmecc_sector_size; /* TODO: need check whether cap & sector_size is validate */ - +#if defined(NO_GALOIS_TABLE_IN_ROM) + /* + * As pmecc_rom_base is the begin of the gallois field table, So the + * index offset just set as 0. + */ + host->pmecc_index_table_offset = 0; +#else 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; +#endif MTDDEBUG(MTD_DEBUG_LEVEL1, "Initialize PMECC params, cap: %d, sector: %d\n", @@ -822,7 +891,17 @@ static int atmel_pmecc_nand_init_params(struct nand_chip *nand, host->pmecc = (struct pmecc_regs __iomem *) ATMEL_BASE_PMECC; host->pmerrloc = (struct pmecc_errloc_regs __iomem *) ATMEL_BASE_PMERRLOC; +#if defined(NO_GALOIS_TABLE_IN_ROM) + pmecc_galois_table = create_lookup_table(host->pmecc_sector_size); + if (!pmecc_galois_table) { + dev_err(host->dev, "out of memory\n"); + return -ENOMEM; + } + + host->pmecc_rom_base = (void __iomem *)pmecc_galois_table; +#else host->pmecc_rom_base = (void __iomem *) ATMEL_BASE_ROM; +#endif /* ECC is calculated for the whole page (1 step) */ nand->ecc.size = mtd->writesize; @@ -887,6 +966,10 @@ static int atmel_pmecc_nand_init_params(struct nand_chip *nand, nand->ecc.write_page = atmel_nand_pmecc_write_page; nand->ecc.strength = cap; + /* Check the PMECC ip version */ + host->pmecc_version = pmecc_readl(host->pmerrloc, version); + dev_dbg(host->dev, "PMECC IP version is: %x\n", host->pmecc_version); + atmel_pmecc_core_init(mtd); return 0; @@ -1187,7 +1270,7 @@ static int nand_command(int block, int page, uint32_t offs, u8 cmd) void (*hwctrl)(struct mtd_info *mtd, int cmd, unsigned int ctrl) = this->cmd_ctrl; - while (this->dev_ready(&mtd)) + while (!this->dev_ready(&mtd)) ; if (cmd == NAND_CMD_READOOB) { @@ -1212,7 +1295,7 @@ static int nand_command(int block, int page, uint32_t offs, u8 cmd) 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)) + while (!this->dev_ready(&mtd)) ; return 0; @@ -1273,6 +1356,37 @@ static int nand_read_page(int block, int page, void *dst) return 0; } + +int spl_nand_erase_one(int block, int page) +{ + struct nand_chip *this = mtd.priv; + void (*hwctrl)(struct mtd_info *mtd, int cmd, + unsigned int ctrl) = this->cmd_ctrl; + int page_addr; + + if (nand_chip.select_chip) + nand_chip.select_chip(&mtd, 0); + + page_addr = page + block * CONFIG_SYS_NAND_PAGE_COUNT; + hwctrl(&mtd, NAND_CMD_ERASE1, NAND_CTRL_CLE | NAND_CTRL_CHANGE); + /* Row address */ + hwctrl(&mtd, (page_addr & 0xff), NAND_CTRL_ALE | NAND_CTRL_CHANGE); + hwctrl(&mtd, ((page_addr >> 8) & 0xff), + NAND_CTRL_ALE | NAND_CTRL_CHANGE); +#ifdef CONFIG_SYS_NAND_5_ADDR_CYCLE + /* One more address cycle for devices > 128MiB */ + hwctrl(&mtd, (page_addr >> 16) & 0x0f, + NAND_CTRL_ALE | NAND_CTRL_CHANGE); +#endif + hwctrl(&mtd, NAND_CMD_ERASE2, NAND_CTRL_CLE | NAND_CTRL_CHANGE); + + while (!this->dev_ready(&mtd)) + ; + + nand_deselect(); + + return 0; +} #else static int nand_read_page(int block, int page, void *dst) { @@ -1319,7 +1433,7 @@ int at91_nand_wait_ready(struct mtd_info *mtd) udelay(this->chip_delay); - return 0; + return 1; } int board_nand_init(struct nand_chip *nand) @@ -1340,6 +1454,9 @@ int board_nand_init(struct nand_chip *nand) nand->dev_ready = at91_nand_wait_ready; #endif nand->chip_delay = 20; +#ifdef CONFIG_SYS_NAND_USE_FLASH_BBT + nand->bbt_options |= NAND_BBT_USE_FLASH; +#endif #ifdef CONFIG_ATMEL_NAND_HWECC #ifdef CONFIG_ATMEL_NAND_HW_PMECC @@ -1406,6 +1523,9 @@ int atmel_nand_chip_init(int devnum, ulong base_addr) nand->dev_ready = at91_nand_ready; #endif nand->chip_delay = 75; +#ifdef CONFIG_SYS_NAND_USE_FLASH_BBT + nand->bbt_options |= NAND_BBT_USE_FLASH; +#endif ret = nand_scan_ident(mtd, CONFIG_SYS_NAND_MAX_CHIPS, NULL); if (ret)