[resending] [PATCH] [MTD] [NAND] Add OMAP2 / OMAP3 NAND driver
vimal singh
vimalsingh at ti.com
Wed Apr 29 01:57:25 EDT 2009
Andrew,
Thanks for your valuable comments.
On Wed, Apr 29, 2009 at 10:19 AM, Andrew Morton <akpm at linux-foundation.org> wrote:
> On Mon, 27 Apr 2009 12:40:26 +0530 (IST) "vimal singh" <vimalsingh at ti.com>
wrote:
>
>> I am sending this patch again, after Fixing Artem's comments. Also CC'ed to
lkml.
>>
>> --
>> Best regards,
>> vimal
>>
>>
>> This driver is present in the OMAP tree, now pushing it to MTD.
>>
>> Original author(s):
>> Jian Zhang <jzhang at ti.com>
>
> That's not a particularly illuminating changelog.
>
>> +config MTD_NAND_OMAP2
>> + tristate "NAND Flash device on OMAP2 and OMAP3"
>> + depends on ARM && MTD_NAND && (ARCH_OMAP2 || ARCH_OMAP3)
>> + help
>> + Support for NAND flash on Texas Instruments OMAP2 and OMAP3
platforms.
>
> OK, that tells us more.
>
>
> Please pass this (and all other) patches through scripts/checkpatch.pl.
> checkpatch finds problem in this patch which you would have fixed, had
> you known about them.
I took this code from Linux-omap tree, so ignored to run checkpatch.pl.
I'll do the same this time.
>
>> +#define TF(value) (value ? 1 : 0)
>> +
>> +#define P2048e(a) (TF(a & NAND_Ecc_P2048e) << 0)
>> +#define P2048o(a) (TF(a & NAND_Ecc_P2048o) << 1)
>> +#define P1e(a) (TF(a & NAND_Ecc_P1e) << 2)
>> +#define P1o(a) (TF(a & NAND_Ecc_P1o) << 3)
>> +#define P2e(a) (TF(a & NAND_Ecc_P2e) << 4)
>> +#define P2o(a) (TF(a & NAND_Ecc_P2o) << 5)
>> +#define P4e(a) (TF(a & NAND_Ecc_P4e) << 6)
>> +#define P4o(a) (TF(a & NAND_Ecc_P4o) << 7)
>> +
>> +#define P8e(a) (TF(a & NAND_Ecc_P8e) << 0)
>> +#define P8o(a) (TF(a & NAND_Ecc_P8o) << 1)
>> +#define P16e(a) (TF(a & NAND_Ecc_P16e) << 2)
>> +#define P16o(a) (TF(a & NAND_Ecc_P16o) << 3)
>> +#define P32e(a) (TF(a & NAND_Ecc_P32e) << 4)
>> +#define P32o(a) (TF(a & NAND_Ecc_P32o) << 5)
>> +#define P64e(a) (TF(a & NAND_Ecc_P64e) << 6)
>> +#define P64o(a) (TF(a & NAND_Ecc_P64o) << 7)
>> +
>> +#define P128e(a) (TF(a & NAND_Ecc_P128e) << 0)
>> +#define P128o(a) (TF(a & NAND_Ecc_P128o) << 1)
>> +#define P256e(a) (TF(a & NAND_Ecc_P256e) << 2)
>> +#define P256o(a) (TF(a & NAND_Ecc_P256o) << 3)
>> +#define P512e(a) (TF(a & NAND_Ecc_P512e) << 4)
>> +#define P512o(a) (TF(a & NAND_Ecc_P512o) << 5)
>> +#define P1024e(a) (TF(a & NAND_Ecc_P1024e) << 6)
>> +#define P1024o(a) (TF(a & NAND_Ecc_P1024o) << 7)
>> +
>> +#define P8e_s(a) (TF(a & NAND_Ecc_P8e) << 0)
>> +#define P8o_s(a) (TF(a & NAND_Ecc_P8o) << 1)
>> +#define P16e_s(a) (TF(a & NAND_Ecc_P16e) << 2)
>> +#define P16o_s(a) (TF(a & NAND_Ecc_P16o) << 3)
>> +#define P1e_s(a) (TF(a & NAND_Ecc_P1e) << 4)
>> +#define P1o_s(a) (TF(a & NAND_Ecc_P1o) << 5)
>> +#define P2e_s(a) (TF(a & NAND_Ecc_P2e) << 6)
>> +#define P2o_s(a) (TF(a & NAND_Ecc_P2o) << 7)
>> +
>> +#define P4e_s(a) (TF(a & NAND_Ecc_P4e) << 0)
>> +#define P4o_s(a) (TF(a & NAND_Ecc_P4o) << 1)
>
> (ick)
>
> I suspect that the above will expand into quite large amounts of poor
> code at the sites where they are invoked.
>
> eg:
>
> ecc_buf[2] = ~(P4o(tmp) | P4e(tmp) | P2o(tmp) | P2e(tmp) | P1o(tmp) |
> P1e(tmp) | P2048o(tmp) | P2048e(tmp));
>
> this might cause the generation of eight test-n-branch operations,
> whereas it could have been done with one.
Actually I have plan to change HW ECC correction method, in a separate patch,
where all these macros will get removed. So, I did not bother much at this.
I can try to simplify these, if you still insist.
>
>> +/**
>> + * omap_nand_wp - This function enable or disable the Write Protect feature on
>> + * NAND device
>
> Alas, kerneldoc doesn't support that. The description ("This function
> enable or disable the Write Protect feature on NAND device") must all
> be on a single line.
I'll fix this.
>
>> + * @mtd: MTD device structure
>> + * @mode: WP ON/OFF
>> + */
>> +static void omap_nand_wp(struct mtd_info *mtd, int mode)
>> +{
>> + struct omap_nand_info *info = container_of(mtd,
>> + struct omap_nand_info, mtd);
>> +
>> + unsigned long config = __raw_readl(info->gpmc_baseaddr + GPMC_CONFIG);
>> +
>> + if (mode)
>> + config &= ~(NAND_WP_BIT); /* WP is ON */
>> + else
>> + config |= (NAND_WP_BIT); /* WP is OFF */
>> +
>> + __raw_writel(config, (info->gpmc_baseaddr + GPMC_CONFIG));
>> +}
>> +
>> +/**
>> + * hardware specific access to control-lines
>> + * NOTE: boards may use different bits for these!!
>> + *
>> + * @ctrl:
>> + * NAND_NCE: bit 0 - don't care
>> + * NAND_CLE: bit 1 -> Command Latch
>> + * NAND_ALE: bit 2 -> Address Latch
>> + */
>
> This comment purports to be a kerneldoc comment (it starts with /**) ,
> but in fact it is not a kerneldoc comment.
>
> Please review the comments in this patch.
OK.
>
>> + GPMC_CS_NAND_DATA;
>> + break;
>> +
>> + case NAND_CTRL_CHANGE | NAND_CTRL_ALE:
>> + info->nand.IO_ADDR_W = info->gpmc_cs_baseaddr +
>> + GPMC_CS_NAND_ADDRESS;
>> + info->nand.IO_ADDR_R = info->gpmc_cs_baseaddr +
>> + GPMC_CS_NAND_DATA;
>> + break;
>> +
>> + case NAND_CTRL_CHANGE | NAND_NCE:
>> + info->nand.IO_ADDR_W = info->gpmc_cs_baseaddr +
>> + GPMC_CS_NAND_DATA;
>> + info->nand.IO_ADDR_R = info->gpmc_cs_baseaddr +
>> + GPMC_CS_NAND_DATA;
>> + break;
>> + }
>> +
>> + if (cmd != NAND_CMD_NONE)
>> + __raw_writeb(cmd, info->nand.IO_ADDR_W);
>> +}
>> +
>>
>> ...
>>
>> +/**
>> + * omap_calcuate_ecc - Generate non-inverted ECC bytes.
>> + * 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.
>> + * @mtd: MTD device structure
>> + * @dat: The pointer to data on which ecc is computed
>> + * @ecc_code: The ecc_code buffer
>> + */
>
> I believe the description of the function arguments must precede the
> general discussion.
Yes, I'll fix this.
>
>> +static int omap_calculate_ecc(struct mtd_info *mtd, const u_char *dat,
>> + u_char *ecc_code)
>> +{
>> + struct omap_nand_info *info = container_of(mtd, struct omap_nand_info,
>> + mtd);
>> + unsigned long val = 0x0;
>> + unsigned long reg;
>> +
>> + /* Start Reading from HW ECC1_Result = 0x200 */
>> + reg = (unsigned long)(info->gpmc_baseaddr + GPMC_ECC1_RESULT);
>> + val = __raw_readl(reg);
>> + *ecc_code++ = val; /* P128e, ..., P1e */
>> + *ecc_code++ = val >> 16; /* P128o, ..., P1o */
>> + /* P2048o, P1024o, P512o, P256o, P2048e, P1024e, P512e, P256e */
>> + *ecc_code++ = ((val >> 8) & 0x0f) | ((val >> 20) & 0xf0);
>> + reg += 4;
>> +
>> + return 0;
>> +}
>> +
>> +/**
>> + * omap_enable_hwecc - This function enables the hardware ecc functionality
>> + * @mtd: MTD device structure
>> + * @mode: Read/Write mode
>> + */
>> +static void omap_enable_hwecc(struct mtd_info *mtd, int mode)
>> +{
>> + struct omap_nand_info *info = container_of(mtd, struct omap_nand_info,
>> + mtd);
>> + register struct nand_chip *chip = mtd->priv;
>
> gcc has ignored keyword `register' for a decade at least (unless
> invoked with -O0). Please zap.
sure, I'll remove this.
>
>> + unsigned int dev_width = (chip->options & NAND_BUSWIDTH_16) ? 1 : 0;
>> + unsigned long val = __raw_readl(info->gpmc_baseaddr + GPMC_ECC_CONFIG);
>> +
>> + switch (mode) {
>> + case NAND_ECC_READ :
>> + __raw_writel(0x101, info->gpmc_baseaddr + GPMC_ECC_CONTROL);
>> + /* (ECC 16 or 8 bit col) | ( CS ) | ECC Enable */
>> + val = (dev_width << 7) | (info->gpmc_cs << 1) | (0x1);
>> + break;
>> + case NAND_ECC_READSYN :
>> + __raw_writel(0x100, info->gpmc_baseaddr + GPMC_ECC_CONTROL);
>> + /* (ECC 16 or 8 bit col) | ( CS ) | ECC Enable */
>> + val = (dev_width << 7) | (info->gpmc_cs << 1) | (0x1);
>> + break;
>> + case NAND_ECC_WRITE :
>> + __raw_writel(0x101, info->gpmc_baseaddr + GPMC_ECC_CONTROL);
>> + /* (ECC 16 or 8 bit col) | ( CS ) | ECC Enable */
>> + val = (dev_width << 7) | (info->gpmc_cs << 1) | (0x1);
>> + break;
>> + default:
>> + DEBUG(MTD_DEBUG_LEVEL0, "Error: Unrecognized Mode[%d]!\n",
>> + mode);
>> + break;
>> + }
>> +
>> + __raw_writel(val, info->gpmc_baseaddr + GPMC_ECC_CONFIG);
>> +}
>> +#endif
>> +
>> +/**
>> + * omap_wait - Wait function is called during Program and erase
>> + * operations and the way it is called from MTD layer, we should wait
>> + * till the NAND chip is ready after the programming/erase operation
>> + * has completed.
>> + * @mtd: MTD device structure
>> + * @chip: NAND Chip structure
>> + */
>> +static int omap_wait(struct mtd_info *mtd, struct nand_chip *chip)
>> +{
>> + register struct nand_chip *this = mtd->priv;
>> + struct omap_nand_info *info = container_of(mtd, struct omap_nand_info,
>> + mtd);
>> + int status = 0;
>> +
>> + this->IO_ADDR_W = (void *) info->gpmc_cs_baseaddr +
>> + GPMC_CS_NAND_COMMAND;
>> + this->IO_ADDR_R = (void *) info->gpmc_cs_baseaddr + GPMC_CS_NAND_DATA;
>> +
>> + while (!(status & 0x40)) {
>> + __raw_writeb(NAND_CMD_STATUS & 0xFF, this->IO_ADDR_W);
>> + status = __raw_readb(this->IO_ADDR_R);
>> + }
>
> This loop looks like it could consume rather a lot of energy. Can it
> be optimised?
Well... here improvement could be to introduce a timeout. I'll do this.
I'll fix all your comments and resend the patch.
---
Best Regards,
\/ | |\/| /-\ |_
More information about the linux-mtd
mailing list