Groups | Search | Server Info | Keyboard shortcuts | Login | Register [http] [https] [nntp] [nntps]


Groups > linux.kernel > #1191812 > unrolled thread

[PATCH v7 0/5] mtd: nand: vf610_nfc: Freescale NFC for VF610

Started byStefan Agner <stefan@agner.ch>
First post2015-07-24 15:20 +0200
Last post2015-07-24 15:20 +0200
Articles 6 — 2 participants

Back to article view | Back to linux.kernel


Contents

  [PATCH v7 0/5] mtd: nand: vf610_nfc: Freescale NFC for VF610 Stefan Agner <stefan@agner.ch> - 2015-07-24 15:20 +0200
    [PATCH v7 5/5] ARM: dts: vf-colibri: enable NAND flash controller Stefan Agner <stefan@agner.ch> - 2015-07-24 15:20 +0200
    [PATCH v7 4/5] ARM: dts: vf610twr: add NAND flash controller peripherial Stefan Agner <stefan@agner.ch> - 2015-07-24 15:20 +0200
      Re: [PATCH v7 4/5] ARM: dts: vf610twr: add NAND flash controller  peripherial Shawn Guo <shawnguo@kernel.org> - 2015-07-25 05:40 +0200
    [PATCH v7 3/5] mtd: nand: vf610_nfc: add device tree bindings Stefan Agner <stefan@agner.ch> - 2015-07-24 15:20 +0200
    [PATCH v7 2/5] mtd: nand: vf610_nfc: add hardware BCH-ECC support Stefan Agner <stefan@agner.ch> - 2015-07-24 15:20 +0200

#1191812 — [PATCH v7 0/5] mtd: nand: vf610_nfc: Freescale NFC for VF610

FromStefan Agner <stefan@agner.ch>
Date2015-07-24 15:20 +0200
Subject[PATCH v7 0/5] mtd: nand: vf610_nfc: Freescale NFC for VF610
Message-ID<pPL3j-6PY-7@gated-at.bofh.it>
This seventh revision simplifies the config symbols somewhat, but
is otherwise just a rebase version on current l2-mtd/master.

I reran the MTD tests, they still all succeed.

Some more information and the full test log can be found in the
cover letter of the last revision v6:
http://thread.gmane.org/gmane.linux.kernel/1979868

Changes since v6:
- Rebased ontop of l2-mtd/master (v4.2-rc1 based)
- Removed HAVE_NAND_VF610_NFC and use depends on. This made
  "[PATCH v6 4/6] ARM: vf610: enable NAND Flash Controller" unnecessary

Changes since v5:
- Removed fsl,mpc5125-nfc compatible string
- Removed readl/writel_relaxed
- Change interface of vf610_nfc_transfer_size to match other accessors

Changes since v4:
- Rebased ontop of l2-mtd/master (v4.1-rc4 based)
- Eliminate unnecessary page read (NAND_CMD_SEQIN) since the driver does
  not support sub-page writes anyway (improves write performance)
- Support ONFI by enabling READID command with offset and parameter page
  reads (CMD_PARAM)
- Change to dedicated read_page/write_page function, enables raw writes
- Use __LITTLE_ENDIAN to distingush between LE/BE relevant statements
- Eliminated vf610_nfc_probe_dt in favor of common DT init code
- Use wait_for_completion_timeout
- Some style fixes (spaces, etc.)

Changes since v3:
- Make the driver selectable when COMPILE_TEST is set
- Fix compile error due to superfluous ECC_STATUS configuration in initial
  patch (without ECC correction ECC_STATUS does not need to be configured)
- Remove custom BBT pattern and switch to in-band BBT in the initial patch
- Include two bug fixes, for details see the corresponding U-Boot patches:
  http://thread.gmane.org/gmane.comp.boot-loaders.u-boot/215802

Changes since v2:
- Updated binding documentation

Changes since v1:
- Nest nfc_config struct within the main nfc struct
- Use assigned clock binding to specify NFC clock
- Rebased ontop of MSCM IR patchset (driver parts have been merged)
- Split out arch Kconfig in a separate config
- Fix module license
- Updated MAINTAINERS

Changes since RFC (Bill Pringlemeir):
- Renamed driver from fsl_nfc to vf610_nfc
- Use readl/writel for all register in accessor functions
- Optimized field accessor functions
- Implemented PM (suspend/resume) functions
- Implemented basic support for ECC strength/ECC step size from dt
- Improved performance of count_written_bits by using hweight32
- Support ECC with 60-bytes to correct up to 32 bit errors
- Changed to in-band BBT (NAND_BBT_NO_OOB) which also allows ECC modes
  which uses up to 60 bytes on 64 byte OOB
- Removed custom (downstream) BBT pattern since BBT table won't be
  compatible anyway (due to the change above)

Stefan Agner (5):
  mtd: nand: vf610_nfc: Freescale NFC for VF610, MPC5125 and others
  mtd: nand: vf610_nfc: add hardware BCH-ECC support
  mtd: nand: vf610_nfc: add device tree bindings
  ARM: dts: vf610twr: add NAND flash controller peripherial
  ARM: dts: vf-colibri: enable NAND flash controller

 .../devicetree/bindings/mtd/vf610-nfc.txt          |  45 ++
 MAINTAINERS                                        |   6 +
 arch/arm/boot/dts/vf-colibri.dtsi                  |  32 +
 arch/arm/boot/dts/vf610-twr.dts                    |  44 ++
 arch/arm/boot/dts/vfxxx.dtsi                       |   8 +
 drivers/mtd/nand/Kconfig                           |  11 +
 drivers/mtd/nand/Makefile                          |   1 +
 drivers/mtd/nand/vf610_nfc.c                       | 839 +++++++++++++++++++++
 8 files changed, 986 insertions(+)
 create mode 100644 Documentation/devicetree/bindings/mtd/vf610-nfc.txt
 create mode 100644 drivers/mtd/nand/vf610_nfc.c

-- 
2.4.5

--
To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
the body of a message to majordomo@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html
Please read the FAQ at  http://www.tux.org/lkml/

[toc] | [next] | [standalone]


#1191813 — [PATCH v7 5/5] ARM: dts: vf-colibri: enable NAND flash controller

FromStefan Agner <stefan@agner.ch>
Date2015-07-24 15:20 +0200
Subject[PATCH v7 5/5] ARM: dts: vf-colibri: enable NAND flash controller
Message-ID<pPL3j-6PY-9@gated-at.bofh.it>
In reply to#1191812
Enable NAND access by adding pinmux and NAND flash controller node
to device tree. The NAND chips currently used on the Colibri VF61
requires 8-bit ECC per 512 byte page, hence specify 32-bit ECC
strength per 2k page size.

Signed-off-by: Stefan Agner <stefan@agner.ch>
---
 arch/arm/boot/dts/vf-colibri.dtsi | 32 ++++++++++++++++++++++++++++++++
 1 file changed, 32 insertions(+)

diff --git a/arch/arm/boot/dts/vf-colibri.dtsi b/arch/arm/boot/dts/vf-colibri.dtsi
index 68ca125..8d7986a 100644
--- a/arch/arm/boot/dts/vf-colibri.dtsi
+++ b/arch/arm/boot/dts/vf-colibri.dtsi
@@ -52,6 +52,19 @@
 	pinctrl-0 = <&pinctrl_i2c0>;
 };
 
+&nfc {
+	assigned-clocks = <&clks VF610_CLK_NFC>;
+	assigned-clock-rates = <33000000>;
+	nand-bus-width = <8>;
+	nand-ecc-mode = "hw";
+	nand-ecc-step-size = <2048>;
+	nand-ecc-strength = <32>;
+	nand-on-flash-bbt;
+	pinctrl-names = "default";
+	pinctrl-0 = <&pinctrl_nfc_1>;
+	status = "okay";
+};
+
 &pwm0 {
 	pinctrl-names = "default";
 	pinctrl-0 = <&pinctrl_pwm0>;
@@ -156,6 +169,25 @@
 			>;
 		};
 
+		pinctrl_nfc_1: nfcgrp_1 {
+			fsl,pins = <
+				VF610_PAD_PTD23__NF_IO7		0x28df
+				VF610_PAD_PTD22__NF_IO6		0x28df
+				VF610_PAD_PTD21__NF_IO5		0x28df
+				VF610_PAD_PTD20__NF_IO4		0x28df
+				VF610_PAD_PTD19__NF_IO3		0x28df
+				VF610_PAD_PTD18__NF_IO2		0x28df
+				VF610_PAD_PTD17__NF_IO1		0x28df
+				VF610_PAD_PTD16__NF_IO0		0x28df
+				VF610_PAD_PTB24__NF_WE_B	0x28c2
+				VF610_PAD_PTB25__NF_CE0_B	0x28c2
+				VF610_PAD_PTB27__NF_RE_B	0x28c2
+				VF610_PAD_PTC26__NF_RB_B	0x283d
+				VF610_PAD_PTC27__NF_ALE		0x28c2
+				VF610_PAD_PTC28__NF_CLE		0x28c2
+			>;
+		};
+
 		pinctrl_pwm0: pwm0grp {
 			fsl,pins = <
 				VF610_PAD_PTB0__FTM0_CH0		0x1182
-- 
2.4.5

--
To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
the body of a message to majordomo@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html
Please read the FAQ at  http://www.tux.org/lkml/

[toc] | [prev] | [next] | [standalone]


#1191817 — [PATCH v7 4/5] ARM: dts: vf610twr: add NAND flash controller peripherial

FromStefan Agner <stefan@agner.ch>
Date2015-07-24 15:20 +0200
Subject[PATCH v7 4/5] ARM: dts: vf610twr: add NAND flash controller peripherial
Message-ID<pPL3k-6PY-23@gated-at.bofh.it>
In reply to#1191812
This adds the NAND flash controller (NFC) peripherial. The driver
supports the SLC NAND chips found on Freescale's Vybrid Tower System
Module. The Micron NAND chip on the module needs 4-bit ECC per 512
byte page. Use 24-bit ECC per 2k page, which is supported by the
driver.

Signed-off-by: Bill Pringlemeir <bpringlemeir@nbsps.com>
Signed-off-by: Stefan Agner <stefan@agner.ch>
---
 arch/arm/boot/dts/vf610-twr.dts | 44 +++++++++++++++++++++++++++++++++++++++++
 arch/arm/boot/dts/vfxxx.dtsi    |  8 ++++++++
 2 files changed, 52 insertions(+)

diff --git a/arch/arm/boot/dts/vf610-twr.dts b/arch/arm/boot/dts/vf610-twr.dts
index 375ab23..0b2b932 100644
--- a/arch/arm/boot/dts/vf610-twr.dts
+++ b/arch/arm/boot/dts/vf610-twr.dts
@@ -287,6 +287,50 @@
 	status = "okay";
 };
 
+&iomuxc {
+	vf610-twr {
+		pinctrl_nfc_1: nfcgrp_1 {
+			fsl,pins = <
+			VF610_PAD_PTD31__NF_IO15	0x28df
+			VF610_PAD_PTD30__NF_IO14	0x28df
+			VF610_PAD_PTD29__NF_IO13	0x28df
+			VF610_PAD_PTD28__NF_IO12	0x28df
+			VF610_PAD_PTD27__NF_IO11	0x28df
+			VF610_PAD_PTD26__NF_IO10	0x28df
+			VF610_PAD_PTD25__NF_IO9		0x28df
+			VF610_PAD_PTD24__NF_IO8		0x28df
+			VF610_PAD_PTD23__NF_IO7		0x28df
+			VF610_PAD_PTD22__NF_IO6		0x28df
+			VF610_PAD_PTD21__NF_IO5		0x28df
+			VF610_PAD_PTD20__NF_IO4		0x28df
+			VF610_PAD_PTD19__NF_IO3		0x28df
+			VF610_PAD_PTD18__NF_IO2		0x28df
+			VF610_PAD_PTD17__NF_IO1		0x28df
+			VF610_PAD_PTD16__NF_IO0		0x28df
+			VF610_PAD_PTB24__NF_WE_B	0x28c2
+			VF610_PAD_PTB25__NF_CE0_B	0x28c2
+			VF610_PAD_PTB27__NF_RE_B	0x28c2
+			VF610_PAD_PTC26__NF_RB_B	0x283d
+			VF610_PAD_PTC27__NF_ALE		0x28c2
+			VF610_PAD_PTC28__NF_CLE		0x28c2
+			>;
+		};
+	};
+};
+
+&nfc {
+	assigned-clocks = <&clks VF610_CLK_NFC>;
+	assigned-clock-rates = <33000000>;
+	nand-bus-width = <16>;
+	nand-ecc-mode = "hw";
+	nand-ecc-step-size = <2048>;
+	nand-ecc-strength = <24>;
+	nand-on-flash-bbt;
+	pinctrl-names = "default";
+	pinctrl-0 = <&pinctrl_nfc_1>;
+	status = "okay";
+};
+
 &uart1 {
 	pinctrl-names = "default";
 	pinctrl-0 = <&pinctrl_uart1>;
diff --git a/arch/arm/boot/dts/vfxxx.dtsi b/arch/arm/boot/dts/vfxxx.dtsi
index 4aa3351..2f4b04d 100644
--- a/arch/arm/boot/dts/vfxxx.dtsi
+++ b/arch/arm/boot/dts/vfxxx.dtsi
@@ -520,6 +520,14 @@
 				status = "disabled";
 			};
 
+			nfc: nand@400e0000 {
+				compatible = "fsl,vf610-nfc";
+				reg = <0x400e0000 0x4000>;
+				interrupts = <83 IRQ_TYPE_LEVEL_HIGH>;
+				clocks = <&clks VF610_CLK_NFC>;
+				clock-names = "nfc";
+				status = "disabled";
+			};
 		};
 	};
 };
-- 
2.4.5

--
To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
the body of a message to majordomo@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html
Please read the FAQ at  http://www.tux.org/lkml/

[toc] | [prev] | [next] | [standalone]


#1192278 — Re: [PATCH v7 4/5] ARM: dts: vf610twr: add NAND flash controller peripherial

FromShawn Guo <shawnguo@kernel.org>
Date2015-07-25 05:40 +0200
SubjectRe: [PATCH v7 4/5] ARM: dts: vf610twr: add NAND flash controller peripherial
Message-ID<pPYtA-Yy-7@gated-at.bofh.it>
In reply to#1191817
On Fri, Jul 24, 2015 at 03:16:23PM +0200, Stefan Agner wrote:
> This adds the NAND flash controller (NFC) peripherial. The driver
> supports the SLC NAND chips found on Freescale's Vybrid Tower System
> Module. The Micron NAND chip on the module needs 4-bit ECC per 512
> byte page. Use 24-bit ECC per 2k page, which is supported by the
> driver.
> 
> Signed-off-by: Bill Pringlemeir <bpringlemeir@nbsps.com>
> Signed-off-by: Stefan Agner <stefan@agner.ch>
> ---
>  arch/arm/boot/dts/vf610-twr.dts | 44 +++++++++++++++++++++++++++++++++++++++++
>  arch/arm/boot/dts/vfxxx.dtsi    |  8 ++++++++
>  2 files changed, 52 insertions(+)
> 
> diff --git a/arch/arm/boot/dts/vf610-twr.dts b/arch/arm/boot/dts/vf610-twr.dts
> index 375ab23..0b2b932 100644
> --- a/arch/arm/boot/dts/vf610-twr.dts
> +++ b/arch/arm/boot/dts/vf610-twr.dts
> @@ -287,6 +287,50 @@
>  	status = "okay";
>  };
>  
> +&iomuxc {
> +	vf610-twr {
> +		pinctrl_nfc_1: nfcgrp_1 {

The suffix "_1" is meaningless.  Please drop it here as well as patch
#5.

Shawn

> +			fsl,pins = <
> +			VF610_PAD_PTD31__NF_IO15	0x28df
> +			VF610_PAD_PTD30__NF_IO14	0x28df
> +			VF610_PAD_PTD29__NF_IO13	0x28df
> +			VF610_PAD_PTD28__NF_IO12	0x28df
> +			VF610_PAD_PTD27__NF_IO11	0x28df
> +			VF610_PAD_PTD26__NF_IO10	0x28df
> +			VF610_PAD_PTD25__NF_IO9		0x28df
> +			VF610_PAD_PTD24__NF_IO8		0x28df
> +			VF610_PAD_PTD23__NF_IO7		0x28df
> +			VF610_PAD_PTD22__NF_IO6		0x28df
> +			VF610_PAD_PTD21__NF_IO5		0x28df
> +			VF610_PAD_PTD20__NF_IO4		0x28df
> +			VF610_PAD_PTD19__NF_IO3		0x28df
> +			VF610_PAD_PTD18__NF_IO2		0x28df
> +			VF610_PAD_PTD17__NF_IO1		0x28df
> +			VF610_PAD_PTD16__NF_IO0		0x28df
> +			VF610_PAD_PTB24__NF_WE_B	0x28c2
> +			VF610_PAD_PTB25__NF_CE0_B	0x28c2
> +			VF610_PAD_PTB27__NF_RE_B	0x28c2
> +			VF610_PAD_PTC26__NF_RB_B	0x283d
> +			VF610_PAD_PTC27__NF_ALE		0x28c2
> +			VF610_PAD_PTC28__NF_CLE		0x28c2
> +			>;
> +		};
> +	};
> +};
> +
> +&nfc {
> +	assigned-clocks = <&clks VF610_CLK_NFC>;
> +	assigned-clock-rates = <33000000>;
> +	nand-bus-width = <16>;
> +	nand-ecc-mode = "hw";
> +	nand-ecc-step-size = <2048>;
> +	nand-ecc-strength = <24>;
> +	nand-on-flash-bbt;
> +	pinctrl-names = "default";
> +	pinctrl-0 = <&pinctrl_nfc_1>;
> +	status = "okay";
> +};
> +
>  &uart1 {
>  	pinctrl-names = "default";
>  	pinctrl-0 = <&pinctrl_uart1>;
> diff --git a/arch/arm/boot/dts/vfxxx.dtsi b/arch/arm/boot/dts/vfxxx.dtsi
> index 4aa3351..2f4b04d 100644
> --- a/arch/arm/boot/dts/vfxxx.dtsi
> +++ b/arch/arm/boot/dts/vfxxx.dtsi
> @@ -520,6 +520,14 @@
>  				status = "disabled";
>  			};
>  
> +			nfc: nand@400e0000 {
> +				compatible = "fsl,vf610-nfc";
> +				reg = <0x400e0000 0x4000>;
> +				interrupts = <83 IRQ_TYPE_LEVEL_HIGH>;
> +				clocks = <&clks VF610_CLK_NFC>;
> +				clock-names = "nfc";
> +				status = "disabled";
> +			};
>  		};
>  	};
>  };
> -- 
> 2.4.5
> 
> 
> _______________________________________________
> linux-arm-kernel mailing list
> linux-arm-kernel@lists.infradead.org
> http://lists.infradead.org/mailman/listinfo/linux-arm-kernel
> 
--
To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
the body of a message to majordomo@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html
Please read the FAQ at  http://www.tux.org/lkml/

[toc] | [prev] | [next] | [standalone]


#1191821 — [PATCH v7 3/5] mtd: nand: vf610_nfc: add device tree bindings

FromStefan Agner <stefan@agner.ch>
Date2015-07-24 15:20 +0200
Subject[PATCH v7 3/5] mtd: nand: vf610_nfc: add device tree bindings
Message-ID<pPL3l-6PY-33@gated-at.bofh.it>
In reply to#1191812
Signed-off-by: Bill Pringlemeir <bpringlemeir@nbsps.com>
Signed-off-by: Stefan Agner <stefan@agner.ch>
---
 .../devicetree/bindings/mtd/vf610-nfc.txt          | 45 ++++++++++++++++++++++
 1 file changed, 45 insertions(+)
 create mode 100644 Documentation/devicetree/bindings/mtd/vf610-nfc.txt

diff --git a/Documentation/devicetree/bindings/mtd/vf610-nfc.txt b/Documentation/devicetree/bindings/mtd/vf610-nfc.txt
new file mode 100644
index 0000000..cae5f25
--- /dev/null
+++ b/Documentation/devicetree/bindings/mtd/vf610-nfc.txt
@@ -0,0 +1,45 @@
+Freescale's NAND flash controller (NFC)
+
+This variant of the Freescale NAND flash controller (NFC) can be found on
+Vybrid (vf610), MPC5125, MCF54418 and Kinetis K70.
+
+Required properties:
+- compatible: Should be set to "fsl,vf610-nfc"
+- reg: address range of the NFC
+- interrupts: interrupt of the NFC
+- nand-bus-width: see nand.txt
+- nand-ecc-mode: see nand.txt
+- nand-on-flash-bbt: see nand.txt
+- assigned-clocks: main clock from the SoC, for Vybrid <&clks VF610_CLK_NFC>;
+- assigned-clock-rates: The NAND bus timing is derived from this clock
+    rate and should not exceed maximum timing for any NAND memory chip
+    in a board stuffing. Typical NAND memory timings derived from this
+    clock are found in the SoC hardware reference manual. Furthermore,
+    there might be restrictions on maximum rates when using hardware ECC.
+
+- #address-cells, #size-cells : Must be present if the device has sub-nodes
+  representing partitions.
+
+Required properties for hardware ECC:
+- nand-ecc-strength: supported strengths are 24 and 32 bit (see nand.txt)
+- nand-ecc-step-size: step size equals page size, currently only 2k pages are
+    supported
+
+Example:
+
+	nfc: nand@400e0000 {
+		compatible = "fsl,vf610-nfc";
+		#address-cells = <1>;
+		#size-cells = <1>;
+		reg = <0x400e0000 0x4000>;
+		interrupts = <GIC_SPI 83 IRQ_TYPE_LEVEL_HIGH>;
+		clocks = <&clks VF610_CLK_NFC>;
+		clock-names = "nfc";
+		assigned-clocks = <&clks VF610_CLK_NFC>;
+		assigned-clock-rates = <33000000>;
+		nand-bus-width = <8>;
+		nand-ecc-mode = "hw";
+		nand-ecc-strength = <32>;
+		nand-ecc-step-size = <2048>;
+		nand-on-flash-bbt;
+	};
-- 
2.4.5

--
To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
the body of a message to majordomo@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html
Please read the FAQ at  http://www.tux.org/lkml/

[toc] | [prev] | [next] | [standalone]


#1191826 — [PATCH v7 2/5] mtd: nand: vf610_nfc: add hardware BCH-ECC support

FromStefan Agner <stefan@agner.ch>
Date2015-07-24 15:20 +0200
Subject[PATCH v7 2/5] mtd: nand: vf610_nfc: add hardware BCH-ECC support
Message-ID<pPL3l-6PY-43@gated-at.bofh.it>
In reply to#1191812
This adds hardware ECC support using the BCH encoder in the NFC IP.
The ECC encoder supports up to 32-bit correction by using 60 error
correction bytes. There is no sub-page ECC step, ECC is calculated
always accross the whole page (up to 2k pages). Raw writes writes
are possible through the common nand_write_page_raw implementation,
however raw reads are not possible since the hardware ECC mode need
to be enabled at command time.

Signed-off-by: Bill Pringlemeir <bpringlemeir@nbsps.com>
Signed-off-by: Stefan Agner <stefan@agner.ch>
---
 drivers/mtd/nand/Kconfig     |   6 +-
 drivers/mtd/nand/vf610_nfc.c | 201 ++++++++++++++++++++++++++++++++++++++++++-
 2 files changed, 204 insertions(+), 3 deletions(-)

diff --git a/drivers/mtd/nand/Kconfig b/drivers/mtd/nand/Kconfig
index 8550b14..e05f53c 100644
--- a/drivers/mtd/nand/Kconfig
+++ b/drivers/mtd/nand/Kconfig
@@ -469,8 +469,10 @@ config MTD_NAND_VF610_NFC
 	help
 	  Enables support for NAND Flash Controller on some Freescale
 	  processors like the VF610, MPC5125, MCF54418 or Kinetis K70.
-	  The driver supports a maximum 2k page size. The driver
-	  currently does not support hardware ECC.
+	  The driver supports a maximum 2k page size. With 2k pages and
+	  64 bytes or more of OOB, hardware ECC with up to 32-bit error
+	  correction is supported. Hardware ECC is only enabled through
+	  device tree.
 
 config MTD_NAND_MXC
 	tristate "MXC NAND support"
diff --git a/drivers/mtd/nand/vf610_nfc.c b/drivers/mtd/nand/vf610_nfc.c
index 0da500e..4d795a5 100644
--- a/drivers/mtd/nand/vf610_nfc.c
+++ b/drivers/mtd/nand/vf610_nfc.c
@@ -19,6 +19,8 @@
  * - Untested on MPC5125 and M54418.
  * - DMA not used.
  * - 2K pages or less.
+ * - Only 2K page w. 64+ OOB and hardware ECC.
+ * - Raw page reads not implemented when using ECC.
  */
 
 #include <linux/module.h>
@@ -72,6 +74,8 @@
 
 /* NFC ECC mode define */
 #define ECC_BYPASS			0
+#define ECC_45_BYTE			6
+#define ECC_60_BYTE			7
 
 /*** Register Mask and bit definitions */
 
@@ -104,6 +108,8 @@
 #define STATUS_BYTE1_MASK			0x000000FF
 
 /* NFC_FLASH_CONFIG Field */
+#define CONFIG_ECC_SRAM_ADDR_MASK		0x7FC00000
+#define CONFIG_ECC_SRAM_ADDR_SHIFT		22
 #define CONFIG_ECC_SRAM_REQ_BIT			(1<<21)
 #define CONFIG_DMA_REQ_BIT			(1<<20)
 #define CONFIG_ECC_MODE_MASK			0x000E0000
@@ -122,6 +128,21 @@
 #define CMD_DONE_CLEAR_BIT			(1<<18)
 #define IDLE_CLEAR_BIT				(1<<17)
 
+/* ECC status placed at end of buffers. */
+#define ECC_SRAM_ADDR	((PAGE_2K + 256 - 8) >> 3)
+#define ECC_STATUS_MASK	0x80
+#define ECC_ERR_COUNT	0x3F
+
+/*
+ * ECC status is stored at NFC_CFG[ECCADD] +4 for little-endian
+ * and +7 for big-endian SoCs.
+ */
+#ifdef __LITTLE_ENDIAN
+#define ECC_OFFSET	4
+#else
+#define ECC_OFFSET	7
+#endif
+
 struct vf610_nfc {
 	struct mtd_info mtd;
 	struct nand_chip chip;
@@ -136,10 +157,40 @@ struct vf610_nfc {
 #define ALT_BUF_STAT 2
 #define ALT_BUF_ONFI 3
 	struct clk *clk;
+	bool use_hw_ecc;
+	u32 ecc_mode;
 };
 
 #define mtd_to_nfc(_mtd) container_of(_mtd, struct vf610_nfc, mtd)
 
+static struct nand_ecclayout vf610_nfc_ecc45 = {
+	.eccbytes = 45,
+	.eccpos = {19, 20, 21, 22, 23,
+		   24, 25, 26, 27, 28, 29, 30, 31,
+		   32, 33, 34, 35, 36, 37, 38, 39,
+		   40, 41, 42, 43, 44, 45, 46, 47,
+		   48, 49, 50, 51, 52, 53, 54, 55,
+		   56, 57, 58, 59, 60, 61, 62, 63},
+	.oobfree = {
+		{.offset = 2,
+		 .length = 17} }
+};
+
+static struct nand_ecclayout vf610_nfc_ecc60 = {
+	.eccbytes = 60,
+	.eccpos = { 4,  5,  6,  7,  8,  9, 10, 11,
+		   12, 13, 14, 15, 16, 17, 18, 19,
+		   20, 21, 22, 23, 24, 25, 26, 27,
+		   28, 29, 30, 31, 32, 33, 34, 35,
+		   36, 37, 38, 39, 40, 41, 42, 43,
+		   44, 45, 46, 47, 48, 49, 50, 51,
+		   52, 53, 54, 55, 56, 57, 58, 59,
+		   60, 61, 62, 63 },
+	.oobfree = {
+		{.offset = 2,
+		 .length = 2} }
+};
+
 static inline u32 vf610_nfc_read(struct vf610_nfc *nfc, uint reg)
 {
 	return readl(nfc->regs + reg);
@@ -281,6 +332,13 @@ static void vf610_nfc_addr_cycle(struct vf610_nfc *nfc, int column, int page)
 				    ROW_ADDR_SHIFT, page);
 }
 
+static inline void vf610_nfc_ecc_mode(struct vf610_nfc *nfc, int ecc_mode)
+{
+	vf610_nfc_set_field(nfc, NFC_FLASH_CONFIG,
+			    CONFIG_ECC_MODE_MASK,
+			    CONFIG_ECC_MODE_SHIFT, ecc_mode);
+}
+
 static inline void vf610_nfc_transfer_size(struct vf610_nfc *nfc, int size)
 {
 	vf610_nfc_write(nfc, NFC_SECTOR_SIZE, size);
@@ -299,13 +357,20 @@ static void vf610_nfc_command(struct mtd_info *mtd, unsigned command,
 	case NAND_CMD_SEQIN:
 		/* Use valid column/page from preread... */
 		vf610_nfc_addr_cycle(nfc, column, page);
+		nfc->buf_offset = 0;
+
 		/*
 		 * SEQIN => data => PAGEPROG sequence is done by the controller
 		 * hence we do not need to issue the command here...
 		 */
 		return;
 	case NAND_CMD_PAGEPROG:
-		page_sz += mtd->writesize + mtd->oobsize;
+		page_sz += nfc->page_sz;
+		if (nfc->use_hw_ecc)
+			vf610_nfc_ecc_mode(nfc, nfc->ecc_mode);
+		else
+			vf610_nfc_ecc_mode(nfc, ECC_BYPASS);
+
 		vf610_nfc_transfer_size(nfc, page_sz);
 		vf610_nfc_send_commands(nfc, NAND_CMD_SEQIN,
 					command, PROGRAM_PAGE_CMD_CODE);
@@ -323,11 +388,13 @@ static void vf610_nfc_command(struct mtd_info *mtd, unsigned command,
 		vf610_nfc_send_commands(nfc, NAND_CMD_READ0,
 					NAND_CMD_READSTART, READ_PAGE_CMD_CODE);
 		vf610_nfc_addr_cycle(nfc, column, page);
+		vf610_nfc_ecc_mode(nfc, ECC_BYPASS);
 		break;
 
 	case NAND_CMD_READ0:
 		page_sz += mtd->writesize + mtd->oobsize;
 		vf610_nfc_transfer_size(nfc, page_sz);
+		vf610_nfc_ecc_mode(nfc, nfc->ecc_mode);
 		vf610_nfc_send_commands(nfc, NAND_CMD_READ0,
 					NAND_CMD_READSTART, READ_PAGE_CMD_CODE);
 		vf610_nfc_addr_cycle(nfc, column, page);
@@ -339,6 +406,7 @@ static void vf610_nfc_command(struct mtd_info *mtd, unsigned command,
 		vf610_nfc_send_command(nfc, command, READ_ONFI_PARAM_CMD_CODE);
 		vf610_nfc_set_field(nfc, NFC_ROW_ADDR, ROW_ADDR_MASK,
 				    ROW_ADDR_SHIFT, column);
+		vf610_nfc_ecc_mode(nfc, ECC_BYPASS);
 		break;
 
 	case NAND_CMD_ERASE1:
@@ -367,6 +435,9 @@ static void vf610_nfc_command(struct mtd_info *mtd, unsigned command,
 	}
 
 	vf610_nfc_done(nfc);
+
+	nfc->use_hw_ecc = false;
+	nfc->page_sz = 0;
 }
 
 static void vf610_nfc_read_buf(struct mtd_info *mtd, u_char *buf, int len)
@@ -392,6 +463,7 @@ static void vf610_nfc_write_buf(struct mtd_info *mtd, const uint8_t *buf,
 	l = min_t(uint, len, mtd->writesize + mtd->oobsize - c);
 	vf610_nfc_memcpy(nfc->regs + NFC_MAIN_AREA(0) + c, buf, l);
 
+	nfc->page_sz += l;
 	nfc->buf_offset += l;
 }
 
@@ -459,6 +531,84 @@ static void vf610_nfc_select_chip(struct mtd_info *mtd, int chip)
 #endif
 }
 
+/* Count the number of 0's in buff up to max_bits */
+static inline int count_written_bits(uint8_t *buff, int size, int max_bits)
+{
+	uint32_t *buff32 = (uint32_t *)buff;
+	int k, written_bits = 0;
+
+	for (k = 0; k < (size / 4); k++) {
+		written_bits += hweight32(~buff32[k]);
+		if (written_bits > max_bits)
+			break;
+	}
+
+	return written_bits;
+}
+
+static inline int vf610_nfc_correct_data(struct mtd_info *mtd, uint8_t *dat)
+{
+	struct vf610_nfc *nfc = mtd_to_nfc(mtd);
+	u8 ecc_status;
+	u8 ecc_count;
+	int flip;
+
+	ecc_status = __raw_readb(nfc->regs + ECC_SRAM_ADDR * 8 + ECC_OFFSET);
+	ecc_count = ecc_status & ECC_ERR_COUNT;
+	if (!(ecc_status & ECC_STATUS_MASK))
+		return ecc_count;
+
+	/*
+	 * On an erased page, bit count should be zero or at least
+	 * less then half of the ECC strength
+	 */
+	flip = count_written_bits(dat, nfc->chip.ecc.size, ecc_count);
+
+	if (flip > ecc_count && flip > (nfc->chip.ecc.strength / 2))
+		return -1;
+
+	/* Erased page. */
+	memset(dat, 0xff, nfc->chip.ecc.size);
+	return 0;
+}
+
+static int vf610_nfc_read_page(struct mtd_info *mtd, struct nand_chip *chip,
+				uint8_t *buf, int oob_required, int page)
+{
+	int eccsize = chip->ecc.size;
+	int stat;
+
+	vf610_nfc_read_buf(mtd, buf, eccsize);
+
+	if (oob_required)
+		vf610_nfc_read_buf(mtd, chip->oob_poi, mtd->oobsize);
+
+	stat = vf610_nfc_correct_data(mtd, buf);
+
+	if (stat < 0)
+		mtd->ecc_stats.failed++;
+	else
+		mtd->ecc_stats.corrected += stat;
+
+	return 0;
+}
+
+static int vf610_nfc_write_page(struct mtd_info *mtd, struct nand_chip *chip,
+			       const uint8_t *buf, int oob_required)
+{
+	struct vf610_nfc *nfc = mtd_to_nfc(mtd);
+
+	vf610_nfc_write_buf(mtd, buf, mtd->writesize);
+	if (oob_required)
+		vf610_nfc_write_buf(mtd, chip->oob_poi, mtd->oobsize);
+
+	/* Always write whole page including OOB due to HW ECC */
+	nfc->use_hw_ecc = true;
+	nfc->page_sz = mtd->writesize + mtd->oobsize;
+
+	return 0;
+}
+
 static const struct of_device_id vf610_nfc_dt_ids[] = {
 	{ .compatible = "fsl,vf610-nfc" },
 	{ /* sentinel */ }
@@ -483,6 +633,16 @@ static int vf610_nfc_init_controller(struct vf610_nfc *nfc)
 	vf610_nfc_set_field(nfc, NFC_FLASH_CONFIG, CONFIG_PAGE_CNT_MASK,
 			    CONFIG_PAGE_CNT_SHIFT, 1);
 
+	if (nfc->chip.ecc.mode == NAND_ECC_HW) {
+		/* Set ECC_STATUS offset */
+		vf610_nfc_set_field(nfc, NFC_FLASH_CONFIG,
+				    CONFIG_ECC_SRAM_ADDR_MASK,
+				    CONFIG_ECC_SRAM_ADDR_SHIFT, ECC_SRAM_ADDR);
+
+		/* Enable ECC_STATUS */
+		vf610_nfc_set(nfc, NFC_FLASH_CONFIG, CONFIG_ECC_SRAM_REQ_BIT);
+	}
+
 	return 0;
 }
 
@@ -565,6 +725,45 @@ static int vf610_nfc_probe(struct platform_device *pdev)
 		goto error;
 	}
 
+	if (chip->ecc.mode == NAND_ECC_HW) {
+		if (mtd->writesize != PAGE_2K && mtd->oobsize < 64) {
+			dev_err(nfc->dev, "Unsupported flash with hwecc\n");
+			err = -ENXIO;
+			goto error;
+		}
+
+		if (chip->ecc.size != mtd->writesize) {
+			dev_err(nfc->dev, "Step size needs to be page size\n");
+			err = -ENXIO;
+			goto error;
+		}
+
+		/* Only 64 byte ECC layouts known */
+		if (mtd->oobsize > 64)
+			mtd->oobsize = 64;
+
+		if (chip->ecc.strength == 32) {
+			nfc->ecc_mode = ECC_60_BYTE;
+			chip->ecc.bytes = 60;
+			chip->ecc.layout = &vf610_nfc_ecc60;
+		} else if (chip->ecc.strength == 24) {
+			nfc->ecc_mode = ECC_45_BYTE;
+			chip->ecc.bytes = 45;
+			chip->ecc.layout = &vf610_nfc_ecc45;
+		} else {
+			dev_err(nfc->dev, "Unsupported ECC strength\n");
+			err = -ENXIO;
+			goto error;
+		}
+
+		/* propagate ecc.layout to mtd_info */
+		mtd->ecclayout = chip->ecc.layout;
+		chip->ecc.read_page = vf610_nfc_read_page;
+		chip->ecc.write_page = vf610_nfc_write_page;
+
+		chip->ecc.size = PAGE_2K;
+	}
+
 	/* second phase scan */
 	if (nand_scan_tail(mtd)) {
 		err = -ENXIO;
-- 
2.4.5

--
To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
the body of a message to majordomo@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html
Please read the FAQ at  http://www.tux.org/lkml/

[toc] | [prev] | [standalone]


Back to top | Article view | linux.kernel


csiph-web