123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991 |
- /*
- * 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 <memalign.h>
- #include <nand.h>
- #include <asm/arch/clock.h>
- #include <asm/arch/funcmux.h>
- #include <asm/arch-tegra/clk_rst.h>
- #include <linux/errno.h>
- #include <asm/gpio.h>
- #include <fdtdec.h>
- #include <bouncebuf.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 gpio_desc wp_gpio; /* write-protect GPIO */
- s32 width; /* bit width, normally 8 */
- u32 timing[FDT_NAND_TIMING_COUNT];
- };
- struct nand_drv {
- struct nand_ctlr *reg;
- 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];
- /**
- * 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_to_nand(mtd);
- struct nand_drv *info;
- info = (struct nand_drv *)nand_get_controller_data(chip);
- writel(CMD_GO | CMD_PIO | CMD_RX | CMD_CE0 | CMD_A_VALID,
- &info->reg->command);
- if (!nand_waitfor_cmd_completion(info->reg))
- printf("Command timeout\n");
- return (uint8_t)readl(&info->reg->resp);
- }
- /**
- * 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_to_nand(mtd);
- struct nand_drv *info = (struct nand_drv *)nand_get_controller_data(chip);
- 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_to_nand(mtd);
- int reg_val;
- struct nand_drv *info;
- info = (struct nand_drv *)nand_get_controller_data(chip);
- 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_to_nand(mtd);
- struct nand_drv *info;
- info = (struct nand_drv *)nand_get_controller_data(chip);
- /*
- * 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_CE0,
- &info->reg->command);
- 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);
- 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;
- unsigned int bbflags;
- struct bounce_buffer bbstate, bbstate_oob;
- if ((uintptr_t)buf & 0x03) {
- printf("buf %p has to be 4-byte aligned\n", buf);
- return -EINVAL;
- }
- info = (struct nand_drv *)nand_get_controller_data(chip);
- 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);
- if (is_writing)
- bbflags = GEN_BB_READ;
- else
- bbflags = GEN_BB_WRITE;
- bounce_buffer_start(&bbstate, (void *)buf, 1 << chip->page_shift,
- bbflags);
- writel((1 << chip->page_shift) - 1, &info->reg->dma_cfg_a);
- writel(virt_to_phys(bbstate.bounce_buffer), &info->reg->data_block_ptr);
- /* Set ECC selection, configure ECC settings */
- if (with_ecc) {
- if (is_writing)
- memcpy(tag_ptr, chip->oob_poi + free->offset,
- chip->ecc.layout->oobavail + TAG_ECC_BYTES);
- 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;
- bounce_buffer_start(&bbstate_oob, (void *)tag_ptr, tag_size,
- bbflags);
- } 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));
- bounce_buffer_start(&bbstate_oob, (void *)chip->oob_poi,
- tag_size, bbflags);
- }
- writel(reg_val, &info->reg->config);
- writel(virt_to_phys(bbstate_oob.bounce_buffer), &info->reg->tag_ptr);
- 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;
- }
- bounce_buffer_stop(&bbstate_oob);
- bounce_buffer_stop(&bbstate);
- 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)
- {
- 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)
- {
- 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;
- unsigned int bbflags;
- struct bounce_buffer bbstate_oob;
- if (((int)chip->oob_poi) & 0x03)
- return -EINVAL;
- info = (struct nand_drv *)nand_get_controller_data(chip);
- if (set_bus_width_page_size(&info->config, ®_val))
- return -EINVAL;
- stop_command(info->reg);
- /* 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);
- if (is_writing && with_ecc)
- tag_size -= TAG_ECC_BYTES;
- if (is_writing)
- bbflags = GEN_BB_READ;
- else
- bbflags = GEN_BB_WRITE;
- bounce_buffer_start(&bbstate_oob, (void *)chip->oob_poi, tag_size,
- bbflags);
- writel(virt_to_phys(bbstate_oob.bounce_buffer), &info->reg->tag_ptr);
- 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_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;
- }
- bounce_buffer_stop(&bbstate_oob);
- 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" compatible 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 = gpio_request_by_name_nodev(blob, node, "nvidia,wp-gpios", 0,
- &config->wp_gpio, GPIOD_IS_OUT);
- 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_set_controller_data(nand, &nand_ctrl);
- /* Disable subpage writes as we do not provide ecc->hwctl */
- nand->options |= NAND_NO_SUBPAGE_WRITE;
- /* 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);
- dm_gpio_set_value(&config->wp_gpio, 1);
- our_mtd = nand_to_mtd(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, our_mtd);
- 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");
- }
|