mtd/nand/fsmc related modifications
Subsystems (2)
v2 cover mtd/nand/fsmc related modifications
Hello Artem,
These are the patches 8-20 of the original patchset of which 1-7 have already been applied by you. I have rebased these patches overgit://git.infradead.org/users/dedekind/l2-mtd.git to help you apply these easily
Modifications in v2
- Add support for partition information to be passed from platform data
- Default partition information removed from driver
- Remove sparse errors and warnings
Modifications in v1
- DMA support
- Word read/write support to improve performance
- Move platform related things(ALE/CLE) from driver to platfrom files
- Add default partition support for more devices with erase sizes (256KB, 512KB,
1024KB, 2048KB)
- Bugfixes
- Read only 512 + 13 bytes for 8bit NAND devices
- Flip the bit only if the error index is < 4096
- Fixed data abort inside change_bit()
Regards
Vipin
Armando Visconti (1):
nand/fsmc: Remove default partition information from driver
Shiraz Hashim (1):
mtd/fsmc_nand: add pm callbacks to support hibernation
Vipin Kumar (11):
nand/fsmc: Pass partition information through platform data nand/fsmc: Correct the multiline comment format nand/fsmc: Read only 512 + 13 bytes for 8bit NAND devices nand/fsmc: Flip the bit only if the error index is < 4096 nand/fsmc: Initialize the badblockbits to 7
nand/fsmc: Modify fsmc driver to accept nand timing parameters via
platform
nand/fsmc: Use devm routines
nand/fsmc: Use dev_err to report error scenario nand/fsmc: Access the NAND device word by word whenever possible nand/fsmc: Add DMA support
nand/fsmc: Remove sparse warnings and errors
drivers/mtd/nand/fsmc_nand.c | 572 ++++++++++++++++++++++++++---------------- include/linux/mtd/fsmc.h | 151 +++++++----- 2 files changed, 443 insertions(+), 280 deletions(-)
PATCH v2 1/13 nand/fsmc: Pass partition information through platform data
This patch reimplements the passing of partition information through platform data. This was unintentionally deleted in commit 0d04eda1430e9a796214bee644b7e05d99cfe613
"mtd: fsmc_nand.c: use mtd_device_parse_register"
--- drivers/mtd/nand/fsmc_nand.c | 15 ++++++++------- 1 files changed, 8 insertions(+), 7 deletions(-)
drivers/mtd/nand/fsmc_nand.c +8 -7
@@ -333,6 +333,8 @@ static struct mtd_partition partition_info_128KB_blk[] = {* @pid: Part ID on the AMBA PrimeCell format * @mtd: MTD info for a NAND flash. * @nand: Chip related info for a NAND flash. +* @partitions: Partition info for a NAND Flash. +* @nr_partitions: Total number of partition of a NAND flash. * * @ecc_place: ECC placing locations in oobfree type format. * @bank: Bank number for probed device.
@@ -347,6 +349,8 @@ struct fsmc_nand_data {u32 pid;struct mtd_info mtd;struct nand_chip nand; +struct mtd_partition *partitions; +unsigned int nr_partitions;struct fsmc_eccplace *ecc_place;unsigned int bank;
@@ -833,6 +837,8 @@ static int __init fsmc_nand_probe(struct platform_device *pdev) host->bank = pdata->bank; host->select_chip = pdata->select_bank; + host->partitions = pdata->partitions; + host->nr_partitions = pdata->nr_partitions; regs = host->regs_va;/* Link all private pointers */
@@ -942,13 +948,8 @@ static int __init fsmc_nand_probe(struct platform_device *pdev)* Check for partition info passed */ host->mtd.name ="nand" ; - ret =mtd_device_parse_register (&host->mtd,NULL ,NULL , - host->mtd.size <=0x04000000 ? - partition_info_16KB_blk : - partition_info_128KB_blk, - host->mtd.size <=0x04000000 ? -ARRAY_SIZE (partition_info_16KB_blk) : -ARRAY_SIZE (partition_info_128KB_blk)); + ret =mtd_device_parse_register (&host->mtd,NULL ,0 , host->partitions, + host->nr_partitions);if (ret) goto err_probe;
Signature · 1 line
1.7.0.4
Re: [PATCH v2 01/13] nand/fsmc: Pass partition information through platform data
Quoted 6 lines · Vipin Kumar
This patch reimplements the passing of partition information through platform data. This was unintentionally deleted in commit
0d04eda1430e9a796214bee644b7e05d99cfe613
"mtd:fsmc_nand.c: usemtd_device_parse_register"Signed-off-by Vipin Kumar <[email protected]>
Acked/Reviewed/Signed -off-by: Linus Walleij <[email protected]>
Also recommend adding Cc: [email protected] on this then.
Thanks!
Linus Walleij
Re: [PATCH v2 01/13] nand/fsmc: Pass partition information through platform data
Quoted 3 lines · Linus Walleij
Acked/Reviewed/Signed -off-by: Linus Walleij <[email protected]>
Also recommend adding Cc: [email protected] on this then.
Thanks, I will add -stable to CC.
Signature · 2 lines
Best Regards, Artem Bityutskiy
Re: [PATCH v2 01/13] nand/fsmc: Pass partition information through platform data
In reply to Vipin KumarQuoted 6 lines · On Wednesday 14 March 2012 07:17:07 Vipin Kumar wrote:
This patch reimplements the passing of partition information through platform data. This was unintentionally deleted in commit
0d04eda1430e9a796214bee644b7e05d99cfe613
"mtd:fsmc_nand.c: usemtd_device_parse_register"Signed-off-by Vipin Kumar <[email protected]>
Thanks,
Stefan
Re: [PATCH v2 01/13] nand/fsmc: Pass partition information through platform data
In reply to Vipin Kumardrivers/mtd/nand/fsmc_nand.c static int __init fsmc_nand_probe(struct platform_device *pdev) · line 952
Quoted 2 lines · Vipin Kumar
drivers/mtd/nand/fsmc_nand.c +2
-0+ ret =mtd_device_parse_register (&host->mtd,NULL ,0 , host->partitions, + host->nr_partitions);
This causes a GCC warning about passing plain 0 as NULL. But I'll amend the patch myself and fix this.
Signature · 2 lines
Best Regards, Artem Bityutskiy
Re: [PATCH v2 01/13] nand/fsmc: Pass partition information through platform data
Quoted 7 lines · Artem Bityutskiy
drivers/mtd/nand/fsmc_nand.c static int __init fsmc_nand_probe(struct platform_device *pdev) · line 952
Quoted 2 lines · Vipin Kumar
drivers/mtd/nand/fsmc_nand.c +2
-0+ ret =mtd_device_parse_register (&host->mtd,NULL ,0 , host->partitions, + host->nr_partitions);This causes a GCC warning about passing plain 0 as NULL. But I'll amend the patch myself and fix this.
Thanks Artem
PATCH v2 2/13 nand/fsmc: Remove default partition information from driver
In reply to Vipin KumarFrom: Armando Visconti <[email protected]>
--- drivers/mtd/nand/fsmc_nand.c | 58 ------------------------------------------ 1 files changed, 0 insertions(+), 58 deletions(-)
drivers/mtd/nand/fsmc_nand.c +0 -58
@@ -269,64 +269,6 @@ static struct fsmc_eccplace fsmc_ecc4_sp_place = { } }; -/* -* Default partition tables to be used if the partition information not -* provided through platform data. -* -* Default partition layout for small page(= 512 bytes) devices -* Size for "Root file system" is updated in driver based on actual device size -*/ -static struct mtd_partition partition_info_16KB_blk[] = { - { - .name ="X-loader" , - .offset =0 , - .size =4 *0x4000 , - }, - { - .name ="U-Boot" , - .offset =0x10000 , - .size =20 *0x4000 , - }, - { - .name ="Kernel" , - .offset =0x60000 , - .size =256 *0x4000 , - }, - { - .name ="Root File System" , - .offset =0x460000 , - .size =MTDPART_SIZ_FULL , - }, -}; - -/* -* Default partition layout for large page(> 512 bytes) devices -* Size for "Root file system" is updated in driver based on actual device size -*/ -static struct mtd_partition partition_info_128KB_blk[] = { - { - .name ="X-loader" , - .offset =0 , - .size =4 *0x20000 , - }, - { - .name ="U-Boot" , - .offset =0x80000 , - .size =12 *0x20000 , - }, - { - .name ="Kernel" , - .offset =0x200000 , - .size =48 *0x20000 , - }, - { - .name ="Root File System" , - .offset =0x800000 , - .size =MTDPART_SIZ_FULL , - }, -}; - -/** * struct fsmc_nand_data - structure for FSMC NAND device state *
Signature · 1 line
1.7.0.4
PATCH v2 3/13 nand/fsmc: Correct the multiline comment format
In reply to Vipin Kumar--- drivers/mtd/nand/fsmc_nand.c | 8 ++++---- 1 files changed, 4 insertions(+), 4 deletions(-)
drivers/mtd/nand/fsmc_nand.c +4 -4
@@ -545,10 +545,10 @@ static int fsmc_read_page_hwecc(struct mtd_info *mtd, struct nand_chip *chip, group++;/* -* length is intentionally kept a higher multiple of 2 -* to read at least 13 bytes even in case of 16 bit NAND -* devices -*/ +* length is intentionally kept a higher multiple of 2 +* to read at least 13 bytes even in case of 16 bit NAND +* devices +*/ len =roundup (len,2 ); chip->cmdfunc (mtd,NAND_CMD_READOOB , off, page); chip->read_buf (mtd, oob + j, len);
Signature · 1 line
1.7.0.4
PATCH v2 4/13 nand/fsmc: Read only 512 + 13 bytes for 8bit NAND devices
In reply to Vipin KumarThe ECC logic of FSMC works on 512 bytes data + 13 bytes ECC to generate error indices of upto 8 incorrect bits. The FSMC driver reads 14 instead of 13 oob bytes to accommodate for 16 bit device as well.
Unfortunately, the internal ecc state machine gets corrupted for 8 bit devices reading 512 + 14 bytes of data resulting in error indices not getting reported.
Fix this by reading 14 bytes only for 16 bit devices
--- drivers/mtd/nand/fsmc_nand.c | 4 +++- 1 files changed, 3 insertions(+), 1 deletions(-)
drivers/mtd/nand/fsmc_nand.c +3 -1
@@ -549,7 +549,9 @@ static int fsmc_read_page_hwecc(struct mtd_info *mtd, struct nand_chip *chip,* to read at least 13 bytes even in case of 16 bit NAND * devices */ - len =roundup (len,2 ); +if (chip->options &NAND_BUSWIDTH_16 ) + len =roundup (len,2 ); + chip->cmdfunc (mtd,NAND_CMD_READOOB , off, page); chip->read_buf (mtd, oob + j, len); j += len;
Signature · 1 line
1.7.0.4
PATCH v2 5/13 nand/fsmc: Flip the bit only if the error index is < 4096
In reply to Vipin KumarECC can correct upto 8 bits in 512 bytes data + 13 bytes ecc. This means that the algorithm can correct a max of 8 bits in 4200 bits ie the error indices can be from 0 to 4199. Of these 0 to 4095 are for data and 4096 to 4199 for ecc.
The driver flips the bit only if the index is <= 4096. This is a bug since the data bits are only from 0 to 4095.
This patch modifies the check as < 4096
--- drivers/mtd/nand/fsmc_nand.c | 2 +- 1 files changed, 1 insertions(+), 1 deletions(-)
drivers/mtd/nand/fsmc_nand.c +1 -1
@@ -654,7 +654,7 @@ static int fsmc_bch8_correct_data(struct mtd_info *mtd, uint8_t *dat,change_bit (0 , (unsigned long *)&err_idx[i]);change_bit (1 , (unsigned long *)&err_idx[i]); -if (err_idx[i] <= chip->ecc.size *8 ) { +if (err_idx[i] < chip->ecc.size *8 ) {change_bit (err_idx[i], (unsigned long *)dat); i++; }
Signature · 1 line
1.7.0.4
PATCH v2 6/13 nand/fsmc: Initialize the badblockbits to 7
In reply to Vipin KumarIdeally, the block should have 0xff written on the bad block position. Any value other than 0xff implies a bad block. In practical situations, there can be bit flips in the oob area as well which means that a block with 0x7f being read at bad block position may imply a bad block but it is infact only a bit flip in the bad block byte.
To resolve this problem, the block is marked as good if number of high bits is greater than or equal to badblockbits (initialized to 7)
--- drivers/mtd/nand/fsmc_nand.c | 1 + 1 files changed, 1 insertions(+), 0 deletions(-)
drivers/mtd/nand/fsmc_nand.c +1 -0
@@ -802,6 +802,7 @@ static int __init fsmc_nand_probe(struct platform_device *pdev) nand->ecc.size =512 ; nand->options = pdata->options; nand->select_chip = fsmc_select_chip; + nand->badblockbits =7 ;if (pdata->width ==FSMC_NAND_BW16 ) nand->options |=NAND_BUSWIDTH_16 ;
Signature · 1 line
1.7.0.4
PATCH v2 7/13 mtd/fsmc_nand: add pm callbacks to support hibernation
In reply to Vipin KumarFrom: Shiraz Hashim <[email protected]>
--- drivers/mtd/nand/fsmc_nand.c | 12 ++++++------ 1 files changed, 6 insertions(+), 6 deletions(-)
drivers/mtd/nand/fsmc_nand.c +6 -6
@@ -382,7 +382,7 @@ static void fsmc_cmd_ctrl(struct mtd_info *mtd, int cmd, unsigned int ctrl)* This routine initializes timing parameters related to NAND memory access in * FSMC registers */ -static void __init fsmc_nand_setup (struct fsmc_regs *regs,uint32_t bank, +static void fsmc_nand_setup (struct fsmc_regs *regs,uint32_t bank,uint32_t busw) {uint32_t value =FSMC_DEVTYPE_NAND |FSMC_ENABLE |FSMC_WAITON ;
@@ -976,15 +976,15 @@ static int fsmc_nand_suspend(struct device *dev)static int fsmc_nand_resume (struct device *dev) {struct fsmc_nand_data *host =dev_get_drvdata (dev); -if (host) +if (host) {clk_enable (host->clk); +fsmc_nand_setup (host->regs_va, host->bank, + host->nand.options &NAND_BUSWIDTH_16 ); + }return 0 ; } -static const struct dev_pm_ops fsmc_nand_pm_ops = { - .suspend = fsmc_nand_suspend, - .resume = fsmc_nand_resume, -}; +static SIMPLE_DEV_PM_OPS(fsmc_nand_pm_ops, fsmc_nand_suspend, fsmc_nand_resume);#endif static struct platform_driver fsmc_nand_driver = {
Signature · 1 line
1.7.0.4
PATCH v2 8/13 nand/fsmc: Modify fsmc driver to accept nand timing parameters via platform
In reply to Vipin KumarFSMC controllers provide registers to program the required timing values for attached NAND device. The timing values used until now are relaxed and should work for all devices.
Although, for read/write performance improvements, the fsmc nand driver should accept nand timings as a platform data and program the timing parameters into fsmc registers accordingly.
This patch implements this modification. Additionally, it programs the default timing parameters if these are not passed via platform data.
--- drivers/mtd/nand/fsmc_nand.c | 41 +++++++++++++++++++++++++++++++++-------- include/linux/mtd/fsmc.h | 34 ++++++++++++++++++++++++++++------ 2 files changed, 61 insertions(+), 14 deletions(-)
drivers/mtd/nand/fsmc_nand.c +33 -8
@@ -303,6 +303,8 @@ struct fsmc_nand_data {struct resource *resaddr;struct resource *resdata; +struct fsmc_nand_timings *dev_timings; +void __iomem *data_va;void __iomem *cmd_va;void __iomem *addr_va;
@@ -383,21 +385,41 @@ static void fsmc_cmd_ctrl(struct mtd_info *mtd, int cmd, unsigned int ctrl)* FSMC registers */ static void fsmc_nand_setup (struct fsmc_regs *regs,uint32_t bank, -uint32_t busw) +uint32_t busw,struct fsmc_nand_timings *timings) {uint32_t value =FSMC_DEVTYPE_NAND |FSMC_ENABLE |FSMC_WAITON ; +uint32_t tclr, tar, thiz, thold, twait, tset; +struct fsmc_nand_timings *tims; +struct fsmc_nand_timings default_timings = { + .tclr =FSMC_TCLR_1 , + .tar =FSMC_TAR_1 , + .thiz =FSMC_THIZ_1 , + .thold =FSMC_THOLD_4 , + .twait =FSMC_TWAIT_6 , + .tset =FSMC_TSET_0 , + }; + +if (timings) + tims = timings; +else + tims = &default_timings; + + tclr = (tims->tclr &FSMC_TCLR_MASK ) <<FSMC_TCLR_SHIFT ; + tar = (tims->tar &FSMC_TAR_MASK ) <<FSMC_TAR_SHIFT ; + thiz = (tims->thiz &FSMC_THIZ_MASK ) <<FSMC_THIZ_SHIFT ; + thold = (tims->thold &FSMC_THOLD_MASK ) <<FSMC_THOLD_SHIFT ; + twait = (tims->twait &FSMC_TWAIT_MASK ) <<FSMC_TWAIT_SHIFT ; + tset = (tims->tset &FSMC_TSET_MASK ) <<FSMC_TSET_SHIFT ;if (busw)writel (value |FSMC_DEVWID_16 , ®s->bank_regs[bank].pc);else writel (value |FSMC_DEVWID_8 , ®s->bank_regs[bank].pc); -writel (readl (®s->bank_regs[bank].pc) |FSMC_TCLR_1 |FSMC_TAR_1 , +writel (readl (®s->bank_regs[bank].pc) | tclr | tar, ®s->bank_regs[bank].pc); -writel (FSMC_THIZ_1 |FSMC_THOLD_4 |FSMC_TWAIT_6 |FSMC_TSET_0 , - ®s->bank_regs[bank].comm); -writel (FSMC_THIZ_1 |FSMC_THOLD_4 |FSMC_TWAIT_6 |FSMC_TSET_0 , - ®s->bank_regs[bank].attrib); +writel (thiz | thold | twait | tset, ®s->bank_regs[bank].comm); +writel (thiz | thold | twait | tset, ®s->bank_regs[bank].attrib); }/*
@@ -783,6 +805,7 @@ static int __init fsmc_nand_probe(struct platform_device *pdev) host->select_chip = pdata->select_bank; host->partitions = pdata->partitions; host->nr_partitions = pdata->nr_partitions; + host->dev_timings = pdata->nand_timings; regs = host->regs_va;/* Link all private pointers */
@@ -807,7 +830,8 @@ static int __init fsmc_nand_probe(struct platform_device *pdev)if (pdata->width ==FSMC_NAND_BW16 ) nand->options |=NAND_BUSWIDTH_16 ; -fsmc_nand_setup (regs, host->bank, nand->options &NAND_BUSWIDTH_16 ); +fsmc_nand_setup (regs, host->bank, nand->options &NAND_BUSWIDTH_16 , + host->dev_timings);if (AMBA_REV_BITS (host->pid) >=8 ) { nand->ecc.read_page = fsmc_read_page_hwecc;
@@ -979,7 +1003,8 @@ static int fsmc_nand_resume(struct device *dev)if (host) {clk_enable (host->clk);fsmc_nand_setup (host->regs_va, host->bank, - host->nand.options &NAND_BUSWIDTH_16 ); + host->nand.options &NAND_BUSWIDTH_16 , + host->dev_timings); }return 0 ; }
include/linux/mtd/fsmc.h +28 -6
@@ -90,17 +90,29 @@ struct fsmc_regs {#define FSMC_ECCEN (1 << 6)#define FSMC_ECCPLEN_512 (0 << 7)#define FSMC_ECCPLEN_256 (1 << 7) -#define FSMC_TCLR_1 (1 << 9) -#define FSMC_TAR_1 (1 << 13) +#define FSMC_TCLR_1 (1) +#define FSMC_TCLR_SHIFT (9) +#define FSMC_TCLR_MASK (0xF) +#define FSMC_TAR_1 (1) +#define FSMC_TAR_SHIFT (13) +#define FSMC_TAR_MASK (0xF)/* sts register definitions */ #define FSMC_CODE_RDY (1 << 15)/* comm register definitions */ -#define FSMC_TSET_0 (0 << 0) -#define FSMC_TWAIT_6 (6 << 8) -#define FSMC_THOLD_4 (4 << 16) -#define FSMC_THIZ_1 (1 << 24) +#define FSMC_TSET_0 0 +#define FSMC_TSET_SHIFT 0 +#define FSMC_TSET_MASK 0xFF +#define FSMC_TWAIT_6 6 +#define FSMC_TWAIT_SHIFT 8 +#define FSMC_TWAIT_MASK 0xFF +#define FSMC_THOLD_4 4 +#define FSMC_THOLD_SHIFT 16 +#define FSMC_THOLD_MASK 0xFF +#define FSMC_THIZ_1 1 +#define FSMC_THIZ_SHIFT 24 +#define FSMC_THIZ_MASK 0xFF/* * There are 13 bytes of ecc for every 512 byte block in FSMC version 8
@@ -120,6 +132,15 @@ struct fsmc_eccplace {struct fsmc_nand_eccplace eccplace[MAX_ECCPLACE_ENTRIES ]; }; +struct fsmc_nand_timings { +uint8_t tclr; +uint8_t tar; +uint8_t thiz; +uint8_t thold; +uint8_t twait; +uint8_t tset; +}; +/** * fsmc_nand_platform_data - platform specific NAND controller config * @partitions: partition table for the platform, use a default fallback
@@ -133,6 +154,7 @@ struct fsmc_eccplace {* this may be set to NULL */ struct fsmc_nand_platform_data { +struct fsmc_nand_timings *nand_timings;struct mtd_partition *partitions;unsigned int nr_partitions;unsigned int options;
Signature · 1 line
1.7.0.4
PATCH v2 9/13 nand/fsmc: Use devm routines
In reply to Vipin Kumarfsmc_nand driver currently uses normal kzalloc, request_mem etc routines. This patch replaces these routines with devm_kzalloc and devm_request_mem_region etc. Consequently, the error and driver removal scenarios are curtailed.
--- drivers/mtd/nand/fsmc_nand.c | 134 +++++++++++++---------------------------- 1 files changed, 43 insertions(+), 91 deletions(-)
drivers/mtd/nand/fsmc_nand.c +43 -91
@@ -298,11 +298,6 @@ struct fsmc_nand_data {unsigned int bank;struct clk *clk; -struct resource *resregs; -struct resource *rescmd; -struct resource *resaddr; -struct resource *resdata; -struct fsmc_nand_timings *dev_timings;void __iomem *data_va;
@@ -706,88 +701,81 @@ static int __init fsmc_nand_probe(struct platform_device *pdev) }/* Allocate memory for the device structure (and zero it) */ - host =kzalloc (sizeof (*host),GFP_KERNEL ); + host =devm_kzalloc (&pdev->dev,sizeof (*host),GFP_KERNEL );if (!host) {dev_err (&pdev->dev,"failed to allocate device structure\n" );return -ENOMEM ; } res =platform_get_resource_byname (pdev,IORESOURCE_MEM ,"nand_data" ); -if (!res) { - ret = -EIO ; - goto err_probe1; - } +if (!res) +return -EINVAL ; - host->resdata =request_mem_region (res->start,resource_size (res), - pdev->name); -if (!host->resdata) { - ret = -EIO ; - goto err_probe1; +if (!devm_request_mem_region (&pdev->dev, res->start,resource_size (res), + pdev->name)) { +dev_err (&pdev->dev,"Failed to get memory data resourse\n" ); +return -ENOENT ; } - host->data_va =ioremap (res->start,resource_size (res)); + host->data_va =devm_ioremap (&pdev->dev, res->start, +resource_size (res));if (!host->data_va) { - ret = -EIO ; - goto err_probe1; +dev_err (&pdev->dev,"data ioremap failed\n" ); +return -ENOMEM ; } - host->resaddr =request_mem_region (res->start + pdata->ale_off, -resource_size (res), pdev->name); -if (!host->resaddr) { - ret = -EIO ; - goto err_probe1; +if (!devm_request_mem_region (&pdev->dev, res->start + pdata->ale_off, +resource_size (res), pdev->name)) { +dev_err (&pdev->dev,"Failed to get memory ale resourse\n" ); +return -ENOENT ; } - host->addr_va =ioremap (res->start + pdata->ale_off, + host->addr_va =devm_ioremap (&pdev->dev, res->start + pdata->ale_off,resource_size (res));if (!host->addr_va) { - ret = -EIO ; - goto err_probe1; +dev_err (&pdev->dev,"ale ioremap failed\n" ); +return -ENOMEM ; } - host->rescmd =request_mem_region (res->start + pdata->cle_off, -resource_size (res), pdev->name); -if (!host->rescmd) { - ret = -EIO ; - goto err_probe1; +if (!devm_request_mem_region (&pdev->dev, res->start + pdata->cle_off, +resource_size (res), pdev->name)) { +dev_err (&pdev->dev,"Failed to get memory cle resourse\n" ); +return -ENOENT ; } - host->cmd_va =ioremap (res->start + pdata->cle_off,resource_size (res)); + host->cmd_va =devm_ioremap (&pdev->dev, res->start + pdata->cle_off, +resource_size (res));if (!host->cmd_va) { - ret = -EIO ; - goto err_probe1; +dev_err (&pdev->dev,"ale ioremap failed\n" ); +return -ENOMEM ; } res =platform_get_resource_byname (pdev,IORESOURCE_MEM ,"fsmc_regs" ); -if (!res) { - ret = -EIO ; - goto err_probe1; - } +if (!res) +return -EINVAL ; - host->resregs =request_mem_region (res->start,resource_size (res), - pdev->name); -if (!host->resregs) { - ret = -EIO ; - goto err_probe1; +if (!devm_request_mem_region (&pdev->dev, res->start,resource_size (res), + pdev->name)) { +dev_err (&pdev->dev,"Failed to get memory regs resourse\n" ); +return -ENOENT ; } - host->regs_va =ioremap (res->start,resource_size (res)); + host->regs_va =devm_ioremap (&pdev->dev, res->start, +resource_size (res));if (!host->regs_va) { - ret = -EIO ; - goto err_probe1; +dev_err (&pdev->dev,"regs ioremap failed\n" ); +return -ENOMEM ; } host->clk =clk_get (&pdev->dev,NULL );if (IS_ERR (host->clk)) {dev_err (&pdev->dev,"failed to fetch block clock\n" ); - ret =PTR_ERR (host->clk); - host->clk =NULL ; - goto err_probe1; +return PTR_ERR (host->clk); } ret =clk_enable (host->clk);if (ret) - goto err_probe1; + goto err_clk_enable;/* * This device ID is actually a common AMBA ID as used on the
@@ -852,7 +840,7 @@ static int __init fsmc_nand_probe(struct platform_device *pdev)if (nand_scan_ident (&host->mtd,1 ,NULL )) { ret = -ENXIO ;dev_err (&pdev->dev,"No NAND Device found!\n" ); - goto err_probe; + goto err_scan_ident; }if (AMBA_REV_BITS (host->pid) >=8 ) {
@@ -927,32 +915,10 @@ static int __init fsmc_nand_probe(struct platform_device *pdev)return 0 ; err_probe: +err_scan_ident:clk_disable (host->clk); -err_probe1: -if (host->clk) -clk_put (host->clk); -if (host->regs_va) -iounmap (host->regs_va); -if (host->resregs) -release_mem_region (host->resregs->start, -resource_size (host->resregs)); -if (host->cmd_va) -iounmap (host->cmd_va); -if (host->rescmd) -release_mem_region (host->rescmd->start, -resource_size (host->rescmd)); -if (host->addr_va) -iounmap (host->addr_va); -if (host->resaddr) -release_mem_region (host->resaddr->start, -resource_size (host->resaddr)); -if (host->data_va) -iounmap (host->data_va); -if (host->resdata) -release_mem_region (host->resdata->start, -resource_size (host->resdata)); - -kfree (host); +err_clk_enable: +clk_put (host->clk);return ret; }
@@ -969,22 +935,8 @@ static int fsmc_nand_remove(struct platform_device *pdev)nand_release (&host->mtd);clk_disable (host->clk);clk_put (host->clk); - -iounmap (host->regs_va); -release_mem_region (host->resregs->start, -resource_size (host->resregs)); -iounmap (host->cmd_va); -release_mem_region (host->rescmd->start, -resource_size (host->rescmd)); -iounmap (host->addr_va); -release_mem_region (host->resaddr->start, -resource_size (host->resaddr)); -iounmap (host->data_va); -release_mem_region (host->resdata->start, -resource_size (host->resdata)); - -kfree (host); } +return 0 ; }
Signature · 1 line
1.7.0.4
PATCH v2 10/13 nand/fsmc: Use dev_err to report error scenario
In reply to Vipin Kumarfsmc controller takes time to calculate the bch8 codes and the error offsets. The calculate logic checks for completion upto a timeout. This patch adds a error print when this timer expires and the ecc or error offsets are not yet calculated.
--- drivers/mtd/nand/fsmc_nand.c | 7 +++++++ 1 files changed, 7 insertions(+), 0 deletions(-)
drivers/mtd/nand/fsmc_nand.c +7 -0
@@ -296,6 +296,7 @@ struct fsmc_nand_data {struct fsmc_eccplace *ecc_place;unsigned int bank; +struct device *dev;struct clk *clk;struct fsmc_nand_timings *dev_timings;
@@ -457,6 +458,11 @@ static int fsmc_read_hwecc_ecc4(struct mtd_info *mtd, const uint8_t *data,cond_resched (); }while (!time_after_eq (jiffies, deadline)); +if (time_after_eq (jiffies, deadline)) { +dev_err (host->dev,"calculate ecc timed out\n" ); +return -ETIMEDOUT ; + } + ecc_tmp =readl (®s->bank_regs[bank].ecc1); ecc[0 ] = (uint8_t ) (ecc_tmp >>0 ); ecc[1 ] = (uint8_t ) (ecc_tmp >>8 );
@@ -793,6 +799,7 @@ static int __init fsmc_nand_probe(struct platform_device *pdev) host->select_chip = pdata->select_bank; host->partitions = pdata->partitions; host->nr_partitions = pdata->nr_partitions; + host->dev = &pdev->dev; host->dev_timings = pdata->nand_timings; regs = host->regs_va;
Signature · 1 line
1.7.0.4
PATCH v2 11/13 nand/fsmc: Access the NAND device word by word whenever possible
In reply to Vipin KumarThe default way of accessing nand device is using the nand width. This means that 8bit devices are using u8 * and 16bit devices are accessed using u16 *.
This results in a non-optimal performance since the FSMC is designed to translate the normal word accesses into device width based accesses. This patch implements read_buf and write_buf callbacks using word by word accesses.
--- drivers/mtd/nand/fsmc_nand.c | 55 ++++++++++++++++++++++++++++++++++++++++++ include/linux/mtd/fsmc.h | 6 ++++ 2 files changed, 61 insertions(+), 0 deletions(-)
drivers/mtd/nand/fsmc_nand.c +55 -0
@@ -524,6 +524,52 @@ static int count_written_bits(uint8_t *buff, int size, int max_bits) }/* +* fsmc_write_buf - write buffer to chip +* @mtd: MTD device structure +* @buf: data buffer +* @len: number of bytes to write +*/ +static void fsmc_write_buf (struct mtd_info *mtd,const uint8_t *buf,int len) +{ +int i; +struct nand_chip *chip = mtd->priv; + +if (IS_ALIGNED ((uint32_t )buf,sizeof (uint32_t )) && +IS_ALIGNED (len,sizeof (uint32_t ))) { +uint32_t *p = (uint32_t *)buf; + len = len >>2 ; +for (i =0 ; i < len; i++) +writel (p[i], chip->IO_ADDR_W); + }else { +for (i =0 ; i < len; i++) +writeb (buf[i], chip->IO_ADDR_W); + } +} + +/* +* fsmc_read_buf - read chip data into buffer +* @mtd: MTD device structure +* @buf: buffer to store date +* @len: number of bytes to read +*/ +static void fsmc_read_buf (struct mtd_info *mtd,uint8_t *buf,int len) +{ +int i; +struct nand_chip *chip = mtd->priv; + +if (IS_ALIGNED ((uint32_t )buf,sizeof (uint32_t )) && +IS_ALIGNED (len,sizeof (uint32_t ))) { +uint32_t *p = (uint32_t *)buf; + len = len >>2 ; +for (i =0 ; i < len; i++) + p[i] =readl (chip->IO_ADDR_R); + }else { +for (i =0 ; i < len; i++) + buf[i] =readb (chip->IO_ADDR_R); + } +} + +/* * fsmc_read_page_hwecc * @mtd: mtd info structure * @chip: nand chip info structure
@@ -825,6 +871,15 @@ static int __init fsmc_nand_probe(struct platform_device *pdev)if (pdata->width ==FSMC_NAND_BW16 ) nand->options |=NAND_BUSWIDTH_16 ; +/* +* use customized (word by word) version of read_buf, write_buf if +* access_with_dev_width is reset supported +*/ +if (pdata->mode ==USE_WORD_ACCESS ) { + nand->read_buf = fsmc_read_buf; + nand->write_buf = fsmc_write_buf; + } +fsmc_nand_setup (regs, host->bank, nand->options &NAND_BUSWIDTH_16 , host->dev_timings);
include/linux/mtd/fsmc.h +6 -0
@@ -141,6 +141,11 @@ struct fsmc_nand_timings {uint8_t tset; }; +enum access_mode { +USE_DMA_ACCESS =1 , +USE_WORD_ACCESS , +}; +/** * fsmc_nand_platform_data - platform specific NAND controller config * @partitions: partition table for the platform, use a default fallback
@@ -164,6 +169,7 @@ struct fsmc_nand_platform_data {/* CLE, ALE offsets */ unsigned long cle_off;unsigned long ale_off; +enum access_mode mode;void (*select_bank)(uint32_t bank,uint32_t busw); };
Signature · 1 line
1.7.0.4
PATCH v2 12/13 nand/fsmc: Add DMA support
In reply to Vipin KumarThe fsmc_nand driver uses cpu to read/write onto the device. This is inefficient because of two reasons
- the cpu gets locked on AHB bus while reading from NAND
- the cpu is unnecessarily used when dma can do the job
This patch adds the support for accessing the device through DMA
--- drivers/mtd/nand/fsmc_nand.c | 168 ++++++++++++++++++++++++++++++++++++++++- include/linux/mtd/fsmc.h | 4 + 2 files changed, 167 insertions(+), 5 deletions(-)
drivers/mtd/nand/fsmc_nand.c +163 -5
@@ -17,6 +17,10 @@*/ #include <linux/clk.h> +#include <linux/completion.h> +#include <linux/dmaengine.h> +#include <linux/dma-direction.h> +#include <linux/dma-mapping.h> #include <linux/err.h> #include <linux/init.h> #include <linux/module.h>
@@ -282,6 +286,11 @@ static struct fsmc_eccplace fsmc_ecc4_sp_place = {* @bank: Bank number for probed device. * @clk: Clock structure for FSMC. * +* @read_dma_chan: DMA channel for read access +* @write_dma_chan: DMA channel for write access to NAND +* @dma_access_complete: Completion structure +* +* @data_pa: NAND Physical port for Data. * @data_va: NAND port for Data. * @cmd_va: NAND port for Command. * @addr_va: NAND port for Address.
@@ -297,10 +306,17 @@ struct fsmc_nand_data {struct fsmc_eccplace *ecc_place;unsigned int bank;struct device *dev; +enum access_mode mode;struct clk *clk; +/* DMA related objects */ +struct dma_chan *read_dma_chan; +struct dma_chan *write_dma_chan; +struct completion dma_access_complete; +struct fsmc_nand_timings *dev_timings; +dma_addr_t data_pa;void __iomem *data_va;void __iomem *cmd_va;void __iomem *addr_va;
@@ -523,6 +539,77 @@ static int count_written_bits(uint8_t *buff, int size, int max_bits)return written_bits; } +static void dma_complete (void *param) +{ +struct fsmc_nand_data *host = param; + +complete (&host->dma_access_complete); +} + +static int dma_xfer (struct fsmc_nand_data *host,void *buffer,int len, +enum dma_data_direction direction) +{ +struct dma_chan *chan; +struct dma_device *dma_dev; +struct dma_async_tx_descriptor *tx; +dma_addr_t dma_dst, dma_src, dma_addr; +dma_cookie_t cookie; +unsigned long flags =DMA_CTRL_ACK |DMA_PREP_INTERRUPT ; +int ret; + +if (direction ==DMA_TO_DEVICE ) + chan = host->write_dma_chan; +else if (direction ==DMA_FROM_DEVICE ) + chan = host->read_dma_chan; +else +return -EINVAL ; + + dma_dev = chan->device; + dma_addr =dma_map_single (dma_dev->dev, buffer, len, direction); + +if (direction ==DMA_TO_DEVICE ) { + dma_src = dma_addr; + dma_dst = host->data_pa; + flags |=DMA_COMPL_SRC_UNMAP_SINGLE |DMA_COMPL_SKIP_DEST_UNMAP ; + }else { + dma_src = host->data_pa; + dma_dst = dma_addr; + flags |=DMA_COMPL_DEST_UNMAP_SINGLE |DMA_COMPL_SKIP_SRC_UNMAP ; + } + + tx = dma_dev->device_prep_dma_memcpy (chan, dma_dst, dma_src, + len, flags); + +if (!tx) { +dev_err (host->dev,"device_prep_dma_memcpy error\n" ); +dma_unmap_single (dma_dev->dev, dma_addr, len, direction); +return -EIO ; + } + + tx->callback = dma_complete; + tx->callback_param = host; + cookie = tx->tx_submit (tx); + + ret =dma_submit_error (cookie); +if (ret) { +dev_err (host->dev,"dma_submit_error %d\n" , cookie); +return ret; + } + +dma_async_issue_pending (chan); + + ret = +wait_for_completion_interruptible_timeout (&host->dma_access_complete, +msecs_to_jiffies (3000 )); +if (ret <=0 ) { + chan->device->device_control (chan,DMA_TERMINATE_ALL ,0 ); +dev_err (host->dev,"wait_for_completion_timeout\n" ); +return ret ? ret : -ETIMEDOUT ; + } + +return 0 ; +} +/* * fsmc_write_buf - write buffer to chip * @mtd: MTD device structure
@@ -570,6 +657,35 @@ static void fsmc_read_buf(struct mtd_info *mtd, uint8_t *buf, int len) }/* +* fsmc_read_buf_dma - read chip data into buffer +* @mtd: MTD device structure +* @buf: buffer to store date +* @len: number of bytes to read +*/ +static void fsmc_read_buf_dma (struct mtd_info *mtd,uint8_t *buf,int len) +{ +struct fsmc_nand_data *host; + + host = container_of(mtd, struct fsmc_nand_data, mtd); +dma_xfer (host, buf, len,DMA_FROM_DEVICE ); +} + +/* +* fsmc_write_buf_dma - write buffer to chip +* @mtd: MTD device structure +* @buf: data buffer +* @len: number of bytes to write +*/ +static void fsmc_write_buf_dma (struct mtd_info *mtd,const uint8_t *buf, +int len) +{ +struct fsmc_nand_data *host; + + host = container_of(mtd, struct fsmc_nand_data, mtd); +dma_xfer (host, (void *)buf, len,DMA_TO_DEVICE ); +} + +/* * fsmc_read_page_hwecc * @mtd: mtd info structure * @chip: nand chip info structure
@@ -731,6 +847,12 @@ static int fsmc_bch8_correct_data(struct mtd_info *mtd, uint8_t *dat,return i; } +static bool filter (struct dma_chan *chan,void *slave) +{ + chan->private = slave; +return true; +} +/* * fsmc_nand_probe - Probe function * @pdev: platform device structure
@@ -743,6 +865,7 @@ static int __init fsmc_nand_probe(struct platform_device *pdev)struct nand_chip *nand;struct fsmc_regs *regs;struct resource *res; +dma_cap_mask_t mask;int ret =0 ;u32 pid;int i;
@@ -769,6 +892,7 @@ static int __init fsmc_nand_probe(struct platform_device *pdev)return -ENOENT ; } + host->data_pa = (dma_addr_t )res->start; host->data_va =devm_ioremap (&pdev->dev, res->start,resource_size (res));if (!host->data_va) {
@@ -847,6 +971,11 @@ static int __init fsmc_nand_probe(struct platform_device *pdev) host->nr_partitions = pdata->nr_partitions; host->dev = &pdev->dev; host->dev_timings = pdata->nand_timings; + host->mode = pdata->mode; + +if (host->mode ==USE_DMA_ACCESS ) +init_completion (&host->dma_access_complete); + regs = host->regs_va;/* Link all private pointers */
@@ -871,13 +1000,31 @@ static int __init fsmc_nand_probe(struct platform_device *pdev)if (pdata->width ==FSMC_NAND_BW16 ) nand->options |=NAND_BUSWIDTH_16 ; -/* -* use customized (word by word) version of read_buf, write_buf if -* access_with_dev_width is reset supported -*/ -if (pdata->mode ==USE_WORD_ACCESS ) { +switch (host->mode) { +case USE_DMA_ACCESS : +dma_cap_zero (mask); +dma_cap_set (DMA_MEMCPY , mask); + host->read_dma_chan =dma_request_channel (mask, filter, + pdata->read_dma_priv); +if (!host->read_dma_chan) { +dev_err (&pdev->dev,"Unable to get read dma channel\n" ); + goto err_req_read_chnl; + } + host->write_dma_chan =dma_request_channel (mask, filter, + pdata->write_dma_priv); +if (!host->write_dma_chan) { +dev_err (&pdev->dev,"Unable to get write dma channel\n" ); + goto err_req_write_chnl; + } + nand->read_buf = fsmc_read_buf_dma; + nand->write_buf = fsmc_write_buf_dma; +break ; + +default : +case USE_WORD_ACCESS : nand->read_buf = fsmc_read_buf; nand->write_buf = fsmc_write_buf; +break ; } fsmc_nand_setup(regs, host->bank, nand->options & NAND_BUSWIDTH_16,
@@ -978,6 +1125,12 @@ static int __init fsmc_nand_probe(struct platform_device *pdev) err_probe: err_scan_ident: +if (host->mode ==USE_DMA_ACCESS ) +dma_release_channel (host->write_dma_chan); +err_req_write_chnl: +if (host->mode ==USE_DMA_ACCESS ) +dma_release_channel (host->read_dma_chan); +err_req_read_chnl:clk_disable (host->clk); err_clk_enable:clk_put (host->clk);
@@ -995,6 +1148,11 @@ static int fsmc_nand_remove(struct platform_device *pdev)if (host) {nand_release (&host->mtd); + +if (host->mode ==USE_DMA_ACCESS ) { +dma_release_channel (host->write_dma_chan); +dma_release_channel (host->read_dma_chan); + }clk_disable (host->clk);clk_put (host->clk); }
include/linux/mtd/fsmc.h +4 -0
@@ -172,6 +172,10 @@ struct fsmc_nand_platform_data {enum access_mode mode;void (*select_bank)(uint32_t bank,uint32_t busw); + +/* priv structures for dma accesses */ +void *read_dma_priv; +void *write_dma_priv; }; extern int __init fsmc_nor_init(struct platform_device *pdev,
Signature · 1 line
1.7.0.4
PATCH v2 13/13 nand/fsmc: Remove sparse warnings and errors
In reply to Vipin KumarThis patch removes the sparse below warnings and errors for nand/fsmc driver /root/vipin/spear/kernel/3.3/linux-3.3/drivers/mtd/nand/fsmc_nand.c:363:31:
warning: incorrect type in initializer (different address spaces) /root/vipin/spear/kernel/3.3/linux-3.3/drivers/mtd/nand/fsmc_nand.c:363:31:
expected struct fsmc_regs *regs /root/vipin/spear/kernel/3.3/linux-3.3/drivers/mtd/nand/fsmc_nand.c:363:31:
got void [noderef] <asn:2>*regs_va
[...]
--- drivers/mtd/nand/fsmc_nand.c | 91 +++++++++++++------------- include/linux/mtd/fsmc.h | 143 +++++++++++++++++++---------------------- 2 files changed, 111 insertions(+), 123 deletions(-)
drivers/mtd/nand/fsmc_nand.c +45 -46
@@ -360,28 +360,29 @@ static void fsmc_cmd_ctrl(struct mtd_info *mtd, int cmd, unsigned int ctrl)struct nand_chip *this = mtd->priv;struct fsmc_nand_data *host =container_of (mtd, struct fsmc_nand_data, mtd); -struct fsmc_regs *regs = host->regs_va; +void *__iomem *regs = host->regs_va;unsigned int bank = host->bank;if (ctrl &NAND_CTRL_CHANGE ) { +u32 pc; +if (ctrl &NAND_CLE ) { - this->IO_ADDR_R = (void __iomem *)host->cmd_va; - this->IO_ADDR_W = (void __iomem *)host->cmd_va; + this->IO_ADDR_R = host->cmd_va; + this->IO_ADDR_W = host->cmd_va; }else if (ctrl &NAND_ALE ) { - this->IO_ADDR_R = (void __iomem *)host->addr_va; - this->IO_ADDR_W = (void __iomem *)host->addr_va; + this->IO_ADDR_R = host->addr_va; + this->IO_ADDR_W = host->addr_va; }else { - this->IO_ADDR_R = (void __iomem *)host->data_va; - this->IO_ADDR_W = (void __iomem *)host->data_va; + this->IO_ADDR_R = host->data_va; + this->IO_ADDR_W = host->data_va; } -if (ctrl &NAND_NCE ) { -writel (readl (®s->bank_regs[bank].pc) |FSMC_ENABLE , - ®s->bank_regs[bank].pc); - }else { -writel (readl (®s->bank_regs[bank].pc) & ~FSMC_ENABLE , - ®s->bank_regs[bank].pc); - } + pc =readl (FSMC_NAND_REG (regs, bank,PC )); +if (ctrl &NAND_NCE ) + pc |=FSMC_ENABLE ; +else + pc &= ~FSMC_ENABLE ; +writel (pc,FSMC_NAND_REG (regs, bank,PC )); }mb ();
@@ -396,7 +397,7 @@ static void fsmc_cmd_ctrl(struct mtd_info *mtd, int cmd, unsigned int ctrl)* This routine initializes timing parameters related to NAND memory access in * FSMC registers */ -static void fsmc_nand_setup (struct fsmc_regs *regs,uint32_t bank, +static void fsmc_nand_setup (void __iomem *regs,uint32_t bank,uint32_t busw,struct fsmc_nand_timings *timings) {uint32_t value =FSMC_DEVTYPE_NAND |FSMC_ENABLE |FSMC_WAITON ;
@@ -424,14 +425,14 @@ static void fsmc_nand_setup(struct fsmc_regs *regs, uint32_t bank, tset = (tims->tset &FSMC_TSET_MASK ) <<FSMC_TSET_SHIFT ;if (busw) -writel (value |FSMC_DEVWID_16 , ®s->bank_regs[bank].pc); +writel (value |FSMC_DEVWID_16 ,FSMC_NAND_REG (regs, bank,PC ));else -writel (value |FSMC_DEVWID_8 , ®s->bank_regs[bank].pc); +writel (value |FSMC_DEVWID_8 ,FSMC_NAND_REG (regs, bank,PC )); -writel (readl (®s->bank_regs[bank].pc) | tclr | tar, - ®s->bank_regs[bank].pc); -writel (thiz | thold | twait | tset, ®s->bank_regs[bank].comm); -writel (thiz | thold | twait | tset, ®s->bank_regs[bank].attrib); +writel (readl (FSMC_NAND_REG (regs, bank,PC )) | tclr | tar, +FSMC_NAND_REG (regs, bank,PC )); +writel (thiz | thold | twait | tset,FSMC_NAND_REG (regs, bank,COMM )); +writel (thiz | thold | twait | tset,FSMC_NAND_REG (regs, bank,ATTRIB )); }/*
@@ -441,15 +442,15 @@ static void fsmc_enable_hwecc(struct mtd_info *mtd, int mode) {struct fsmc_nand_data *host =container_of (mtd, struct fsmc_nand_data, mtd); -struct fsmc_regs *regs = host->regs_va; +void __iomem *regs = host->regs_va;uint32_t bank = host->bank; -writel (readl (®s->bank_regs[bank].pc) & ~FSMC_ECCPLEN_256 , - ®s->bank_regs[bank].pc); -writel (readl (®s->bank_regs[bank].pc) & ~FSMC_ECCEN , - ®s->bank_regs[bank].pc); -writel (readl (®s->bank_regs[bank].pc) |FSMC_ECCEN , - ®s->bank_regs[bank].pc); +writel (readl (FSMC_NAND_REG (regs, bank,PC )) & ~FSMC_ECCPLEN_256 , +FSMC_NAND_REG (regs, bank,PC )); +writel (readl (FSMC_NAND_REG (regs, bank,PC )) & ~FSMC_ECCEN , +FSMC_NAND_REG (regs, bank,PC )); +writel (readl (FSMC_NAND_REG (regs, bank,PC )) |FSMC_ECCEN , +FSMC_NAND_REG (regs, bank,PC )); }/*
@@ -462,13 +463,13 @@ static int fsmc_read_hwecc_ecc4(struct mtd_info *mtd, const uint8_t *data, {struct fsmc_nand_data *host =container_of (mtd, struct fsmc_nand_data, mtd); -struct fsmc_regs *regs = host->regs_va; +void __iomem *regs = host->regs_va;uint32_t bank = host->bank;uint32_t ecc_tmp;unsigned long deadline = jiffies +FSMC_BUSY_WAIT_TIMEOUT ; do { - if (readl(®s->bank_regs[bank].sts) & FSMC_CODE_RDY) + if (readl(FSMC_NAND_REG(regs, bank, STS)) & FSMC_CODE_RDY) break; else cond_resched();
@@ -479,25 +480,25 @@ static int fsmc_read_hwecc_ecc4(struct mtd_info *mtd, const uint8_t *data,return -ETIMEDOUT ; } - ecc_tmp =readl (®s->bank_regs[bank].ecc1); + ecc_tmp =readl (FSMC_NAND_REG (regs, bank,ECC1 )); ecc[0 ] = (uint8_t ) (ecc_tmp >>0 ); ecc[1 ] = (uint8_t ) (ecc_tmp >>8 ); ecc[2 ] = (uint8_t ) (ecc_tmp >>16 ); ecc[3 ] = (uint8_t ) (ecc_tmp >>24 ); - ecc_tmp =readl (®s->bank_regs[bank].ecc2); + ecc_tmp =readl (FSMC_NAND_REG (regs, bank,ECC2 )); ecc[4 ] = (uint8_t ) (ecc_tmp >>0 ); ecc[5 ] = (uint8_t ) (ecc_tmp >>8 ); ecc[6 ] = (uint8_t ) (ecc_tmp >>16 ); ecc[7 ] = (uint8_t ) (ecc_tmp >>24 ); - ecc_tmp =readl (®s->bank_regs[bank].ecc3); + ecc_tmp =readl (FSMC_NAND_REG (regs, bank,ECC3 )); ecc[8 ] = (uint8_t ) (ecc_tmp >>0 ); ecc[9 ] = (uint8_t ) (ecc_tmp >>8 ); ecc[10 ] = (uint8_t ) (ecc_tmp >>16 ); ecc[11 ] = (uint8_t ) (ecc_tmp >>24 ); - ecc_tmp =readl (®s->bank_regs[bank].sts); + ecc_tmp =readl (FSMC_NAND_REG (regs, bank,STS )); ecc[12 ] = (uint8_t ) (ecc_tmp >>16 );return 0 ;
@@ -513,11 +514,11 @@ static int fsmc_read_hwecc_ecc1(struct mtd_info *mtd, const uint8_t *data, {struct fsmc_nand_data *host =container_of (mtd, struct fsmc_nand_data, mtd); -struct fsmc_regs *regs = host->regs_va; +void __iomem *regs = host->regs_va;uint32_t bank = host->bank;uint32_t ecc_tmp; - ecc_tmp =readl (®s->bank_regs[bank].ecc1); + ecc_tmp =readl (FSMC_NAND_REG (regs, bank,ECC1 )); ecc[0 ] = (uint8_t ) (ecc_tmp >>0 ); ecc[1 ] = (uint8_t ) (ecc_tmp >>8 ); ecc[2 ] = (uint8_t ) (ecc_tmp >>16 );
@@ -771,13 +772,13 @@ static int fsmc_bch8_correct_data(struct mtd_info *mtd, uint8_t *dat,struct fsmc_nand_data *host =container_of (mtd, struct fsmc_nand_data, mtd);struct nand_chip *chip = mtd->priv; -struct fsmc_regs *regs = host->regs_va; +void __iomem *regs = host->regs_va;unsigned int bank = host->bank;uint32_t err_idx[8 ];uint32_t num_err, i;uint32_t ecc1, ecc2, ecc3, ecc4; - num_err = (readl (®s->bank_regs[bank].sts) >>10 ) &0xF ; + num_err = (readl (FSMC_NAND_REG (regs, bank,STS )) >>10 ) &0xF ;/* no bit flipping */ if (likely (num_err ==0 ))
@@ -820,10 +821,10 @@ static int fsmc_bch8_correct_data(struct mtd_info *mtd, uint8_t *dat,* uint64_t array and error offset indexes are populated in err_idx * array */ - ecc1 =readl (®s->bank_regs[bank].ecc1); - ecc2 =readl (®s->bank_regs[bank].ecc2); - ecc3 =readl (®s->bank_regs[bank].ecc3); - ecc4 =readl (®s->bank_regs[bank].sts); + ecc1 =readl (FSMC_NAND_REG (regs, bank,ECC1 )); + ecc2 =readl (FSMC_NAND_REG (regs, bank,ECC2 )); + ecc3 =readl (FSMC_NAND_REG (regs, bank,ECC3 )); + ecc4 =readl (FSMC_NAND_REG (regs, bank,STS )); err_idx[0 ] = (ecc1 >>0 ) &0x1FFF ; err_idx[1 ] = (ecc1 >>13 ) &0x1FFF ;
@@ -863,7 +864,6 @@ static int __init fsmc_nand_probe(struct platform_device *pdev)struct fsmc_nand_data *host;struct mtd_info *mtd;struct nand_chip *nand; -struct fsmc_regs *regs;struct resource *res;dma_cap_mask_t mask;int ret =0 ;
@@ -976,8 +976,6 @@ static int __init fsmc_nand_probe(struct platform_device *pdev)if (host->mode ==USE_DMA_ACCESS )init_completion (&host->dma_access_complete); - regs = host->regs_va; -/* Link all private pointers */ mtd = &host->mtd; nand = &host->nand;
@@ -1027,7 +1025,8 @@ static int __init fsmc_nand_probe(struct platform_device *pdev)break ; } -fsmc_nand_setup (regs, host->bank, nand->options &NAND_BUSWIDTH_16 , +fsmc_nand_setup (host->regs_va, host->bank, + nand->options &NAND_BUSWIDTH_16 , host->dev_timings);if (AMBA_REV_BITS (host->pid) >=8 ) {
include/linux/mtd/fsmc.h +66 -77
154 lines not on this page · raw message
Signature · 1 line
1.7.0.4
Quoted 10 lines · Vipin Kumar
Hello Artem,
These are the patches 8-20 of the original patchset of which 1-7 have already been applied by you. I have rebased these patches over
git://git.infradead.org/users/dedekind/l2-mtd.gitto help you apply these easilyModifications in v2
- Add support for partition information to be passed from platform data
- Default partition information removed from driver
- Remove sparse errors and warnings
Pushed all to l2-mtd.git, thanks!
Signature · 2 lines
Best Regards, Artem Bityutskiy