mtd/nand: fsmc driver updates
Subsystems (5)
cover mtd/nand: fsmc driver updates
This patch-set contains several fixes and a few enhancements in fsmc driver. Modifications include
- General enhancements
* Add ready/busy support through a GPIO pin
* Add software bch support
* Increase ecc loactions to 640
* Support multiple banks
* Use relaxed io accessors for increased throughput
- Enhance DT support
* Add timing parameters
- Several fixes
* Fix the type for regs
* Replace change_bit routine to handle unaligned addresses
* Provide contiguous buffers for DMA operation
Vipin Kumar (11):
fsmc/nand:FIX: Change the type for regs to void __iomem * fsmc/nand: Rearrange the fsmc_nand_data structure and update comments fsmc/nand: Support multiple banks connected to controller fsmc/nand: Accept nand timing parameters via DT
fsmc: Implement ready/busy through gpio pin
fsmc/nand: Modify the wait to uninterruptible
fsmc/nand: Provide contiguous buffers to dma
fsmc/nand: Use relaxed variants of io accessors fsmc/nand:FIX: replace change_bit routine
fsmc/nand: Add sw bch support for ecc calculation/correction
nand: Increase the ecc placement locations to 640
.../devicetree/bindings/mtd/fsmc-nand.txt | 29 ++ arch/arm/boot/dts/spear300.dtsi | 1 + arch/arm/boot/dts/spear310.dtsi | 1 + arch/arm/boot/dts/spear320.dtsi | 1 + arch/arm/boot/dts/spear600.dtsi | 1 + arch/arm/mach-u300/core.c | 1 + drivers/mtd/nand/fsmc_nand.c | 419 ++++++++++++++------- include/linux/mtd/fsmc.h | 18 +- include/linux/mtd/mtd.h | 2 +- 9 files changed, 332 insertions(+), 141 deletions(-)
Signature · 1 line
1.7.11.4
PATCH 1/11 fsmc/nand:FIX: Change the type for regs to void __iomem *
--- drivers/mtd/nand/fsmc_nand.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-)
drivers/mtd/nand/fsmc_nand.c +1 -1
@@ -361,7 +361,7 @@ 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); -void *__iomem *regs = host->regs_va; +void __iomem *regs = host->regs_va;unsigned int bank = host->bank;if (ctrl &NAND_CTRL_CHANGE ) {
Signature · 1 line
1.7.11.4
PATCH 1/11 fsmc/nand:FIX: Change the type for regs to void __iomem *
Quoted 10 lines · Vipin Kumar
Signed-off-by Vipin Kumar <[email protected]>--- drivers/mtd/nand/fsmc_nand.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-)drivers/mtd/nand/fsmc_nand.c +0
-0
drivers/mtd/nand/fsmc_nand.c static void fsmc_cmd_ctrl(struct mtd_info *mtd, int cmd, unsigned int ctrl) · line 364
Quoted 5 lines
drivers/mtd/nand/fsmc_nand.c +1
-1@@ -361,7 +361,7 @@ 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); -void *__iomem *regs = host->regs_va; +void __iomem *regs = host->regs_va;
PATCH 1/11 fsmc/nand:FIX: Change the type for regs to void __iomem *
In reply to Vipin KumarQuoted 1 line · Vipin Kumar
Signed-off-by Vipin Kumar <[email protected]>
Yours,
Linus Walleij
PATCH 1/11 fsmc/nand:FIX: Change the type for regs to void __iomem *
In reply to Vipin KumarQuoted 1 line · Vipin Kumar
Signed-off-by Vipin Kumar <[email protected]>
Pushed this one to l2-mtd.git, thanks!
Signature · 9 lines
Best Regards, Artem Bityutskiy -------------- next part -------------- A non-text attachment was scrubbed... Name: signature.asc Type: application/pgp-signature Size: 836 bytes Desc: This is a digitally signed message part URL: <http://lists.infradead.org/pipermail/linux-arm-kernel/attachments/20121017/4621e9f2/attachment.sig>
PATCH 2/11 fsmc/nand: Rearrange the fsmc_nand_data structure and update comments
In reply to Vipin Kumar--- drivers/mtd/nand/fsmc_nand.c | 51 ++++++++++++++++++++++++++------------------ 1 file changed, 30 insertions(+), 21 deletions(-)
drivers/mtd/nand/fsmc_nand.c +30 -21
@@ -278,52 +278,61 @@ static struct fsmc_eccplace fsmc_ecc4_sp_place = {* struct fsmc_nand_data - structure for FSMC NAND device state * * @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. -* @clk: Clock structure for FSMC. +* @mtd: MTD info for a NAND flash +* @nand: Chip related info for a NAND flash +* @dev: Device structure pointer +* @clk: Clock structure for FSMC +* @ecc_place: ECC placing locations in oobfree type format +* @bank: Bank number for probed device * * @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. -* @regs_va: FSMC regs base address. +* @dev_timings: Timings to be programmed in controller +* @partitions: Partition info for a NAND Flash +* @nr_partitions: Total number of partition of a NAND flash +* @mode: Defines the NAND device access mode +* Can be one of: +* - DMA access +* - Word access (CPU) +* - None (Use driver default ie bus width specific +* CPU access) +* @select_chip: Select a particular bank +* +* @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 +* @regs_va: FSMC regs base address */ 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;struct device *dev; -enum access_mode mode;struct clk *clk; +struct fsmc_eccplace *ecc_place; +unsigned int bank;/* DMA related objects */ struct dma_chan *read_dma_chan;struct dma_chan *write_dma_chan;struct completion dma_access_complete; +/* Recieved from plat data */ struct fsmc_nand_timings *dev_timings; +struct mtd_partition *partitions; +unsigned int nr_partitions; +enum access_mode mode; +void (*select_chip)(uint32_t bank,uint32_t busw); +/* Virtual/Physical addresses for CPU/DMA access */ dma_addr_t data_pa;void __iomem *data_va;void __iomem *cmd_va;void __iomem *addr_va;void __iomem *regs_va; - -void (*select_chip)(uint32_t bank,uint32_t busw); };/* Assert CS signal based on chipnr */
Signature · 1 line
1.7.11.4
PATCH 2/11 fsmc/nand: Rearrange the fsmc_nand_data structure and update comments
Quoted 68 lines · Vipin Kumar
Signed-off-by Vipin Kumar <[email protected]>--- drivers/mtd/nand/fsmc_nand.c | 51 ++++++++++++++++++++++++++------------------ 1 file changed, 30 insertions(+), 21 deletions(-)drivers/mtd/nand/fsmc_nand.c +24
-19@@ -278,52 +278,61 @@ static struct fsmc_eccplace fsmc_ecc4_sp_place = {* struct fsmc_nand_data - structure for FSMC NAND device state * * @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. -* @clk: Clock structure for FSMC. +* @mtd: MTD info for a NAND flash +* @nand: Chip related info for a NAND flash +* @dev: Device structure pointer +* @clk: Clock structure for FSMC +* @ecc_place: ECC placing locations in oobfree type format +* @bank: Bank number for probed device * * @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. -* @regs_va: FSMC regs base address. +* @dev_timings: Timings to be programmed in controller +* @partitions: Partition info for a NAND Flash +* @nr_partitions: Total number of partition of a NAND flash +* @mode: Defines the NAND device access mode +* Can be one of: +* - DMA access +* - Word access (CPU) +* - None (Use driver default ie bus width specific +* CPU access) +* @select_chip: Select a particular bank +* +* @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 +* @regs_va: FSMC regs base address */ 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;struct device *dev; -enum access_mode mode;struct clk *clk; +struct fsmc_eccplace *ecc_place; +unsigned int bank;
drivers/mtd/nand/fsmc_nand.c static struct fsmc_eccplace fsmc_ecc4_sp_place = { · line 326
Quoted 10 lines
drivers/mtd/nand/fsmc_nand.c +3
-0/* DMA related objects */ struct dma_chan *read_dma_chan;struct dma_chan *write_dma_chan;struct completion dma_access_complete; +/* Recieved from plat data */ struct fsmc_nand_timings *dev_timings; +struct mtd_partition *partitions; +unsigned int nr_partitions;
where do you use those execpt at probe time
Quoted 17 lines
drivers/mtd/nand/fsmc_nand.c +3
-2+enum access_mode mode; +void (*select_chip)(uint32_t bank,uint32_t busw); +/* Virtual/Physical addresses for CPU/DMA access */ dma_addr_t data_pa;void __iomem *data_va;void __iomem *cmd_va;void __iomem *addr_va;void __iomem *regs_va; - -void (*select_chip)(uint32_t bank,uint32_t busw); };/* Assert CS signal based on chipnr */ Signature · 1 line
1.7.11.4
PATCH 2/11 fsmc/nand: Rearrange the fsmc_nand_data structure and update comments
Quoted 75 lines · Jean-Christophe PLAGNIOL-VILLARD
Quoted 74 lines · Vipin Kumar
Signed-off-by Vipin Kumar<[email protected]>--- drivers/mtd/nand/fsmc_nand.c | 51 ++++++++++++++++++++++++++------------------ 1 file changed, 30 insertions(+), 21 deletions(-)drivers/mtd/nand/fsmc_nand.c +24
-19@@ -278,52 +278,61 @@ static struct fsmc_eccplace fsmc_ecc4_sp_place = {* struct fsmc_nand_data - structure for FSMC NAND device state * * @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. -* @clk: Clock structure for FSMC. +* @mtd: MTD info for a NAND flash +* @nand: Chip related info for a NAND flash +* @dev: Device structure pointer +* @clk: Clock structure for FSMC +* @ecc_place: ECC placing locations in oobfree type format +* @bank: Bank number for probed device * * @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. -* @regs_va: FSMC regs base address. +* @dev_timings: Timings to be programmed in controller +* @partitions: Partition info for a NAND Flash +* @nr_partitions: Total number of partition of a NAND flash +* @mode: Defines the NAND device access mode +* Can be one of: +* - DMA access +* - Word access (CPU) +* - None (Use driver default ie bus width specific +* CPU access) +* @select_chip: Select a particular bank +* +* @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 +* @regs_va: FSMC regs base address */ 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;struct device *dev; -enum access_mode mode;struct clk *clk; +struct fsmc_eccplace *ecc_place; +unsigned int bank;/* DMA related objects */ struct dma_chan *read_dma_chan;struct dma_chan *write_dma_chan;struct completion dma_access_complete;
Quoted 5 lines
drivers/mtd/nand/fsmc_nand.c static struct fsmc_eccplace fsmc_ecc4_sp_place = { · line 326
Quoted 4 lines
drivers/mtd/nand/fsmc_nand.c +3
-0+/* Recieved from plat data */ struct fsmc_nand_timings *dev_timings; +struct mtd_partition *partitions; +unsigned int nr_partitions;where do you use those execpt at probe time
Yes, I can remove it completely. Thanks for that
PATCH 2/11 fsmc/nand: Rearrange the fsmc_nand_data structure and update comments
In reply to Vipin KumarQuoted 4 lines · Vipin Kumar
Signed-off-by Vipin Kumar <[email protected]>--- drivers/mtd/nand/fsmc_nand.c | 51 ++++++++++++++++++++++++++------------------ 1 file changed, 30 insertions(+), 21 deletions(-)
PATCH 3/11 fsmc/nand: Support multiple banks connected to controller
In reply to Vipin KumarSupport up to max_banks number of banks in fsmc driver.
--- .../devicetree/bindings/mtd/fsmc-nand.txt | 2 ++ arch/arm/boot/dts/spear300.dtsi | 1 + arch/arm/boot/dts/spear310.dtsi | 1 + arch/arm/boot/dts/spear320.dtsi | 1 + arch/arm/boot/dts/spear600.dtsi | 1 + arch/arm/mach-u300/core.c | 1 + drivers/mtd/nand/fsmc_nand.c | 26 +++++++++++++++------- include/linux/mtd/fsmc.h | 2 +- 8 files changed, 26 insertions(+), 9 deletions(-)
Documentation/devicetree/bindings/mtd/fsmc-nand.txt +2 -0
@@ -6,6 +6,7 @@ Required properties: - reg-names: Should contain the reg names "fsmc_regs" and "nand_data" - st,ale-off : Chip specific offset to ALE - st,cle-off : Chip specific offset to CLE +- maxbanks: Number of banks supported by SoC Optional properties: - bank-width : Width (in bytes) of the device. If not present, the width
@@ -23,6 +24,7 @@ Example: reg-names = "fsmc_regs", "nand_data"; st,ale-off = <0x20000>; st,cle-off = <0x10000>; + maxbanks = <1>; bank-width = <1>; nand-skip-bbtscan;
arch/arm/boot/dts/spear300.dtsi +1 -0
@@ -42,6 +42,7 @@ reg-names = "fsmc_regs", "nand_data"; st,ale-off = <0x20000>; st,cle-off = <0x10000>; + maxbanks = <1>; status = "disabled"; };
arch/arm/boot/dts/spear310.dtsi +1 -0
@@ -36,6 +36,7 @@ reg-names = "fsmc_regs", "nand_data"; st,ale-off = <0x10000>; st,cle-off = <0x20000>; + maxbanks = <1>; status = "disabled"; };
arch/arm/boot/dts/spear320.dtsi +1 -0
@@ -42,6 +42,7 @@ reg-names = "fsmc_regs", "nand_data"; st,ale-off = <0x20000>; st,cle-off = <0x10000>; + maxbanks = <1>; status = "disabled"; };
arch/arm/boot/dts/spear600.dtsi +1 -0
@@ -71,6 +71,7 @@ reg-names = "fsmc_regs", "nand_data"; st,ale-off = <0x20000>; st,cle-off = <0x10000>; + maxbanks = <1>; status = "disabled"; };
arch/arm/mach-u300/core.c +1 -0
@@ -1546,6 +1546,7 @@ static struct fsmc_nand_platform_data nand_platform_data = { .width = FSMC_NAND_BW8, .ale_off = PLAT_NAND_ALE, .cle_off = PLAT_NAND_CLE, + .max_banks = 1, };static struct platform_device nand_device = {
drivers/mtd/nand/fsmc_nand.c +18 -8
@@ -298,6 +298,7 @@ static struct fsmc_eccplace fsmc_ecc4_sp_place = {* - Word access (CPU) * - None (Use driver default ie bus width specific * CPU access) +* @max_banks: Maximum number of banks supported * @select_chip: Select a particular bank * * @data_pa: NAND Physical port for Data
@@ -325,6 +326,7 @@ struct fsmc_nand_data {struct mtd_partition *partitions;unsigned int nr_partitions;enum access_mode mode; +uint32_t max_banks;void (*select_chip)(uint32_t bank,uint32_t busw);/* Virtual/Physical addresses for CPU/DMA access */
@@ -343,6 +345,7 @@ static void fsmc_select_chip(struct mtd_info *mtd, int chipnr) host = container_of(mtd, struct fsmc_nand_data, mtd); + host->bank = chipnr;switch (chipnr) {case -1 : chip->cmd_ctrl (mtd,NAND_CMD_NONE ,0 |NAND_CTRL_CHANGE );
@@ -889,6 +892,7 @@ static int __devinit fsmc_nand_probe_config_dt(struct platform_device *pdev,of_property_read_u32 (np,"st,cle-off" , &pdata->cle_off);if (of_get_property (np,"nand-skip-bbtscan" ,NULL )) pdata->options =NAND_SKIP_BBTSCAN ; +of_property_read_u32 (np,"maxbanks" , &pdata->max_banks);return 0 ; }
@@ -915,7 +919,7 @@ static int __init fsmc_nand_probe(struct platform_device *pdev)struct resource *res;dma_cap_mask_t mask;int ret =0 ; -u32 pid; +u32 pid, bank;int i;if (np) {
@@ -1023,13 +1027,13 @@ static int __init fsmc_nand_probe(struct platform_device *pdev)AMBA_PART_BITS (pid),AMBA_MANF_BITS (pid), AMBA_REV_BITS(pid), AMBA_CONFIG_BITS(pid)); - host->bank = pdata->bank; 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; host->mode = pdata->mode; + host->max_banks = pdata->max_banks;if (host->mode ==USE_DMA_ACCESS )init_completion (&host->dma_access_complete);
@@ -1083,9 +1087,10 @@ static int __init fsmc_nand_probe(struct platform_device *pdev)break ; } -fsmc_nand_setup (host->regs_va, host->bank, - nand->options &NAND_BUSWIDTH_16 , - host->dev_timings); +for (bank =0 ; bank < host->max_banks; bank++) +fsmc_nand_setup (host->regs_va, bank, + nand->options &NAND_BUSWIDTH_16 , + host->dev_timings);if (AMBA_REV_BITS (host->pid) >=8 ) { nand->ecc.read_page = fsmc_read_page_hwecc;
@@ -1230,11 +1235,16 @@ 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); +uint32_t bank; +if (host) {clk_prepare_enable (host->clk); -fsmc_nand_setup (host->regs_va, host->bank, - host->nand.options &NAND_BUSWIDTH_16 , - host->dev_timings); + +for (bank =0 ; bank < host->max_banks; bank++) +fsmc_nand_setup (host->regs_va, bank, + host->nand.options &NAND_BUSWIDTH_16 , + host->dev_timings); + }return 0 ; }
include/linux/mtd/fsmc.h +1 -1
@@ -153,7 +153,7 @@ struct fsmc_nand_platform_data {unsigned int nr_partitions;unsigned int options;unsigned int width; -unsigned int bank; +unsigned int max_banks;/* CLE, ALE offsets */ unsigned int cle_off;
Signature · 1 line
1.7.11.4
PATCH 3/11 fsmc/nand: Support multiple banks connected to controller
Quoted 3 lines · Vipin Kumar
Support up to
max_banksnumber of banks in fsmc driver.Signed-off-by Vipin Kumar <[email protected]>
please rebase this over my patch that drop -off to resource
Quoted 16 lines
--- .../devicetree/bindings/mtd/fsmc-nand.txt | 2 ++ arch/arm/boot/dts/spear300.dtsi | 1 + arch/arm/boot/dts/spear310.dtsi | 1 + arch/arm/boot/dts/spear320.dtsi | 1 + arch/arm/boot/dts/spear600.dtsi | 1 + arch/arm/mach-u300/core.c | 1 + drivers/mtd/nand/fsmc_nand.c | 26 +++++++++++++++------- include/linux/mtd/fsmc.h | 2 +- 8 files changed, 26 insertions(+), 9 deletions(-)Documentation/devicetree/bindings/mtd/fsmc-nand.txt +0
-0
Documentation/devicetree/bindings/mtd/fsmc-nand.txt Required properties: · line 9
Quoted 4 lines
Documentation/devicetree/bindings/mtd/fsmc-nand.txt +1
-0@@ -6,6 +6,7 @@ Required properties: - reg-names: Should contain the reg names "fsmc_regs" and "nand_data" - st,ale-off : Chip specific offset to ALE - st,cle-off : Chip specific offset to CLE +- maxbanks: Number of banks supported by SoC
make it optionnal will simplify the binding with 1 by default and will allow to avoid issue
Quoted 181 lines
Documentation/devicetree/bindings/mtd/fsmc-nand.txt +1
-0Optional properties: - bank-width : Width (in bytes) of the device. If not present, the width@@ -23,6 +24,7 @@ Example: reg-names = "fsmc_regs", "nand_data"; st,ale-off = <0x20000>; st,cle-off = <0x10000>; + maxbanks = <1>; bank-width = <1>; nand-skip-bbtscan;arch/arm/boot/dts/spear300.dtsi +1
-0@@ -42,6 +42,7 @@ reg-names = "fsmc_regs", "nand_data"; st,ale-off = <0x20000>; st,cle-off = <0x10000>; + maxbanks = <1>; status = "disabled"; };arch/arm/boot/dts/spear310.dtsi +1
-0@@ -36,6 +36,7 @@ reg-names = "fsmc_regs", "nand_data"; st,ale-off = <0x10000>; st,cle-off = <0x20000>; + maxbanks = <1>; status = "disabled"; };arch/arm/boot/dts/spear320.dtsi +1
-0@@ -42,6 +42,7 @@ reg-names = "fsmc_regs", "nand_data"; st,ale-off = <0x20000>; st,cle-off = <0x10000>; + maxbanks = <1>; status = "disabled"; };arch/arm/boot/dts/spear600.dtsi +1
-0@@ -71,6 +71,7 @@ reg-names = "fsmc_regs", "nand_data"; st,ale-off = <0x20000>; st,cle-off = <0x10000>; + maxbanks = <1>; status = "disabled"; };arch/arm/mach-u300/core.c +1
-0@@ -1546,6 +1546,7 @@ static struct fsmc_nand_platform_data nand_platform_data = { .width = FSMC_NAND_BW8, .ale_off = PLAT_NAND_ALE, .cle_off = PLAT_NAND_CLE, + .max_banks = 1, };static struct platform_device nand_device = {drivers/mtd/nand/fsmc_nand.c +18
-8@@ -298,6 +298,7 @@ static struct fsmc_eccplace fsmc_ecc4_sp_place = {* - Word access (CPU) * - None (Use driver default ie bus width specific * CPU access) +* @max_banks: Maximum number of banks supported * @select_chip: Select a particular bank * * @data_pa: NAND Physical port for Data @@ -325,6 +326,7 @@ struct fsmc_nand_data {struct mtd_partition *partitions;unsigned int nr_partitions;enum access_mode mode; +uint32_t max_banks;void (*select_chip)(uint32_t bank,uint32_t busw);/* Virtual/Physical addresses for CPU/DMA access */ @@ -343,6 +345,7 @@ static void fsmc_select_chip(struct mtd_info *mtd, int chipnr) host = container_of(mtd, struct fsmc_nand_data, mtd); + host->bank = chipnr;switch (chipnr) {case -1 : chip->cmd_ctrl (mtd,NAND_CMD_NONE ,0 |NAND_CTRL_CHANGE );@@ -889,6 +892,7 @@ static int __devinit fsmc_nand_probe_config_dt(struct platform_device *pdev,of_property_read_u32 (np,"st,cle-off" , &pdata->cle_off);if (of_get_property (np,"nand-skip-bbtscan" ,NULL )) pdata->options =NAND_SKIP_BBTSCAN ; +of_property_read_u32 (np,"maxbanks" , &pdata->max_banks);return 0 ; }@@ -915,7 +919,7 @@ static int __init fsmc_nand_probe(struct platform_device *pdev)struct resource *res;dma_cap_mask_t mask;int ret =0 ; -u32 pid; +u32 pid, bank;int i;if (np) {@@ -1023,13 +1027,13 @@ static int __init fsmc_nand_probe(struct platform_device *pdev)AMBA_PART_BITS (pid),AMBA_MANF_BITS (pid), AMBA_REV_BITS(pid), AMBA_CONFIG_BITS(pid)); - host->bank = pdata->bank; 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; host->mode = pdata->mode; + host->max_banks = pdata->max_banks;if (host->mode ==USE_DMA_ACCESS )init_completion (&host->dma_access_complete);@@ -1083,9 +1087,10 @@ static int __init fsmc_nand_probe(struct platform_device *pdev)break ; } -fsmc_nand_setup (host->regs_va, host->bank, - nand->options &NAND_BUSWIDTH_16 , - host->dev_timings); +for (bank =0 ; bank < host->max_banks; bank++) +fsmc_nand_setup (host->regs_va, bank, + nand->options &NAND_BUSWIDTH_16 , + host->dev_timings);if (AMBA_REV_BITS (host->pid) >=8 ) { nand->ecc.read_page = fsmc_read_page_hwecc;@@ -1230,11 +1235,16 @@ 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); +uint32_t bank; +if (host) {clk_prepare_enable (host->clk); -fsmc_nand_setup (host->regs_va, host->bank, - host->nand.options &NAND_BUSWIDTH_16 , - host->dev_timings); + +for (bank =0 ; bank < host->max_banks; bank++) +fsmc_nand_setup (host->regs_va, bank, + host->nand.options &NAND_BUSWIDTH_16 , + host->dev_timings); + }return 0 ; }include/linux/mtd/fsmc.h +1
-1@@ -153,7 +153,7 @@ struct fsmc_nand_platform_data {unsigned int nr_partitions;unsigned int options;unsigned int width; -unsigned int bank; +unsigned int max_banks;/* CLE, ALE offsets */ unsigned int cle_off;Signature · 1 line
1.7.11.4
PATCH 3/11 fsmc/nand: Support multiple banks connected to controller
Quoted 5 lines · Jean-Christophe PLAGNIOL-VILLARD
Quoted 3 lines · Vipin Kumar
Support up to
max_banksnumber of banks in fsmc driver.Signed-off-by Vipin Kumar<[email protected]>please rebase this over my patch that drop -off to resource
Sure, I will do that. I actually planned to do it but forgot while sending it
Quoted 11 lines
Quoted 11 lines
--- .../devicetree/bindings/mtd/fsmc-nand.txt | 2 ++ arch/arm/boot/dts/spear300.dtsi | 1 + arch/arm/boot/dts/spear310.dtsi | 1 + arch/arm/boot/dts/spear320.dtsi | 1 + arch/arm/boot/dts/spear600.dtsi | 1 + arch/arm/mach-u300/core.c | 1 + drivers/mtd/nand/fsmc_nand.c | 26 +++++++++++++++------- include/linux/mtd/fsmc.h | 2 +- 8 files changed, 26 insertions(+), 9 deletions(-)
Quoted 12 lines
Documentation/devicetree/bindings/mtd/fsmc-nand.txt Required properties: · line 9
Quoted 9 lines
Documentation/devicetree/bindings/mtd/fsmc-nand.txt +1
-0@@ -6,6 +6,7 @@ Required properties: - reg-names: Should contain the reg names "fsmc_regs" and "nand_data" - st,ale-off : Chip specific offset to ALE - st,cle-off : Chip specific offset to CLE +- maxbanks: Number of banks supported by SoCmake it optionnal will simplify the binding with 1 by default and will allow to avoid issue
hmmm....OK
I think you are right. May be optional with a default of 1 is a better option
Quoted 183 lines
Quoted 179 lines
Documentation/devicetree/bindings/mtd/fsmc-nand.txt +1
-0Optional properties: - bank-width : Width (in bytes) of the device. If not present, the width@@ -23,6 +24,7 @@ Example: reg-names = "fsmc_regs", "nand_data"; st,ale-off =<0x20000>; st,cle-off =<0x10000>; + maxbanks =<1>; bank-width =<1>; nand-skip-bbtscan;arch/arm/boot/dts/spear300.dtsi +1
-0@@ -42,6 +42,7 @@ reg-names = "fsmc_regs", "nand_data"; st,ale-off =<0x20000>; st,cle-off =<0x10000>; + maxbanks =<1>; status = "disabled"; };arch/arm/boot/dts/spear310.dtsi +1
-0@@ -36,6 +36,7 @@ reg-names = "fsmc_regs", "nand_data"; st,ale-off =<0x10000>; st,cle-off =<0x20000>; + maxbanks =<1>; status = "disabled"; };arch/arm/boot/dts/spear320.dtsi +1
-0@@ -42,6 +42,7 @@ reg-names = "fsmc_regs", "nand_data"; st,ale-off =<0x20000>; st,cle-off =<0x10000>; + maxbanks =<1>; status = "disabled"; };arch/arm/boot/dts/spear600.dtsi +1
-0@@ -71,6 +71,7 @@ reg-names = "fsmc_regs", "nand_data"; st,ale-off =<0x20000>; st,cle-off =<0x10000>; + maxbanks =<1>; status = "disabled"; };arch/arm/mach-u300/core.c +1
-0@@ -1546,6 +1546,7 @@ static struct fsmc_nand_platform_data nand_platform_data = { .width = FSMC_NAND_BW8, .ale_off = PLAT_NAND_ALE, .cle_off = PLAT_NAND_CLE, + .max_banks = 1, };static struct platform_device nand_device = {drivers/mtd/nand/fsmc_nand.c +18
-8@@ -298,6 +298,7 @@ static struct fsmc_eccplace fsmc_ecc4_sp_place = {* - Word access (CPU) * - None (Use driver default ie bus width specific * CPU access) +* @max_banks: Maximum number of banks supported * @select_chip: Select a particular bank * * @data_pa: NAND Physical port for Data @@ -325,6 +326,7 @@ struct fsmc_nand_data {struct mtd_partition *partitions;unsigned int nr_partitions;enum access_mode mode; +uint32_t max_banks;void (*select_chip)(uint32_t bank,uint32_t busw);/* Virtual/Physical addresses for CPU/DMA access */ @@ -343,6 +345,7 @@ static void fsmc_select_chip(struct mtd_info *mtd, int chipnr) host = container_of(mtd, struct fsmc_nand_data, mtd); + host->bank = chipnr;switch (chipnr) {case -1 : chip->cmd_ctrl (mtd,NAND_CMD_NONE ,0 |NAND_CTRL_CHANGE );@@ -889,6 +892,7 @@ static int __devinit fsmc_nand_probe_config_dt(struct platform_device *pdev,of_property_read_u32 (np,"st,cle-off" ,&pdata->cle_off);if (of_get_property (np,"nand-skip-bbtscan" ,NULL )) pdata->options =NAND_SKIP_BBTSCAN ; +of_property_read_u32 (np,"maxbanks" ,&pdata->max_banks);return 0 ; }@@ -915,7 +919,7 @@ static int __init fsmc_nand_probe(struct platform_device *pdev)struct resource *res;dma_cap_mask_t mask;int ret =0 ; -u32 pid; +u32 pid, bank;int i;if (np) {@@ -1023,13 +1027,13 @@ static int __init fsmc_nand_probe(struct platform_device *pdev)AMBA_PART_BITS (pid),AMBA_MANF_BITS (pid), AMBA_REV_BITS(pid), AMBA_CONFIG_BITS(pid)); - host->bank = pdata->bank; 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; host->mode = pdata->mode; + host->max_banks = pdata->max_banks;if (host->mode ==USE_DMA_ACCESS )init_completion (&host->dma_access_complete);@@ -1083,9 +1087,10 @@ static int __init fsmc_nand_probe(struct platform_device *pdev)break ; } -fsmc_nand_setup (host->regs_va, host->bank, - nand->options&NAND_BUSWIDTH_16 , - host->dev_timings); +for (bank =0 ; bank< host->max_banks; bank++) +fsmc_nand_setup (host->regs_va, bank, + nand->options&NAND_BUSWIDTH_16 , + host->dev_timings);if (AMBA_REV_BITS (host->pid)>=8 ) { nand->ecc.read_page = fsmc_read_page_hwecc;@@ -1230,11 +1235,16 @@ 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); +uint32_t bank; +if (host) {clk_prepare_enable (host->clk); -fsmc_nand_setup (host->regs_va, host->bank, - host->nand.options&NAND_BUSWIDTH_16 , - host->dev_timings); + +for (bank =0 ; bank< host->max_banks; bank++) +fsmc_nand_setup (host->regs_va, bank, + host->nand.options&NAND_BUSWIDTH_16 , + host->dev_timings); + }return 0 ; }include/linux/mtd/fsmc.h +1
-2@@ -153,7 +153,7 @@ struct fsmc_nand_platform_data {unsigned int nr_partitions;unsigned int options;unsigned int width; -unsigned int bank; +unsigned int max_banks;/* CLE, ALE offsets */ unsigned int cle_off; --Quoted 2 lines
1.7.11.4
.
PATCH 3/11 fsmc/nand: Support multiple banks connected to controller
In reply to Vipin KumarQuoted 3 lines · Vipin Kumar
Support up to
max_banksnumber of banks in fsmc driver.Signed-off-by Vipin Kumar <[email protected]>
I tried to apply this, but it does not apply cleanly to l2-mtd.git, which is based on 3.7-rc1.
Signature · 9 lines
Best Regards, Artem Bityutskiy -------------- next part -------------- A non-text attachment was scrubbed... Name: signature.asc Type: application/pgp-signature Size: 836 bytes Desc: This is a digitally signed message part URL: <http://lists.infradead.org/pipermail/linux-arm-kernel/attachments/20121017/8034920f/attachment.sig>
PATCH 4/11 fsmc/nand: Accept nand timing parameters via DT
In reply to Vipin KumarAdd support to accept nand timing parameters via device tree
--- .../devicetree/bindings/mtd/fsmc-nand.txt | 20 ++++++++ drivers/mtd/nand/fsmc_nand.c | 59 ++++++++++++++-------- include/linux/mtd/fsmc.h | 2 +- 3 files changed, 59 insertions(+), 22 deletions(-)
Documentation/devicetree/bindings/mtd/fsmc-nand.txt +20 -0
@@ -13,6 +13,18 @@ Optional properties: defaults to 1 byte - nand-skip-bbtscan: Indicates the the BBT scanning should be skipped +- nand-timings-enabled: Indicates if the timing parameters are passed + via DT +- nand-timings,tclr: +- nand-timings,tar: +- nand-timings,thiz: +- nand-timings,thold: +- nand-timings,twait: +- nand-timings,tset: All these timing parameters come from the actual + nand device specification. Each of this represents a number of time + period of hclk ie a number 4 in thold with hclk = 166MHz means that + thold = (1000 / 166) * 4 ns = 24.09ns + Example: fsmc: flash at d1800000 {
@@ -26,6 +38,14 @@ Example: st,cle-off = <0x10000>; maxbanks = <1>; + nand-timings-enabled; + nand-timings,tclr = <1>; + nand-timings,tar = <1>; + nand-timings,thiz = <1>; + nand-timings,thold = <4>; + nand-timings,twait = <6>; + nand-timings,tset = <0>; + bank-width = <1>; nand-skip-bbtscan;
drivers/mtd/nand/fsmc_nand.c +38 -21
84 lines not on this page · raw message
include/linux/mtd/fsmc.h +1 -1
@@ -148,7 +148,7 @@ enum access_mode {* this may be set to NULL */ struct fsmc_nand_platform_data { -struct fsmc_nand_timings *nand_timings; +struct fsmc_nand_timings nand_timings;struct mtd_partition *partitions;unsigned int nr_partitions;unsigned int options;
Signature · 1 line
1.7.11.4
PATCH 4/11 fsmc/nand: Accept nand timing parameters via DT
Quoted 101 lines · Vipin Kumar
Add support to accept nand timing parameters via device tree
Signed-off-by Vipin Kumar <[email protected]>--- .../devicetree/bindings/mtd/fsmc-nand.txt | 20 ++++++++ drivers/mtd/nand/fsmc_nand.c | 59 ++++++++++++++-------- include/linux/mtd/fsmc.h | 2 +- 3 files changed, 59 insertions(+), 22 deletions(-)Documentation/devicetree/bindings/mtd/fsmc-nand.txt +20
-0@@ -13,6 +13,18 @@ Optional properties: defaults to 1 byte - nand-skip-bbtscan: Indicates the the BBT scanning should be skipped +- nand-timings-enabled: Indicates if the timing parameters are passed + via DT +- nand-timings,tclr: +- nand-timings,tar: +- nand-timings,thiz: +- nand-timings,thold: +- nand-timings,twait: +- nand-timings,tset: All these timing parameters come from the actual + nand device specification. Each of this represents a number of time + period of hclk ie a number 4 in thold with hclk = 166MHz means that + thold = (1000 / 166) * 4 ns = 24.09ns + Example: fsmc: flash at d1800000 {@@ -26,6 +38,14 @@ Example: st,cle-off = <0x10000>; maxbanks = <1>; + nand-timings-enabled; + nand-timings,tclr = <1>; + nand-timings,tar = <1>; + nand-timings,thiz = <1>; + nand-timings,thold = <4>; + nand-timings,twait = <6>; + nand-timings,tset = <0>; + bank-width = <1>; nand-skip-bbtscan;drivers/mtd/nand/fsmc_nand.c +14
-20@@ -415,27 +415,13 @@ static void fsmc_nand_setup(void __iomem *regs, uint32_t bank, {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 ; + tclr = (timings->tclr &FSMC_TCLR_MASK ) <<FSMC_TCLR_SHIFT ; + tar = (timings->tar &FSMC_TAR_MASK ) <<FSMC_TAR_SHIFT ; + thiz = (timings->thiz &FSMC_THIZ_MASK ) <<FSMC_THIZ_SHIFT ; + thold = (timings->thold &FSMC_THOLD_MASK ) <<FSMC_THOLD_SHIFT ; + twait = (timings->twait &FSMC_TWAIT_MASK ) <<FSMC_TWAIT_SHIFT ; + tset = (timings->tset &FSMC_TSET_MASK ) <<FSMC_TSET_SHIFT ;if (busw)writel (value |FSMC_DEVWID_16 ,FSMC_NAND_REG (regs, bank,PC ));@@ -876,6 +862,14 @@ static int __devinit fsmc_nand_probe_config_dt(struct platform_device *pdev, struct device_node *np) {struct fsmc_nand_platform_data *pdata =dev_get_platdata (&pdev->dev); +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 , + };u32 val;/* Set default NAND width to 8 bits */
drivers/mtd/nand/fsmc_nand.c static int __devinit fsmc_nand_probe_config_dt(struct platform_device *pdev, · line 893
Quoted 6 lines
drivers/mtd/nand/fsmc_nand.c +3
-0@@ -894,6 +888,29 @@ static int __devinit fsmc_nand_probe_config_dt(struct platform_device *pdev, pdata->options =NAND_SKIP_BBTSCAN ;of_property_read_u32 (np,"maxbanks" , &pdata->max_banks); +if (of_property_read_bool (np,"nand-timings-enabled" )) { +of_property_read_u32 (np,"nand-timings,tclr" , &val); + pdata->nand_timings.tclr = (uint8_t )val;
use a mask will be better
Quoted 48 lines
drivers/mtd/nand/fsmc_nand.c +21
-1+ +of_property_read_u32 (np,"nand-timings,tar" , &val); + pdata->nand_timings.tar = (uint8_t )val; + +of_property_read_u32 (np,"nand-timings,thiz" , &val); + pdata->nand_timings.thiz = (uint8_t )val; + +of_property_read_u32 (np,"nand-timings,thold" , &val); + pdata->nand_timings.thold = (uint8_t )val; + +of_property_read_u32 (np,"nand-timings,twait" , &val); + pdata->nand_timings.twait = (uint8_t )val; + +of_property_read_u32 (np,"nand-timings,tset" , &val); + pdata->nand_timings.tset = (uint8_t)val; + }else { +memcpy (&pdata->nand_timings, &default_timings, +sizeof (default_timings)); + } +return 0 ; }#else @@ -1031,7 +1048,7 @@ static int __init fsmc_nand_probe(struct platform_device *pdev) host->partitions = pdata->partitions; host->nr_partitions = pdata->nr_partitions; host->dev = &pdev->dev; - host->dev_timings = pdata->nand_timings; + host->dev_timings = &pdata->nand_timings; host->mode = pdata->mode; host->max_banks = pdata->max_banks;include/linux/mtd/fsmc.h +1
-1@@ -148,7 +148,7 @@ enum access_mode {* this may be set to NULL */ struct fsmc_nand_platform_data { -struct fsmc_nand_timings *nand_timings; +struct fsmc_nand_timings nand_timings;struct mtd_partition *partitions;unsigned int nr_partitions;unsigned int options;Signature · 1 line
1.7.11.4
PATCH 4/11 fsmc/nand: Accept nand timing parameters via DT
Quoted 105 lines · Jean-Christophe PLAGNIOL-VILLARD
Quoted 104 lines · Vipin Kumar
Add support to accept nand timing parameters via device tree
Signed-off-by Vipin Kumar<[email protected]>--- .../devicetree/bindings/mtd/fsmc-nand.txt | 20 ++++++++ drivers/mtd/nand/fsmc_nand.c | 59 ++++++++++++++-------- include/linux/mtd/fsmc.h | 2 +- 3 files changed, 59 insertions(+), 22 deletions(-)Documentation/devicetree/bindings/mtd/fsmc-nand.txt +20
-0@@ -13,6 +13,18 @@ Optional properties: defaults to 1 byte - nand-skip-bbtscan: Indicates the the BBT scanning should be skipped +- nand-timings-enabled: Indicates if the timing parameters are passed + via DT +- nand-timings,tclr: +- nand-timings,tar: +- nand-timings,thiz: +- nand-timings,thold: +- nand-timings,twait: +- nand-timings,tset: All these timing parameters come from the actual + nand device specification. Each of this represents a number of time + period of hclk ie a number 4 in thold with hclk = 166MHz means that + thold = (1000 / 166) * 4 ns = 24.09ns + Example: fsmc: flash at d1800000 {@@ -26,6 +38,14 @@ Example: st,cle-off =<0x10000>; maxbanks =<1>; + nand-timings-enabled; + nand-timings,tclr =<1>; + nand-timings,tar =<1>; + nand-timings,thiz =<1>; + nand-timings,thold =<4>; + nand-timings,twait =<6>; + nand-timings,tset =<0>; + bank-width =<1>; nand-skip-bbtscan;drivers/mtd/nand/fsmc_nand.c +14
-20@@ -415,27 +415,13 @@ static void fsmc_nand_setup(void __iomem *regs, uint32_t bank, {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 ; + tclr = (timings->tclr&FSMC_TCLR_MASK )<<FSMC_TCLR_SHIFT ; + tar = (timings->tar&FSMC_TAR_MASK )<<FSMC_TAR_SHIFT ; + thiz = (timings->thiz&FSMC_THIZ_MASK )<<FSMC_THIZ_SHIFT ; + thold = (timings->thold&FSMC_THOLD_MASK )<<FSMC_THOLD_SHIFT ; + twait = (timings->twait&FSMC_TWAIT_MASK )<<FSMC_TWAIT_SHIFT ; + tset = (timings->tset&FSMC_TSET_MASK )<<FSMC_TSET_SHIFT ;if (busw)writel (value |FSMC_DEVWID_16 ,FSMC_NAND_REG (regs, bank,PC ));@@ -876,6 +862,14 @@ static int __devinit fsmc_nand_probe_config_dt(struct platform_device *pdev, struct device_node *np) {struct fsmc_nand_platform_data *pdata =dev_get_platdata (&pdev->dev); +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 , + };u32 val;/* Set default NAND width to 8 bits */ @@ -894,6 +888,29 @@ static int __devinit fsmc_nand_probe_config_dt(struct platform_device *pdev, pdata->options =NAND_SKIP_BBTSCAN ;of_property_read_u32 (np,"maxbanks" ,&pdata->max_banks);
Quoted 4 lines
drivers/mtd/nand/fsmc_nand.c static int __devinit fsmc_nand_probe_config_dt(struct platform_device *pdev, · line 893
Quoted 3 lines
drivers/mtd/nand/fsmc_nand.c +3
-0+if (of_property_read_bool (np,"nand-timings-enabled" )) { +of_property_read_u32 (np,"nand-timings,tclr" ,&val); + pdata->nand_timings.tclr = (uint8_t )val;use a mask will be better
OK, will add a mask in v2
Quoted 50 lines
Quoted 46 lines
drivers/mtd/nand/fsmc_nand.c +21
-1+ +of_property_read_u32 (np,"nand-timings,tar" ,&val); + pdata->nand_timings.tar = (uint8_t )val; + +of_property_read_u32 (np,"nand-timings,thiz" ,&val); + pdata->nand_timings.thiz = (uint8_t )val; + +of_property_read_u32 (np,"nand-timings,thold" ,&val); + pdata->nand_timings.thold = (uint8_t )val; + +of_property_read_u32 (np,"nand-timings,twait" ,&val); + pdata->nand_timings.twait = (uint8_t )val; + +of_property_read_u32 (np,"nand-timings,tset" ,&val); + pdata->nand_timings.tset = (uint8_t)val; + }else { +memcpy (&pdata->nand_timings,&default_timings, +sizeof (default_timings)); + } +return 0 ; }#else @@ -1031,7 +1048,7 @@ static int __init fsmc_nand_probe(struct platform_device *pdev) host->partitions = pdata->partitions; host->nr_partitions = pdata->nr_partitions; host->dev =&pdev->dev; - host->dev_timings = pdata->nand_timings; + host->dev_timings =&pdata->nand_timings; host->mode = pdata->mode; host->max_banks = pdata->max_banks;include/linux/mtd/fsmc.h +1
-2@@ -148,7 +148,7 @@ enum access_mode {* this may be set to NULL */ struct fsmc_nand_platform_data { -struct fsmc_nand_timings *nand_timings; +struct fsmc_nand_timings nand_timings;struct mtd_partition *partitions;unsigned int nr_partitions;unsigned int options; --Quoted 2 lines
1.7.11.4
.
PATCH 4/11 fsmc/nand: Accept nand timing parameters via DT
In reply to Vipin KumarDocumentation/devicetree/bindings/mtd/fsmc-nand.txt Optional properties: · line 26
Quoted 13 lines · Vipin Kumar
Documentation/devicetree/bindings/mtd/fsmc-nand.txt +11
-0+- nand-timings-enabled: Indicates if the timing parameters are passed + via DT +- nand-timings,tclr: +- nand-timings,tar: +- nand-timings,thiz: +- nand-timings,thold: +- nand-timings,twait: +- nand-timings,tset: All these timing parameters come from the actual + nand device specification. Each of this represents a number of time + period of hclk ie a number 4 in thold with hclk = 166MHz means that + thold = (1000 / 166) * 4 ns = 24.09ns
Are they specific to fsmc controller or nand memory type? If to fsmc then please add my
else
I would suggest to add these to mtd bindings instead, so that same fields can be used by multiple drivers....
Similar approach is used for mmc controllers too.
PATCH 5/11 fsmc: Implement ready/busy through gpio pin
In reply to Vipin KumarThe NAND devices have a ready/busy (active low) output which is connected to the FSMC controller FSMC_RnB pin
The CPU can work in following two ways
* CPU keeps waiting for a ready response and it halts until it receives a ready response from NAND device. This halts the ldr instruction in between and in effect holds the CPU down for a number of cycles. During this period, CPU can't even service interrupts. This behavior is enabled via WAIT_ON bit of FSMC controller
* CPU merely issues the command and does not wait for response. The NAND device is later probed for being ready by reading the NAND_RnB signal
Until now, WAIT_ON was enabled by default. This patch implements reading the device ready state through a gpio. The gpio number is passed via DT and this patch also adds a corresponding binding for fsmc
--- .../devicetree/bindings/mtd/fsmc-nand.txt | 5 ++ drivers/mtd/nand/fsmc_nand.c | 54 +++++++++++++++++++--- include/linux/mtd/fsmc.h | 11 +++++ 3 files changed, 64 insertions(+), 6 deletions(-)
Documentation/devicetree/bindings/mtd/fsmc-nand.txt +5 -0
@@ -25,6 +25,11 @@ Optional properties: period of hclk ie a number 4 in thold with hclk = 166MHz means that thold = (1000 / 166) * 4 ns = 24.09ns +- st,ready-busy: Should contain either of "rb-gpio" or "rb-wait". When + this property is not defined, the default is to use rb-wait. +- st,rb-gpios: When the st,ready-busy is defined as "rb-gpio", a gpio + pin number is defined in this property + Example: fsmc: flash at d1800000 {
drivers/mtd/nand/fsmc_nand.c +48 -6
136 lines not on this page · raw message
include/linux/mtd/fsmc.h +11 -0
@@ -130,6 +130,16 @@ struct fsmc_nand_timings {uint8_t tset; }; +enum rbpin { +FSMC_RB_WAIT =0 , +FSMC_RB_GPIO , +}; + +struct fsmc_rbpin { +enum rbpin use_pin; +uint32_t gpio_pin; +}; +enum access_mode {USE_DMA_ACCESS =1 ,USE_WORD_ACCESS ,
@@ -149,6 +159,7 @@ enum access_mode {*/ struct fsmc_nand_platform_data {struct fsmc_nand_timings nand_timings; +struct fsmc_rbpin rbpin;struct mtd_partition *partitions;unsigned int nr_partitions;unsigned int options;
Signature · 1 line
1.7.11.4
PATCH 5/11 fsmc: Implement ready/busy through gpio pin
Quoted 214 lines · Vipin Kumar
The NAND devices have a ready/busy (active low) output which is connected to the FSMC controller
FSMC_RnBpinThe CPU can work in following two ways
* CPU keeps waiting for a ready response and it halts until it receives a ready response from NAND device. This halts the ldr instruction in between and in effect holds the CPU down for a number of cycles. During this period, CPU can't even service interrupts. This behavior is enabled viaWAIT_ONbit of FSMC controller
* CPU merely issues the command and does not wait for response. The NAND device is later probed for being ready by reading theNAND_RnBsignalUntil now,
WAIT_ONwas enabled by default. This patch implements reading the device ready state through a gpio. The gpio number is passed via DT and this patch also adds a corresponding binding for fsmcSigned-off-by Vipin Kumar <[email protected]>--- .../devicetree/bindings/mtd/fsmc-nand.txt | 5 ++ drivers/mtd/nand/fsmc_nand.c | 54 +++++++++++++++++++--- include/linux/mtd/fsmc.h | 11 +++++ 3 files changed, 64 insertions(+), 6 deletions(-)Documentation/devicetree/bindings/mtd/fsmc-nand.txt +5
-0@@ -25,6 +25,11 @@ Optional properties: period of hclk ie a number 4 in thold with hclk = 166MHz means that thold = (1000 / 166) * 4 ns = 24.09ns +- st,ready-busy: Should contain either of "rb-gpio" or "rb-wait". When + this property is not defined, the default is to use rb-wait. +- st,rb-gpios: When the st,ready-busy is defined as "rb-gpio", a gpio + pin number is defined in this property + Example: fsmc: flash at d1800000 {drivers/mtd/nand/fsmc_nand.c +48
-6@@ -22,6 +22,7 @@#include <linux/dma-direction.h> #include <linux/dma-mapping.h> #include <linux/err.h> +#include <linux/gpio.h> #include <linux/init.h> #include <linux/module.h> #include <linux/resource.h> @@ -32,6 +33,7 @@#include <linux/mtd/nand_ecc.h> #include <linux/platform_device.h> #include <linux/of.h> +#include <linux/of_gpio.h> #include <linux/mtd/partitions.h> #include <linux/io.h> #include <linux/slab.h> @@ -289,6 +291,7 @@ static struct fsmc_eccplace fsmc_ecc4_sp_place = {* @write_dma_chan: DMA channel for write access to NAND * @dma_access_complete: Completion structure * +* @rb_pin: Ready/Busy data * @dev_timings: Timings to be programmed in controller * @partitions: Partition info for a NAND Flash * @nr_partitions: Total number of partition of a NAND flash @@ -322,6 +325,7 @@ struct fsmc_nand_data {struct completion dma_access_complete;/* Recieved from plat data */ +struct fsmc_rbpin *rbpin;struct fsmc_nand_timings *dev_timings;struct mtd_partition *partitions;unsigned int nr_partitions;@@ -410,12 +414,16 @@ 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 (void __iomem *regs,uint32_t bank, -uint32_t busw,struct fsmc_nand_timings *timings) +static void fsmc_nand_setup (void __iomem *regs,uint32_t bank,uint32_t busw, +struct fsmc_nand_timings *timings, +struct fsmc_rbpin *rbpin) { -uint32_t value =FSMC_DEVTYPE_NAND |FSMC_ENABLE |FSMC_WAITON ; +uint32_t value =FSMC_DEVTYPE_NAND |FSMC_ENABLE ;uint32_t tclr, tar, thiz, thold, twait, tset; +if (!rbpin || (rbpin->use_pin ==FSMC_RB_WAIT )) + value |=FSMC_WAITON ; + tclr = (timings->tclr &FSMC_TCLR_MASK ) <<FSMC_TCLR_SHIFT ; tar = (timings->tar &FSMC_TAR_MASK ) <<FSMC_TAR_SHIFT ; thiz = (timings->thiz &FSMC_THIZ_MASK ) <<FSMC_THIZ_SHIFT ;@@ -857,6 +865,14 @@ static bool filter(struct dma_chan *chan, void *slave)return true; } +static int fsmc_dev_ready (struct mtd_info *mtd) +{ +struct fsmc_nand_data *host =container_of (mtd, + struct fsmc_nand_data, mtd); + +return !!gpio_get_value (host->rbpin->gpio_pin); +} +#ifdef CONFIG_OF static int __devinit fsmc_nand_probe_config_dt (struct platform_device *pdev,struct device_node *np)@@ -870,7 +886,9 @@ static int __devinit fsmc_nand_probe_config_dt(struct platform_device *pdev, .twait = FSMC_TWAIT_6, .tset = FSMC_TSET_0, }; +const char *rb;u32 val; +enum of_gpio_flags flags;/* Set default NAND width to 8 bits */ pdata->width =8 ;@@ -911,6 +929,14 @@ static int __devinit fsmc_nand_probe_config_dt(struct platform_device *pdev, sizeof(default_timings)); } +if (!of_property_read_string (np,"st,ready-busy" , &rb) && + !strcmp (rb,"rb-gpio" )) { + pdata->rbpin.use_pin =FSMC_RB_GPIO ; + pdata->rbpin.gpio_pin = +of_get_named_gpio_flags (np,"st,rb-gpios" ,0 , &flags); + }else + pdata->rbpin.use_pin =FSMC_RB_WAIT ; +return 0 ; }#else @@ -1049,6 +1075,8 @@ 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->rbpin = &pdata->rbpin; + host->mode = pdata->mode; host->max_banks = pdata->max_banks;@@ -1074,6 +1102,18 @@ static int __init fsmc_nand_probe(struct platform_device *pdev) nand->select_chip = fsmc_select_chip; nand->badblockbits =7 ; +if (host->rbpin->use_pin !=FSMC_RB_WAIT ) + nand->dev_ready = fsmc_dev_ready; + +if (host->rbpin->use_pin ==FSMC_RB_GPIO ) { + ret =gpio_request (host->rbpin->gpio_pin,"fsmc-rb" ); +if (ret <0 ) { +dev_err (&pdev->dev,"gpio request fail: %d\n" , + host->rbpin->gpio_pin); + goto err_gpio_req; + } + } +if (pdata->width ==FSMC_NAND_BW16 ) nand->options |=NAND_BUSWIDTH_16 ;@@ -1107,7 +1147,7 @@ static int __init fsmc_nand_probe(struct platform_device *pdev)for (bank =0 ; bank < host->max_banks; bank++)fsmc_nand_setup (host->regs_va, bank, nand->options &NAND_BUSWIDTH_16 , - host->dev_timings); + host->dev_timings, host->rbpin);if (AMBA_REV_BITS (host->pid) >=8 ) { nand->ecc.read_page = fsmc_read_page_hwecc;@@ -1211,6 +1251,9 @@ err_req_write_chnl:if (host->mode ==USE_DMA_ACCESS )dma_release_channel (host->read_dma_chan); err_req_read_chnl: +if (host->rbpin->use_pin ==FSMC_RB_GPIO ) +gpio_free (host->rbpin->gpio_pin); +err_gpio_req:clk_disable_unprepare (host->clk); err_clk_prepare_enable:clk_put (host->clk);@@ -1260,8 +1303,7 @@ static int fsmc_nand_resume(struct device *dev)for (bank =0 ; bank < host->max_banks; bank++)fsmc_nand_setup (host->regs_va, bank, host->nand.options &NAND_BUSWIDTH_16 , - host->dev_timings); - + host->dev_timings, host->rbpin); }return 0 ; }include/linux/mtd/fsmc.h +10
-0@@ -130,6 +130,16 @@ struct fsmc_nand_timings {uint8_t tset; }; +enum rbpin { +FSMC_RB_WAIT =0 , +FSMC_RB_GPIO , +}; + +struct fsmc_rbpin { +enum rbpin use_pin; +uint32_t gpio_pin; +}; +enum access_mode {USE_DMA_ACCESS =1 ,USE_WORD_ACCESS ,
include/linux/mtd/fsmc.h enum access_mode { · line 162
Quoted 4 lines
include/linux/mtd/fsmc.h +1
-0@@ -149,6 +159,7 @@ enum access_mode {*/ struct fsmc_nand_platform_data {struct fsmc_nand_timings nand_timings; +struct fsmc_rbpin rbpin;
do more simple
int rbpin; and set it as -EINVAL to use RB_WAIT
so in the binding if you do not specifcy a gpio or a valid one we switch to wait
Best Regards,
J.
PATCH 5/11 fsmc: Implement ready/busy through gpio pin
In reply to Vipin KumarDocumentation/devicetree/bindings/mtd/fsmc-nand.txt Optional properties: · line 31
Quoted 5 lines · Vipin Kumar
Documentation/devicetree/bindings/mtd/fsmc-nand.txt +4
-0+- st,ready-busy: Should contain either of "rb-gpio" or "rb-wait". When + this property is not defined, the default is to use rb-wait. +- st,rb-gpios: When the st,ready-busy is defined as "rb-gpio", a gpio + pin number is defined in this property
Why st,*** maybe fsmc,***?
Would be better if you update the example too in this file.
drivers/mtd/nand/fsmc_nand.c struct fsmc_nand_data { · line 328
Quoted 5 lines
drivers/mtd/nand/fsmc_nand.c +2
-0+ * @rb_pin: Ready/Busy data +struct fsmc_rbpin *rbpin;
comment variable mismatch :(
drivers/mtd/nand/fsmc_nand.c static void fsmc_cmd_ctrl(struct mtd_info *mtd, int cmd, unsigned int ctrl) · line 419
Quoted 5 lines
drivers/mtd/nand/fsmc_nand.c +3
-2-static void fsmc_nand_setup (void __iomem *regs,uint32_t bank, -uint32_t busw,struct fsmc_nand_timings *timings) +static void fsmc_nand_setup (void __iomem *regs,uint32_t bank,uint32_t busw, +struct fsmc_nand_timings *timings, +struct fsmc_rbpin *rbpin)
Can function prototype come in two lines instead of three?
drivers/mtd/nand/fsmc_nand.c static int __init fsmc_nand_probe(struct platform_device *pdev) · line 1115
Quoted 10 lines
drivers/mtd/nand/fsmc_nand.c +8
-0@@ -1049,6 +1075,8 @@ static int __init fsmc_nand_probe(struct platform_device *pdev) +if (host->rbpin->use_pin ==FSMC_RB_GPIO ) { + ret =gpio_request (host->rbpin->gpio_pin,"fsmc-rb" ); +if (ret <0 ) { +dev_err (&pdev->dev,"gpio request fail: %d\n" , + host->rbpin->gpio_pin); + goto err_gpio_req; + } + }
Don't you want to set its direction to input?
PATCH 6/11 fsmc/nand: Modify the wait to uninterruptible
In reply to Vipin KumarInterruptible wait caused trouble in fsmc hardware state machine if the application was killed abruptly. To make fsmc operation safe turn wait in to un-interruptible.
--- drivers/mtd/nand/fsmc_nand.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-)
drivers/mtd/nand/fsmc_nand.c +1 -1
@@ -607,7 +607,7 @@ static int dma_xfer(struct fsmc_nand_data *host, void *buffer, int len,dma_async_issue_pending (chan); ret = -wait_for_completion_interruptible_timeout (&host->dma_access_complete, +wait_for_completion_timeout (&host->dma_access_complete,msecs_to_jiffies (3000 ));if (ret <=0 ) { chan->device->device_control (chan,DMA_TERMINATE_ALL ,0 );
Signature · 1 line
1.7.11.4
PATCH 6/11 fsmc/nand: Modify the wait to uninterruptible
Quoted 5 lines · Vipin Kumar
Interruptible wait caused trouble in fsmc hardware state machine if the application was killed abruptly. To make fsmc operation safe turn wait in to un-interruptible.
Signed-off-by Vipin Kumar <[email protected]>
Yes this is wise.
Yours,
Linus Walleij
PATCH 6/11 fsmc/nand: Modify the wait to uninterruptible
In reply to Vipin KumarQuoted 5 lines · Vipin Kumar
Interruptible wait caused trouble in fsmc hardware state machine if the application was killed abruptly. To make fsmc operation safe turn wait in to un-interruptible.
Signed-off-by Vipin Kumar <[email protected]>
Pushed this one to l2-mtd.git, thanks!
Signature · 9 lines
Best Regards, Artem Bityutskiy -------------- next part -------------- A non-text attachment was scrubbed... Name: signature.asc Type: application/pgp-signature Size: 836 bytes Desc: This is a digitally signed message part URL: <http://lists.infradead.org/pipermail/linux-arm-kernel/attachments/20121017/59249ec7/attachment-0001.sig>
PATCH 7/11 fsmc/nand: Provide contiguous buffers to dma
In reply to Vipin Kumarread_buf/write_buf callbacks should be able to accept a user space memory address (virtually contiguous memory) as buffer pointer.
This patch allocates a logically contiguous memory area which is use for dma xfers during read and write accesses.
--- drivers/mtd/nand/fsmc_nand.c | 17 +++++++++++++++-- 1 file changed, 15 insertions(+), 2 deletions(-)
drivers/mtd/nand/fsmc_nand.c +15 -2
@@ -323,6 +323,7 @@ struct fsmc_nand_data {struct dma_chan *read_dma_chan;struct dma_chan *write_dma_chan;struct completion dma_access_complete; +void *dma_buf;/* Recieved from plat data */ struct fsmc_rbpin *rbpin;
@@ -675,7 +676,8 @@ 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 ); +dma_xfer (host, host->dma_buf, len,DMA_FROM_DEVICE ); +memcpy (buf, (const void *)host->dma_buf, len); }/*
@@ -690,7 +692,8 @@ static void fsmc_write_buf_dma(struct mtd_info *mtd, const uint8_t *buf,struct fsmc_nand_data *host; host = container_of(mtd, struct fsmc_nand_data, mtd); -dma_xfer (host, (void *)buf, len,DMA_TO_DEVICE ); +memcpy (host->dma_buf, buf, len); +dma_xfer (host, host->dma_buf, len,DMA_TO_DEVICE ); }/*
@@ -1133,6 +1136,13 @@ static int __init fsmc_nand_probe(struct platform_device *pdev)dev_err (&pdev->dev,"Unable to get write dma channel\n" ); goto err_req_write_chnl; } + + host->dma_buf =kmalloc (NAND_MAX_PAGESIZE +NAND_MAX_OOBSIZE , +GFP_KERNEL ); +if (!host->dma_buf) { +dev_err (&pdev->dev,"failed to allocate dma buffer\n" ); + goto err_req_dma_buf; + } nand->read_buf = fsmc_read_buf_dma; nand->write_buf = fsmc_write_buf_dma;break ;
@@ -1246,6 +1256,9 @@ static int __init fsmc_nand_probe(struct platform_device *pdev) err_probe: err_scan_ident:if (host->mode ==USE_DMA_ACCESS ) +kfree (host->dma_buf); +err_req_dma_buf: +if (host->mode ==USE_DMA_ACCESS )dma_release_channel (host->write_dma_chan); err_req_write_chnl:if (host->mode ==USE_DMA_ACCESS )
Signature · 1 line
1.7.11.4
PATCH 7/11 fsmc/nand: Provide contiguous buffers to dma
drivers/mtd/nand/fsmc_nand.c static void fsmc_read_buf_dma(struct mtd_info *mtd, uint8_t *buf, int len) · line 680
Quoted 8 lines · Vipin Kumar
drivers/mtd/nand/fsmc_nand.c +2
-1@@ -675,7 +676,8 @@ 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 ); +dma_xfer (host, host->dma_buf, len,DMA_FROM_DEVICE ); +memcpy (buf, (const void *)host->dma_buf, len);
Ahh.. Too much overhead. Can't you do something better here?
- DMA can be done to user buffers too, Pratyush has done some work in past on this.
- There must be some other way of sharing kernel buffer to user space.
--
viresh
PATCH 7/11 fsmc/nand: Provide contiguous buffers to dma
In reply to Vipin KumarQuoted 4 lines · Vipin Kumar
read_buf/write_buf callbacks should be able to accept a user space memory address (virtually contiguous memory) as buffer pointer.
This patch allocates a logically contiguous memory area which is use for dma
You mean PHYSICALLY contigous, don't you?
Quoted 3 lines
xfers during read and write accesses.
Signed-off-by Vipin Kumar <[email protected]>
If you really want a physically contigous buffer you need to use CMA, but I don't think that is the real problem here...
We're already using userspace buffers in e.g. the MMCI driver (drivers/mmc/host/mmci.c).
The real problem is likely the DMA driver. The stuf that get fed into dma.device_prep_dma_memcpy() needs to be converted to a scatterlist and then set up in the LLI list for the controller.
IIRC SPEAr is using drivers/dma/dw_dmac.c so
check this driver's dwc_prep_dma_memcpy().
It does seem like it is checking whether src or
dest is scattered in this for() loop:
for (offset = 0; offset < len; offset += xfer_count << src_width) {}
dma_sync_single_for_device() is translating the virtual address to physical for every chunk BTW.
So instead of doing this copying, debug the problem, and see if there is a bug in that for()-loop or similar, if it needs to be rewritten or so.
Yours,
Linus Walleij
PATCH 7/11 fsmc/nand: Provide contiguous buffers to dma
Quoted 6 lines · Linus Walleij
The real problem is likely the DMA driver. The stuf that get fed into
dma.device_prep_dma_memcpy()needs to be converted to a scatterlist and then set up in the LLI list for the controller.IIRC SPEAr is using
drivers/dma/dw_dmac.cso
Both dw_dmac and pl080 for different SPEAr SoC's.
Quoted 4 lines
check this driver's
dwc_prep_dma_memcpy().
It does seem like it is checking whether src or
dest is scattered in thisfor()loop:
Quoted 8 lines
for (offset = 0; offset < len; offset +=
xfer_count<<src_width) {}
dma_sync_single_for_device()is translating the virtual address to physical for every chunk BTW.So instead of doing this copying, debug the problem, and see if there is a bug in that for()-loop or similar, if it needs to be rewritten or so.
But what's the problem you saw vipin, for which you generated this patch?
PATCH 7/11 fsmc/nand: Provide contiguous buffers to dma
Quoted 20 lines · viresh kumar
Quoted 6 lines · Linus Walleij
The real problem is likely the DMA driver. The stuf that get fed into
dma.device_prep_dma_memcpy()needs to be converted to a scatterlist and then set up in the LLI list for the controller.IIRC SPEAr is using
drivers/dma/dw_dmac.csoBoth
dw_dmacand pl080 for different SPEAr SoC's.Quoted 9 lines
check this driver's
dwc_prep_dma_memcpy().
It does seem like it is checking whether src or
dest is scattered in thisfor()loop:for (offset = 0; offset< len; offset += xfer_count<<
src_width) {}
dma_sync_single_for_device()is translating the virtual address to physical for every chunk BTW.
Quoted 7 lines
Quoted 3 lines
So instead of doing this copying, debug the problem, and see if there is a bug in that for()-loop or similar, if it needs to be rewritten or so.
But what's the problem you saw vipin, for which you generated this patch? .
The nand tests were failing and that was because of a user pointer being passed to them but it was a long time back and this patch just carried on in the local repo. It is only now that I am sending it
It seems may be the dma drivers also got updated so it needs another test cycle it. I will do the needful and re-reply back on this mail
Vipin
PATCH 7/11 fsmc/nand: Provide contiguous buffers to dma
In reply to Linus WalleijQuoted 9 lines · Linus Walleij
Quoted 4 lines · Vipin Kumar
read_buf/write_buf callbacks should be able to accept a user space memory address (virtually contiguous memory) as buffer pointer.
This patch allocates a logically contiguous memory area which is use for dma
You mean PHYSICALLY contigous, don't you?
Yes Sorry for that :)
Quoted 20 lines
Quoted 3 lines
xfers during read and write accesses.
Signed-off-by Vipin Kumar<[email protected]>If you really want a physically contigous buffer you need to use CMA, but I don't think that is the real problem here...
We're already using userspace buffers in e.g. the MMCI driver (
drivers/mmc/host/mmci.c).The real problem is likely the DMA driver. The stuf that get fed into
dma.device_prep_dma_memcpy()needs to be converted to a scatterlist and then set up in the LLI list for the controller.IIRC SPEAr is using
drivers/dma/dw_dmac.cso
check this driver'sdwc_prep_dma_memcpy().
It does seem like it is checking whether src or
dest is scattered in thisfor()loop:
Quoted 9 lines
for (offset = 0; offset< len; offset += xfer_count<<
src_width) {}
dma_sync_single_for_device()is translating the virtual address to physical for every chunk BTW.So instead of doing this copying, debug the problem, and see if there is a bug in that for()-loop or similar, if it needs to be rewritten or so.
I would debug again and reply to this mail soon
Quoted 4 lines
Yours,
Linus Walleij
.
PATCH 7/11 fsmc/nand: Provide contiguous buffers to dma
In reply to Linus WalleijQuoted 12 lines · Linus Walleij
On Tue, Oct 9, 2012 at 12:44 PM, Vipin Kumar <[email protected]> wrote:
The real problem is likely the DMA driver. The stuf that get fed into
dma.device_prep_dma_memcpy()needs to be converted to a scatterlist and then set up in the LLI list for the controller.IIRC SPEAr is using
drivers/dma/dw_dmac.cso
check this driver'sdwc_prep_dma_memcpy().
It does seem like it is checking whether src or
dest is scattered in thisfor()loop:
Quoted 4 lines
for (offset = 0; offset < len; offset +=
xfer_count<<src_width) {}
dma_sync_single_for_device()is translating the virtual address to physical for every chunk BTW.
I pray that i am wrong here, otherwise i would be thrown out from the maintainers list for this driver :)
dma_sync_single_for_device() is not doing anything on the buffer, but on the LLI item. Actually it is flushing LLI struct so that DMA h/w can get the correct values.
dwc_prep_dma_memcpy() doesn't expect a virtual address, look at type of src & dest bufs: dma_addr_t. It is responsibility of user drivers to pass physically contiguous address to it.
--
viresh
PATCH 7/11 fsmc/nand: Provide contiguous buffers to dma
Quoted 6 lines · viresh kumar
Quoted 2 lines · Linus Walleij
dma_sync_single_for_device()is translating the virtual address to physical for every chunk BTW.
Quoted 6 lines
I pray that i am wrong here, otherwise i would be thrown out from the maintainers list for this driver :)
dma_sync_single_for_device()is not doing anything on the buffer, but on the LLI item. Actually it is flushing LLI struct so that DMA h/w can get the correct values.
Sorry no, I'm the one who's wrong...
So the DMA engine memcpy() is not mapping virt->phys but expects physical addresses to be provided.
So dma_map_single() needs to be called on the stuff passed in to dev->device_prep_dma_memcpy().
And currently there is indeed a dma_map_single() in dma_xfer() in fsmc_nand.c which should work just fine.
dma_map_single() will only work if the buffer is physically contiguous.
And the block layer of the subsystem should take care of only handing the driver buffers that are contiguous I think? Not that I'm an expert here ... more some guesswork :-/
Artem will know I hope!
Yours,
Linus Walleij
PATCH 7/11 fsmc/nand: Provide contiguous buffers to dma
Quoted 2 lines · Linus Walleij
Quoted 1 line · viresh kumar
I pray that i am wrong here, otherwise i would be thrown out from
s/am/am not/ :(
Quoted 7 lines
Quoted 5 lines
the maintainers list for this driver :)
dma_sync_single_for_device()is not doing anything on the buffer, but on the LLI item. Actually it is flushing LLI struct so that DMA h/w can get the correct values.Sorry no, I'm the one who's wrong...
Glad to hear that. :)
It happens very few times in one's lifetime, that a beginner like me is correct and an expert like you is not. Just kidding :)
Quoted 2 lines
And the block layer of the subsystem should take care of only handing the driver buffers that are contiguous
But why should that be a constraint on block layer? It is working in virtual space and is concerned about that onlly.
--
viresh
PATCH 7/11 fsmc/nand: Provide contiguous buffers to dma
Quoted 7 lines · viresh kumar
Quoted 3 lines · Linus Walleij
And the block layer of the subsystem should take care of only handing the driver buffers that are contiguous
But why should that be a constraint on block layer? It is working in virtual space and is concerned about that onlly.
Not the block layer, the block layer of the subsystem.
It has to pick out the chunks that get transferred down to the drivers.
For example drivers/mmc/card/block.c will convert transfers into sglists and pass down to the MMC drivers. mmc_queue_map_sg() calls blk_rq_map_sg() to do the job. It's even documented in Documentation/block/biodoc.txt
I don't know how that works in MTD...
Yours,
Linus Walleij
PATCH 7/11 fsmc/nand: Provide contiguous buffers to dma
In reply to Linus WalleijQuoted 25 lines · Linus Walleij
Quoted 6 lines · viresh kumar
Quoted 2 lines · Linus Walleij
dma_sync_single_for_device()is translating the virtual address to physical for every chunk BTW.Quoted 6 lines
I pray that i am wrong here, otherwise i would be thrown out from the maintainers list for this driver :)
dma_sync_single_for_device()is not doing anything on the buffer, but on the LLI item. Actually it is flushing LLI struct so that DMA h/w can get the correct values.Sorry no, I'm the one who's wrong...
So the DMA engine
memcpy()is not mappingvirt->physbut expects physical addresses to be provided.So
dma_map_single()needs to be called on the stuff passed in todev->device_prep_dma_memcpy().And currently there is indeed a
dma_map_single()indma_xfer()infsmc_nand.cwhich should work just fine.
Quoted 7 lines
dma_map_single()will only work if the buffer is physically contiguous.And the block layer of the subsystem should take care of only handing the driver buffers that are contiguous I think? Not that I'm an expert here ... more some guesswork :-/
The buffers provided to the driver are actually user buffers. The reason I say that is because the generic nand test modules eg drivers/mtd/nand/mtd_stresstest.c calls mtd->_read with a user buffer as an argument
This same buffer directly trickles down to the driver
Artem, should we clearly cast this buffer as a user pointer instead of just a 'uint8_t *'.
Regards
Vipin
PATCH 7/11 fsmc/nand: Provide contiguous buffers to dma
Quoted 4 lines · Vipin Kumar
The buffers provided to the driver are actually user buffers. The reason I say that is because the generic nand test modules eg
drivers/mtd/nand/mtd_stresstest.ccallsmtd->_readwith a user buffer as an argument
I am not sure what does "user" buffers mean, but they are vmalloced() buffer, not kmalloc()'ed, so they are not physically contiguous.
Quoted 4 lines
This same buffer directly trickles down to the driver
Artem, should we clearly cast this buffer as a user pointer instead of just a '
uint8_t*'.
They are not "_user", they are really kernel buffers. Or what do you mean, which exactly type do you suggest?
This stuff is something many people are bringing up for many years already. Drivers that do DMA do not cope with vmalloc()ed memory well, and we grew a number of hacks in several drives. I mean, hacks like the one you are introducing to your driver.
I'd solve the problem by changing the in-kernel mtd users to use physically-contiguous memory instead. The following are the users I can think of:
UBI, UBIFS, JFFS2, mtdtests and probably mtdswap.
They use vmalloc() when they need to read/write entire eraseblock, which is usually 128KiB or 256KiB, and kmalloc() that much may fail if the memory is fragmented.
In many cases, it is easy to read/write in smaller chunk, but several times. E.g., mtdtests could be changed.
In some cases, it is not easy, though.
First thing which comes to mind is that in modern kernels memory fragmentation is not that big issue as it used to be. So may be kmalloc() the memory is not that bad nowadays? We have page migration, memory compaction, etc?
I'd really prefer to just switch to kmalloc() everywhere instead of adding hacks like this to the drivers. Then if this is a problem for someone, he can fix it by either switching to smaller buffers (possible in many places), or by improving memory fragmentation issues on his system, or by just using CMA.
We can even have an mtd-wide funcion which will try kmalloc(), and if that fails, fall-back to CMA.
Then we can add a guard check to all mtd function which accept a buffer and WARN() if it not physically contiguous.
Signature · 9 lines
Best Regards, Artem Bityutskiy -------------- next part -------------- A non-text attachment was scrubbed... Name: signature.asc Type: application/pgp-signature Size: 836 bytes Desc: This is a digitally signed message part URL: <http://lists.infradead.org/pipermail/linux-arm-kernel/attachments/20121015/738aa0ca/attachment-0001.sig>
PATCH 7/11 fsmc/nand: Provide contiguous buffers to dma
Quoted 10 lines · Artem Bityutskiy
First thing which comes to mind is that in modern kernels memory fragmentation is not that big issue as it used to be. So may be
kmalloc()the memory is not that bad nowadays? We have page migration, memory compaction, etc?I'd really prefer to just switch to
kmalloc()everywhere instead of adding hacks like this to the drivers. Then if this is a problem for someone, he can fix it by either switching to smaller buffers (possible in many places), or by improving memory fragmentation issues on his system, or by just using CMA.
I think I can suggest that this is already a problem on real systems. In bringing up a board on v3.3 kernel, I experienced a kernel memory allocation error when trying to memdup_user() in eraseblock-size regions. I believe I would experience more of these if all eraseblock-sized buffers were kmalloc()'d.
See the commit description for the following commit in mtd-utils.git:
commit 71c76e74661492b4f68f670514866cfc85f47089
libmtd: fix mtd_write() issues for large data-only writes
Quoted 2 lines
We can even have an mtd-wide funcion which will try
kmalloc(), and if that fails, fall-back to CMA.
I would prefer not building a solution that hopes kmalloc() can get a large contiguous buffer (remember, eraseblock sizes come as large as 2MB these days). A real solution like CMA or scatter-gather seems like a better idea.
Brian
PATCH 7/11 fsmc/nand: Provide contiguous buffers to dma
Quoted 4 lines · Brian Norris
I would prefer not building a solution that hopes
kmalloc()can get a large contiguous buffer (remember, eraseblock sizes come as large as 2MB these days). A real solution like CMA or scatter-gather seems like a better idea.
+1 on that, and as I think I illustrated the MMC subsystem is using the block layer helpers to form scatter-gather lists for it's requests. I don't see why the MTD subsystem need to be very different?
Yours,
Linus Walleij
PATCH 7/11 fsmc/nand: Provide contiguous buffers to dma
Quoted 11 lines · Linus Walleij
Quoted 4 lines · Brian Norris
I would prefer not building a solution that hopes
kmalloc()can get a large contiguous buffer (remember, eraseblock sizes come as large as 2MB these days). A real solution like CMA or scatter-gather seems like a better idea.+1 on that, and as I think I illustrated the MMC subsystem is using the block layer helpers to form scatter-gather lists for it's requests. I don't see why the MTD subsystem need to be very different?
This is good idea, the problem is that it is a bit more work than hacking the driver, so most people prefer the latter. By removing all kmalloc()'s I basically wish to force people to go this way.
What are the SC functions names you refer?
Signature · 9 lines
Best Regards, Artem Bityutskiy -------------- next part -------------- A non-text attachment was scrubbed... Name: signature.asc Type: application/pgp-signature Size: 836 bytes Desc: This is a digitally signed message part URL: <http://lists.infradead.org/pipermail/linux-arm-kernel/attachments/20121016/e67d78eb/attachment-0001.sig>
PATCH 7/11 fsmc/nand: Provide contiguous buffers to dma
Quoted 13 lines · Artem Bityutskiy
Quoted 11 lines · Linus Walleij
Quoted 4 lines · Brian Norris
I would prefer not building a solution that hopes
kmalloc()can get a large contiguous buffer (remember, eraseblock sizes come as large as 2MB these days). A real solution like CMA or scatter-gather seems like a better idea.+1 on that, and as I think I illustrated the MMC subsystem is using the block layer helpers to form scatter-gather lists for it's requests. I don't see why the MTD subsystem need to be very different?
Quoted 5 lines
This is good idea, the problem is that it is a bit more work than hacking the driver, so most people prefer the latter. By removing all kmalloc()'s I basically wish to force people to go this way.
What are the SC functions names you refer?
I'm mainly thinking of blk_rq_map_sg()
from block/blk-merge.c
Yours,
Linus Walleij
PATCH 7/11 fsmc/nand: Provide contiguous buffers to dma
Quoted 10 lines · Linus Walleij
Quoted 9 lines · Artem Bityutskiy
Quoted 8 lines · Linus Walleij
Quoted 4 lines · Brian Norris
I would prefer not building a solution that hopes
kmalloc()can get a large contiguous buffer (remember, eraseblock sizes come as large as 2MB these days). A real solution like CMA or scatter-gather seems like a better idea.
Quoted 7 lines
Quoted 7 lines
Quoted 3 lines
+1 on that, and as I think I illustrated the MMC subsystem is using the block layer helpers to form scatter-gather lists for it's requests. I don't see why the MTD subsystem need to be very different?
This is good idea, the problem is that it is a bit more work than hacking the driver, so most people prefer the latter. By removing all kmalloc()'s I basically wish to force people to go this way.
Did you mean vmalloc()'s?
Quoted 4 lines
Quoted 1 line
What are the SC functions names you refer?
I'm mainly thinking of
blk_rq_map_sg()
fromblock/blk-merge.c
I am also interested in the potential for the S-G approach. I'll see what kind of work it takes to implement soon, hopefully.
As a side note, my hardware can, in fact, perform scatter-gather DMA. If we were to support both S-G hardware like mine in addition to standard, page-at-time access (nand_chip->write_page, for example), could we introduce a DMA interface to nand_chip? Then this interface would just be set to NULL for those that can't handle it.
Brian
PATCH 7/11 fsmc/nand: Provide contiguous buffers to dma
Quoted 5 lines · Brian Norris
Quoted 3 lines
Quoted 3 lines
This is good idea, the problem is that it is a bit more work than hacking the driver, so most people prefer the latter. By removing all kmalloc()'s I basically wish to force people to go this way.
Did you mean vmalloc()'s?
Yes.
Quoted 5 lines
Quoted 5 lines
Quoted 2 lines
What are the SC functions names you refer?
I'm mainly thinking of
blk_rq_map_sg()
fromblock/blk-merge.c
Yeah, may be re-working or extending MTD api with SG lists would be the way to go, but this is a lot more work...
Signature · 9 lines
Best Regards, Artem Bityutskiy -------------- next part -------------- A non-text attachment was scrubbed... Name: signature.asc Type: application/pgp-signature Size: 836 bytes Desc: This is a digitally signed message part URL: <http://lists.infradead.org/pipermail/linux-arm-kernel/attachments/20121021/243509aa/attachment.sig>
PATCH 7/11 fsmc/nand: Provide contiguous buffers to dma
Quoted 5 lines · Artem Bityutskiy
Quoted 2 lines
Quoted 2 lines
I'm mainly thinking of
blk_rq_map_sg()
fromblock/blk-merge.cYeah, may be re-working or extending MTD api with SG lists would be the way to go, but this is a lot more work...
Sorry, it would be correct to say that re-working MTD API _users_ to incorporate the SG API would be a lot more work.
Signature · 9 lines
Best Regards, Artem Bityutskiy -------------- next part -------------- A non-text attachment was scrubbed... Name: signature.asc Type: application/pgp-signature Size: 836 bytes Desc: This is a digitally signed message part URL: <http://lists.infradead.org/pipermail/linux-arm-kernel/attachments/20121021/28e3b5cc/attachment.sig>
PATCH 7/11 fsmc/nand: Provide contiguous buffers to dma
In reply to Brian NorrisQuoted 12 lines · Brian Norris
Quoted 5 lines
I'd really prefer to just switch to
kmalloc()everywhere instead of adding hacks like this to the drivers. Then if this is a problem for someone, he can fix it by either switching to smaller buffers (possible in many places), or by improving memory fragmentation issues on his system, or by just using CMA.I think I can suggest that this is already a problem on real systems. In bringing up a board on v3.3 kernel, I experienced a kernel memory allocation error when trying to
memdup_user()in eraseblock-size regions. I believe I would experience more of these if all eraseblock-sized buffers were kmalloc()'d.
Quoted 4 lines
See the commit description for the following commit in mtd-utils.git:
commit
71c76e74661492b4f68f670514866cfc85f47089
libmtd: fixmtd_write()issues for large data-only writes
Well, this is another work-around. The better way to fix this would be to change kernel's 'mtdchar_write_ioctl()' to be iterative and avoid calling 'memdup_user(len)' for arbitrary 'len' passed from user-space.
Quoted 4 lines
I would prefer not building a solution that hopes
kmalloc()can get a large contiguous buffer (remember, eraseblock sizes come as large as 2MB these days). A real solution like CMA or scatter-gather seems like a better idea.
Me too. But this does not happen. People bring this up for years. Of course it is easier to hack drivers, and very understandable. So what I would like to do is somehow force people to fix this issue.
So I thought about something like introducing an mtd_alloc() which would:
a. Try doing CMA allocation: dma_alloc_from_contiguous() b. If it fails, use kmalloc().
This function would probably need a cookie which it returns and which the mtd_free() function would use to call either kfree() or dma_release_from_contiguous()...
If both fail - bad luck. Go look at the code and switch to S-G lists instead of allocating contiguous regions. As I said, in many places it is easy to do, and there are few places when you would need to spend a bit more time.
How does this sound to you?
Signature · 11 lines
Best Regards, Artem Bityutskiy -------------- next part -------------- A non-text attachment was scrubbed... Name: signature.asc Type: application/pgp-signature Size: 836 bytes Desc: This is a digitally signed message part URL: <http://lists.infradead.org/pipermail/linux-arm-kernel/attachments/20121016/04d3c8f5/attachment.sig>
PATCH 7/11 fsmc/nand: Provide contiguous buffers to dma
Quoted 7 lines · Artem Bityutskiy
Quoted 4 lines · Brian Norris
See the commit description for the following commit in mtd-utils.git:
commit
71c76e74661492b4f68f670514866cfc85f47089
libmtd: fixmtd_write()issues for large data-only writesWell, this is another work-around.
Yeah, I know it was a workaround. It's another issue of balancing time and the "best" solution. Of course, the solutions actually don't seem that difficult now, so I probably should have just fixed the ioctl() in the first place... But I was simply pointing this out as evidence of a real memory-fragmentation issue.
Quoted 3 lines
The better way to fix this would be
to change kernel's 'mtdchar_write_ioctl()' to be iterative and avoid calling 'memdup_user(len)' for arbitrary 'len' passed from user-space.
That's one way, but it would require specifying some arbitrary iteration length, right? Like some multiple of writesize?
Instead, how about modelling it more closely after mtdchar_write(), using mtd_kmalloc_up_to(), then iteratively call copy_from_user()?
Quoted 4 lines
So I thought about something like introducing an
mtd_alloc()which would:
a. Try doing CMA allocation:dma_alloc_from_contiguous()b. If it fails, usekmalloc().
...
Quoted 6 lines
If both fail - bad luck. Go look at the code and switch to S-G lists instead of allocating contiguous regions. As I said, in many places it is easy to do, and there are few places when you would need to spend a bit more time.
How does this sound to you?
It sounds OK, but that depends on the success rate of dma_alloc_from_contiguous(). I'm not familiar with it.
Brian
PATCH 8/11 fsmc/nand: Use relaxed variants of io accessors
In reply to Vipin KumarUse relaxed variants of readl/writel accessors. readl/writel io accessors use explicit dsb instruction which causes stalls in the processor core resulting several cycles of delay for each access
Use relaxed variants where ever possible. This also results in an improved read/write performance.
--- drivers/mtd/nand/fsmc_nand.c | 54 ++++++++++++++++++++++++-------------------- 1 file changed, 29 insertions(+), 25 deletions(-)
drivers/mtd/nand/fsmc_nand.c +29 -25
@@ -400,13 +400,13 @@ static void fsmc_cmd_ctrl(struct mtd_info *mtd, int cmd, unsigned int ctrl) pc |=FSMC_ENABLE ; else pc &= ~FSMC_ENABLE; -writel (pc,FSMC_NAND_REG (regs, bank,PC )); +writel_relaxed (pc,FSMC_NAND_REG (regs, bank,PC )); }mb ();if (cmd !=NAND_CMD_NONE ) -writeb (cmd, this->IO_ADDR_W); +writeb_relaxed (cmd, this->IO_ADDR_W); }/*
@@ -433,14 +433,18 @@ static void fsmc_nand_setup(void __iomem *regs, uint32_t bank, uint32_t busw, tset = (timings->tset &FSMC_TSET_MASK ) <<FSMC_TSET_SHIFT ;if (busw) -writel (value |FSMC_DEVWID_16 ,FSMC_NAND_REG (regs, bank,PC )); +writel_relaxed (value |FSMC_DEVWID_16 , +FSMC_NAND_REG (regs, bank,PC ));else -writel (value |FSMC_DEVWID_8 ,FSMC_NAND_REG (regs, bank,PC )); +writel_relaxed (value |FSMC_DEVWID_8 , +FSMC_NAND_REG (regs, bank,PC )); -writel (readl (FSMC_NAND_REG (regs, bank,PC )) | tclr | tar, +writel_relaxed (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 )); +writel_relaxed (thiz | thold | twait | tset, +FSMC_NAND_REG (regs, bank,COMM )); +writel_relaxed (thiz | thold | twait | tset, +FSMC_NAND_REG (regs, bank,ATTRIB )); }/*
@@ -453,11 +457,11 @@ static void fsmc_enable_hwecc(struct mtd_info *mtd, int mode)void __iomem *regs = host->regs_va;uint32_t bank = host->bank; -writel (readl (FSMC_NAND_REG (regs, bank,PC )) & ~FSMC_ECCPLEN_256 , +writel_relaxed (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 , +writel_relaxed (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 , +writel_relaxed (readl (FSMC_NAND_REG (regs, bank,PC )) |FSMC_ECCEN ,FSMC_NAND_REG (regs, bank,PC )); }
@@ -477,7 +481,7 @@ static int fsmc_read_hwecc_ecc4(struct mtd_info *mtd, const uint8_t *data,unsigned long deadline = jiffies +FSMC_BUSY_WAIT_TIMEOUT ; do { - if (readl(FSMC_NAND_REG(regs, bank, STS)) & FSMC_CODE_RDY) + if (readl_relaxed(FSMC_NAND_REG(regs, bank, STS)) & FSMC_CODE_RDY) break; else cond_resched();
@@ -488,25 +492,25 @@ static int fsmc_read_hwecc_ecc4(struct mtd_info *mtd, const uint8_t *data,return -ETIMEDOUT ; } - ecc_tmp =readl (FSMC_NAND_REG (regs, bank,ECC1 )); + ecc_tmp =readl_relaxed (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 (FSMC_NAND_REG (regs, bank,ECC2 )); + ecc_tmp =readl_relaxed (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 (FSMC_NAND_REG (regs, bank,ECC3 )); + ecc_tmp =readl_relaxed (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 (FSMC_NAND_REG (regs, bank,STS )); + ecc_tmp =readl_relaxed (FSMC_NAND_REG (regs, bank,STS )); ecc[12 ] = (uint8_t ) (ecc_tmp >>16 );return 0 ;
@@ -526,7 +530,7 @@ static int fsmc_read_hwecc_ecc1(struct mtd_info *mtd, const uint8_t *data,uint32_t bank = host->bank;uint32_t ecc_tmp; - ecc_tmp =readl (FSMC_NAND_REG (regs, bank,ECC1 )); + ecc_tmp =readl_relaxed (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 );
@@ -635,10 +639,10 @@ static void fsmc_write_buf(struct mtd_info *mtd, const uint8_t *buf, int len)uint32_t *p = (uint32_t *)buf; len = len >>2 ;for (i =0 ; i < len; i++) -writel (p[i], chip->IO_ADDR_W); +writel_relaxed (p[i], chip->IO_ADDR_W); }else {for (i =0 ; i < len; i++) -writeb (buf[i], chip->IO_ADDR_W); +writeb_relaxed (buf[i], chip->IO_ADDR_W); } }
@@ -658,10 +662,10 @@ static void fsmc_read_buf(struct mtd_info *mtd, uint8_t *buf, int len)uint32_t *p = (uint32_t *)buf; len = len >>2 ;for (i =0 ; i < len; i++) - p[i] =readl (chip->IO_ADDR_R); + p[i] =readl_relaxed (chip->IO_ADDR_R); }else {for (i =0 ; i < len; i++) - buf[i] =readb (chip->IO_ADDR_R); + buf[i] =readb_relaxed (chip->IO_ADDR_R); } }
@@ -792,7 +796,7 @@ static int fsmc_bch8_correct_data(struct mtd_info *mtd, uint8_t *dat,uint32_t num_err, i;uint32_t ecc1, ecc2, ecc3, ecc4; - num_err = (readl (FSMC_NAND_REG (regs, bank,STS )) >>10 ) &0xF ; + num_err = (readl_relaxed (FSMC_NAND_REG (regs, bank,STS )) >>10 ) &0xF ;/* no bit flipping */ if (likely (num_err ==0 ))
@@ -835,10 +839,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 (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 )); + ecc1 =readl_relaxed (FSMC_NAND_REG (regs, bank,ECC1 )); + ecc2 =readl_relaxed (FSMC_NAND_REG (regs, bank,ECC2 )); + ecc3 =readl_relaxed (FSMC_NAND_REG (regs, bank,ECC3 )); + ecc4 =readl_relaxed (FSMC_NAND_REG (regs, bank,STS )); err_idx[0 ] = (ecc1 >>0 ) &0x1FFF ; err_idx[1 ] = (ecc1 >>13 ) &0x1FFF ;
Signature · 1 line
1.7.11.4
PATCH 8/11 fsmc/nand: Use relaxed variants of io accessors
Quoted 6 lines · Vipin Kumar
Use relaxed variants of readl/writel accessors. readl/writel io accessors use explicit dsb instruction which causes stalls in the processor core resulting several cycles of delay for each access
Use relaxed variants where ever possible. This also results in an improved read/write performance.
Good change.
PATCH 8/11 fsmc/nand: Use relaxed variants of io accessors
In reply to Vipin KumarQuoted 8 lines · Vipin Kumar
Use relaxed variants of readl/writel accessors. readl/writel io accessors use explicit dsb instruction which causes stalls in the processor core resulting several cycles of delay for each access
Use relaxed variants where ever possible. This also results in an improved read/write performance.
Signed-off-by Vipin Kumar <[email protected]>
Good idea for any performance-critical code! Thanks!
Yours,
Linus Walleij
PATCH 9/11 fsmc/nand:FIX: replace change_bit routine
In reply to Vipin Kumarchange_bit routine accepts only ulong pointers as buffer, so an unaligned char pointer passed to change_bit may lead to a crash.
Fix this bug by accessing the buffer as char pointer.
--- drivers/mtd/nand/fsmc_nand.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-)
drivers/mtd/nand/fsmc_nand.c +3 -1
@@ -859,7 +859,9 @@ static int fsmc_bch8_correct_data(struct mtd_info *mtd, uint8_t *dat,change_bit (1 , (unsigned long *)&err_idx[i]);if (err_idx[i] < chip->ecc.size *8 ) { -change_bit (err_idx[i], (unsigned long *)dat); +uint8_t *p = dat + err_idx[i] /8 ; + *p = *p ^ (1 << (err_idx[i] %8 )); + i++; } }
Signature · 1 line
1.7.11.4
PATCH 9/11 fsmc/nand:FIX: replace change_bit routine
Quoted 4 lines · Vipin Kumar
change_bitroutine accepts only ulong pointers as buffer, so an unaligned char pointer passed tochange_bitmay lead to a crash.Fix this bug by accessing the buffer as char pointer.
Why not see if we can fix change_bit() instead? Since I suspect this is on ARM I bet Russell and Nico want to hear about this if there is a problem.
Can the ARM change_bit() not be fixed, so that long arguments are the only option?
drivers/mtd/nand/fsmc_nand.c static int fsmc_bch8_correct_data(struct mtd_info *mtd, uint8_t *dat, · line 863
Quoted 4 lines
if (err_idx[i] < chip->ecc.size * 8) {drivers/mtd/nand/fsmc_nand.c +2
-1-change_bit (err_idx[i], (unsigned long *)dat); +uint8_t *p = dat + err_idx[i] /8 ; + *p = *p ^ (1 << (err_idx[i] %8 ));
I'm one of these people who would write >>3 and &7 rather than /8 or %8 but I guess we are all different. Atleast consider it if you stick with this...
Yours,
Linus Walleij
PATCH 9/11 fsmc/nand:FIX: replace change_bit routine
Quoted 5 lines · Linus Walleij
Quoted 3 lines · Vipin Kumar
change_bitroutine accepts only ulong pointers as buffer, so an unaligned char pointer passed tochange_bitmay lead to a crash.
Quoted 8 lines
Quoted 1 line
Fix this bug by accessing the buffer as char pointer.
Why not see if we can fix
change_bit()instead? Since I suspect this is on ARM I bet Russell and Nico want to hear about this if there is a problem.Can the ARM
change_bit()not be fixed, so that long arguments are the only option?
No. It is this code which is totally broken.
The change_bit() is defined to operate on long values, in the _native_ endian. Now imagine what this is going to do to your data buffer if instead you are running on a big endian device.
And I doubt there is anything requiring atomic bit manipulation here either.
Quoted 8 lines
drivers/mtd/nand/fsmc_nand.c static int fsmc_bch8_correct_data(struct mtd_info *mtd, uint8_t *dat, · line 863
Quoted 4 lines
if (err_idx[i] < chip->ecc.size * 8) {drivers/mtd/nand/fsmc_nand.c +2
-1-change_bit (err_idx[i], (unsigned long *)dat); +uint8_t *p = dat + err_idx[i] /8 ; + *p = *p ^ (1 << (err_idx[i] %8 ));I'm one of these people who would write >>3 and &7 rather than /8 or %8 but I guess we are all different. Atleast consider it if you stick with this...
Better yet:
dat[err_idx[i] / 8] ^= (1 << (err_idx[i] % 8));
The /8 and %8 will be changed into >>3 and &7 by the compiler anyway, while the /8 and %8 form is possibly a bit less obscure.
Of course, this needs to be done over _all_ this driver, not only a few cases.
Nicolas
PATCH 9/11 fsmc/nand:FIX: replace change_bit routine
Quoted 7 lines · Nicolas Pitre
Quoted 5 lines · Linus Walleij
Quoted 3 lines · Vipin Kumar
change_bitroutine accepts only ulong pointers as buffer, so an unaligned char pointer passed tochange_bitmay lead to a crash.
Quoted 9 lines
Quoted 8 lines
Quoted 1 line
Fix this bug by accessing the buffer as char pointer.
Why not see if we can fix
change_bit()instead? Since I suspect this is on ARM I bet Russell and Nico want to hear about this if there is a problem.Can the ARM
change_bit()not be fixed, so that long arguments are the only option?
Hello Nicolas
Quoted 2 lines
No. It is this code which is totally broken.
Yes, I understand and accept the probelm. That's why the fix
Quoted 7 lines
The
change_bit()is defined to operate on long values, in the _native_ endian. Now imagine what this is going to do to your data buffer if instead you are running on a big endian device.And I doubt there is anything requiring atomic bit manipulation here either.
No, there is no requirement for an atomic change_bit
Quoted 9 lines
Quoted 8 lines
drivers/mtd/nand/fsmc_nand.c static int fsmc_bch8_correct_data(struct mtd_info *mtd, uint8_t *dat,
Quoted 4 lines
if (err_idx[i]< chip->ecc.size * 8) {drivers/mtd/nand/fsmc_nand.c +2
-1-change_bit (err_idx[i], (unsigned long *)dat); +uint8_t *p = dat + err_idx[i] /8 ; + *p = *p ^ (1 << (err_idx[i] %8 ));I'm one of these people who would write>>3 and &7 rather than /8 or %8 but I guess we are all different. Atleast consider it if you stick with this...
Quoted 7 lines
Better yet:
dat[err_idx[i] / 8] ^= (1<< (err_idx[i] % 8));The /8 and %8 will be changed into>>3 and&7 by the compiler anyway, while the /8 and %8 form is possibly a bit less obscure.
Yes, that's exactly why I kept /8 and %8. I would change the code as suggested by you
Quoted 3 lines
Of course, this needs to be done over _all_ this driver, not only a few cases.
There is only one place which needs a change_bit. I would send a v2 with the suggested change
Vipin
Quoted 4 lines
Nicolas
.
PATCH 9/11 fsmc/nand:FIX: replace change_bit routine
In reply to Linus WalleijQuoted 10 lines · Linus Walleij
Quoted 4 lines · Vipin Kumar
change_bitroutine accepts only ulong pointers as buffer, so an unaligned char pointer passed tochange_bitmay lead to a crash.Fix this bug by accessing the buffer as char pointer.
Why not see if we can fix
change_bit()instead? Since I suspect this is on ARM I bet Russell and Nico want to hear about this if there is a problem.
Not particularly. There's a reason the argument to change_bit() is typed 'unsigned long' and that's not because it can take a void, char, or a short. It's because it _expects_ the buffer to be aligned to an "unsigned long" quantity.
That's because on many architectures, misaligned loads and stores are not atomic operations - and in this case, load/store exclusive will fail when they're misalighed.
So...
- change_bit(err_idx[i], (unsigned long *)dat);
is highly invalid code.
Quoted 2 lines
Can the ARM
change_bit()not be fixed, so that long arguments are the only option?
Spot the intentional cast:
Quoted 1 line
Quoted 1 line
-
change_bit(err_idx[i], (unsigned long *)dat);
which tries to work around this. Remember my attitude towards casts:
if you're having to use a cast, you are _probably_ doing something wrong. In this case, it's hiding a warning which was saying that the code is doing something wrong, and then the result blows up. By adding that cast, the wrong wire was cut... you get to keep the remains. ;)
PATCH 9/11 fsmc/nand:FIX: replace change_bit routine
Quoted 21 lines · Russell King - ARM Linux
Quoted 10 lines · Linus Walleij
Quoted 4 lines · Vipin Kumar
change_bitroutine accepts only ulong pointers as buffer, so an unaligned char pointer passed tochange_bitmay lead to a crash.Fix this bug by accessing the buffer as char pointer.
Why not see if we can fix
change_bit()instead? Since I suspect this is on ARM I bet Russell and Nico want to hear about this if there is a problem.Not particularly. There's a reason the argument to
change_bit()is typed 'unsigned long' and that's not because it can take a void, char, or a short. It's because it _expects_ the buffer to be aligned to an "unsigned long" quantity.That's because on many architectures, misaligned loads and stores are not atomic operations - and in this case, load/store exclusive will fail when they're misalighed.
Quoted 6 lines
So...
-
change_bit(err_idx[i], (unsigned long *)dat);is highly invalid code.
Thanks. Got your point
Quoted 7 lines
Quoted 2 lines
Can the ARM
change_bit()not be fixed, so that long arguments are the only option?Spot the intentional cast:
Quoted 1 line
Quoted 1 line
-
change_bit(err_idx[i], (unsigned long *)dat);
Quoted 7 lines
which tries to work around this. Remember my attitude towards casts:
if you're having to use a cast, you are _probably_ doing something wrong. In this case, it's hiding a warning which was saying that the code is doing something wrong, and then the result blows up. By adding that cast, the wrong wire was cut... you get to keep the remains. ;)
.
I agree with you. Although I was a bit relaxed this time, I would really think before adding a cast explicitly just to avoid a warning
-Vipin
PATCH 10/11 fsmc/nand: Add sw bch support for ecc calculation/correction
In reply to Vipin Kumar--- .../devicetree/bindings/mtd/fsmc-nand.txt | 2 + drivers/mtd/nand/fsmc_nand.c | 156 +++++++++++++-------- include/linux/mtd/fsmc.h | 3 + 3 files changed, 106 insertions(+), 55 deletions(-)
Documentation/devicetree/bindings/mtd/fsmc-nand.txt +2 -0
@@ -30,6 +30,8 @@ Optional properties: - st,rb-gpios: When the st,ready-busy is defined as "rb-gpio", a gpio pin number is defined in this property +- nand-sw-ecc: boolean indicating whether s/w ecc is supported + Example: fsmc: flash at d1800000 {
drivers/mtd/nand/fsmc_nand.c +101 -55
187 lines not on this page · raw message
include/linux/mtd/fsmc.h +3 -0
@@ -176,6 +176,9 @@ struct fsmc_nand_platform_data {/* priv structures for dma accesses */ void *read_dma_priv;void *write_dma_priv; + +/* whether s/w ecc is supported */ +bool sw_ecc; }; extern int __init fsmc_nor_init(struct platform_device *pdev,
Signature · 1 line
1.7.11.4
PATCH 10/11 fsmc/nand: Add sw bch support for ecc calculation/correction
Quoted 12 lines · Vipin Kumar
Signed-off-by Vipin Kumar <[email protected]>--- .../devicetree/bindings/mtd/fsmc-nand.txt | 2 + drivers/mtd/nand/fsmc_nand.c | 156 +++++++++++++-------- include/linux/mtd/fsmc.h | 3 + 3 files changed, 106 insertions(+), 55 deletions(-)Documentation/devicetree/bindings/mtd/fsmc-nand.txt +0
-0
Documentation/devicetree/bindings/mtd/fsmc-nand.txt Optional properties: · line 34
Quoted 5 lines
Documentation/devicetree/bindings/mtd/fsmc-nand.txt +2
-0@@ -30,6 +30,8 @@ Optional properties: - st,rb-gpios: When the st,ready-busy is defined as "rb-gpio", a gpio pin number is defined in this property +- nand-sw-ecc: boolean indicating whether s/w ecc is supported +
please use the generic binding
- nand-ecc-mode = xx
Quoted 8 lines
Documentation/devicetree/bindings/mtd/fsmc-nand.txt +0
-0Example: fsmc: flash at d1800000 {drivers/mtd/nand/fsmc_nand.c +0
-0
drivers/mtd/nand/fsmc_nand.c static int __devinit fsmc_nand_probe_config_dt(struct platform_device *pdev, · line 951
Quoted 6 lines
drivers/mtd/nand/fsmc_nand.c +3
-0@@ -946,6 +946,9 @@ static int __devinit fsmc_nand_probe_config_dt(struct platform_device *pdev, }else pdata->rbpin.use_pin =FSMC_RB_WAIT ; +if (of_property_read_bool (np,"nand-sw-ecc" )) + pdata->sw_ecc = true; +
of_get_nand_ecc_mode
Quoted 202 lines
drivers/mtd/nand/fsmc_nand.c +98
-55return 0; }#else @@ -972,6 +975,7 @@ static int __init fsmc_nand_probe(struct platform_device *pdev)dma_cap_mask_t mask;int ret =0 ;u32 pid, bank; +uint oobeccsize, m;int i;if (np) {@@ -1104,9 +1108,24 @@ static int __init fsmc_nand_probe(struct platform_device *pdev) nand->cmd_ctrl = fsmc_cmd_ctrl; nand->chip_delay =30 ; - nand->ecc.mode =NAND_ECC_HW ; - nand->ecc.hwctl = fsmc_enable_hwecc; - nand->ecc.size =512 ; +if (pdata->sw_ecc) { + nand->ecc.mode =NAND_ECC_SOFT_BCH ; +/* +* The recent devices require n-bit correctibility in x bytes. +* The values of n and x varies as below +* n - 1 to 100 +* x - 512 to 1K +* TODO: For now, take x = 1K for all sw bch mathematics. Think +* of a better way to handle other device dependent +* requirements. May be it should come from board dts files +*/ + nand->ecc.size =1024 ; + }else { + nand->ecc.mode =NAND_ECC_HW ; + nand->ecc.hwctl = fsmc_enable_hwecc; + nand->ecc.size =512 ; + } + nand->options = pdata->options; nand->select_chip = fsmc_select_chip; nand->badblockbits =7 ;@@ -1165,17 +1184,19 @@ static int __init fsmc_nand_probe(struct platform_device *pdev) nand->options &NAND_BUSWIDTH_16 , host->dev_timings, host->rbpin); -if (AMBA_REV_BITS (host->pid) >=8 ) { - nand->ecc.read_page = fsmc_read_page_hwecc; - nand->ecc.calculate = fsmc_read_hwecc_ecc4; - nand->ecc.correct = fsmc_bch8_correct_data; - nand->ecc.bytes =13 ; - nand->ecc.strength =8 ; - }else { - nand->ecc.calculate = fsmc_read_hwecc_ecc1; - nand->ecc.correct = nand_correct_data; - nand->ecc.bytes =3 ; - nand->ecc.strength =1 ; +if (nand->ecc.mode !=NAND_ECC_SOFT_BCH ) { +if (AMBA_REV_BITS (host->pid) >=8 ) { + nand->ecc.read_page = fsmc_read_page_hwecc; + nand->ecc.calculate = fsmc_read_hwecc_ecc4; + nand->ecc.correct = fsmc_bch8_correct_data; + nand->ecc.bytes =13 ; + nand->ecc.strength =8 ; + }else { + nand->ecc.calculate = fsmc_read_hwecc_ecc1; + nand->ecc.correct = nand_correct_data; + nand->ecc.bytes =3 ; + nand->ecc.strength =1 ; + } }/* @@ -1187,48 +1208,73 @@ static int __init fsmc_nand_probe(struct platform_device *pdev) goto err_scan_ident; } -if (AMBA_REV_BITS (host->pid) >=8 ) { -switch (host->mtd.oobsize) { -case 16 : - nand->ecc.layout = &fsmc_ecc4_16_layout; - host->ecc_place = &fsmc_ecc4_sp_place; -break ; -case 64 : - nand->ecc.layout = &fsmc_ecc4_64_layout; - host->ecc_place = &fsmc_ecc4_lp_place; -break ; -case 128 : - nand->ecc.layout = &fsmc_ecc4_128_layout; - host->ecc_place = &fsmc_ecc4_lp_place; -break ; -case 224 : - nand->ecc.layout = &fsmc_ecc4_224_layout; - host->ecc_place = &fsmc_ecc4_lp_place; -break ; -case 256 : - nand->ecc.layout = &fsmc_ecc4_256_layout; - host->ecc_place = &fsmc_ecc4_lp_place; -break ; -default : -printk (KERN_WARNING "No oob scheme defined for " -"oobsize %d\n" , mtd->oobsize); -BUG (); - } +if (nand->ecc.mode ==NAND_ECC_SOFT_BCH ) { +/* +* Initialize the ecc bytes and strength dynamically based on eccsize +* and writesize. +* +* Parameters @eccsize and @eccbytes are used to compute BCH parameters +* m (Galois field order) and t (error correction capability). @eccbytes +* should be equal to the number of bytes required to store m*t bits, +* where m is such that 2^m-1 > @eccsize*8. +* +* Example: to configure 4 bit correction per 512 bytes, you should pass +* @eccsize = 512 (thus, m=13 is the smallest integer such that 2^m-1 > +* 512*8) @eccbytes = 7 (7 bytes are required to store m*t = 13*4 = 52 +* bits) +* +* Note: 2 bytes of oob are considered reserved for bad block marking +*/ + m =fls (1 +8 * nand->ecc.size); + oobeccsize = ((host->mtd.oobsize -2 ) * \ + nand->ecc.size) / host->mtd.writesize; + nand->ecc.bytes = (oobeccsize / m) * m; + nand->ecc.strength = (nand->ecc.bytes *8 ) / m; + nand->ecc.layout =NULL ; }else { -switch (host->mtd.oobsize) { -case 16 : - nand->ecc.layout = &fsmc_ecc1_16_layout; -break ; -case 64 : - nand->ecc.layout = &fsmc_ecc1_64_layout; -break ; -case 128 : - nand->ecc.layout = &fsmc_ecc1_128_layout; -break ; -default : -printk (KERN_WARNING "No oob scheme defined for " -"oobsize %d\n" , mtd->oobsize); -BUG (); +if (AMBA_REV_BITS (host->pid) >=8 ) { +switch (host->mtd.oobsize) { +case 16 : + nand->ecc.layout = &fsmc_ecc4_16_layout; + host->ecc_place = &fsmc_ecc4_sp_place; +break ; +case 64 : + nand->ecc.layout = &fsmc_ecc4_64_layout; + host->ecc_place = &fsmc_ecc4_lp_place; +break ; +case 128 : + nand->ecc.layout = &fsmc_ecc4_128_layout; + host->ecc_place = &fsmc_ecc4_lp_place; +break ; +case 224 : + nand->ecc.layout = &fsmc_ecc4_224_layout; + host->ecc_place = &fsmc_ecc4_lp_place; +break ; +case 256 : + nand->ecc.layout = &fsmc_ecc4_256_layout; + host->ecc_place = &fsmc_ecc4_lp_place; +break ; +default : +printk (KERN_WARNING "No oob scheme defined for " +"oobsize %d\n" , mtd->oobsize); +BUG (); + } + }else { +switch (host->mtd.oobsize) { +case 16 : + nand->ecc.layout = &fsmc_ecc1_16_layout; +break ; +case 64 : + nand->ecc.layout = &fsmc_ecc1_64_layout; +break ; +case 128 : + nand->ecc.layout = &fsmc_ecc1_128_layout; +break ; +default : +printk (KERN_WARNING "No oob scheme defined for " +"oobsize %d\n" , mtd->oobsize); +BUG (); + } } }include/linux/mtd/fsmc.h +3
-0@@ -176,6 +176,9 @@ struct fsmc_nand_platform_data {/* priv structures for dma accesses */ void *read_dma_priv;void *write_dma_priv; + +/* whether s/w ecc is supported */ +bool sw_ecc; }; extern int __init fsmc_nor_init(struct platform_device *pdev,Signature · 1 line
1.7.11.4
PATCH 10/11 fsmc/nand: Add sw bch support for ecc calculation/correction
Quoted 16 lines · Jean-Christophe PLAGNIOL-VILLARD
Quoted 15 lines · Vipin Kumar
Signed-off-by Vipin Kumar<[email protected]>--- .../devicetree/bindings/mtd/fsmc-nand.txt | 2 + drivers/mtd/nand/fsmc_nand.c | 156 +++++++++++++-------- include/linux/mtd/fsmc.h | 3 + 3 files changed, 106 insertions(+), 55 deletions(-)Documentation/devicetree/bindings/mtd/fsmc-nand.txt +0
-0@@ -30,6 +30,8 @@ Optional properties: - st,rb-gpios: When the st,ready-busy is defined as "rb-gpio", a gpio pin number is defined in this property
Quoted 4 lines
Documentation/devicetree/bindings/mtd/fsmc-nand.txt Optional properties: · line 34
Quoted 2 lines
Documentation/devicetree/bindings/mtd/fsmc-nand.txt +2
-0+- nand-sw-ecc: boolean indicating whether s/w ecc is supported +please use the generic binding
- nand-ecc-mode = xx
Thanks for pointing. I will do the needful
Quoted 11 lines
Quoted 11 lines
Documentation/devicetree/bindings/mtd/fsmc-nand.txt +0
-0Example: fsmc: flash at d1800000 {drivers/mtd/nand/fsmc_nand.c +0
-0@@ -946,6 +946,9 @@ static int __devinit fsmc_nand_probe_config_dt(struct platform_device *pdev, }else pdata->rbpin.use_pin =FSMC_RB_WAIT ;
Quoted 5 lines
drivers/mtd/nand/fsmc_nand.c static int __devinit fsmc_nand_probe_config_dt(struct platform_device *pdev, · line 951
Quoted 3 lines
drivers/mtd/nand/fsmc_nand.c +3
-0+if (of_property_read_bool (np,"nand-sw-ecc" )) + pdata->sw_ecc = true; +
of_get_nand_ecc_mode
Sure
-Vipin
PATCH 11/11 nand: Increase the ecc placement locations to 640
In reply to Vipin KumarFew devices like H27UBG8T2CTR have a writesize/oobsize of 8KB/640B. This means that the maximum oobsize has gone up to 640 bytes and consequently the maximum ecc placement locations have also gone up to 640.
--- include/linux/mtd/mtd.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-)
include/linux/mtd/mtd.h +1 -1
@@ -98,7 +98,7 @@ struct mtd_oob_ops { };#define MTD_MAX_OOBFREE_ENTRIES_LARGE 32 -#define MTD_MAX_ECCPOS_ENTRIES_LARGE 448 +#define MTD_MAX_ECCPOS_ENTRIES_LARGE 640/* * Internal ECC layout control structure. For historical reasons, there is a * similar, smaller struct nand_ecclayout_user (in mtd-abi.h) that is retained
Signature · 1 line
1.7.11.4
PATCH 11/11 nand: Increase the ecc placement locations to 640
Quoted 5 lines · Vipin Kumar
Few devices like H27UBG8T2CTR have a writesize/oobsize of 8KB/640B. This means that the maximum oobsize has gone up to 640 bytes and consequently the maximum ecc placement locations have also gone up to 640.
Signed-off-by Vipin Kumar <[email protected]>
Pushed this one to l2-mtd.git, thanks!
Signature · 9 lines
Best Regards, Artem Bityutskiy -------------- next part -------------- A non-text attachment was scrubbed... Name: signature.asc Type: application/pgp-signature Size: 836 bytes Desc: This is a digitally signed message part URL: <http://lists.infradead.org/pipermail/linux-arm-kernel/attachments/20121017/508f73cf/attachment.sig>
PATCH 11/11 nand: Increase the ecc placement locations to 640
In reply to Vipin KumarQuoted 3 lines · Vipin Kumar
Few devices like H27UBG8T2CTR have a writesize/oobsize of 8KB/640B. This means that the maximum oobsize has gone up to 640 bytes and consequently the maximum ecc placement locations have also gone up to 640.
We really need to change the nand_ecclayout struct sometime. Each one takes something like 4+4?640+4+32?8 = 2824 bytes now, and we have 4 of them statically declared in nand_base.c. And most drivers just declare their own anyway. (fsl_{elbc,ifc}_nand.c have 4 and 5 of them each)
I've thought about dynamically allocating and/or changing its layout so that we can do eccpos ranges, similar to the oobfree entries. But this gets harder, with the old ioctl(ECCGETLAYOUT) still hanging around, a few platform uses of nand_ecclayout, and probably some other complications.
Anyway, this comes off as basically a complaint, while in fact, I wanted to see if anyone else agreed and/or had any suggestions. Or, maybe somebody could convince me not to care...
Brian
cover mtd/nand: fsmc driver updates
In reply to Vipin KumarQuoted 2 lines · Vipin Kumar
This patch-set contains several fixes and a few enhancements in fsmc driver. Modifications include
OK, picked some patches from your series, some do not apply. Please, send v2 against the l2-mtd.git tree:
git://git.infradead.org/users/dedekind/l2-mtd.git
Thanks!
Signature · 9 lines
Best Regards, Artem Bityutskiy -------------- next part -------------- A non-text attachment was scrubbed... Name: signature.asc Type: application/pgp-signature Size: 836 bytes Desc: This is a digitally signed message part URL: <http://lists.infradead.org/pipermail/linux-arm-kernel/attachments/20121017/d73a2a7b/attachment.sig>
cover mtd/nand: fsmc driver updates
Quoted 9 lines · Artem Bityutskiy
Quoted 2 lines · Vipin Kumar
This patch-set contains several fixes and a few enhancements in fsmc driver. Modifications include
OK, picked some patches from your series, some do not apply. Please, send v2 against the l2-mtd.git tree:
git://git.infradead.org/users/dedekind/l2-mtd.git
Sure, I would do that soon. Thanks
-Vipin