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 a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox