From: Ilya Yanok <yanok@emcraft.com>
To: u-boot@lists.denx.de
Subject: [U-Boot] [PATCH 4/7] mxc_nand: add nand driver for MX2/MX3
Date: Fri, 17 Jul 2009 14:48:38 +0400 [thread overview]
Message-ID: <4A605706.9020909@emcraft.com> (raw)
In-Reply-To: <20090622234349.GE4756@b07421-ec1.am.freescale.net>
Hi Scott,
please review the updated patch (will be posted as a follow-up).
Scott Wood wrote:
> Please look at drivers/mtd/nand/mpc5121_nfc.c, which AFAICT is very
> similar hardware, and see if anything can be factored out into common
> code, and try to keep the rest looking the same except where the hardware
> actually differs.
>
Hmm... For now we just can't spend enough effort for this...
>> +static struct nand_ecclayout nand_hw_eccoob_16 = {
>> + .eccbytes = 5,
>> + .eccpos = {6, 7, 8, 9, 10},
>> + .oobfree = {{0, 6}, {12, 4}, }
>> +};
>>
>
> This implies the bad block marker is one byte at offset 11 (it's all
> that's left), but I don't see any override of the bad block pattern.
>
This is surely a bug. Fixed.
>> +static void *mxc_nand_memcpy32(void *dest, void *source, size_t size)
>> +{
>> + uint32_t *s = source, *d = dest;
>> +
>> + size >>= 2;
>> + while (size--)
>> + *d++ = *s++;
>> + return dest;
>> +}
>>
>
> This should probably be using I/O accessors (possibly raw) -- and should
> take uint32_t *, not void *.
>
Fixed.
>> +/*
>> + * 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)
>> +{
>> + void __iomem *main_buf = host->regs->main_area1;
>> + uint32_t store;
>> + uint16_t ret, tmp;
>> + /* Issue status request to NAND device */
>> +
>> + /* store the main area1 first word, later do recovery */
>> + store = readl(main_buf);
>> + /*
>> + * NANDFC buffer 1 is used for device status to prevent
>> + * corruption of read/write buffer on status requests.
>> + */
>> + writew(1, &host->regs->nfc_buf_addr);
>>
>
> But it looks like buffer 1 is used for data with large page flash.
>
Well, we save first word of the buffer and then recover it.
> Other drivers don't seem to have any problem with status reads clobbering
> the buffer...
>
>
>> +/* This functions is used by upper layer to checks if device is ready */
>> +static int mxc_nand_dev_ready(struct mtd_info *mtd)
>>
>
> "This functions is"? I'd say this comment is pretty redundant with respect
> to the function name anyway...
>
Fixed.
>> +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, rd_word;
>> + uint16_t __iomem *main_buf =
>> + (uint16_t __iomem *)host->regs->main_area0;
>> + uint16_t __iomem *spare_buf =
>> + (uint16_t __iomem *)host->regs->spare_area0;
>>
>
> According to Magnus Lilja, "the nand flash controller can only handle 32
> bit read/write operations, any other size will cause an abort (or
> something like that)". But now we're accessing it as 16-bit?
>
16-bit accesses work quite well. Problem was with 8-bit accesses.
>> +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, rd_word, 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_area0 + (col >> 1));
>> + } else {
>> + p = (uint16_t __iomem *)(host->regs->spare_area0 +
>> + ((col - mtd->writesize) >> 1));
>> + }
>> +
>> + if (col & 1) {
>> + rd_word = readw(p);
>> + ret = (rd_word >> 8) & 0xff;
>> + rd_word = readw(&p[1]);
>> + ret |= (rd_word << 8) & 0xff00;
>> +
>>
>
> col should never be odd if you're reading words.
>
It can be odd if previously we've read a byte.
>> +/*
>> + * 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) {
>>
>
> Safer to do while (n > 0), especially when the code is this complex.
>
Fixed.
>> + void __iomem *p;
>> +
>> + if (col < mtd->writesize) {
>> + p = host->regs->main_area0 + (col & ~3);
>> + } else {
>> + p = host->regs->spare_area0 -
>> + mtd->writesize + (col & ~3);
>> + }
>> +
>> + MTDDEBUG(MTD_DEBUG_LEVEL3, "%s:%d: p = %p\n", __func__,
>> + __LINE__, p);
>> +
>> + if (((col | (int)&buf[i]) & 3) || n < 16) {
>>
>
> Do not cast pointers to "int". Use "uintptr_t" or "unsigned long" if you
> must.
>
> Why < 16 and not < 4?
>
Fixed.
>> + uint32_t data = 0;
>> +
>> + if (col & 3 || n < 4)
>> + data = readl(p);
>>
>
> If that condition doesn't hold, the data we use is zero?
>
If that condition doesn't hold we are going to rewrite a whole 32-bit
word so there is no need to read it's old content. But I've changed that
piece of code as you suggested anyway.
>> +
>> + switch (col & 3) {
>> + case 0:
>> + if (n) {
>> + data = (data & 0xffffff00) |
>> + (buf[i++] << 0);
>> + n--;
>> + col++;
>> + }
>> + case 1:
>> + if (n) {
>> + data = (data & 0xffff00ff) |
>> + (buf[i++] << 8);
>> + n--;
>> + col++;
>> + }
>> + case 2:
>> + if (n) {
>> + data = (data & 0xff00ffff) |
>> + (buf[i++] << 16);
>> + n--;
>> + col++;
>> + }
>> + case 3:
>> + if (n) {
>> + data = (data & 0x00ffffff) |
>> + (buf[i++] << 24);
>> + n--;
>> + col++;
>> + }
>> + }
>> + writel(data, p);
>>
>
> Might I suggest this?
>
> 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);
>
> As a side benefit, you lose the endian dependency.
>
Thanks! I've used your code.
>> + mxc_nand_memcpy32(p, (void *)&buf[i], m);
>>
>
> Unnecessary cast.
>
Fixed.
>> + /* Update saved column address */
>> + host->col_addr = col;
>> +
>> +}
>>
>
> No blank lines before the brace at the end of a block.
>
Fixed.
>> +
>> +/*
>> + * 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)
>> +{
>> + return -EFAULT;
>> +}
>>
>
> Umm...
>
I've added verify_buf function.
>> + case NAND_CMD_SEQIN:
>> + if (column >= mtd->writesize) {
>> + /*
>> + * FIXME: before send SEQIN command for write OOB,
>> + * We must read one page out.
>> + * For K9F1GXX has no READ1 command to set current HW
>> + * pointer to spare area, we must write the whole page
>> + * including OOB together.
>> + */
>> + if (host->pagesize_2k) {
>> + /* call ourself to read a page */
>> + mxc_nand_command(mtd, NAND_CMD_READ0, 0,
>> + page_addr);
>> + }
>>
>
> Should this be #ifdef HWECC? And update the comment to indicate the
> actual problem, which is the unusual hardware ECC implementation. I
> don't see what the lack of a "READ1" command has to do with it.
>
I've updated the comment.
> And is this actually a FIXME if it's already being done?
>
>
>> +#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;
>> + this->ecc.mode = NAND_ECC_HW;
>> + this->ecc.size = 512;
>> + this->ecc.bytes = 3;
>> + this->ecc.layout = &nand_hw_eccoob_8;
>> + tmp = readw(&host->regs->nfc_config1);
>> + tmp |= NFC_ECC_EN;
>> + writew(tmp, &host->regs->nfc_config1);
>> +#else
>> + this->ecc.size = 512;
>> + this->ecc.bytes = 3;
>> + this->ecc.layout = &nand_hw_eccoob_8;
>> + this->ecc.mode = NAND_ECC_SOFT;
>> + tmp = readw(&host->regs->nfc_config1);
>> + tmp &= ~NFC_ECC_EN;
>> + writew(tmp, &host->regs->nfc_config1);
>> +#endif
>>
>
> Soft ECC only supports 256-byte ECC blocks (anything you set here to the
> contrary will just be overwritten), and you'll need a layout that
> accommodates that with enough ECC bytes.
>
> Alternatively, you can implement 512-byte soft ECC if you don't want to
> waste those 3 extra OOB bytes. :-)
>
>
>> + host->pagesize_2k = 0;
>>
>
> So large page is currently unsupported?
>
Linux driver was fixed recently and now it claims to support 2K page
size... I've added all needed fixes but I can understand how this driver
should detect the pagesize... Linux driver calls nand_scan_ident()
itself for this... Do you think I can calls nand_scan_ident() from my
board_nand_init() function?
Regards, Ilya.
next prev parent reply other threads:[~2009-07-17 10:48 UTC|newest]
Thread overview: 74+ messages / expand[flat|nested] mbox.gz Atom feed top
2009-06-08 0:12 [U-Boot] [PATCH 0/7][v3] Support for LogicPD i.MX27-LITEKIT development board Ilya Yanok
2009-06-08 0:12 ` [U-Boot] [PATCH 1/7] mx27: basic cpu support Ilya Yanok
2009-06-20 13:13 ` Jean-Christophe PLAGNIOL-VILLARD
2009-06-08 0:12 ` [U-Boot] [PATCH 2/7] serial_mx31: allow it to work with mx27 too and rename to serial_mxc Ilya Yanok
2009-06-20 13:18 ` Jean-Christophe PLAGNIOL-VILLARD
2009-06-08 0:12 ` [U-Boot] [PATCH 3/7] fec_imx27: driver for FEC ethernet controller on i.MX27 Ilya Yanok
2009-07-17 10:57 ` [U-Boot] [PATCH] fec_mxc: " Ilya Yanok
2009-07-17 14:05 ` Ben Warren
2009-07-21 15:32 ` Ilya Yanok
2009-07-22 22:23 ` Jean-Christophe PLAGNIOL-VILLARD
2009-07-22 23:03 ` Ben Warren
2009-07-23 6:28 ` Ben Warren
2009-06-08 0:12 ` [U-Boot] [PATCH 4/7] mxc_nand: add nand driver for MX2/MX3 Ilya Yanok
2009-06-20 13:22 ` Jean-Christophe PLAGNIOL-VILLARD
2009-06-22 23:43 ` Scott Wood
2009-06-23 20:03 ` Magnus Lilja
2009-07-03 19:03 ` Paul Thomas
2009-07-03 19:11 ` Paul Thomas
2009-07-17 10:48 ` Ilya Yanok [this message]
2009-07-17 10:53 ` [U-Boot] [PATCH] " Ilya Yanok
2009-07-22 21:33 ` Jean-Christophe PLAGNIOL-VILLARD
2009-07-28 22:37 ` Scott Wood
2009-08-03 1:45 ` Ilya Yanok
2009-08-04 23:32 ` Scott Wood
2009-08-10 22:32 ` Ilya Yanok
2009-08-11 22:53 ` Scott Wood
2009-08-03 2:01 ` Ilya Yanok
2009-08-03 16:58 ` Scott Wood
2009-07-17 16:00 ` [U-Boot] [PATCH 4/7] " Scott Wood
2009-06-08 0:12 ` [U-Boot] [PATCH 5/7] mxc-mmc: sdhc host driver for MX2 and MX3 proccessor Ilya Yanok
2009-06-21 11:04 ` Jean-Christophe PLAGNIOL-VILLARD
2009-06-23 23:02 ` alfred steele
2009-08-07 20:13 ` Jean-Christophe PLAGNIOL-VILLARD
2009-06-08 0:12 ` [U-Boot] [PATCH 6/7] arm: add support for CONFIG_GENERIC_MMC Ilya Yanok
2009-06-20 13:20 ` Jean-Christophe PLAGNIOL-VILLARD
2009-06-08 0:12 ` [U-Boot] [PATCH 7/7] imx27lite: add support for imx27lite board from LogicPD Ilya Yanok
2009-06-21 11:21 ` Jean-Christophe PLAGNIOL-VILLARD
2009-06-23 16:55 ` Detlev Zundel
2009-07-07 19:24 ` Wolfgang Denk
2009-07-17 11:00 ` [U-Boot] [PATCH] " Ilya Yanok
2009-07-22 21:37 ` Jean-Christophe PLAGNIOL-VILLARD
2009-07-22 22:17 ` Ilya Yanok
2009-07-23 21:37 ` Jean-Christophe PLAGNIOL-VILLARD
2009-08-03 1:46 ` Ilya Yanok
2009-08-03 5:32 ` Jean-Christophe PLAGNIOL-VILLARD
2009-08-03 8:19 ` Wolfgang Denk
2009-08-03 12:17 ` Jean-Christophe PLAGNIOL-VILLARD
2009-08-03 14:35 ` Wolfgang Denk
2009-08-05 10:09 ` javier Martin
2009-08-05 12:30 ` javier Martin
2009-08-05 12:45 ` Wolfgang Denk
2009-08-05 14:17 ` javier Martin
2009-08-05 14:21 ` Wolfgang Denk
2009-08-05 15:01 ` javier Martin
2009-08-06 20:10 ` Wolfgang Denk
2009-08-07 7:18 ` javier Martin
2009-08-07 9:13 ` Wolfgang Denk
2009-08-06 19:29 ` [U-Boot] [PATCH] ARM EABI: add new helper functions resp. function names Wolfgang Denk
2009-08-08 6:50 ` Dirk Behme
2009-08-08 7:16 ` Wolfgang Denk
2009-08-08 7:39 ` Dirk Behme
2009-08-09 21:28 ` Wolfgang Denk
2009-08-10 22:32 ` [U-Boot] [PATCH] imx27lite: add support for imx27lite board from LogicPD Ilya Yanok
2009-08-11 18:47 ` Fabio Estevam
2009-08-11 19:12 ` Ilya Yanok
2009-08-14 7:03 ` Jean-Christophe PLAGNIOL-VILLARD
2009-08-26 20:14 ` Wolfgang Denk
2009-08-26 20:43 ` Scott Wood
2009-09-01 20:10 ` Jean-Christophe PLAGNIOL-VILLARD
2009-06-28 9:52 ` [U-Boot] [PATCH 0/7][v3] Support for LogicPD i.MX27-LITEKIT development board Jean-Christophe PLAGNIOL-VILLARD
-- strict thread matches above, loose matches on Subject: below --
2009-05-19 23:55 [U-Boot] [PATCH 00/10][v2] " Ilya Yanok
2009-05-19 23:55 ` [U-Boot] [PATCH 4/7] mxc_nand: add nand driver for MX2/MX3 Ilya Yanok
2009-05-28 23:06 ` Wolfgang Denk
2009-05-29 6:22 ` Magnus Lilja
2009-05-29 8:40 ` Wolfgang Denk
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=4A605706.9020909@emcraft.com \
--to=yanok@emcraft.com \
--cc=u-boot@lists.denx.de \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.