All of lore.kernel.org
 help / color / mirror / Atom feed
* [U-Boot] [PATCH 0/7] sunxi: Add support for the CHIP Pro
@ 2016-11-08 16:21 Maxime Ripard
  2016-11-08 16:21 ` [U-Boot] [PATCH 1/7] sunxi: Sync GR8 DTS and AXP209 with the kernel Maxime Ripard
                   ` (7 more replies)
  0 siblings, 8 replies; 44+ messages in thread
From: Maxime Ripard @ 2016-11-08 16:21 UTC (permalink / raw)
  To: u-boot

The CHIP Pro is a SoM made by NextThing Co, and that embeds a GR8 SIP, an
AXP209 PMIC, a WiFi BT chip and a 512MB SLC NAND.

Since the first Allwinner device coming whit an SLC NAND that doesn't have
the shortcomings (and breakages) the MLC NAND has, we can finally enable
the NAND support on a board by default.

This is the occasion to introduce a bunch of additions needed imo to be
able to come up with a sane NAND support for our users.

The biggest pain point is that the BROM uses a different ECC and randomizer
configuration than for the rest of the NAND. In order to lessen the number
of bitflips, you also need to pad with random data the SPL image.

Since it's quite tedious to do right (and most users won't be able to
figure it out) and since if it is not done right, it will eventually turn
into an unusable system (which is bad UX), we think that the best solution
is to generate an SPL image that already embeds all this. We'll possible
have to do the same thing for the U-Boot image (at least for the random
padding) on MLC NANDs.

The only drawback from that is that you need to flash it raw, instead of
using the usual nand write, but it's just a different command, nothing
major anyway.

In order to flash it, from a device switched in FEL, on your host:
sunxi-fel spl spl/sunxi-spl.bin
sunxi-fel write 0x4a000000 u-boot-dtb.bin
sunxi-fel write 0x43000000 spl/sunxi-spl-with-ecc.bin
sunxi-fel exe 0x4a000000

And on the board, once u-boot is running (assuming the NAND is already
erased):

nand write.raw.noverify 0x43000000 0 40
nand write.raw.noverify 0x43000000 0x400000 40

nand write 0x4a000000 0x800000 0xc0000

I also encountered some weird bug in the private libgcc that prevents
U-Boot from loading. Disabling CONFIG_USE_PRIVATE_LIBGCC fixes that.

Let me know what you think,
Maxime

Boris Brezillon (1):
  mtd: nand: add support for the TC58NVG2S0H chip

Hans de Goede (1):
  sunxi: Enable UBI and NAND support

Maxime Ripard (5):
  sunxi: Sync GR8 DTS and AXP209 with the kernel
  tools: sunxi: Add spl image builder
  nand: sunxi: Add options for the SPL NAND configuration
  scripts: sunxi: Build an raw SPL image
  sunxi: Add support for the CHIP Pro

 Makefile                          |    3 +-
 arch/arm/dts/Makefile             |    1 +-
 arch/arm/dts/axp209.dtsi          |    6 +-
 arch/arm/dts/ntc-gr8-chip-pro.dts |  266 +++++++-
 arch/arm/dts/ntc-gr8.dtsi         | 1132 ++++++++++++++++++++++++++++++-
 configs/CHIP_pro_defconfig        |   27 +-
 drivers/mtd/nand/Kconfig          |   16 +-
 drivers/mtd/nand/nand_ids.c       |    3 +-
 include/configs/sunxi-common.h    |   26 +-
 scripts/Makefile.spl              |   12 +-
 tools/.gitignore                  |    1 +-
 tools/Makefile                    |    1 +-
 tools/sunxi-spl-image-builder.c   | 1113 +++++++++++++++++++++++++++++-
 13 files changed, 2603 insertions(+), 4 deletions(-)
 create mode 100644 arch/arm/dts/ntc-gr8-chip-pro.dts
 create mode 100644 arch/arm/dts/ntc-gr8.dtsi
 create mode 100644 configs/CHIP_pro_defconfig
 create mode 100644 tools/sunxi-spl-image-builder.c

base-commit: d8bdfc80da39211d95f10d24e79f2e867305f71b
-- 
git-series 0.8.11

^ permalink raw reply	[flat|nested] 44+ messages in thread

* [U-Boot] [PATCH 1/7] sunxi: Sync GR8 DTS and AXP209 with the kernel
  2016-11-08 16:21 [U-Boot] [PATCH 0/7] sunxi: Add support for the CHIP Pro Maxime Ripard
@ 2016-11-08 16:21 ` Maxime Ripard
  2016-11-14 11:15   ` Hans de Goede
  2016-11-08 16:21 ` [U-Boot] [PATCH 2/7] mtd: nand: add support for the TC58NVG2S0H chip Maxime Ripard
                   ` (6 subsequent siblings)
  7 siblings, 1 reply; 44+ messages in thread
From: Maxime Ripard @ 2016-11-08 16:21 UTC (permalink / raw)
  To: u-boot

Those DT will be part of 4.10, sync them so we can have our own config.

Signed-off-by: Maxime Ripard <maxime.ripard@free-electrons.com>
---
 arch/arm/dts/Makefile             |    1 +-
 arch/arm/dts/axp209.dtsi          |    6 +-
 arch/arm/dts/ntc-gr8-chip-pro.dts |  266 +++++++-
 arch/arm/dts/ntc-gr8.dtsi         | 1132 ++++++++++++++++++++++++++++++-
 4 files changed, 1405 insertions(+), 0 deletions(-)
 create mode 100644 arch/arm/dts/ntc-gr8-chip-pro.dts
 create mode 100644 arch/arm/dts/ntc-gr8.dtsi

diff --git a/arch/arm/dts/Makefile b/arch/arm/dts/Makefile
index 836a8c4d1ee2..932dbe07cf14 100644
--- a/arch/arm/dts/Makefile
+++ b/arch/arm/dts/Makefile
@@ -180,6 +180,7 @@ dtb-$(CONFIG_MACH_SUN4I) += \
 	sun4i-a10-pcduino2.dtb \
 	sun4i-a10-pov-protab2-ips9.dtb
 dtb-$(CONFIG_MACH_SUN5I) += \
+	ntc-gr8-chip-pro.dtb \
 	sun5i-a10s-auxtek-t003.dtb \
 	sun5i-a10s-auxtek-t004.dtb \
 	sun5i-a10s-mk802.dtb \
diff --git a/arch/arm/dts/axp209.dtsi b/arch/arm/dts/axp209.dtsi
index afbe89c01df5..675bb0f30825 100644
--- a/arch/arm/dts/axp209.dtsi
+++ b/arch/arm/dts/axp209.dtsi
@@ -53,6 +53,12 @@
 	interrupt-controller;
 	#interrupt-cells = <1>;
 
+	axp_gpio: gpio {
+		compatible = "x-powers,axp209-gpio";
+		gpio-controller;
+		#gpio-cells = <2>;
+	};
+
 	regulators {
 		/* Default work frequency for buck regulators */
 		x-powers,dcdc-freq = <1500>;
diff --git a/arch/arm/dts/ntc-gr8-chip-pro.dts b/arch/arm/dts/ntc-gr8-chip-pro.dts
new file mode 100644
index 000000000000..c4be912df481
--- /dev/null
+++ b/arch/arm/dts/ntc-gr8-chip-pro.dts
@@ -0,0 +1,266 @@
+/*
+ * Copyright 2016 Free Electrons
+ * Copyright 2016 NextThing Co
+ *
+ * Maxime Ripard <maxime.ripard@free-electrons.com>
+ *
+ * This file is dual-licensed: you can use it either under the terms
+ * of the GPL or the X11 license, at your option. Note that this dual
+ * licensing only applies to this file, and not this project as a
+ * whole.
+ *
+ *  a) This file is free software; you can redistribute it and/or
+ *     modify it under the terms of the GNU General Public License as
+ *     published by the Free Software Foundation; either version 2 of the
+ *     License, or (at your option) any later version.
+ *
+ *     This file is distributed in the hope that it will be useful,
+ *     but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *     GNU General Public License for more details.
+ *
+ * Or, alternatively,
+ *
+ *  b) Permission is hereby granted, free of charge, to any person
+ *     obtaining a copy of this software and associated documentation
+ *     files (the "Software"), to deal in the Software without
+ *     restriction, including without limitation the rights to use,
+ *     copy, modify, merge, publish, distribute, sublicense, and/or
+ *     sell copies of the Software, and to permit persons to whom the
+ *     Software is furnished to do so, subject to the following
+ *     conditions:
+ *
+ *     The above copyright notice and this permission notice shall be
+ *     included in all copies or substantial portions of the Software.
+ *
+ *     THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ *     EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
+ *     OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ *     NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
+ *     HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
+ *     WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ *     FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+ *     OTHER DEALINGS IN THE SOFTWARE.
+ */
+
+/dts-v1/;
+#include "ntc-gr8.dtsi"
+#include "sunxi-common-regulators.dtsi"
+
+#include <dt-bindings/gpio/gpio.h>
+#include <dt-bindings/input/input.h>
+#include <dt-bindings/interrupt-controller/irq.h>
+
+/ {
+	model = "NextThing C.H.I.P. Pro";
+	compatible = "nextthing,chip-pro", "nextthing,gr8";
+
+	aliases {
+		i2c0 = &i2c0;
+		i2c1 = &i2c1;
+		serial0 = &uart1;
+		serial1 = &uart2;
+		serial2 = &uart3;
+	};
+
+	chosen {
+		stdout-path = "serial0:115200n8";
+	};
+
+	leds {
+		compatible = "gpio-leds";
+
+		status {
+			label = "chip-pro:white:status";
+			gpios = <&axp_gpio 2 GPIO_ACTIVE_HIGH>;
+			default-state = "on";
+		};
+	};
+
+	mmc0_pwrseq: mmc0_pwrseq {
+		compatible = "mmc-pwrseq-simple";
+		pinctrl-names = "default";
+		pinctrl-0 = <&wifi_reg_on_pin_chip_pro>;
+		reset-gpios = <&pio 1 10 GPIO_ACTIVE_LOW>; /* PB10 */
+	};
+};
+
+&codec {
+	status = "okay";
+};
+
+&ehci0 {
+	status = "okay";
+};
+
+&i2c0 {
+	pinctrl-names = "default";
+	pinctrl-0 = <&i2c0_pins_a>;
+	status = "okay";
+
+	axp209: pmic at 34 {
+		reg = <0x34>;
+
+		/*
+		* The interrupt is routed through the "External Fast
+		* Interrupt Request" pin (ball G13 of the module)
+		* directly to the main interrupt controller, without
+		* any other controller interfering.
+		*/
+		interrupts = <0>;
+	};
+};
+
+#include "axp209.dtsi"
+
+&i2c1 {
+	pinctrl-names = "default";
+	pinctrl-0 = <&i2c1_pins_a>;
+	status = "disabled";
+};
+
+&i2s0 {
+	pinctrl-names = "default";
+	pinctrl-0 = <&i2s0_mclk_pins_a>, <&i2s0_data_pins_a>;
+	status = "disabled";
+};
+
+&mmc0 {
+	pinctrl-names = "default";
+	pinctrl-0 = <&mmc0_pins_a>;
+	vmmc-supply = <&reg_vcc3v3>;
+	mmc-pwrseq = <&mmc0_pwrseq>;
+	bus-width = <4>;
+	non-removable;
+	status = "okay";
+};
+
+&nfc {
+	pinctrl-names = "default";
+	pinctrl-0 = <&nand_pins_a &nand_cs0_pins_a &nand_rb0_pins_a>;
+	status = "okay";
+
+	nand at 0 {
+		#address-cells = <2>;
+		#size-cells = <2>;
+		reg = <0>;
+		allwinner,rb = <0>;
+		nand-ecc-mode = "hw";
+	};
+};
+
+&ohci0 {
+	status = "okay";
+};
+
+&otg_sram {
+	status = "okay";
+};
+
+&pio {
+	usb0_id_pin_chip_pro: usb0-id-pin at 0 {
+		allwinner,pins = "PG2";
+		allwinner,function = "gpio_in";
+		allwinner,drive = <SUN4I_PINCTRL_10_MA>;
+		allwinner,pull = <SUN4I_PINCTRL_NO_PULL>;
+	};
+
+	wifi_reg_on_pin_chip_pro: wifi-reg-on-pin at 0 {
+		allwinner,pins = "PB10";
+		allwinner,function = "gpio_out";
+		allwinner,drive = <SUN4I_PINCTRL_10_MA>;
+		allwinner,pull = <SUN4I_PINCTRL_NO_PULL>;
+	};
+};
+
+&pwm {
+	pinctrl-names = "default";
+	pinctrl-0 = <&pwm0_pins_a>, <&pwm1_pins>;
+	status = "disabled";
+};
+
+&reg_dcdc2 {
+	regulator-min-microvolt = <1000000>;
+	regulator-max-microvolt = <1400000>;
+	regulator-name = "vdd-cpu";
+	regulator-always-on;
+};
+
+&reg_dcdc3 {
+	regulator-min-microvolt = <1000000>;
+	regulator-max-microvolt = <1300000>;
+	regulator-name = "vdd-sys";
+	regulator-always-on;
+};
+
+&reg_ldo1 {
+	regulator-name = "vdd-rtc";
+};
+
+&reg_ldo2 {
+	regulator-min-microvolt = <2700000>;
+	regulator-max-microvolt = <3300000>;
+	regulator-name = "avcc";
+	regulator-always-on;
+};
+
+/*
+ * Both LDO3 and LDO4 are used in parallel to power up the
+ * WiFi/BT chip.
+ */
+&reg_ldo3 {
+	regulator-min-microvolt = <3300000>;
+	regulator-max-microvolt = <3300000>;
+	regulator-name = "vcc-wifi-1";
+	regulator-always-on;
+};
+
+&reg_ldo4 {
+	regulator-min-microvolt = <3300000>;
+	regulator-max-microvolt = <3300000>;
+	regulator-name = "vcc-wifi-2";
+	regulator-always-on;
+};
+
+&uart1 {
+	pinctrl-names = "default";
+	pinctrl-0 = <&uart1_pins_a>, <&uart1_cts_rts_pins_a>;
+	status = "okay";
+};
+
+&uart2 {
+	pinctrl-names = "default";
+	pinctrl-0 = <&uart2_pins_a>, <&uart2_cts_rts_pins_a>;
+	status = "disabled";
+};
+
+&uart3 {
+	pinctrl-names = "default";
+	pinctrl-0 = <&uart3_pins_a>, <&uart3_cts_rts_pins_a>;
+	status = "okay";
+};
+
+&usb_otg {
+	/*
+	 * The CHIP Pro doesn't have a controllable VBUS, nor does it
+	 * have any 5v rail on the board itself.
+	 *
+	 * If one wants to use it as a true OTG port, it should be
+	 * done in the baseboard, and its DT / overlay will add it.
+	 */
+	dr_mode = "otg";
+	status = "okay";
+};
+
+&usb_power_supply {
+	status = "okay";
+};
+
+&usbphy {
+	pinctrl-names = "default";
+	pinctrl-0 = <&usb0_id_pin_chip_pro>;
+	usb0_id_det-gpio = <&pio 6 2 GPIO_ACTIVE_HIGH>; /* PG2 */
+	usb0_vbus_power-supply = <&usb_power_supply>;
+	usb1_vbus-supply = <&reg_vcc5v0>;
+	status = "okay";
+};
diff --git a/arch/arm/dts/ntc-gr8.dtsi b/arch/arm/dts/ntc-gr8.dtsi
new file mode 100644
index 000000000000..ea86d4d58db6
--- /dev/null
+++ b/arch/arm/dts/ntc-gr8.dtsi
@@ -0,0 +1,1132 @@
+/*
+ * Copyright 2016 Myl?ne Josserand
+ *
+ * Myl?ne Josserand <mylene.josserand@free-electrons.com>
+ *
+ * This file is dual-licensed: you can use it either under the terms
+ * of the GPL or the X11 license, at your option. Note that this dual
+ * licensing only applies to this file, and not this project as a
+ * whole.
+ *
+ *  a) This library is free software; you can redistribute it and/or
+ *     modify it under the terms of the GNU General Public License as
+ *     published by the Free Software Foundation; either version 2 of the
+ *     License, or (at your option) any later version.
+ *
+ *     This library is distributed in the hope that it will be useful,
+ *     but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *     GNU General Public License for more details.
+ *
+ * Or, alternatively,
+ *
+ *  b) Permission is hereby granted, free of charge, to any person
+ *     obtaining a copy of this software and associated documentation
+ *     files (the "Software"), to deal in the Software without
+ *     restriction, including without limitation the rights to use,
+ *     copy, modify, merge, publish, distribute, sublicense, and/or
+ *     sell copies of the Software, and to permit persons to whom the
+ *     Software is furnished to do so, subject to the following
+ *     conditions:
+ *
+ *     The above copyright notice and this permission notice shall be
+ *     included in all copies or substantial portions of the Software.
+ *
+ *     THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ *     EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
+ *     OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ *     NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
+ *     HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
+ *     WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ *     FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+ *     OTHER DEALINGS IN THE SOFTWARE.
+ */
+
+#include <dt-bindings/clock/sun4i-a10-pll2.h>
+#include <dt-bindings/dma/sun4i-a10.h>
+#include <dt-bindings/pinctrl/sun4i-a10.h>
+
+/ {
+	interrupt-parent = <&intc>;
+	#address-cells = <1>;
+	#size-cells = <1>;
+
+	cpus {
+		#address-cells = <1>;
+		#size-cells = <0>;
+
+		cpu0: cpu at 0 {
+			device_type = "cpu";
+			compatible = "arm,cortex-a8";
+			reg = <0x0>;
+			clocks = <&cpu>;
+		};
+	};
+
+	clocks {
+		#address-cells = <1>;
+		#size-cells = <1>;
+		ranges;
+
+		/*
+		 * This is a dummy clock, to be used as placeholder on
+		 * other mux clocks when a specific parent clock is not
+		 * yet implemented. It should be dropped when the driver
+		 * is complete.
+		 */
+		dummy: dummy {
+			#clock-cells = <0>;
+			compatible = "fixed-clock";
+			clock-frequency = <0>;
+		};
+
+		osc24M: clk at 01c20050 {
+			#clock-cells = <0>;
+			compatible = "allwinner,sun4i-a10-osc-clk";
+			reg = <0x01c20050 0x4>;
+			clock-frequency = <24000000>;
+			clock-output-names = "osc24M";
+		};
+
+		osc3M: osc3M-clk {
+			compatible = "fixed-factor-clock";
+			#clock-cells = <0>;
+			clock-div = <8>;
+			clock-mult = <1>;
+			clocks = <&osc24M>;
+			clock-output-names = "osc3M";
+		};
+
+		osc32k: clk at 0 {
+			#clock-cells = <0>;
+			compatible = "fixed-clock";
+			clock-frequency = <32768>;
+			clock-output-names = "osc32k";
+		};
+
+		pll1: clk at 01c20000 {
+			#clock-cells = <0>;
+			compatible = "allwinner,sun4i-a10-pll1-clk";
+			reg = <0x01c20000 0x4>;
+			clocks = <&osc24M>;
+			clock-output-names = "pll1";
+		};
+
+		pll2: clk at 01c20008 {
+			#clock-cells = <1>;
+			compatible = "allwinner,sun5i-a13-pll2-clk";
+			reg = <0x01c20008 0x8>;
+			clocks = <&osc24M>;
+			clock-output-names = "pll2-1x", "pll2-2x",
+					     "pll2-4x", "pll2-8x";
+		};
+
+		pll3: clk at 01c20010 {
+			#clock-cells = <0>;
+			compatible = "allwinner,sun4i-a10-pll3-clk";
+			reg = <0x01c20010 0x4>;
+			clocks = <&osc3M>;
+			clock-output-names = "pll3";
+		};
+
+		pll3x2: pll3x2-clk {
+			compatible = "allwinner,sun4i-a10-pll3-2x-clk";
+			#clock-cells = <0>;
+			clock-div = <1>;
+			clock-mult = <2>;
+			clocks = <&pll3>;
+			clock-output-names = "pll3-2x";
+		};
+
+		pll4: clk at 01c20018 {
+			#clock-cells = <0>;
+			compatible = "allwinner,sun4i-a10-pll1-clk";
+			reg = <0x01c20018 0x4>;
+			clocks = <&osc24M>;
+			clock-output-names = "pll4";
+		};
+
+		pll5: clk at 01c20020 {
+			#clock-cells = <1>;
+			compatible = "allwinner,sun4i-a10-pll5-clk";
+			reg = <0x01c20020 0x4>;
+			clocks = <&osc24M>;
+			clock-output-names = "pll5_ddr", "pll5_other";
+		};
+
+		pll6: clk at 01c20028 {
+			#clock-cells = <1>;
+			compatible = "allwinner,sun4i-a10-pll6-clk";
+			reg = <0x01c20028 0x4>;
+			clocks = <&osc24M>;
+			clock-output-names = "pll6_sata", "pll6_other", "pll6";
+		};
+
+		pll7: clk at 01c20030 {
+			#clock-cells = <0>;
+			compatible = "allwinner,sun4i-a10-pll3-clk";
+			reg = <0x01c20030 0x4>;
+			clocks = <&osc3M>;
+			clock-output-names = "pll7";
+		};
+
+		pll7x2: pll7x2-clk {
+			compatible = "allwinner,sun4i-a10-pll3-2x-clk";
+			#clock-cells = <0>;
+			clock-div = <1>;
+			clock-mult = <2>;
+			clocks = <&pll7>;
+			clock-output-names = "pll7-2x";
+		};
+
+		/* dummy is 200M */
+		cpu: cpu at 01c20054 {
+			#clock-cells = <0>;
+			compatible = "allwinner,sun4i-a10-cpu-clk";
+			reg = <0x01c20054 0x4>;
+			clocks = <&osc32k>, <&osc24M>, <&pll1>, <&dummy>;
+			clock-output-names = "cpu";
+		};
+
+		axi: axi at 01c20054 {
+			#clock-cells = <0>;
+			compatible = "allwinner,sun4i-a10-axi-clk";
+			reg = <0x01c20054 0x4>;
+			clocks = <&cpu>;
+			clock-output-names = "axi";
+		};
+
+		ahb: ahb at 01c20054 {
+			#clock-cells = <0>;
+			compatible = "allwinner,sun5i-a13-ahb-clk";
+			reg = <0x01c20054 0x4>;
+			clocks = <&axi>, <&cpu>, <&pll6 1>;
+			clock-output-names = "ahb";
+			/*
+			 * Use PLL6 as parent, instead of CPU/AXI
+			 * which has rate changes due to cpufreq
+			 */
+			assigned-clocks = <&ahb>;
+			assigned-clock-parents = <&pll6 1>;
+		};
+
+		apb0: apb0 at 01c20054 {
+			#clock-cells = <0>;
+			compatible = "allwinner,sun4i-a10-apb0-clk";
+			reg = <0x01c20054 0x4>;
+			clocks = <&ahb>;
+			clock-output-names = "apb0";
+		};
+
+		apb1: clk at 01c20058 {
+			#clock-cells = <0>;
+			compatible = "allwinner,sun4i-a10-apb1-clk";
+			reg = <0x01c20058 0x4>;
+			clocks = <&osc24M>, <&pll6 1>, <&osc32k>;
+			clock-output-names = "apb1";
+		};
+
+		axi_gates: clk at 01c2005c {
+			#clock-cells = <1>;
+			compatible = "allwinner,sun4i-a10-gates-clk";
+			reg = <0x01c2005c 0x4>;
+			clocks = <&axi>;
+			clock-indices = <0>;
+			clock-output-names = "axi_dram";
+		};
+
+		ahb_gates: clk at 01c20060 {
+			#clock-cells = <1>;
+			compatible = "allwinner,sun5i-a13-ahb-gates-clk";
+			reg = <0x01c20060 0x8>;
+			clocks = <&ahb>;
+			clock-indices = <0>, <1>,
+					<2>, <5>, <6>,
+					<7>, <8>, <9>,
+					<10>, <13>,
+					<14>, <17>, <20>,
+					<21>, <22>,
+					<28>, <32>, <34>,
+					<36>, <40>, <44>,
+					<46>, <51>,
+					<52>;
+			clock-output-names = "ahb_usbotg", "ahb_ehci",
+					     "ahb_ohci", "ahb_ss", "ahb_dma",
+					     "ahb_bist", "ahb_mmc0", "ahb_mmc1",
+					     "ahb_mmc2", "ahb_nand",
+					     "ahb_sdram", "ahb_emac", "ahb_spi0",
+					     "ahb_spi1", "ahb_spi2",
+					     "ahb_hstimer", "ahb_ve", "ahb_tve",
+					     "ahb_lcd", "ahb_csi", "ahb_de_be",
+					     "ahb_de_fe", "ahb_iep",
+					     "ahb_mali400";
+		};
+
+		apb0_gates: clk at 01c20068 {
+			#clock-cells = <1>;
+			compatible = "allwinner,sun4i-a10-gates-clk";
+			reg = <0x01c20068 0x4>;
+			clocks = <&apb0>;
+			clock-indices = <0>, <3>,
+					<5>, <6>;
+			clock-output-names = "apb0_codec", "apb0_i2s0",
+					     "apb0_pio", "apb0_ir";
+		};
+
+		apb1_gates: clk at 01c2006c {
+			#clock-cells = <1>;
+			compatible = "allwinner,sun4i-a10-gates-clk";
+			reg = <0x01c2006c 0x4>;
+			clocks = <&apb1>;
+			clock-indices = <0>, <1>,
+					<2>, <17>,
+					<18>, <19>;
+			clock-output-names = "apb1_i2c0", "apb1_i2c1",
+					     "apb1_i2c2", "apb1_uart1",
+					     "apb1_uart2", "apb1_uart3";
+		};
+
+		nand_clk: clk at 01c20080 {
+			#clock-cells = <0>;
+			compatible = "allwinner,sun4i-a10-mod0-clk";
+			reg = <0x01c20080 0x4>;
+			clocks = <&osc24M>, <&pll6 1>, <&pll5 1>;
+			clock-output-names = "nand";
+		};
+
+		ms_clk: clk at 01c20084 {
+			#clock-cells = <0>;
+			compatible = "allwinner,sun4i-a10-mod0-clk";
+			reg = <0x01c20084 0x4>;
+			clocks = <&osc24M>, <&pll6 1>, <&pll5 1>;
+			clock-output-names = "ms";
+		};
+
+		mmc0_clk: clk at 01c20088 {
+			#clock-cells = <1>;
+			compatible = "allwinner,sun4i-a10-mmc-clk";
+			reg = <0x01c20088 0x4>;
+			clocks = <&osc24M>, <&pll6 1>, <&pll5 1>;
+			clock-output-names = "mmc0",
+					     "mmc0_output",
+					     "mmc0_sample";
+		};
+
+		mmc1_clk: clk at 01c2008c {
+			#clock-cells = <1>;
+			compatible = "allwinner,sun4i-a10-mmc-clk";
+			reg = <0x01c2008c 0x4>;
+			clocks = <&osc24M>, <&pll6 1>, <&pll5 1>;
+			clock-output-names = "mmc1",
+					     "mmc1_output",
+					     "mmc1_sample";
+		};
+
+		mmc2_clk: clk at 01c20090 {
+			#clock-cells = <1>;
+			compatible = "allwinner,sun4i-a10-mmc-clk";
+			reg = <0x01c20090 0x4>;
+			clocks = <&osc24M>, <&pll6 1>, <&pll5 1>;
+			clock-output-names = "mmc2",
+					     "mmc2_output",
+					     "mmc2_sample";
+		};
+
+		ts_clk: clk at 01c20098 {
+			#clock-cells = <0>;
+			compatible = "allwinner,sun4i-a10-mod0-clk";
+			reg = <0x01c20098 0x4>;
+			clocks = <&osc24M>, <&pll6 1>, <&pll5 1>;
+			clock-output-names = "ts";
+		};
+
+		ss_clk: clk at 01c2009c {
+			#clock-cells = <0>;
+			compatible = "allwinner,sun4i-a10-mod0-clk";
+			reg = <0x01c2009c 0x4>;
+			clocks = <&osc24M>, <&pll6 1>, <&pll5 1>;
+			clock-output-names = "ss";
+		};
+
+		spi0_clk: clk at 01c200a0 {
+			#clock-cells = <0>;
+			compatible = "allwinner,sun4i-a10-mod0-clk";
+			reg = <0x01c200a0 0x4>;
+			clocks = <&osc24M>, <&pll6 1>, <&pll5 1>;
+			clock-output-names = "spi0";
+		};
+
+		spi1_clk: clk at 01c200a4 {
+			#clock-cells = <0>;
+			compatible = "allwinner,sun4i-a10-mod0-clk";
+			reg = <0x01c200a4 0x4>;
+			clocks = <&osc24M>, <&pll6 1>, <&pll5 1>;
+			clock-output-names = "spi1";
+		};
+
+		spi2_clk: clk at 01c200a8 {
+			#clock-cells = <0>;
+			compatible = "allwinner,sun4i-a10-mod0-clk";
+			reg = <0x01c200a8 0x4>;
+			clocks = <&osc24M>, <&pll6 1>, <&pll5 1>;
+			clock-output-names = "spi2";
+		};
+
+		ir0_clk: clk at 01c200b0 {
+			#clock-cells = <0>;
+			compatible = "allwinner,sun4i-a10-mod0-clk";
+			reg = <0x01c200b0 0x4>;
+			clocks = <&osc24M>, <&pll6 1>, <&pll5 1>;
+			clock-output-names = "ir0";
+		};
+
+		i2s0_clk: clk at 01c200b8 {
+			#clock-cells = <0>;
+			compatible = "allwinner,sun4i-a10-mod1-clk";
+			reg = <0x01c200b8 0x4>;
+			clocks = <&pll2 SUN4I_A10_PLL2_8X>,
+				 <&pll2 SUN4I_A10_PLL2_4X>,
+				 <&pll2 SUN4I_A10_PLL2_2X>,
+				 <&pll2 SUN4I_A10_PLL2_1X>;
+			clock-output-names = "i2s0";
+		};
+
+		spdif_clk: clk at 01c200c0 {
+			#clock-cells = <0>;
+			compatible = "allwinner,sun4i-a10-mod1-clk";
+			reg = <0x01c200c0 0x4>;
+			clocks = <&pll2 SUN4I_A10_PLL2_8X>,
+				 <&pll2 SUN4I_A10_PLL2_4X>,
+				 <&pll2 SUN4I_A10_PLL2_2X>,
+				 <&pll2 SUN4I_A10_PLL2_1X>;
+			clock-output-names = "spdif";
+		};
+
+		usb_clk: clk at 01c200cc {
+			#clock-cells = <1>;
+			#reset-cells = <1>;
+			compatible = "allwinner,sun5i-a13-usb-clk";
+			reg = <0x01c200cc 0x4>;
+			clocks = <&pll6 1>;
+			clock-output-names = "usb_ohci0", "usb_phy";
+		};
+
+		dram_gates: clk at 01c20100 {
+			#clock-cells = <1>;
+			compatible = "nextthing,gr8-dram-gates-clk",
+				     "allwinner,sun4i-a10-gates-clk";
+			reg = <0x01c20100 0x4>;
+			clocks = <&pll5 0>;
+			clock-indices = <0>,
+					<1>,
+					<25>,
+					<26>,
+					<29>,
+					<31>;
+			clock-output-names = "dram_ve",
+					     "dram_csi",
+					     "dram_de_fe",
+					     "dram_de_be",
+					     "dram_ace",
+					     "dram_iep";
+		};
+
+		de_be_clk: clk at 01c20104 {
+			#clock-cells = <0>;
+			#reset-cells = <0>;
+			compatible = "allwinner,sun4i-a10-display-clk";
+			reg = <0x01c20104 0x4>;
+			clocks = <&pll3>, <&pll7>, <&pll5 1>;
+			clock-output-names = "de-be";
+		};
+
+		de_fe_clk: clk at 01c2010c {
+			#clock-cells = <0>;
+			#reset-cells = <0>;
+			compatible = "allwinner,sun4i-a10-display-clk";
+			reg = <0x01c2010c 0x4>;
+			clocks = <&pll3>, <&pll7>, <&pll5 1>;
+			clock-output-names = "de-fe";
+		};
+
+		tcon_ch0_clk: clk at 01c20118 {
+			#clock-cells = <0>;
+			#reset-cells = <1>;
+			compatible = "allwinner,sun4i-a10-tcon-ch0-clk";
+			reg = <0x01c20118 0x4>;
+			clocks = <&pll3>, <&pll7>, <&pll3x2>, <&pll7x2>;
+			clock-output-names = "tcon-ch0-sclk";
+		};
+
+		tcon_ch1_clk: clk at 01c2012c {
+			#clock-cells = <0>;
+			compatible = "allwinner,sun4i-a10-tcon-ch1-clk";
+			reg = <0x01c2012c 0x4>;
+			clocks = <&pll3>, <&pll7>, <&pll3x2>, <&pll7x2>;
+			clock-output-names = "tcon-ch1-sclk";
+		};
+
+		codec_clk: clk at 01c20140 {
+			#clock-cells = <0>;
+			compatible = "allwinner,sun4i-a10-codec-clk";
+			reg = <0x01c20140 0x4>;
+			clocks = <&pll2 SUN4I_A10_PLL2_1X>;
+			clock-output-names = "codec";
+		};
+
+		mbus_clk: clk at 01c2015c {
+			#clock-cells = <0>;
+			compatible = "allwinner,sun5i-a13-mbus-clk";
+			reg = <0x01c2015c 0x4>;
+			clocks = <&osc24M>, <&pll6 1>, <&pll5 1>;
+			clock-output-names = "mbus";
+		};
+	};
+
+	display-engine {
+		compatible = "allwinner,sun5i-a13-display-engine";
+		allwinner,pipelines = <&fe0>;
+	};
+
+	soc at 01c00000 {
+		compatible = "simple-bus";
+		#address-cells = <1>;
+		#size-cells = <1>;
+		ranges;
+
+		sram-controller at 01c00000 {
+			compatible = "allwinner,sun4i-a10-sram-controller";
+			reg = <0x01c00000 0x30>;
+			#address-cells = <1>;
+			#size-cells = <1>;
+			ranges;
+
+			sram_a: sram at 00000000 {
+				compatible = "mmio-sram";
+				reg = <0x00000000 0xc000>;
+				#address-cells = <1>;
+				#size-cells = <1>;
+				ranges = <0 0x00000000 0xc000>;
+			};
+
+			sram_d: sram at 00010000 {
+				compatible = "mmio-sram";
+				reg = <0x00010000 0x1000>;
+				#address-cells = <1>;
+				#size-cells = <1>;
+				ranges = <0 0x00010000 0x1000>;
+
+				otg_sram: sram-section at 0000 {
+					compatible = "allwinner,sun4i-a10-sram-d";
+					reg = <0x0000 0x1000>;
+					status = "disabled";
+				};
+			};
+		};
+
+		dma: dma-controller at 01c02000 {
+			compatible = "allwinner,sun4i-a10-dma";
+			reg = <0x01c02000 0x1000>;
+			interrupts = <27>;
+			clocks = <&ahb_gates 6>;
+			#dma-cells = <2>;
+		};
+
+		nfc: nand at 01c03000 {
+			compatible = "allwinner,sun4i-a10-nand";
+			reg = <0x01c03000 0x1000>;
+			interrupts = <37>;
+			clocks = <&ahb_gates 13>, <&nand_clk>;
+			clock-names = "ahb", "mod";
+			dmas = <&dma SUN4I_DMA_DEDICATED 3>;
+			dma-names = "rxtx";
+			status = "disabled";
+			#address-cells = <1>;
+			#size-cells = <0>;
+		};
+
+		spi0: spi at 01c05000 {
+			compatible = "allwinner,sun4i-a10-spi";
+			reg = <0x01c05000 0x1000>;
+			interrupts = <10>;
+			clocks = <&ahb_gates 20>, <&spi0_clk>;
+			clock-names = "ahb", "mod";
+			dmas = <&dma SUN4I_DMA_DEDICATED 27>,
+			       <&dma SUN4I_DMA_DEDICATED 26>;
+			dma-names = "rx", "tx";
+			status = "disabled";
+			#address-cells = <1>;
+			#size-cells = <0>;
+		};
+
+		spi1: spi at 01c06000 {
+			compatible = "allwinner,sun4i-a10-spi";
+			reg = <0x01c06000 0x1000>;
+			interrupts = <11>;
+			clocks = <&ahb_gates 21>, <&spi1_clk>;
+			clock-names = "ahb", "mod";
+			dmas = <&dma SUN4I_DMA_DEDICATED 9>,
+			       <&dma SUN4I_DMA_DEDICATED 8>;
+			dma-names = "rx", "tx";
+			status = "disabled";
+			#address-cells = <1>;
+			#size-cells = <0>;
+		};
+
+		tve0: tv-encoder at 01c0a000 {
+			compatible = "allwinner,sun4i-a10-tv-encoder";
+			reg = <0x01c0a000 0x1000>;
+			clocks = <&ahb_gates 34>;
+			resets = <&tcon_ch0_clk 0>;
+			status = "disabled";
+
+			port {
+				#address-cells = <1>;
+				#size-cells = <0>;
+
+				tve0_in_tcon0: endpoint at 0 {
+					reg = <0>;
+					remote-endpoint = <&tcon0_out_tve0>;
+				};
+			};
+		};
+
+		tcon0: lcd-controller at 01c0c000 {
+			compatible = "allwinner,sun5i-a13-tcon";
+			reg = <0x01c0c000 0x1000>;
+			interrupts = <44>;
+			resets = <&tcon_ch0_clk 1>;
+			reset-names = "lcd";
+			clocks = <&ahb_gates 36>,
+				 <&tcon_ch0_clk>,
+				 <&tcon_ch1_clk>;
+			clock-names = "ahb",
+				      "tcon-ch0",
+				      "tcon-ch1";
+			clock-output-names = "tcon-pixel-clock";
+			status = "disabled";
+
+			ports {
+				#address-cells = <1>;
+				#size-cells = <0>;
+
+				tcon0_in: port at 0 {
+					#address-cells = <1>;
+					#size-cells = <0>;
+					reg = <0>;
+
+					tcon0_in_be0: endpoint at 0 {
+						reg = <0>;
+						remote-endpoint = <&be0_out_tcon0>;
+					};
+				};
+
+				tcon0_out: port at 1 {
+					#address-cells = <1>;
+					#size-cells = <0>;
+					reg = <1>;
+
+					tcon0_out_tve0: endpoint at 1 {
+						reg = <1>;
+						remote-endpoint = <&tve0_in_tcon0>;
+					};
+				};
+			};
+		};
+
+		mmc0: mmc at 01c0f000 {
+			compatible = "allwinner,sun5i-a13-mmc";
+			reg = <0x01c0f000 0x1000>;
+			clocks = <&ahb_gates 8>,
+				 <&mmc0_clk 0>,
+				 <&mmc0_clk 1>,
+				 <&mmc0_clk 2>;
+			clock-names = "ahb",
+				      "mmc",
+				      "output",
+				      "sample";
+			interrupts = <32>;
+			status = "disabled";
+			#address-cells = <1>;
+			#size-cells = <0>;
+		};
+
+		mmc1: mmc at 01c10000 {
+			compatible = "allwinner,sun5i-a13-mmc";
+			reg = <0x01c10000 0x1000>;
+			clocks = <&ahb_gates 9>,
+				 <&mmc1_clk 0>,
+				 <&mmc1_clk 1>,
+				 <&mmc1_clk 2>;
+			clock-names = "ahb",
+				      "mmc",
+				      "output",
+				      "sample";
+			interrupts = <33>;
+			status = "disabled";
+			#address-cells = <1>;
+			#size-cells = <0>;
+		};
+
+		mmc2: mmc at 01c11000 {
+			compatible = "allwinner,sun5i-a13-mmc";
+			reg = <0x01c11000 0x1000>;
+			clocks = <&ahb_gates 10>,
+				 <&mmc2_clk 0>,
+				 <&mmc2_clk 1>,
+				 <&mmc2_clk 2>;
+			clock-names = "ahb",
+				      "mmc",
+				      "output",
+				      "sample";
+			interrupts = <34>;
+			status = "disabled";
+			#address-cells = <1>;
+			#size-cells = <0>;
+		};
+
+		usb_otg: usb at 01c13000 {
+			compatible = "allwinner,sun4i-a10-musb";
+			reg = <0x01c13000 0x0400>;
+			clocks = <&ahb_gates 0>;
+			interrupts = <38>;
+			interrupt-names = "mc";
+			phys = <&usbphy 0>;
+			phy-names = "usb";
+			extcon = <&usbphy 0>;
+			allwinner,sram = <&otg_sram 1>;
+			status = "disabled";
+
+			dr_mode = "otg";
+		};
+
+		usbphy: phy at 01c13400 {
+			#phy-cells = <1>;
+			compatible = "allwinner,sun5i-a13-usb-phy";
+			reg = <0x01c13400 0x10 0x01c14800 0x4>;
+			reg-names = "phy_ctrl", "pmu1";
+			clocks = <&usb_clk 8>;
+			clock-names = "usb_phy";
+			resets = <&usb_clk 0>, <&usb_clk 1>;
+			reset-names = "usb0_reset", "usb1_reset";
+			status = "disabled";
+		};
+
+		ehci0: usb at 01c14000 {
+			compatible = "allwinner,sun5i-a13-ehci", "generic-ehci";
+			reg = <0x01c14000 0x100>;
+			interrupts = <39>;
+			clocks = <&ahb_gates 1>;
+			phys = <&usbphy 1>;
+			phy-names = "usb";
+			status = "disabled";
+		};
+
+		ohci0: usb at 01c14400 {
+			compatible = "allwinner,sun5i-a13-ohci", "generic-ohci";
+			reg = <0x01c14400 0x100>;
+			interrupts = <40>;
+			clocks = <&usb_clk 6>, <&ahb_gates 2>;
+			phys = <&usbphy 1>;
+			phy-names = "usb";
+			status = "disabled";
+		};
+
+		spi2: spi at 01c17000 {
+			compatible = "allwinner,sun4i-a10-spi";
+			reg = <0x01c17000 0x1000>;
+			interrupts = <12>;
+			clocks = <&ahb_gates 22>, <&spi2_clk>;
+			clock-names = "ahb", "mod";
+			dmas = <&dma SUN4I_DMA_DEDICATED 29>,
+			       <&dma SUN4I_DMA_DEDICATED 28>;
+			dma-names = "rx", "tx";
+			status = "disabled";
+			#address-cells = <1>;
+			#size-cells = <0>;
+		};
+
+		intc: interrupt-controller at 01c20400 {
+			compatible = "allwinner,sun4i-a10-ic";
+			reg = <0x01c20400 0x400>;
+			interrupt-controller;
+			#interrupt-cells = <1>;
+		};
+
+		pio: pinctrl at 01c20800 {
+			compatible = "nextthing,gr8-pinctrl";
+			reg = <0x01c20800 0x400>;
+			interrupts = <28>;
+			clocks = <&apb0_gates 5>;
+			gpio-controller;
+			interrupt-controller;
+			#interrupt-cells = <3>;
+			#gpio-cells = <3>;
+
+			i2c0_pins_a: i2c0 at 0 {
+				allwinner,pins = "PB0", "PB1";
+				allwinner,function = "i2c0";
+				allwinner,drive = <SUN4I_PINCTRL_10_MA>;
+				allwinner,pull = <SUN4I_PINCTRL_NO_PULL>;
+			};
+
+			i2c1_pins_a: i2c1 at 0 {
+				allwinner,pins = "PB15", "PB16";
+				allwinner,function = "i2c1";
+				allwinner,drive = <SUN4I_PINCTRL_10_MA>;
+				allwinner,pull = <SUN4I_PINCTRL_NO_PULL>;
+			};
+
+			i2c2_pins_a: i2c2 at 0 {
+				allwinner,pins = "PB17", "PB18";
+				allwinner,function = "i2c2";
+				allwinner,drive = <SUN4I_PINCTRL_10_MA>;
+				allwinner,pull = <SUN4I_PINCTRL_NO_PULL>;
+			};
+
+			i2s0_data_pins_a: i2s0-data at 0 {
+				allwinner,pins = "PB6", "PB7", "PB8", "PB9";
+				allwinner,function = "i2s0";
+				allwinner,drive = <SUN4I_PINCTRL_10_MA>;
+				allwinner,pull = <SUN4I_PINCTRL_NO_PULL>;
+			};
+
+			i2s0_mclk_pins_a: i2s0-mclk at 0 {
+				allwinner,pins = "PB5";
+				allwinner,function = "i2s0";
+				allwinner,drive = <SUN4I_PINCTRL_10_MA>;
+				allwinner,pull = <SUN4I_PINCTRL_NO_PULL>;
+			};
+
+			ir0_rx_pins_a: ir0 at 0 {
+				allwinner,pins = "PB4";
+				allwinner,function = "ir0";
+				allwinner,drive = <SUN4I_PINCTRL_10_MA>;
+				allwinner,pull = <SUN4I_PINCTRL_NO_PULL>;
+			};
+
+			lcd_rgb666_pins: lcd-rgb666 at 0 {
+				allwinner,pins = "PD2", "PD3", "PD4", "PD5", "PD6", "PD7",
+						 "PD10", "PD11", "PD12", "PD13", "PD14", "PD15",
+						 "PD18", "PD19", "PD20", "PD21", "PD22", "PD23",
+						 "PD24", "PD25", "PD26", "PD27";
+				allwinner,function = "lcd0";
+				allwinner,drive = <SUN4I_PINCTRL_10_MA>;
+				allwinner,pull = <SUN4I_PINCTRL_NO_PULL>;
+			};
+
+			mmc0_pins_a: mmc0 at 0 {
+				allwinner,pins = "PF0", "PF1", "PF2", "PF3",
+						 "PF4", "PF5";
+				allwinner,function = "mmc0";
+				allwinner,drive = <SUN4I_PINCTRL_30_MA>;
+				allwinner,pull = <SUN4I_PINCTRL_NO_PULL>;
+			};
+
+			nand_pins_a: nand-base0 at 0 {
+				allwinner,pins = "PC0", "PC1", "PC2",
+						"PC5", "PC8", "PC9", "PC10",
+						"PC11", "PC12", "PC13", "PC14",
+						"PC15";
+				allwinner,function = "nand0";
+				allwinner,drive = <SUN4I_PINCTRL_10_MA>;
+				allwinner,pull = <SUN4I_PINCTRL_NO_PULL>;
+			};
+
+			nand_cs0_pins_a: nand-cs at 0 {
+				allwinner,pins = "PC4";
+				allwinner,function = "nand0";
+				allwinner,drive = <SUN4I_PINCTRL_10_MA>;
+				allwinner,pull = <SUN4I_PINCTRL_NO_PULL>;
+			};
+
+			nand_rb0_pins_a: nand-rb at 0 {
+				allwinner,pins = "PC6";
+				allwinner,function = "nand0";
+				allwinner,drive = <SUN4I_PINCTRL_10_MA>;
+				allwinner,pull = <SUN4I_PINCTRL_NO_PULL>;
+			};
+
+			pwm0_pins_a: pwm0 at 0 {
+				allwinner,pins = "PB2";
+				allwinner,function = "pwm0";
+				allwinner,drive = <SUN4I_PINCTRL_10_MA>;
+				allwinner,pull = <SUN4I_PINCTRL_NO_PULL>;
+			};
+
+			pwm1_pins: pwm1 {
+				allwinner,pins = "PG13";
+				allwinner,function = "pwm1";
+				allwinner,drive = <SUN4I_PINCTRL_10_MA>;
+				allwinner,pull = <SUN4I_PINCTRL_NO_PULL>;
+			};
+
+			spdif_tx_pins_a: spdif at 0 {
+				allwinner,pins = "PB10";
+				allwinner,function = "spdif";
+				allwinner,drive = <SUN4I_PINCTRL_10_MA>;
+				allwinner,pull = <SUN4I_PINCTRL_PULL_UP>;
+			};
+
+			uart1_pins_a: uart1 at 1 {
+				allwinner,pins = "PG3", "PG4";
+				allwinner,function = "uart1";
+				allwinner,drive = <SUN4I_PINCTRL_10_MA>;
+				allwinner,pull = <SUN4I_PINCTRL_NO_PULL>;
+			};
+
+			uart1_cts_rts_pins_a: uart1-cts-rts at 0 {
+				allwinner,pins = "PG5", "PG6";
+				allwinner,function = "uart1";
+				allwinner,drive = <SUN4I_PINCTRL_10_MA>;
+				allwinner,pull = <SUN4I_PINCTRL_NO_PULL>;
+			};
+
+			uart2_pins_a: uart2 at 1 {
+				allwinner,pins = "PD2", "PD3";
+				allwinner,function = "uart2";
+				allwinner,drive = <SUN4I_PINCTRL_10_MA>;
+				allwinner,pull = <SUN4I_PINCTRL_NO_PULL>;
+			};
+
+			uart2_cts_rts_pins_a: uart2-cts-rts at 0 {
+				allwinner,pins = "PD4", "PD5";
+				allwinner,function = "uart2";
+				allwinner,drive = <SUN4I_PINCTRL_10_MA>;
+				allwinner,pull = <SUN4I_PINCTRL_NO_PULL>;
+			};
+
+			uart3_pins_a: uart3 at 1 {
+				allwinner,pins = "PG9", "PG10";
+				allwinner,function = "uart3";
+				allwinner,drive = <SUN4I_PINCTRL_10_MA>;
+				allwinner,pull = <SUN4I_PINCTRL_NO_PULL>;
+			};
+
+			uart3_cts_rts_pins_a: uart3-cts-rts at 0 {
+				allwinner,pins = "PG11", "PG12";
+				allwinner,function = "uart3";
+				allwinner,drive = <SUN4I_PINCTRL_10_MA>;
+				allwinner,pull = <SUN4I_PINCTRL_NO_PULL>;
+			};
+		};
+
+		pwm: pwm at 01c20e00 {
+			compatible = "allwinner,sun5i-a10s-pwm";
+			reg = <0x01c20e00 0xc>;
+			clocks = <&osc24M>;
+			#pwm-cells = <3>;
+			status = "disabled";
+		};
+
+		timer at 01c20c00 {
+			compatible = "allwinner,sun4i-a10-timer";
+			reg = <0x01c20c00 0x90>;
+			interrupts = <22>;
+			clocks = <&osc24M>;
+		};
+
+		wdt: watchdog at 01c20c90 {
+			compatible = "allwinner,sun4i-a10-wdt";
+			reg = <0x01c20c90 0x10>;
+		};
+
+		spdif: spdif at 01c21000 {
+			#sound-dai-cells = <0>;
+			compatible = "allwinner,sun4i-a10-spdif";
+			reg = <0x01c21000 0x400>;
+			interrupts = <13>;
+			clocks = <&apb0_gates 1>, <&spdif_clk>;
+			clock-names = "apb", "spdif";
+			dmas = <&dma SUN4I_DMA_NORMAL 2>,
+			       <&dma SUN4I_DMA_NORMAL 2>;
+			dma-names = "rx", "tx";
+			status = "disabled";
+		};
+
+		ir0: ir at 01c21800 {
+			compatible = "allwinner,sun4i-a10-ir";
+			clocks = <&apb0_gates 6>, <&ir0_clk>;
+			clock-names = "apb", "ir";
+			interrupts = <5>;
+			reg = <0x01c21800 0x40>;
+			status = "disabled";
+		};
+
+		i2s0: i2s at 01c22400 {
+			#sound-dai-cells = <0>;
+			compatible = "allwinner,sun4i-a10-i2s";
+			reg = <0x01c22400 0x400>;
+			interrupts = <16>;
+			clocks = <&apb0_gates 3>, <&i2s0_clk>;
+			clock-names = "apb", "mod";
+			dmas = <&dma SUN4I_DMA_NORMAL 3>,
+			       <&dma SUN4I_DMA_NORMAL 3>;
+			dma-names = "rx", "tx";
+			status = "disabled";
+		};
+
+		lradc: lradc at 01c22800 {
+			compatible = "allwinner,sun4i-a10-lradc-keys";
+			reg = <0x01c22800 0x100>;
+			interrupts = <31>;
+			status = "disabled";
+		};
+
+		codec: codec at 01c22c00 {
+			#sound-dai-cells = <0>;
+			compatible = "allwinner,sun4i-a10-codec";
+			reg = <0x01c22c00 0x40>;
+			interrupts = <30>;
+			clocks = <&apb0_gates 0>, <&codec_clk>;
+			clock-names = "apb", "codec";
+			dmas = <&dma SUN4I_DMA_NORMAL 19>,
+			       <&dma SUN4I_DMA_NORMAL 19>;
+			dma-names = "rx", "tx";
+			status = "disabled";
+		};
+
+		rtp: rtp at 01c25000 {
+			compatible = "allwinner,sun5i-a13-ts";
+			reg = <0x01c25000 0x100>;
+			interrupts = <29>;
+			#thermal-sensor-cells = <0>;
+		};
+
+		uart1: serial at 01c28400 {
+			compatible = "snps,dw-apb-uart";
+			reg = <0x01c28400 0x400>;
+			interrupts = <2>;
+			reg-shift = <2>;
+			reg-io-width = <4>;
+			clocks = <&apb1_gates 17>;
+			status = "disabled";
+		};
+
+		uart2: serial at 01c28800 {
+			compatible = "snps,dw-apb-uart";
+			reg = <0x01c28800 0x400>;
+			interrupts = <3>;
+			reg-shift = <2>;
+			reg-io-width = <4>;
+			clocks = <&apb1_gates 18>;
+			status = "disabled";
+		};
+
+		uart3: serial at 01c28c00 {
+			compatible = "snps,dw-apb-uart";
+			reg = <0x01c28c00 0x400>;
+			interrupts = <4>;
+			reg-shift = <2>;
+			reg-io-width = <4>;
+			clocks = <&apb1_gates 19>;
+			status = "disabled";
+		};
+
+		i2c0: i2c at 01c2ac00 {
+			compatible = "allwinner,sun4i-a10-i2c";
+			reg = <0x01c2ac00 0x400>;
+			interrupts = <7>;
+			clocks = <&apb1_gates 0>;
+			status = "disabled";
+			#address-cells = <1>;
+			#size-cells = <0>;
+		};
+
+		i2c1: i2c at 01c2b000 {
+			compatible = "allwinner,sun4i-a10-i2c";
+			reg = <0x01c2b000 0x400>;
+			interrupts = <8>;
+			clocks = <&apb1_gates 1>;
+			status = "disabled";
+			#address-cells = <1>;
+			#size-cells = <0>;
+		};
+
+		i2c2: i2c at 01c2b400 {
+			compatible = "allwinner,sun4i-a10-i2c";
+			reg = <0x01c2b400 0x400>;
+			interrupts = <9>;
+			clocks = <&apb1_gates 2>;
+			status = "disabled";
+			#address-cells = <1>;
+			#size-cells = <0>;
+		};
+
+		timer at 01c60000 {
+			compatible = "allwinner,sun5i-a13-hstimer";
+			reg = <0x01c60000 0x1000>;
+			interrupts = <82>, <83>;
+			clocks = <&ahb_gates 28>;
+		};
+
+		fe0: display-frontend at 01e00000 {
+			compatible = "allwinner,sun5i-a13-display-frontend";
+			reg = <0x01e00000 0x20000>;
+			interrupts = <47>;
+			clocks = <&ahb_gates 46>, <&de_fe_clk>,
+				 <&dram_gates 25>;
+			clock-names = "ahb", "mod",
+				      "ram";
+			resets = <&de_fe_clk>;
+			status = "disabled";
+
+			ports {
+				#address-cells = <1>;
+				#size-cells = <0>;
+
+				fe0_out: port at 1 {
+					#address-cells = <1>;
+					#size-cells = <0>;
+					reg = <1>;
+
+					fe0_out_be0: endpoint at 0 {
+						reg = <0>;
+						remote-endpoint = <&be0_in_fe0>;
+					};
+				};
+			};
+		};
+
+		be0: display-backend at 01e60000 {
+			compatible = "allwinner,sun5i-a13-display-backend";
+			reg = <0x01e60000 0x10000>;
+			clocks = <&ahb_gates 44>, <&de_be_clk>,
+				 <&dram_gates 26>;
+			clock-names = "ahb", "mod",
+				      "ram";
+			resets = <&de_be_clk>;
+			status = "disabled";
+
+			assigned-clocks = <&de_be_clk>;
+			assigned-clock-rates = <300000000>;
+
+			ports {
+				#address-cells = <1>;
+				#size-cells = <0>;
+
+				be0_in: port at 0 {
+					#address-cells = <1>;
+					#size-cells = <0>;
+					reg = <0>;
+
+					be0_in_fe0: endpoint at 0 {
+						reg = <0>;
+						remote-endpoint = <&fe0_out_be0>;
+					};
+				};
+
+				be0_out: port at 1 {
+					#address-cells = <1>;
+					#size-cells = <0>;
+					reg = <1>;
+
+					be0_out_tcon0: endpoint at 0 {
+						reg = <0>;
+						remote-endpoint = <&tcon0_in_be0>;
+					};
+				};
+			};
+		};
+	};
+};
-- 
git-series 0.8.11

^ permalink raw reply related	[flat|nested] 44+ messages in thread

* [U-Boot] [PATCH 2/7] mtd: nand: add support for the TC58NVG2S0H chip
  2016-11-08 16:21 [U-Boot] [PATCH 0/7] sunxi: Add support for the CHIP Pro Maxime Ripard
  2016-11-08 16:21 ` [U-Boot] [PATCH 1/7] sunxi: Sync GR8 DTS and AXP209 with the kernel Maxime Ripard
@ 2016-11-08 16:21 ` Maxime Ripard
  2016-11-14 11:15   ` Hans de Goede
  2016-11-15  5:04   ` Scott Wood
  2016-11-08 16:21 ` [U-Boot] [PATCH 3/7] sunxi: Enable UBI and NAND support Maxime Ripard
                   ` (5 subsequent siblings)
  7 siblings, 2 replies; 44+ messages in thread
From: Maxime Ripard @ 2016-11-08 16:21 UTC (permalink / raw)
  To: u-boot

From: Boris Brezillon <boris.brezillon@free-electrons.com>

Add the description of the Toshiba TC58NVG2S0H SLC nand to the nand_ids
table so we can use the NAND ECC infos and the ONFI timings.

Signed-off-by: Boris Brezillon <boris.brezillon@free-electrons.com>
Signed-off-by: Maxime Ripard <maxime.ripard@free-electrons.com>
---
 drivers/mtd/nand/nand_ids.c | 3 +++
 1 file changed, 3 insertions(+), 0 deletions(-)

diff --git a/drivers/mtd/nand/nand_ids.c b/drivers/mtd/nand/nand_ids.c
index ce0a14e28abb..d36f9006c99d 100644
--- a/drivers/mtd/nand/nand_ids.c
+++ b/drivers/mtd/nand/nand_ids.c
@@ -46,6 +46,9 @@ struct nand_flash_dev nand_flash_ids[] = {
 	{"TC58NVG2S0F 4G 3.3V 8-bit",
 		{ .id = {0x98, 0xdc, 0x90, 0x26, 0x76, 0x15, 0x01, 0x08} },
 		  SZ_4K, SZ_512, SZ_256K, 0, 8, 224, NAND_ECC_INFO(4, SZ_512) },
+	{"TC58NVG2S0H 4G 3.3V 8-bit",
+		{ .id = {0x98, 0xdc, 0x90, 0x26, 0x76, 0x16, 0x08, 0x00} },
+		  SZ_4K, SZ_512, SZ_256K, 0, 8, 256, NAND_ECC_INFO(8, SZ_512) },
 	{"TC58NVG3S0F 8G 3.3V 8-bit",
 		{ .id = {0x98, 0xd3, 0x90, 0x26, 0x76, 0x15, 0x02, 0x08} },
 		  SZ_4K, SZ_1K, SZ_256K, 0, 8, 232, NAND_ECC_INFO(4, SZ_512) },
-- 
git-series 0.8.11

^ permalink raw reply related	[flat|nested] 44+ messages in thread

* [U-Boot] [PATCH 3/7] sunxi: Enable UBI and NAND support
  2016-11-08 16:21 [U-Boot] [PATCH 0/7] sunxi: Add support for the CHIP Pro Maxime Ripard
  2016-11-08 16:21 ` [U-Boot] [PATCH 1/7] sunxi: Sync GR8 DTS and AXP209 with the kernel Maxime Ripard
  2016-11-08 16:21 ` [U-Boot] [PATCH 2/7] mtd: nand: add support for the TC58NVG2S0H chip Maxime Ripard
@ 2016-11-08 16:21 ` Maxime Ripard
  2016-11-08 16:27   ` Boris Brezillon
                     ` (2 more replies)
  2016-11-08 16:21 ` [U-Boot] [PATCH 4/7] tools: sunxi: Add spl image builder Maxime Ripard
                   ` (4 subsequent siblings)
  7 siblings, 3 replies; 44+ messages in thread
From: Maxime Ripard @ 2016-11-08 16:21 UTC (permalink / raw)
  To: u-boot

From: Hans de Goede <hdegoede@redhat.com>

Enable the NAND and UBI support in the configuration header so that we can
(finally) use it.

Signed-off-by: Hans de Goede <hdegoede@redhat.com>
Signed-off-by: Maxime Ripard <maxime.ripard@free-electrons.com>
---
 include/configs/sunxi-common.h | 26 ++++++++++++++++++++++----
 1 file changed, 22 insertions(+), 4 deletions(-)

diff --git a/include/configs/sunxi-common.h b/include/configs/sunxi-common.h
index 8363414828fa..1733767ba53b 100644
--- a/include/configs/sunxi-common.h
+++ b/include/configs/sunxi-common.h
@@ -129,9 +129,23 @@
 #define CONFIG_SERIAL_TAG
 
 #ifdef CONFIG_NAND_SUNXI
+#define CONFIG_SYS_NAND_U_BOOT_OFFS	(8 << 20) /* 8 MiB */
 #define CONFIG_SYS_NAND_MAX_ECCPOS 1664
 #define CONFIG_SYS_NAND_ONFI_DETECTION
 #define CONFIG_SYS_MAX_NAND_DEVICE 8
+
+/* Requirements for UBI */
+#define CONFIG_RBTREE
+#define CONFIG_LZO
+#define CONFIG_CMD_MTDPARTS
+#define CONFIG_CMD_UBI
+#define CONFIG_CMD_UBIFS
+#define CONFIG_MTD_DEVICE
+
+#define CONFIG_MTD_PARTITIONS
+
+#define CONFIG_CMD_NAND
+#define CONFIG_CMD_NAND_TRIMFFS
 #endif
 
 #ifdef CONFIG_SPL_SPI_SUNXI
@@ -143,7 +157,14 @@
 #define CONFIG_GENERIC_MMC
 #define CONFIG_MMC_SUNXI
 #define CONFIG_MMC_SUNXI_SLOT		0
-#define CONFIG_ENV_IS_IN_MMC
+#endif
+
+#if defined(CONFIG_ENV_IS_IN_NAND)
+#define CONFIG_ENV_OFFSET			0xc00000
+#define CONFIG_ENV_SIZE				0x400000
+#elif defined(CONFIG_ENV_IS_IN_MMC)
+#define CONFIG_ENV_OFFSET			(544 << 10) /* (8 + 24 + 512) KiB */
+#define CONFIG_ENV_SIZE				(128 << 10) /* 128 KiB */
 #define CONFIG_SYS_MMC_ENV_DEV		0	/* first detected MMC controller */
 #endif
 
@@ -175,9 +196,6 @@
 
 #define CONFIG_SYS_MONITOR_LEN		(768 << 10)	/* 768 KiB */
 
-#define CONFIG_ENV_OFFSET		(544 << 10) /* (8 + 24 + 512) KiB */
-#define CONFIG_ENV_SIZE			(128 << 10)	/* 128 KiB */
-
 #define CONFIG_FAT_WRITE	/* enable write access */
 
 #define CONFIG_SPL_FRAMEWORK
-- 
git-series 0.8.11

^ permalink raw reply related	[flat|nested] 44+ messages in thread

* [U-Boot] [PATCH 4/7] tools: sunxi: Add spl image builder
  2016-11-08 16:21 [U-Boot] [PATCH 0/7] sunxi: Add support for the CHIP Pro Maxime Ripard
                   ` (2 preceding siblings ...)
  2016-11-08 16:21 ` [U-Boot] [PATCH 3/7] sunxi: Enable UBI and NAND support Maxime Ripard
@ 2016-11-08 16:21 ` Maxime Ripard
  2016-11-08 16:29   ` Boris Brezillon
                     ` (2 more replies)
  2016-11-08 16:21 ` [U-Boot] [PATCH 5/7] nand: sunxi: Add options for the SPL NAND configuration Maxime Ripard
                   ` (3 subsequent siblings)
  7 siblings, 3 replies; 44+ messages in thread
From: Maxime Ripard @ 2016-11-08 16:21 UTC (permalink / raw)
  To: u-boot

This program generates raw SPL images that can be flashed on the NAND with
the ECC and randomizer properly set up.

Signed-off-by: Maxime Ripard <maxime.ripard@free-electrons.com>
---
 tools/.gitignore                |    1 +-
 tools/Makefile                  |    1 +-
 tools/sunxi-spl-image-builder.c | 1113 ++++++++++++++++++++++++++++++++-
 3 files changed, 1115 insertions(+), 0 deletions(-)
 create mode 100644 tools/sunxi-spl-image-builder.c

diff --git a/tools/.gitignore b/tools/.gitignore
index cb1e722d4575..16574467544c 100644
--- a/tools/.gitignore
+++ b/tools/.gitignore
@@ -15,6 +15,7 @@
 /mkexynosspl
 /mxsboot
 /mksunxiboot
+/sunxi-spl-image-builder
 /ncb
 /proftool
 /relocate-rela
diff --git a/tools/Makefile b/tools/Makefile
index 400588cf0f5c..dfeeb23484ce 100644
--- a/tools/Makefile
+++ b/tools/Makefile
@@ -171,6 +171,7 @@ hostprogs-$(CONFIG_MX28) += mxsboot
 HOSTCFLAGS_mxsboot.o := -pedantic
 
 hostprogs-$(CONFIG_ARCH_SUNXI) += mksunxiboot
+hostprogs-$(CONFIG_ARCH_SUNXI) += sunxi-spl-image-builder
 
 hostprogs-$(CONFIG_NETCONSOLE) += ncb
 hostprogs-$(CONFIG_SHA1_CHECK_UB_IMG) += ubsha1
diff --git a/tools/sunxi-spl-image-builder.c b/tools/sunxi-spl-image-builder.c
new file mode 100644
index 000000000000..0f915eb2bdf5
--- /dev/null
+++ b/tools/sunxi-spl-image-builder.c
@@ -0,0 +1,1113 @@
+/*
+ * Generic binary BCH encoding/decoding library
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 as published by
+ * the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
+ * more details.
+ *
+ * You should have received a copy of the GNU General Public License along with
+ * this program; if not, write to the Free Software Foundation, Inc., 51
+ * Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * For the BCH implementation:
+ *
+ * Copyright ? 2011 Parrot S.A.
+ *
+ * Author: Ivan Djelic <ivan.djelic@parrot.com>
+ *
+ * See also:
+ * http://lxr.free-electrons.com/source/lib/bch.c
+ *
+ * For the randomizer and image builder implementation:
+ *
+ * Copyright ? 2016 NextThing Co.
+ * Copyright ? 2016 Free Electrons
+ *
+ * Author: Boris Brezillon <boris.brezillon@free-electrons.com>
+ *
+ */
+
+#include <stdint.h>
+#include <stdlib.h>
+#include <string.h>
+#include <stdio.h>
+#include <linux/kernel.h>
+#include <linux/errno.h>
+#include <asm/byteorder.h>
+#include <endian.h>
+#include <getopt.h>
+#include <version.h>
+
+#if defined(CONFIG_BCH_CONST_PARAMS)
+#define GF_M(_p)               (CONFIG_BCH_CONST_M)
+#define GF_T(_p)               (CONFIG_BCH_CONST_T)
+#define GF_N(_p)               ((1 << (CONFIG_BCH_CONST_M))-1)
+#else
+#define GF_M(_p)               ((_p)->m)
+#define GF_T(_p)               ((_p)->t)
+#define GF_N(_p)               ((_p)->n)
+#endif
+
+#define DIV_ROUND_UP(n,d) (((n) + (d) - 1) / (d))
+
+#define BCH_ECC_WORDS(_p)      DIV_ROUND_UP(GF_M(_p)*GF_T(_p), 32)
+#define BCH_ECC_BYTES(_p)      DIV_ROUND_UP(GF_M(_p)*GF_T(_p), 8)
+
+#ifndef dbg
+#define dbg(_fmt, args...)     do {} while (0)
+#endif
+
+#define cpu_to_be32 htobe32
+#define kfree free
+#define ARRAY_SIZE(arr) (sizeof(arr) / sizeof((arr)[0]))
+
+#define BCH_PRIMITIVE_POLY	0x5803
+
+struct image_info {
+	int ecc_strength;
+	int ecc_step_size;
+	int page_size;
+	int oob_size;
+	int usable_page_size;
+	int eraseblock_size;
+	int scramble;
+	int boot0;
+	off_t offset;
+	const char *source;
+	const char *dest;
+};
+
+/**
+ * struct bch_control - BCH control structure
+ * @m:          Galois field order
+ * @n:          maximum codeword size in bits (= 2^m-1)
+ * @t:          error correction capability in bits
+ * @ecc_bits:   ecc exact size in bits, i.e. generator polynomial degree (<=m*t)
+ * @ecc_bytes:  ecc max size (m*t bits) in bytes
+ * @a_pow_tab:  Galois field GF(2^m) exponentiation lookup table
+ * @a_log_tab:  Galois field GF(2^m) log lookup table
+ * @mod8_tab:   remainder generator polynomial lookup tables
+ * @ecc_buf:    ecc parity words buffer
+ * @ecc_buf2:   ecc parity words buffer
+ * @xi_tab:     GF(2^m) base for solving degree 2 polynomial roots
+ * @syn:        syndrome buffer
+ * @cache:      log-based polynomial representation buffer
+ * @elp:        error locator polynomial
+ * @poly_2t:    temporary polynomials of degree 2t
+ */
+struct bch_control {
+	unsigned int    m;
+	unsigned int    n;
+	unsigned int    t;
+	unsigned int    ecc_bits;
+	unsigned int    ecc_bytes;
+/* private: */
+	uint16_t       *a_pow_tab;
+	uint16_t       *a_log_tab;
+	uint32_t       *mod8_tab;
+	uint32_t       *ecc_buf;
+	uint32_t       *ecc_buf2;
+	unsigned int   *xi_tab;
+	unsigned int   *syn;
+	int            *cache;
+	struct gf_poly *elp;
+	struct gf_poly *poly_2t[4];
+};
+
+static int fls(int x)
+{
+	int r = 32;
+
+	if (!x)
+		return 0;
+	if (!(x & 0xffff0000u)) {
+		x <<= 16;
+		r -= 16;
+	}
+	if (!(x & 0xff000000u)) {
+		x <<= 8;
+		r -= 8;
+	}
+	if (!(x & 0xf0000000u)) {
+		x <<= 4;
+		r -= 4;
+	}
+	if (!(x & 0xc0000000u)) {
+		x <<= 2;
+		r -= 2;
+	}
+	if (!(x & 0x80000000u)) {
+		x <<= 1;
+		r -= 1;
+	}
+	return r;
+}
+
+/*
+ * represent a polynomial over GF(2^m)
+ */
+struct gf_poly {
+	unsigned int deg;    /* polynomial degree */
+	unsigned int c[0];   /* polynomial terms */
+};
+
+/* given its degree, compute a polynomial size in bytes */
+#define GF_POLY_SZ(_d) (sizeof(struct gf_poly)+((_d)+1)*sizeof(unsigned int))
+
+/* polynomial of degree 1 */
+struct gf_poly_deg1 {
+	struct gf_poly poly;
+	unsigned int   c[2];
+};
+
+/*
+ * same as encode_bch(), but process input data one byte@a time
+ */
+static void encode_bch_unaligned(struct bch_control *bch,
+				 const unsigned char *data, unsigned int len,
+				 uint32_t *ecc)
+{
+	int i;
+	const uint32_t *p;
+	const int l = BCH_ECC_WORDS(bch)-1;
+
+	while (len--) {
+		p = bch->mod8_tab + (l+1)*(((ecc[0] >> 24)^(*data++)) & 0xff);
+
+		for (i = 0; i < l; i++)
+			ecc[i] = ((ecc[i] << 8)|(ecc[i+1] >> 24))^(*p++);
+
+		ecc[l] = (ecc[l] << 8)^(*p);
+	}
+}
+
+/*
+ * convert ecc bytes to aligned, zero-padded 32-bit ecc words
+ */
+static void load_ecc8(struct bch_control *bch, uint32_t *dst,
+		      const uint8_t *src)
+{
+	uint8_t pad[4] = {0, 0, 0, 0};
+	unsigned int i, nwords = BCH_ECC_WORDS(bch)-1;
+
+	for (i = 0; i < nwords; i++, src += 4)
+		dst[i] = (src[0] << 24)|(src[1] << 16)|(src[2] << 8)|src[3];
+
+	memcpy(pad, src, BCH_ECC_BYTES(bch)-4*nwords);
+	dst[nwords] = (pad[0] << 24)|(pad[1] << 16)|(pad[2] << 8)|pad[3];
+}
+
+/*
+ * convert 32-bit ecc words to ecc bytes
+ */
+static void store_ecc8(struct bch_control *bch, uint8_t *dst,
+		       const uint32_t *src)
+{
+	uint8_t pad[4];
+	unsigned int i, nwords = BCH_ECC_WORDS(bch)-1;
+
+	for (i = 0; i < nwords; i++) {
+		*dst++ = (src[i] >> 24);
+		*dst++ = (src[i] >> 16) & 0xff;
+		*dst++ = (src[i] >>  8) & 0xff;
+		*dst++ = (src[i] >>  0) & 0xff;
+	}
+	pad[0] = (src[nwords] >> 24);
+	pad[1] = (src[nwords] >> 16) & 0xff;
+	pad[2] = (src[nwords] >>  8) & 0xff;
+	pad[3] = (src[nwords] >>  0) & 0xff;
+	memcpy(dst, pad, BCH_ECC_BYTES(bch)-4*nwords);
+}
+
+/**
+ * encode_bch - calculate BCH ecc parity of data
+ * @bch:   BCH control structure
+ * @data:  data to encode
+ * @len:   data length in bytes
+ * @ecc:   ecc parity data, must be initialized by caller
+ *
+ * The @ecc parity array is used both as input and output parameter, in order to
+ * allow incremental computations. It should be of the size indicated by member
+ * @ecc_bytes of @bch, and should be initialized to 0 before the first call.
+ *
+ * The exact number of computed ecc parity bits is given by member @ecc_bits of
+ * @bch; it may be less than m*t for large values of t.
+ */
+static void encode_bch(struct bch_control *bch, const uint8_t *data,
+		unsigned int len, uint8_t *ecc)
+{
+	const unsigned int l = BCH_ECC_WORDS(bch)-1;
+	unsigned int i, mlen;
+	unsigned long m;
+	uint32_t w, r[l+1];
+	const uint32_t * const tab0 = bch->mod8_tab;
+	const uint32_t * const tab1 = tab0 + 256*(l+1);
+	const uint32_t * const tab2 = tab1 + 256*(l+1);
+	const uint32_t * const tab3 = tab2 + 256*(l+1);
+	const uint32_t *pdata, *p0, *p1, *p2, *p3;
+
+	if (ecc) {
+		/* load ecc parity bytes into internal 32-bit buffer */
+		load_ecc8(bch, bch->ecc_buf, ecc);
+	} else {
+		memset(bch->ecc_buf, 0, sizeof(r));
+	}
+
+	/* process first unaligned data bytes */
+	m = ((uintptr_t)data) & 3;
+	if (m) {
+		mlen = (len < (4-m)) ? len : 4-m;
+		encode_bch_unaligned(bch, data, mlen, bch->ecc_buf);
+		data += mlen;
+		len  -= mlen;
+	}
+
+	/* process 32-bit aligned data words */
+	pdata = (uint32_t *)data;
+	mlen  = len/4;
+	data += 4*mlen;
+	len  -= 4*mlen;
+	memcpy(r, bch->ecc_buf, sizeof(r));
+
+	/*
+	 * split each 32-bit word into 4 polynomials of weight 8 as follows:
+	 *
+	 * 31 ...24  23 ...16  15 ... 8  7 ... 0
+	 * xxxxxxxx  yyyyyyyy  zzzzzzzz  tttttttt
+	 *                               tttttttt  mod g = r0 (precomputed)
+	 *                     zzzzzzzz  00000000  mod g = r1 (precomputed)
+	 *           yyyyyyyy  00000000  00000000  mod g = r2 (precomputed)
+	 * xxxxxxxx  00000000  00000000  00000000  mod g = r3 (precomputed)
+	 * xxxxxxxx  yyyyyyyy  zzzzzzzz  tttttttt  mod g = r0^r1^r2^r3
+	 */
+	while (mlen--) {
+		/* input data is read in big-endian format */
+		w = r[0]^cpu_to_be32(*pdata++);
+		p0 = tab0 + (l+1)*((w >>  0) & 0xff);
+		p1 = tab1 + (l+1)*((w >>  8) & 0xff);
+		p2 = tab2 + (l+1)*((w >> 16) & 0xff);
+		p3 = tab3 + (l+1)*((w >> 24) & 0xff);
+
+		for (i = 0; i < l; i++)
+			r[i] = r[i+1]^p0[i]^p1[i]^p2[i]^p3[i];
+
+		r[l] = p0[l]^p1[l]^p2[l]^p3[l];
+	}
+	memcpy(bch->ecc_buf, r, sizeof(r));
+
+	/* process last unaligned bytes */
+	if (len)
+		encode_bch_unaligned(bch, data, len, bch->ecc_buf);
+
+	/* store ecc parity bytes into original parity buffer */
+	if (ecc)
+		store_ecc8(bch, ecc, bch->ecc_buf);
+}
+
+static inline int modulo(struct bch_control *bch, unsigned int v)
+{
+	const unsigned int n = GF_N(bch);
+	while (v >= n) {
+		v -= n;
+		v = (v & n) + (v >> GF_M(bch));
+	}
+	return v;
+}
+
+/*
+ * shorter and faster modulo function, only works when v < 2N.
+ */
+static inline int mod_s(struct bch_control *bch, unsigned int v)
+{
+	const unsigned int n = GF_N(bch);
+	return (v < n) ? v : v-n;
+}
+
+static inline int deg(unsigned int poly)
+{
+	/* polynomial degree is the most-significant bit index */
+	return fls(poly)-1;
+}
+
+/* Galois field basic operations: multiply, divide, inverse, etc. */
+
+static inline unsigned int gf_mul(struct bch_control *bch, unsigned int a,
+				  unsigned int b)
+{
+	return (a && b) ? bch->a_pow_tab[mod_s(bch, bch->a_log_tab[a]+
+					       bch->a_log_tab[b])] : 0;
+}
+
+static inline unsigned int gf_sqr(struct bch_control *bch, unsigned int a)
+{
+	return a ? bch->a_pow_tab[mod_s(bch, 2*bch->a_log_tab[a])] : 0;
+}
+
+static inline unsigned int a_pow(struct bch_control *bch, int i)
+{
+	return bch->a_pow_tab[modulo(bch, i)];
+}
+
+static inline int a_log(struct bch_control *bch, unsigned int x)
+{
+	return bch->a_log_tab[x];
+}
+
+/*
+ * generate Galois field lookup tables
+ */
+static int build_gf_tables(struct bch_control *bch, unsigned int poly)
+{
+	unsigned int i, x = 1;
+	const unsigned int k = 1 << deg(poly);
+
+	/* primitive polynomial must be of degree m */
+	if (k != (1u << GF_M(bch)))
+		return -1;
+
+	for (i = 0; i < GF_N(bch); i++) {
+		bch->a_pow_tab[i] = x;
+		bch->a_log_tab[x] = i;
+		if (i && (x == 1))
+			/* polynomial is not primitive (a^i=1 with 0<i<2^m-1) */
+			return -1;
+		x <<= 1;
+		if (x & k)
+			x ^= poly;
+	}
+	bch->a_pow_tab[GF_N(bch)] = 1;
+	bch->a_log_tab[0] = 0;
+
+	return 0;
+}
+
+/*
+ * compute generator polynomial remainder tables for fast encoding
+ */
+static void build_mod8_tables(struct bch_control *bch, const uint32_t *g)
+{
+	int i, j, b, d;
+	uint32_t data, hi, lo, *tab;
+	const int l = BCH_ECC_WORDS(bch);
+	const int plen = DIV_ROUND_UP(bch->ecc_bits+1, 32);
+	const int ecclen = DIV_ROUND_UP(bch->ecc_bits, 32);
+
+	memset(bch->mod8_tab, 0, 4*256*l*sizeof(*bch->mod8_tab));
+
+	for (i = 0; i < 256; i++) {
+		/* p(X)=i is a small polynomial of weight <= 8 */
+		for (b = 0; b < 4; b++) {
+			/* we want to compute (p(X).X^(8*b+deg(g))) mod g(X) */
+			tab = bch->mod8_tab + (b*256+i)*l;
+			data = i << (8*b);
+			while (data) {
+				d = deg(data);
+				/* subtract X^d.g(X) from p(X).X^(8*b+deg(g)) */
+				data ^= g[0] >> (31-d);
+				for (j = 0; j < ecclen; j++) {
+					hi = (d < 31) ? g[j] << (d+1) : 0;
+					lo = (j+1 < plen) ?
+						g[j+1] >> (31-d) : 0;
+					tab[j] ^= hi|lo;
+				}
+			}
+		}
+	}
+}
+
+/*
+ * build a base for factoring degree 2 polynomials
+ */
+static int build_deg2_base(struct bch_control *bch)
+{
+	const int m = GF_M(bch);
+	int i, j, r;
+	unsigned int sum, x, y, remaining, ak = 0, xi[m];
+
+	/* find k s.t. Tr(a^k) = 1 and 0 <= k < m */
+	for (i = 0; i < m; i++) {
+		for (j = 0, sum = 0; j < m; j++)
+			sum ^= a_pow(bch, i*(1 << j));
+
+		if (sum) {
+			ak = bch->a_pow_tab[i];
+			break;
+		}
+	}
+	/* find xi, i=0..m-1 such that xi^2+xi = a^i+Tr(a^i).a^k */
+	remaining = m;
+	memset(xi, 0, sizeof(xi));
+
+	for (x = 0; (x <= GF_N(bch)) && remaining; x++) {
+		y = gf_sqr(bch, x)^x;
+		for (i = 0; i < 2; i++) {
+			r = a_log(bch, y);
+			if (y && (r < m) && !xi[r]) {
+				bch->xi_tab[r] = x;
+				xi[r] = 1;
+				remaining--;
+				dbg("x%d = %x\n", r, x);
+				break;
+			}
+			y ^= ak;
+		}
+	}
+	/* should not happen but check anyway */
+	return remaining ? -1 : 0;
+}
+
+static void *bch_alloc(size_t size, int *err)
+{
+	void *ptr;
+
+	ptr = malloc(size);
+	if (ptr == NULL)
+		*err = 1;
+	return ptr;
+}
+
+/*
+ * compute generator polynomial for given (m,t) parameters.
+ */
+static uint32_t *compute_generator_polynomial(struct bch_control *bch)
+{
+	const unsigned int m = GF_M(bch);
+	const unsigned int t = GF_T(bch);
+	int n, err = 0;
+	unsigned int i, j, nbits, r, word, *roots;
+	struct gf_poly *g;
+	uint32_t *genpoly;
+
+	g = bch_alloc(GF_POLY_SZ(m*t), &err);
+	roots = bch_alloc((bch->n+1)*sizeof(*roots), &err);
+	genpoly = bch_alloc(DIV_ROUND_UP(m*t+1, 32)*sizeof(*genpoly), &err);
+
+	if (err) {
+		kfree(genpoly);
+		genpoly = NULL;
+		goto finish;
+	}
+
+	/* enumerate all roots of g(X) */
+	memset(roots , 0, (bch->n+1)*sizeof(*roots));
+	for (i = 0; i < t; i++) {
+		for (j = 0, r = 2*i+1; j < m; j++) {
+			roots[r] = 1;
+			r = mod_s(bch, 2*r);
+		}
+	}
+	/* build generator polynomial g(X) */
+	g->deg = 0;
+	g->c[0] = 1;
+	for (i = 0; i < GF_N(bch); i++) {
+		if (roots[i]) {
+			/* multiply g(X) by (X+root) */
+			r = bch->a_pow_tab[i];
+			g->c[g->deg+1] = 1;
+			for (j = g->deg; j > 0; j--)
+				g->c[j] = gf_mul(bch, g->c[j], r)^g->c[j-1];
+
+			g->c[0] = gf_mul(bch, g->c[0], r);
+			g->deg++;
+		}
+	}
+	/* store left-justified binary representation of g(X) */
+	n = g->deg+1;
+	i = 0;
+
+	while (n > 0) {
+		nbits = (n > 32) ? 32 : n;
+		for (j = 0, word = 0; j < nbits; j++) {
+			if (g->c[n-1-j])
+				word |= 1u << (31-j);
+		}
+		genpoly[i++] = word;
+		n -= nbits;
+	}
+	bch->ecc_bits = g->deg;
+
+finish:
+	kfree(g);
+	kfree(roots);
+
+	return genpoly;
+}
+
+/**
+ *  free_bch - free the BCH control structure
+ *  @bch:    BCH control structure to release
+ */
+static void free_bch(struct bch_control *bch)
+{
+	unsigned int i;
+
+	if (bch) {
+		kfree(bch->a_pow_tab);
+		kfree(bch->a_log_tab);
+		kfree(bch->mod8_tab);
+		kfree(bch->ecc_buf);
+		kfree(bch->ecc_buf2);
+		kfree(bch->xi_tab);
+		kfree(bch->syn);
+		kfree(bch->cache);
+		kfree(bch->elp);
+
+		for (i = 0; i < ARRAY_SIZE(bch->poly_2t); i++)
+			kfree(bch->poly_2t[i]);
+
+		kfree(bch);
+	}
+}
+
+/**
+ * init_bch - initialize a BCH encoder/decoder
+ * @m:          Galois field order, should be in the range 5-15
+ * @t:          maximum error correction capability, in bits
+ * @prim_poly:  user-provided primitive polynomial (or 0 to use default)
+ *
+ * Returns:
+ *  a newly allocated BCH control structure if successful, NULL otherwise
+ *
+ * This initialization can take some time, as lookup tables are built for fast
+ * encoding/decoding; make sure not to call this function from a time critical
+ * path. Usually, init_bch() should be called on module/driver init and
+ * free_bch() should be called to release memory on exit.
+ *
+ * You may provide your own primitive polynomial of degree @m in argument
+ * @prim_poly, or let init_bch() use its default polynomial.
+ *
+ * Once init_bch() has successfully returned a pointer to a newly allocated
+ * BCH control structure, ecc length in bytes is given by member @ecc_bytes of
+ * the structure.
+ */
+static struct bch_control *init_bch(int m, int t, unsigned int prim_poly)
+{
+	int err = 0;
+	unsigned int i, words;
+	uint32_t *genpoly;
+	struct bch_control *bch = NULL;
+
+	const int min_m = 5;
+	const int max_m = 15;
+
+	/* default primitive polynomials */
+	static const unsigned int prim_poly_tab[] = {
+		0x25, 0x43, 0x83, 0x11d, 0x211, 0x409, 0x805, 0x1053, 0x201b,
+		0x402b, 0x8003,
+	};
+
+#if defined(CONFIG_BCH_CONST_PARAMS)
+	if ((m != (CONFIG_BCH_CONST_M)) || (t != (CONFIG_BCH_CONST_T))) {
+		printk(KERN_ERR "bch encoder/decoder was configured to support "
+		       "parameters m=%d, t=%d only!\n",
+		       CONFIG_BCH_CONST_M, CONFIG_BCH_CONST_T);
+		goto fail;
+	}
+#endif
+	if ((m < min_m) || (m > max_m))
+		/*
+		 * values of m greater than 15 are not currently supported;
+		 * supporting m > 15 would require changing table base type
+		 * (uint16_t) and a small patch in matrix transposition
+		 */
+		goto fail;
+
+	/* sanity checks */
+	if ((t < 1) || (m*t >= ((1 << m)-1)))
+		/* invalid t value */
+		goto fail;
+
+	/* select a primitive polynomial for generating GF(2^m) */
+	if (prim_poly == 0)
+		prim_poly = prim_poly_tab[m-min_m];
+
+	bch = malloc(sizeof(*bch));
+	if (bch == NULL)
+		goto fail;
+
+	memset(bch, 0, sizeof(*bch));
+
+	bch->m = m;
+	bch->t = t;
+	bch->n = (1 << m)-1;
+	words  = DIV_ROUND_UP(m*t, 32);
+	bch->ecc_bytes = DIV_ROUND_UP(m*t, 8);
+	bch->a_pow_tab = bch_alloc((1+bch->n)*sizeof(*bch->a_pow_tab), &err);
+	bch->a_log_tab = bch_alloc((1+bch->n)*sizeof(*bch->a_log_tab), &err);
+	bch->mod8_tab  = bch_alloc(words*1024*sizeof(*bch->mod8_tab), &err);
+	bch->ecc_buf   = bch_alloc(words*sizeof(*bch->ecc_buf), &err);
+	bch->ecc_buf2  = bch_alloc(words*sizeof(*bch->ecc_buf2), &err);
+	bch->xi_tab    = bch_alloc(m*sizeof(*bch->xi_tab), &err);
+	bch->syn       = bch_alloc(2*t*sizeof(*bch->syn), &err);
+	bch->cache     = bch_alloc(2*t*sizeof(*bch->cache), &err);
+	bch->elp       = bch_alloc((t+1)*sizeof(struct gf_poly_deg1), &err);
+
+	for (i = 0; i < ARRAY_SIZE(bch->poly_2t); i++)
+		bch->poly_2t[i] = bch_alloc(GF_POLY_SZ(2*t), &err);
+
+	if (err)
+		goto fail;
+
+	err = build_gf_tables(bch, prim_poly);
+	if (err)
+		goto fail;
+
+	/* use generator polynomial for computing encoding tables */
+	genpoly = compute_generator_polynomial(bch);
+	if (genpoly == NULL)
+		goto fail;
+
+	build_mod8_tables(bch, genpoly);
+	kfree(genpoly);
+
+	err = build_deg2_base(bch);
+	if (err)
+		goto fail;
+
+	return bch;
+
+fail:
+	free_bch(bch);
+	return NULL;
+}
+
+static void swap_bits(uint8_t *buf, int len)
+{
+	int i, j;
+
+	for (j = 0; j < len; j++) {
+		uint8_t byte = buf[j];
+
+		buf[j] = 0;
+		for (i = 0; i < 8; i++) {
+			if (byte & (1 << i))
+				buf[j] |= (1 << (7 - i));
+		}
+	}
+}
+
+static uint16_t lfsr_step(uint16_t state, int count)
+{
+	state &= 0x7fff;
+	while (count--)
+		state = ((state >> 1) |
+			 ((((state >> 0) ^ (state >> 1)) & 1) << 14)) & 0x7fff;
+
+	return state;
+}
+
+static uint16_t default_scrambler_seeds[] = {
+	0x2b75, 0x0bd0, 0x5ca3, 0x62d1, 0x1c93, 0x07e9, 0x2162, 0x3a72,
+	0x0d67, 0x67f9, 0x1be7, 0x077d, 0x032f, 0x0dac, 0x2716, 0x2436,
+	0x7922, 0x1510, 0x3860, 0x5287, 0x480f, 0x4252, 0x1789, 0x5a2d,
+	0x2a49, 0x5e10, 0x437f, 0x4b4e, 0x2f45, 0x216e, 0x5cb7, 0x7130,
+	0x2a3f, 0x60e4, 0x4dc9, 0x0ef0, 0x0f52, 0x1bb9, 0x6211, 0x7a56,
+	0x226d, 0x4ea7, 0x6f36, 0x3692, 0x38bf, 0x0c62, 0x05eb, 0x4c55,
+	0x60f4, 0x728c, 0x3b6f, 0x2037, 0x7f69, 0x0936, 0x651a, 0x4ceb,
+	0x6218, 0x79f3, 0x383f, 0x18d9, 0x4f05, 0x5c82, 0x2912, 0x6f17,
+	0x6856, 0x5938, 0x1007, 0x61ab, 0x3e7f, 0x57c2, 0x542f, 0x4f62,
+	0x7454, 0x2eac, 0x7739, 0x42d4, 0x2f90, 0x435a, 0x2e52, 0x2064,
+	0x637c, 0x66ad, 0x2c90, 0x0bad, 0x759c, 0x0029, 0x0986, 0x7126,
+	0x1ca7, 0x1605, 0x386a, 0x27f5, 0x1380, 0x6d75, 0x24c3, 0x0f8e,
+	0x2b7a, 0x1418, 0x1fd1, 0x7dc1, 0x2d8e, 0x43af, 0x2267, 0x7da3,
+	0x4e3d, 0x1338, 0x50db, 0x454d, 0x764d, 0x40a3, 0x42e6, 0x262b,
+	0x2d2e, 0x1aea, 0x2e17, 0x173d, 0x3a6e, 0x71bf, 0x25f9, 0x0a5d,
+	0x7c57, 0x0fbe, 0x46ce, 0x4939, 0x6b17, 0x37bb, 0x3e91, 0x76db,
+};
+
+static uint16_t brom_scrambler_seeds[] = { 0x4a80 };
+
+static void scramble(const struct image_info *info,
+		     int page, uint8_t *data, int datalen)
+{
+	uint16_t state;
+	int i;
+
+	/* Boot0 is always scrambled no matter the command line option. */
+	if (info->boot0) {
+		state = brom_scrambler_seeds[0];
+	} else {
+		unsigned seedmod = info->eraseblock_size / info->page_size;
+
+		/* Bail out earlier if the user didn't ask for scrambling. */
+		if (!info->scramble)
+			return;
+
+		if (seedmod > ARRAY_SIZE(default_scrambler_seeds))
+			seedmod = ARRAY_SIZE(default_scrambler_seeds);
+
+		state = default_scrambler_seeds[page % seedmod];
+	}
+
+	/* Prepare the initial state... */
+	state = lfsr_step(state, 15);
+
+	/* and start scrambling data. */
+	for (i = 0; i < datalen; i++) {
+		data[i] ^= state;
+		state = lfsr_step(state, 8);
+	}
+}
+
+static int write_page(const struct image_info *info, uint8_t *buffer,
+		      FILE *src, FILE *rnd, FILE *dst,
+		      struct bch_control *bch, int page)
+{
+	int steps = info->usable_page_size / info->ecc_step_size;
+	int eccbytes = DIV_ROUND_UP(info->ecc_strength * 14, 8);
+	off_t pos = ftell(dst);
+	size_t pad, cnt;
+	int i;
+
+	if (eccbytes % 2)
+		eccbytes++;
+
+	memset(buffer, 0xff, info->page_size + info->oob_size);
+	cnt = fread(buffer, 1, info->usable_page_size, src);
+	if (!cnt) {
+		if (!feof(src)) {
+			fprintf(stderr,
+				"Failed to read data from the source\n");
+			return -1;
+		} else {
+			return 0;
+		}
+	}
+
+	fwrite(buffer, info->page_size + info->oob_size, 1, dst);
+
+	for (i = 0; i < info->usable_page_size; i++) {
+		if (buffer[i] !=  0xff)
+			break;
+	}
+
+	/* We leave empty pages at 0xff. */
+	if (i == info->usable_page_size)
+		return 0;
+
+	/* Restore the source pointer to read it again. */
+	fseek(src, -cnt, SEEK_CUR);
+
+	/* Randomize unused space if scrambling is required. */
+	if (info->scramble) {
+		int offs;
+
+		if (info->boot0) {
+			offs = steps * (info->ecc_step_size + eccbytes + 4);
+			cnt = info->page_size + info->oob_size - offs;
+			fread(buffer + offs, 1, cnt, rnd);
+		} else {
+			offs = info->page_size + (steps * (eccbytes + 4));
+			cnt = info->page_size + info->oob_size - offs;
+			memset(buffer + offs, 0xff, cnt);
+			scramble(info, page, buffer + offs, cnt);
+		}
+		fseek(dst, pos + offs, SEEK_SET);
+		fwrite(buffer + offs, cnt, 1, dst);
+	}
+
+	for (i = 0; i < steps; i++) {
+		int ecc_offs, data_offs;
+		uint8_t *ecc;
+
+		memset(buffer, 0xff, info->ecc_step_size + eccbytes + 4);
+		ecc = buffer + info->ecc_step_size + 4;
+		if (info->boot0) {
+			data_offs = i * (info->ecc_step_size + eccbytes + 4);
+			ecc_offs = data_offs + info->ecc_step_size + 4;
+		} else {
+			data_offs = i * info->ecc_step_size;
+			ecc_offs = info->page_size + 4 + (i * (eccbytes + 4));
+		}
+
+		cnt = fread(buffer, 1, info->ecc_step_size, src);
+		if (!cnt && !feof(src)) {
+			fprintf(stderr,
+				"Failed to read data from the source\n");
+			return -1;
+		}
+
+		pad = info->ecc_step_size - cnt;
+		if (pad) {
+			if (info->scramble && info->boot0)
+				fread(buffer + cnt, 1, pad, rnd);
+			else
+				memset(buffer + cnt, 0xff, pad);
+		}
+
+		memset(ecc, 0, eccbytes);
+		swap_bits(buffer, info->ecc_step_size + 4);
+		encode_bch(bch, buffer, info->ecc_step_size + 4, ecc);
+		swap_bits(buffer, info->ecc_step_size + 4);
+		swap_bits(ecc, eccbytes);
+		scramble(info, page, buffer, info->ecc_step_size + 4 + eccbytes);
+
+		fseek(dst, pos + data_offs, SEEK_SET);
+		fwrite(buffer, info->ecc_step_size, 1, dst);
+		fseek(dst, pos + ecc_offs - 4, SEEK_SET);
+		fwrite(ecc - 4, eccbytes + 4, 1, dst);
+	}
+
+	/* Fix BBM. */
+	fseek(dst, pos + info->page_size, SEEK_SET);
+	memset(buffer, 0xff, 2);
+	fwrite(buffer, 2, 1, dst);
+
+	/* Make dst pointer point to the next page. */
+	fseek(dst, pos + info->page_size + info->oob_size, SEEK_SET);
+
+	return 0;
+}
+
+static int create_image(const struct image_info *info)
+{
+	off_t page = info->offset / info->page_size;
+	struct bch_control *bch;
+	FILE *src, *dst, *rnd;
+	uint8_t *buffer;
+
+	bch = init_bch(14, info->ecc_strength, BCH_PRIMITIVE_POLY);
+	if (!bch) {
+		fprintf(stderr, "Failed to init the BCH engine\n");
+		return -1;
+	}
+
+	buffer = malloc(info->page_size + info->oob_size);
+	if (!buffer) {
+		fprintf(stderr, "Failed to allocate the NAND page buffer\n");
+		return -1;
+	}
+
+	memset(buffer, 0xff, info->page_size + info->oob_size);
+
+	src = fopen(info->source, "r");
+	if (!src) {
+		fprintf(stderr, "Failed to open source file (%s)\n",
+			info->source);
+		return -1;
+	}
+
+	dst = fopen(info->dest, "w");
+	if (!dst) {
+		fprintf(stderr, "Failed to open dest file (%s)\n", info->dest);
+		return -1;
+	}
+
+	rnd = fopen("/dev/urandom", "r");
+	if (!rnd) {
+		fprintf(stderr, "Failed to open /dev/urandom\n");
+		return -1;
+	}
+
+	while (!feof(src)) {
+		int ret;
+
+		ret = write_page(info, buffer, src, rnd, dst, bch, page++);
+		if (ret)
+			return ret;
+	}
+
+	return 0;
+}
+
+static void display_help(int status)
+{
+	fprintf(status == EXIT_SUCCESS ? stdout : stderr,
+		"sunxi-nand-image-builder %s\n"
+		"\n"
+		"Usage: sunxi-nand-image-builder [OPTIONS] source-image output-image\n"
+		"\n"
+		"Creates a raw NAND image that can be read by the sunxi NAND controller.\n"
+		"\n"
+		"-h               --help               Display this help and exit\n"
+		"-c <str>/<step>  --ecc=<str>/<step>   ECC config (strength/step-size)\n"
+		"-p <size>        --page=<size>        Page size\n"
+		"-o <size>        --oob=<size>         OOB size\n"
+		"-u <size>        --usable=<size>      Usable page size\n"
+		"-e <size>        --eraseblock=<size>  Erase block size\n"
+		"-b               --boot0              Build a boot0 image.\n"
+		"-s               --scramble           Scramble data\n"
+		"-a <offset>      --address=<offset>   Where the image will be programmed.\n"
+		"\n"
+		"Notes:\n"
+		"All the information you need to pass to this tool should be part of\n"
+		"the NAND datasheet.\n"
+		"\n"
+		"The NAND controller only supports the following ECC configs\n"
+		"  Valid ECC strengths: 16, 24, 28, 32, 40, 48, 56, 60 and 64\n"
+		"  Valid ECC step size: 512 and 1024\n"
+		"\n"
+		"If you are building a boot0 image, you'll have specify extra options.\n"
+		"These options should be chosen based on the layouts described here:\n"
+		"  http://linux-sunxi.org/NAND#More_information_on_BROM_NAND\n"
+		"\n"
+		"  --usable should be assigned the 'Hardware page' value\n"
+		"  --ecc should be assigned the 'ECC capacity'/'ECC page' values\n"
+		"  --usable should be smaller than --page\n"
+		"\n"
+		"The --address option is only required for non-boot0 images that are \n"
+		"meant to be programmed at a non eraseblock aligned offset.\n"
+		"\n"
+		"Examples:\n"
+		"  The H27UCG8T2BTR-BC NAND exposes\n"
+		"  * 16k pages\n"
+		"  * 1280 OOB bytes per page\n"
+		"  * 4M eraseblocks\n"
+		"  * requires data scrambling\n"
+		"  * expects a minimum ECC of 40bits/1024bytes\n"
+		"\n"
+		"  A normal image can be generated with\n"
+		"    sunxi-nand-image-builder -p 16384 -o 1280 -e 0x400000 -s -c 40/1024\n"
+		"  A boot0 image can be generated with\n"
+		"    sunxi-nand-image-builder -p 16384 -o 1280 -e 0x400000 -s -b -u 4096 -c 64/1024\n",
+		PLAIN_VERSION);
+	exit(status);
+}
+
+static int check_image_info(struct image_info *info)
+{
+	static int valid_ecc_strengths[] = { 16, 24, 28, 32, 40, 48, 56, 60, 64 };
+	int eccbytes, eccsteps;
+	unsigned i;
+
+	if (!info->page_size) {
+		fprintf(stderr, "--page is missing\n");
+		return -EINVAL;
+	}
+
+	if (!info->page_size) {
+		fprintf(stderr, "--oob is missing\n");
+		return -EINVAL;
+	}
+
+	if (!info->eraseblock_size) {
+		fprintf(stderr, "--eraseblock is missing\n");
+		return -EINVAL;
+	}
+
+	if (info->ecc_step_size != 512 && info->ecc_step_size != 1024) {
+		fprintf(stderr, "Invalid ECC step argument: %d\n",
+			info->ecc_step_size);
+		return -EINVAL;
+	}
+
+	for (i = 0; i < ARRAY_SIZE(valid_ecc_strengths); i++) {
+		if (valid_ecc_strengths[i] == info->ecc_strength)
+			break;
+	}
+
+	if (i == ARRAY_SIZE(valid_ecc_strengths)) {
+		fprintf(stderr, "Invalid ECC strength argument: %d\n",
+			info->ecc_strength);
+		return -EINVAL;
+	}
+
+	eccbytes = DIV_ROUND_UP(info->ecc_strength * 14, 8);
+	if (eccbytes % 2)
+		eccbytes++;
+	eccbytes += 4;
+
+	eccsteps = info->usable_page_size / info->ecc_step_size;
+
+	if (info->page_size + info->oob_size <
+	    info->usable_page_size + (eccsteps * eccbytes)) {
+		fprintf(stderr,
+			"ECC bytes do not fit in the NAND page, choose a weaker ECC\n");
+		return -EINVAL;
+	}
+
+	return 0;
+}
+
+int main(int argc, char **argv)
+{
+	struct image_info info;
+
+	memset(&info, 0, sizeof(info));
+	/*
+	 * Process user arguments
+	 */
+	for (;;) {
+		int option_index = 0;
+		char *endptr = NULL;
+		static const struct option long_options[] = {
+			{"help", no_argument, 0, 'h'},
+			{"ecc", required_argument, 0, 'c'},
+			{"page", required_argument, 0, 'p'},
+			{"oob", required_argument, 0, 'o'},
+			{"usable", required_argument, 0, 'u'},
+			{"eraseblock", required_argument, 0, 'e'},
+			{"boot0", no_argument, 0, 'b'},
+			{"scramble", no_argument, 0, 's'},
+			{"address", required_argument, 0, 'a'},
+			{0, 0, 0, 0},
+		};
+
+		int c = getopt_long(argc, argv, "c:p:o:u:e:ba:sh",
+				long_options, &option_index);
+		if (c == EOF)
+			break;
+
+		switch (c) {
+		case 'h':
+			display_help(0);
+			break;
+		case 's':
+			info.scramble = 1;
+			break;
+		case 'c':
+			info.ecc_strength = strtol(optarg, &endptr, 0);
+			if (endptr || *endptr == '/')
+				info.ecc_step_size = strtol(endptr + 1, NULL, 0);
+			break;
+		case 'p':
+			info.page_size = strtol(optarg, NULL, 0);
+			break;
+		case 'o':
+			info.oob_size = strtol(optarg, NULL, 0);
+			break;
+		case 'u':
+			info.usable_page_size = strtol(optarg, NULL, 0);
+			break;
+		case 'e':
+			info.eraseblock_size = strtol(optarg, NULL, 0);
+			break;
+		case 'b':
+			info.boot0 = 1;
+			break;
+		case 'a':
+			info.offset = strtoull(optarg, NULL, 0);
+			break;
+		case '?':
+			display_help(-1);
+			break;
+		}
+	}
+
+	if ((argc - optind) != 2)
+		display_help(-1);
+
+	info.source = argv[optind];
+	info.dest = argv[optind + 1];
+
+	if (!info.boot0) {
+		info.usable_page_size = info.page_size;
+	} else if (!info.usable_page_size) {
+		if (info.page_size > 8192)
+			info.usable_page_size = 8192;
+		else if (info.page_size > 4096)
+			info.usable_page_size = 4096;
+		else
+			info.usable_page_size = 1024;
+	}
+
+	if (check_image_info(&info))
+		display_help(-1);
+
+	return create_image(&info);
+}
-- 
git-series 0.8.11

^ permalink raw reply related	[flat|nested] 44+ messages in thread

* [U-Boot] [PATCH 5/7] nand: sunxi: Add options for the SPL NAND configuration
  2016-11-08 16:21 [U-Boot] [PATCH 0/7] sunxi: Add support for the CHIP Pro Maxime Ripard
                   ` (3 preceding siblings ...)
  2016-11-08 16:21 ` [U-Boot] [PATCH 4/7] tools: sunxi: Add spl image builder Maxime Ripard
@ 2016-11-08 16:21 ` Maxime Ripard
  2016-11-08 16:31   ` Boris Brezillon
                     ` (2 more replies)
  2016-11-08 16:21 ` [U-Boot] [PATCH 6/7] scripts: sunxi: Build an raw SPL image Maxime Ripard
                   ` (2 subsequent siblings)
  7 siblings, 3 replies; 44+ messages in thread
From: Maxime Ripard @ 2016-11-08 16:21 UTC (permalink / raw)
  To: u-boot

The SPL image needs to be built with a different ECC configuration than the
U-Boot binary.

Add Kconfig options with defaults to provide a value that should work for
anyone, but is still configurable if needs be.

Signed-off-by: Maxime Ripard <maxime.ripard@free-electrons.com>
---
 drivers/mtd/nand/Kconfig | 16 ++++++++++++++++
 1 file changed, 16 insertions(+), 0 deletions(-)

diff --git a/drivers/mtd/nand/Kconfig b/drivers/mtd/nand/Kconfig
index df154bfd32b9..a60abb625ee5 100644
--- a/drivers/mtd/nand/Kconfig
+++ b/drivers/mtd/nand/Kconfig
@@ -73,6 +73,22 @@ config NAND_SUNXI
 	The SPL driver only supports reading from the NAND using DMA
 	transfers.
 
+if NAND_SUNXI
+
+config NAND_SUNXI_SPL_ECC_STRENGTH
+	int "Allwinner NAND SPL ECC Strength"
+	default 64
+
+config NAND_SUNXI_SPL_ECC_SIZE
+	int "Allwinner NAND SPL ECC Step Size"
+	default 1024
+
+config NAND_SUNXI_SPL_USABLE_PAGE_SIZE
+	int "Allwinner NAND SPL Usable Page Size"
+	default 1024
+
+endif
+
 config NAND_ARASAN
 	bool "Configure Arasan Nand"
 	help
-- 
git-series 0.8.11

^ permalink raw reply related	[flat|nested] 44+ messages in thread

* [U-Boot] [PATCH 6/7] scripts: sunxi: Build an raw SPL image
  2016-11-08 16:21 [U-Boot] [PATCH 0/7] sunxi: Add support for the CHIP Pro Maxime Ripard
                   ` (4 preceding siblings ...)
  2016-11-08 16:21 ` [U-Boot] [PATCH 5/7] nand: sunxi: Add options for the SPL NAND configuration Maxime Ripard
@ 2016-11-08 16:21 ` Maxime Ripard
  2016-11-08 16:33   ` Boris Brezillon
  2016-11-14 11:19   ` Hans de Goede
  2016-11-08 16:21 ` [U-Boot] [PATCH 7/7] sunxi: Add support for the CHIP Pro Maxime Ripard
  2016-11-09  7:47 ` [U-Boot] [PATCH 0/7] " Heiko Schocher
  7 siblings, 2 replies; 44+ messages in thread
From: Maxime Ripard @ 2016-11-08 16:21 UTC (permalink / raw)
  To: u-boot

Introduce a new sunxi-spl-with-ecc.bin image with already the right header,
ECC, randomizer and padding for the BROM to be able to read it.

It needs to be flashed using a raw access to the NAND so that the
controller doesn't change a thing to it, since we already have all the
right parameters.

Signed-off-by: Maxime Ripard <maxime.ripard@free-electrons.com>
---
 Makefile             |  3 +++
 scripts/Makefile.spl | 12 ++++++++++++
 2 files changed, 15 insertions(+), 0 deletions(-)

diff --git a/Makefile b/Makefile
index 37cbcb28f75e..12a248e297b5 100644
--- a/Makefile
+++ b/Makefile
@@ -1345,6 +1345,9 @@ spl/u-boot-spl: tools prepare \
 spl/sunxi-spl.bin: spl/u-boot-spl
 	@:
 
+spl/sunxi-spl-with-ecc.bin: spl/sunxi-spl.bin
+	@:
+
 spl/u-boot-spl.sfp: spl/u-boot-spl
 	@:
 
diff --git a/scripts/Makefile.spl b/scripts/Makefile.spl
index e0b0117dc9b6..b41b4e427cc5 100644
--- a/scripts/Makefile.spl
+++ b/scripts/Makefile.spl
@@ -168,6 +168,7 @@ endif
 
 ifdef CONFIG_ARCH_SUNXI
 ALL-y	+= $(obj)/sunxi-spl.bin
+ALL-y	+= $(obj)/sunxi-spl-with-ecc.bin
 endif
 
 ifeq ($(CONFIG_SYS_SOC),"at91")
@@ -276,6 +277,17 @@ cmd_mksunxiboot = $(objtree)/tools/mksunxiboot $< $@
 $(obj)/sunxi-spl.bin: $(obj)/$(SPL_BIN).bin FORCE
 	$(call if_changed,mksunxiboot)
 
+quiet_cmd_sunxi_spl_image_builder = SUNXI_SPL_IMAGE_BUILDER $@
+cmd_sunxi_spl_image_builder = $(objtree)/tools/sunxi-spl-image-builder \
+				-c $(CONFIG_NAND_SUNXI_SPL_ECC_STRENGTH)/$(CONFIG_NAND_SUNXI_SPL_ECC_SIZE) \
+				-p $(CONFIG_SYS_NAND_PAGE_SIZE) \
+				-o $(CONFIG_SYS_NAND_OOBSIZE) \
+				-u $(CONFIG_NAND_SUNXI_SPL_USABLE_PAGE_SIZE) \
+				-e $(CONFIG_SYS_NAND_BLOCK_SIZE) \
+				-s -b $< $@
+$(obj)/sunxi-spl-with-ecc.bin: $(obj)/sunxi-spl.bin
+	$(call if_changed,sunxi_spl_image_builder)
+
 # Rule to link u-boot-spl
 # May be overridden by arch/$(ARCH)/config.mk
 quiet_cmd_u-boot-spl ?= LD      $@
-- 
git-series 0.8.11

^ permalink raw reply related	[flat|nested] 44+ messages in thread

* [U-Boot] [PATCH 7/7] sunxi: Add support for the CHIP Pro
  2016-11-08 16:21 [U-Boot] [PATCH 0/7] sunxi: Add support for the CHIP Pro Maxime Ripard
                   ` (5 preceding siblings ...)
  2016-11-08 16:21 ` [U-Boot] [PATCH 6/7] scripts: sunxi: Build an raw SPL image Maxime Ripard
@ 2016-11-08 16:21 ` Maxime Ripard
  2016-11-14 11:20   ` Hans de Goede
  2016-11-09  7:47 ` [U-Boot] [PATCH 0/7] " Heiko Schocher
  7 siblings, 1 reply; 44+ messages in thread
From: Maxime Ripard @ 2016-11-08 16:21 UTC (permalink / raw)
  To: u-boot

The CHIP Pro is a SoM that features the GR8 SIP, an AXP209, a BT/WiFi chip
and a 512MiB SLC NAND.

This it's an SLC NAND, it doesn't suffer the same drawbacks than found on
the MLC NANDs, and we can enable it right away.

Signed-off-by: Maxime Ripard <maxime.ripard@free-electrons.com>
---
 configs/CHIP_pro_defconfig | 27 +++++++++++++++++++++++++++
 1 file changed, 27 insertions(+), 0 deletions(-)
 create mode 100644 configs/CHIP_pro_defconfig

diff --git a/configs/CHIP_pro_defconfig b/configs/CHIP_pro_defconfig
new file mode 100644
index 000000000000..6008f44f485c
--- /dev/null
+++ b/configs/CHIP_pro_defconfig
@@ -0,0 +1,27 @@
+CONFIG_ARM=y
+CONFIG_ARCH_SUNXI=y
+CONFIG_SPL_I2C_SUPPORT=y
+# CONFIG_SPL_MMC_SUPPORT is not set
+CONFIG_MACH_SUN5I=y
+CONFIG_DRAM_TIMINGS_DDR3_800E_1066G_1333J=y
+# CONFIG_MMC is not set
+CONFIG_USB0_VBUS_PIN="PB10"
+CONFIG_DEFAULT_DEVICE_TREE="ntc-gr8-chip-pro"
+CONFIG_SYS_EXTRA_OPTIONS="CONS_INDEX=2,SYS_NAND_BLOCK_SIZE=0x40000,SYS_NAND_PAGE_SIZE=4096,SYS_NAND_OOBSIZE=256,ENV_IS_IN_NAND"
+CONFIG_SPL=y
+# CONFIG_CMD_IMLS is not set
+CONFIG_CMD_DFU=y
+CONFIG_CMD_USB_MASS_STORAGE=y
+CONFIG_DFU_RAM=y
+CONFIG_AXP_ALDO3_VOLT=3300
+CONFIG_AXP_ALDO4_VOLT=3300
+CONFIG_USB_EHCI_HCD=y
+CONFIG_USB_MUSB_GADGET=y
+CONFIG_USB_GADGET=y
+CONFIG_USB_GADGET_DOWNLOAD=y
+CONFIG_G_DNL_MANUFACTURER="Allwinner Technology"
+CONFIG_G_DNL_VENDOR_NUM=0x1f3a
+CONFIG_G_DNL_PRODUCT_NUM=0x1010
+CONFIG_NAND_SUNXI=y
+CONFIG_SPL_NAND_SUPPORT=y
+CONFIG_MTD_UBI=y
-- 
git-series 0.8.11

^ permalink raw reply related	[flat|nested] 44+ messages in thread

* [U-Boot] [PATCH 3/7] sunxi: Enable UBI and NAND support
  2016-11-08 16:21 ` [U-Boot] [PATCH 3/7] sunxi: Enable UBI and NAND support Maxime Ripard
@ 2016-11-08 16:27   ` Boris Brezillon
  2016-11-08 16:27   ` Boris Brezillon
  2016-11-14 11:18   ` Hans de Goede
  2 siblings, 0 replies; 44+ messages in thread
From: Boris Brezillon @ 2016-11-08 16:27 UTC (permalink / raw)
  To: u-boot

On Tue,  8 Nov 2016 17:21:13 +0100
Maxime Ripard <maxime.ripard@free-electrons.com> wrote:

> From: Hans de Goede <hdegoede@redhat.com>
> 
> Enable the NAND and UBI support in the configuration header so that we can
> (finally) use it.
> 
> Signed-off-by: Hans de Goede <hdegoede@redhat.com>
> Signed-off-by: Maxime Ripard <maxime.ripard@free-electrons.com>
> ---
>  include/configs/sunxi-common.h | 26 ++++++++++++++++++++++----
>  1 file changed, 22 insertions(+), 4 deletions(-)
> 
> diff --git a/include/configs/sunxi-common.h b/include/configs/sunxi-common.h
> index 8363414828fa..1733767ba53b 100644
> --- a/include/configs/sunxi-common.h
> +++ b/include/configs/sunxi-common.h
> @@ -129,9 +129,23 @@
>  #define CONFIG_SERIAL_TAG
>  
>  #ifdef CONFIG_NAND_SUNXI
> +#define CONFIG_SYS_NAND_U_BOOT_OFFS	(8 << 20) /* 8 MiB */


>  #define CONFIG_SYS_NAND_MAX_ECCPOS 1664
>  #define CONFIG_SYS_NAND_ONFI_DETECTION
>  #define CONFIG_SYS_MAX_NAND_DEVICE 8
> +
> +/* Requirements for UBI */
> +#define CONFIG_RBTREE
> +#define CONFIG_LZO
> +#define CONFIG_CMD_MTDPARTS
> +#define CONFIG_CMD_UBI
> +#define CONFIG_CMD_UBIFS
> +#define CONFIG_MTD_DEVICE
> +
> +#define CONFIG_MTD_PARTITIONS
> +
> +#define CONFIG_CMD_NAND
> +#define CONFIG_CMD_NAND_TRIMFFS
>  #endif
>  
>  #ifdef CONFIG_SPL_SPI_SUNXI
> @@ -143,7 +157,14 @@
>  #define CONFIG_GENERIC_MMC
>  #define CONFIG_MMC_SUNXI
>  #define CONFIG_MMC_SUNXI_SLOT		0
> -#define CONFIG_ENV_IS_IN_MMC
> +#endif
> +
> +#if defined(CONFIG_ENV_IS_IN_NAND)
> +#define CONFIG_ENV_OFFSET			0xc00000
> +#define CONFIG_ENV_SIZE				0x400000
> +#elif defined(CONFIG_ENV_IS_IN_MMC)
> +#define CONFIG_ENV_OFFSET			(544 << 10) /* (8 + 24 + 512) KiB */
> +#define CONFIG_ENV_SIZE				(128 << 10) /* 128 KiB */
>  #define CONFIG_SYS_MMC_ENV_DEV		0	/* first detected MMC controller */
>  #endif
>  
> @@ -175,9 +196,6 @@
>  
>  #define CONFIG_SYS_MONITOR_LEN		(768 << 10)	/* 768 KiB */
>  
> -#define CONFIG_ENV_OFFSET		(544 << 10) /* (8 + 24 + 512) KiB */
> -#define CONFIG_ENV_SIZE			(128 << 10)	/* 128 KiB */
> -
>  #define CONFIG_FAT_WRITE	/* enable write access */
>  
>  #define CONFIG_SPL_FRAMEWORK

^ permalink raw reply	[flat|nested] 44+ messages in thread

* [U-Boot] [PATCH 3/7] sunxi: Enable UBI and NAND support
  2016-11-08 16:21 ` [U-Boot] [PATCH 3/7] sunxi: Enable UBI and NAND support Maxime Ripard
  2016-11-08 16:27   ` Boris Brezillon
@ 2016-11-08 16:27   ` Boris Brezillon
  2016-11-09 14:32     ` Maxime Ripard
  2016-11-14 11:18   ` Hans de Goede
  2 siblings, 1 reply; 44+ messages in thread
From: Boris Brezillon @ 2016-11-08 16:27 UTC (permalink / raw)
  To: u-boot

On Tue,  8 Nov 2016 17:21:13 +0100
Maxime Ripard <maxime.ripard@free-electrons.com> wrote:

> From: Hans de Goede <hdegoede@redhat.com>
> 
> Enable the NAND and UBI support in the configuration header so that we can
> (finally) use it.
> 
> Signed-off-by: Hans de Goede <hdegoede@redhat.com>
> Signed-off-by: Maxime Ripard <maxime.ripard@free-electrons.com>
> ---
>  include/configs/sunxi-common.h | 26 ++++++++++++++++++++++----
>  1 file changed, 22 insertions(+), 4 deletions(-)
> 
> diff --git a/include/configs/sunxi-common.h b/include/configs/sunxi-common.h
> index 8363414828fa..1733767ba53b 100644
> --- a/include/configs/sunxi-common.h
> +++ b/include/configs/sunxi-common.h
> @@ -129,9 +129,23 @@
>  #define CONFIG_SERIAL_TAG
>  
>  #ifdef CONFIG_NAND_SUNXI
> +#define CONFIG_SYS_NAND_U_BOOT_OFFS	(8 << 20) /* 8 MiB */

Can we make this configurable through Kconfig?

>  #define CONFIG_SYS_NAND_MAX_ECCPOS 1664
>  #define CONFIG_SYS_NAND_ONFI_DETECTION
>  #define CONFIG_SYS_MAX_NAND_DEVICE 8
> +
> +/* Requirements for UBI */
> +#define CONFIG_RBTREE
> +#define CONFIG_LZO
> +#define CONFIG_CMD_MTDPARTS
> +#define CONFIG_CMD_UBI
> +#define CONFIG_CMD_UBIFS
> +#define CONFIG_MTD_DEVICE
> +
> +#define CONFIG_MTD_PARTITIONS
> +
> +#define CONFIG_CMD_NAND
> +#define CONFIG_CMD_NAND_TRIMFFS
>  #endif
>  
>  #ifdef CONFIG_SPL_SPI_SUNXI
> @@ -143,7 +157,14 @@
>  #define CONFIG_GENERIC_MMC
>  #define CONFIG_MMC_SUNXI
>  #define CONFIG_MMC_SUNXI_SLOT		0
> -#define CONFIG_ENV_IS_IN_MMC
> +#endif
> +
> +#if defined(CONFIG_ENV_IS_IN_NAND)
> +#define CONFIG_ENV_OFFSET			0xc00000
> +#define CONFIG_ENV_SIZE				0x400000

Ditto.

> +#elif defined(CONFIG_ENV_IS_IN_MMC)
> +#define CONFIG_ENV_OFFSET			(544 << 10) /* (8 + 24 + 512) KiB */
> +#define CONFIG_ENV_SIZE				(128 << 10) /* 128 KiB */
>  #define CONFIG_SYS_MMC_ENV_DEV		0	/* first detected MMC controller */
>  #endif
>  
> @@ -175,9 +196,6 @@
>  
>  #define CONFIG_SYS_MONITOR_LEN		(768 << 10)	/* 768 KiB */
>  
> -#define CONFIG_ENV_OFFSET		(544 << 10) /* (8 + 24 + 512) KiB */
> -#define CONFIG_ENV_SIZE			(128 << 10)	/* 128 KiB */
> -
>  #define CONFIG_FAT_WRITE	/* enable write access */
>  
>  #define CONFIG_SPL_FRAMEWORK

^ permalink raw reply	[flat|nested] 44+ messages in thread

* [U-Boot] [PATCH 4/7] tools: sunxi: Add spl image builder
  2016-11-08 16:21 ` [U-Boot] [PATCH 4/7] tools: sunxi: Add spl image builder Maxime Ripard
@ 2016-11-08 16:29   ` Boris Brezillon
  2016-11-08 20:45     ` Maxime Ripard
  2016-11-11 16:20   ` Tom Rini
  2016-11-14 11:18   ` Hans de Goede
  2 siblings, 1 reply; 44+ messages in thread
From: Boris Brezillon @ 2016-11-08 16:29 UTC (permalink / raw)
  To: u-boot

On Tue,  8 Nov 2016 17:21:14 +0100
Maxime Ripard <maxime.ripard@free-electrons.com> wrote:

> This program generates raw SPL images that can be flashed on the NAND with
> the ECC and randomizer properly set up.
> 

Maybe you should mention that this file has been copied from the
sunxi-tools project.

Otherwise,

Acked-by: Boris Brezillon <boris.brezillon@free-electrons.com>

> Signed-off-by: Maxime Ripard <maxime.ripard@free-electrons.com>
> ---
>  tools/.gitignore                |    1 +-
>  tools/Makefile                  |    1 +-
>  tools/sunxi-spl-image-builder.c | 1113 ++++++++++++++++++++++++++++++++-
>  3 files changed, 1115 insertions(+), 0 deletions(-)
>  create mode 100644 tools/sunxi-spl-image-builder.c
> 
> diff --git a/tools/.gitignore b/tools/.gitignore
> index cb1e722d4575..16574467544c 100644
> --- a/tools/.gitignore
> +++ b/tools/.gitignore
> @@ -15,6 +15,7 @@
>  /mkexynosspl
>  /mxsboot
>  /mksunxiboot
> +/sunxi-spl-image-builder
>  /ncb
>  /proftool
>  /relocate-rela
> diff --git a/tools/Makefile b/tools/Makefile
> index 400588cf0f5c..dfeeb23484ce 100644
> --- a/tools/Makefile
> +++ b/tools/Makefile
> @@ -171,6 +171,7 @@ hostprogs-$(CONFIG_MX28) += mxsboot
>  HOSTCFLAGS_mxsboot.o := -pedantic
>  
>  hostprogs-$(CONFIG_ARCH_SUNXI) += mksunxiboot
> +hostprogs-$(CONFIG_ARCH_SUNXI) += sunxi-spl-image-builder
>  
>  hostprogs-$(CONFIG_NETCONSOLE) += ncb
>  hostprogs-$(CONFIG_SHA1_CHECK_UB_IMG) += ubsha1
> diff --git a/tools/sunxi-spl-image-builder.c b/tools/sunxi-spl-image-builder.c
> new file mode 100644
> index 000000000000..0f915eb2bdf5
> --- /dev/null
> +++ b/tools/sunxi-spl-image-builder.c
> @@ -0,0 +1,1113 @@
> +/*
> + * Generic binary BCH encoding/decoding library
> + *
> + * This program is free software; you can redistribute it and/or modify it
> + * under the terms of the GNU General Public License version 2 as published by
> + * the Free Software Foundation.
> + *
> + * This program is distributed in the hope that it will be useful, but WITHOUT
> + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
> + * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
> + * more details.
> + *
> + * You should have received a copy of the GNU General Public License along with
> + * this program; if not, write to the Free Software Foundation, Inc., 51
> + * Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
> + *
> + * For the BCH implementation:
> + *
> + * Copyright ? 2011 Parrot S.A.
> + *
> + * Author: Ivan Djelic <ivan.djelic@parrot.com>
> + *
> + * See also:
> + * http://lxr.free-electrons.com/source/lib/bch.c
> + *
> + * For the randomizer and image builder implementation:
> + *
> + * Copyright ? 2016 NextThing Co.
> + * Copyright ? 2016 Free Electrons
> + *
> + * Author: Boris Brezillon <boris.brezillon@free-electrons.com>
> + *
> + */
> +
> +#include <stdint.h>
> +#include <stdlib.h>
> +#include <string.h>
> +#include <stdio.h>
> +#include <linux/kernel.h>
> +#include <linux/errno.h>
> +#include <asm/byteorder.h>
> +#include <endian.h>
> +#include <getopt.h>
> +#include <version.h>
> +
> +#if defined(CONFIG_BCH_CONST_PARAMS)
> +#define GF_M(_p)               (CONFIG_BCH_CONST_M)
> +#define GF_T(_p)               (CONFIG_BCH_CONST_T)
> +#define GF_N(_p)               ((1 << (CONFIG_BCH_CONST_M))-1)
> +#else
> +#define GF_M(_p)               ((_p)->m)
> +#define GF_T(_p)               ((_p)->t)
> +#define GF_N(_p)               ((_p)->n)
> +#endif
> +
> +#define DIV_ROUND_UP(n,d) (((n) + (d) - 1) / (d))
> +
> +#define BCH_ECC_WORDS(_p)      DIV_ROUND_UP(GF_M(_p)*GF_T(_p), 32)
> +#define BCH_ECC_BYTES(_p)      DIV_ROUND_UP(GF_M(_p)*GF_T(_p), 8)
> +
> +#ifndef dbg
> +#define dbg(_fmt, args...)     do {} while (0)
> +#endif
> +
> +#define cpu_to_be32 htobe32
> +#define kfree free
> +#define ARRAY_SIZE(arr) (sizeof(arr) / sizeof((arr)[0]))
> +
> +#define BCH_PRIMITIVE_POLY	0x5803
> +
> +struct image_info {
> +	int ecc_strength;
> +	int ecc_step_size;
> +	int page_size;
> +	int oob_size;
> +	int usable_page_size;
> +	int eraseblock_size;
> +	int scramble;
> +	int boot0;
> +	off_t offset;
> +	const char *source;
> +	const char *dest;
> +};
> +
> +/**
> + * struct bch_control - BCH control structure
> + * @m:          Galois field order
> + * @n:          maximum codeword size in bits (= 2^m-1)
> + * @t:          error correction capability in bits
> + * @ecc_bits:   ecc exact size in bits, i.e. generator polynomial degree (<=m*t)
> + * @ecc_bytes:  ecc max size (m*t bits) in bytes
> + * @a_pow_tab:  Galois field GF(2^m) exponentiation lookup table
> + * @a_log_tab:  Galois field GF(2^m) log lookup table
> + * @mod8_tab:   remainder generator polynomial lookup tables
> + * @ecc_buf:    ecc parity words buffer
> + * @ecc_buf2:   ecc parity words buffer
> + * @xi_tab:     GF(2^m) base for solving degree 2 polynomial roots
> + * @syn:        syndrome buffer
> + * @cache:      log-based polynomial representation buffer
> + * @elp:        error locator polynomial
> + * @poly_2t:    temporary polynomials of degree 2t
> + */
> +struct bch_control {
> +	unsigned int    m;
> +	unsigned int    n;
> +	unsigned int    t;
> +	unsigned int    ecc_bits;
> +	unsigned int    ecc_bytes;
> +/* private: */
> +	uint16_t       *a_pow_tab;
> +	uint16_t       *a_log_tab;
> +	uint32_t       *mod8_tab;
> +	uint32_t       *ecc_buf;
> +	uint32_t       *ecc_buf2;
> +	unsigned int   *xi_tab;
> +	unsigned int   *syn;
> +	int            *cache;
> +	struct gf_poly *elp;
> +	struct gf_poly *poly_2t[4];
> +};
> +
> +static int fls(int x)
> +{
> +	int r = 32;
> +
> +	if (!x)
> +		return 0;
> +	if (!(x & 0xffff0000u)) {
> +		x <<= 16;
> +		r -= 16;
> +	}
> +	if (!(x & 0xff000000u)) {
> +		x <<= 8;
> +		r -= 8;
> +	}
> +	if (!(x & 0xf0000000u)) {
> +		x <<= 4;
> +		r -= 4;
> +	}
> +	if (!(x & 0xc0000000u)) {
> +		x <<= 2;
> +		r -= 2;
> +	}
> +	if (!(x & 0x80000000u)) {
> +		x <<= 1;
> +		r -= 1;
> +	}
> +	return r;
> +}
> +
> +/*
> + * represent a polynomial over GF(2^m)
> + */
> +struct gf_poly {
> +	unsigned int deg;    /* polynomial degree */
> +	unsigned int c[0];   /* polynomial terms */
> +};
> +
> +/* given its degree, compute a polynomial size in bytes */
> +#define GF_POLY_SZ(_d) (sizeof(struct gf_poly)+((_d)+1)*sizeof(unsigned int))
> +
> +/* polynomial of degree 1 */
> +struct gf_poly_deg1 {
> +	struct gf_poly poly;
> +	unsigned int   c[2];
> +};
> +
> +/*
> + * same as encode_bch(), but process input data one byte at a time
> + */
> +static void encode_bch_unaligned(struct bch_control *bch,
> +				 const unsigned char *data, unsigned int len,
> +				 uint32_t *ecc)
> +{
> +	int i;
> +	const uint32_t *p;
> +	const int l = BCH_ECC_WORDS(bch)-1;
> +
> +	while (len--) {
> +		p = bch->mod8_tab + (l+1)*(((ecc[0] >> 24)^(*data++)) & 0xff);
> +
> +		for (i = 0; i < l; i++)
> +			ecc[i] = ((ecc[i] << 8)|(ecc[i+1] >> 24))^(*p++);
> +
> +		ecc[l] = (ecc[l] << 8)^(*p);
> +	}
> +}
> +
> +/*
> + * convert ecc bytes to aligned, zero-padded 32-bit ecc words
> + */
> +static void load_ecc8(struct bch_control *bch, uint32_t *dst,
> +		      const uint8_t *src)
> +{
> +	uint8_t pad[4] = {0, 0, 0, 0};
> +	unsigned int i, nwords = BCH_ECC_WORDS(bch)-1;
> +
> +	for (i = 0; i < nwords; i++, src += 4)
> +		dst[i] = (src[0] << 24)|(src[1] << 16)|(src[2] << 8)|src[3];
> +
> +	memcpy(pad, src, BCH_ECC_BYTES(bch)-4*nwords);
> +	dst[nwords] = (pad[0] << 24)|(pad[1] << 16)|(pad[2] << 8)|pad[3];
> +}
> +
> +/*
> + * convert 32-bit ecc words to ecc bytes
> + */
> +static void store_ecc8(struct bch_control *bch, uint8_t *dst,
> +		       const uint32_t *src)
> +{
> +	uint8_t pad[4];
> +	unsigned int i, nwords = BCH_ECC_WORDS(bch)-1;
> +
> +	for (i = 0; i < nwords; i++) {
> +		*dst++ = (src[i] >> 24);
> +		*dst++ = (src[i] >> 16) & 0xff;
> +		*dst++ = (src[i] >>  8) & 0xff;
> +		*dst++ = (src[i] >>  0) & 0xff;
> +	}
> +	pad[0] = (src[nwords] >> 24);
> +	pad[1] = (src[nwords] >> 16) & 0xff;
> +	pad[2] = (src[nwords] >>  8) & 0xff;
> +	pad[3] = (src[nwords] >>  0) & 0xff;
> +	memcpy(dst, pad, BCH_ECC_BYTES(bch)-4*nwords);
> +}
> +
> +/**
> + * encode_bch - calculate BCH ecc parity of data
> + * @bch:   BCH control structure
> + * @data:  data to encode
> + * @len:   data length in bytes
> + * @ecc:   ecc parity data, must be initialized by caller
> + *
> + * The @ecc parity array is used both as input and output parameter, in order to
> + * allow incremental computations. It should be of the size indicated by member
> + * @ecc_bytes of @bch, and should be initialized to 0 before the first call.
> + *
> + * The exact number of computed ecc parity bits is given by member @ecc_bits of
> + * @bch; it may be less than m*t for large values of t.
> + */
> +static void encode_bch(struct bch_control *bch, const uint8_t *data,
> +		unsigned int len, uint8_t *ecc)
> +{
> +	const unsigned int l = BCH_ECC_WORDS(bch)-1;
> +	unsigned int i, mlen;
> +	unsigned long m;
> +	uint32_t w, r[l+1];
> +	const uint32_t * const tab0 = bch->mod8_tab;
> +	const uint32_t * const tab1 = tab0 + 256*(l+1);
> +	const uint32_t * const tab2 = tab1 + 256*(l+1);
> +	const uint32_t * const tab3 = tab2 + 256*(l+1);
> +	const uint32_t *pdata, *p0, *p1, *p2, *p3;
> +
> +	if (ecc) {
> +		/* load ecc parity bytes into internal 32-bit buffer */
> +		load_ecc8(bch, bch->ecc_buf, ecc);
> +	} else {
> +		memset(bch->ecc_buf, 0, sizeof(r));
> +	}
> +
> +	/* process first unaligned data bytes */
> +	m = ((uintptr_t)data) & 3;
> +	if (m) {
> +		mlen = (len < (4-m)) ? len : 4-m;
> +		encode_bch_unaligned(bch, data, mlen, bch->ecc_buf);
> +		data += mlen;
> +		len  -= mlen;
> +	}
> +
> +	/* process 32-bit aligned data words */
> +	pdata = (uint32_t *)data;
> +	mlen  = len/4;
> +	data += 4*mlen;
> +	len  -= 4*mlen;
> +	memcpy(r, bch->ecc_buf, sizeof(r));
> +
> +	/*
> +	 * split each 32-bit word into 4 polynomials of weight 8 as follows:
> +	 *
> +	 * 31 ...24  23 ...16  15 ... 8  7 ... 0
> +	 * xxxxxxxx  yyyyyyyy  zzzzzzzz  tttttttt
> +	 *                               tttttttt  mod g = r0 (precomputed)
> +	 *                     zzzzzzzz  00000000  mod g = r1 (precomputed)
> +	 *           yyyyyyyy  00000000  00000000  mod g = r2 (precomputed)
> +	 * xxxxxxxx  00000000  00000000  00000000  mod g = r3 (precomputed)
> +	 * xxxxxxxx  yyyyyyyy  zzzzzzzz  tttttttt  mod g = r0^r1^r2^r3
> +	 */
> +	while (mlen--) {
> +		/* input data is read in big-endian format */
> +		w = r[0]^cpu_to_be32(*pdata++);
> +		p0 = tab0 + (l+1)*((w >>  0) & 0xff);
> +		p1 = tab1 + (l+1)*((w >>  8) & 0xff);
> +		p2 = tab2 + (l+1)*((w >> 16) & 0xff);
> +		p3 = tab3 + (l+1)*((w >> 24) & 0xff);
> +
> +		for (i = 0; i < l; i++)
> +			r[i] = r[i+1]^p0[i]^p1[i]^p2[i]^p3[i];
> +
> +		r[l] = p0[l]^p1[l]^p2[l]^p3[l];
> +	}
> +	memcpy(bch->ecc_buf, r, sizeof(r));
> +
> +	/* process last unaligned bytes */
> +	if (len)
> +		encode_bch_unaligned(bch, data, len, bch->ecc_buf);
> +
> +	/* store ecc parity bytes into original parity buffer */
> +	if (ecc)
> +		store_ecc8(bch, ecc, bch->ecc_buf);
> +}
> +
> +static inline int modulo(struct bch_control *bch, unsigned int v)
> +{
> +	const unsigned int n = GF_N(bch);
> +	while (v >= n) {
> +		v -= n;
> +		v = (v & n) + (v >> GF_M(bch));
> +	}
> +	return v;
> +}
> +
> +/*
> + * shorter and faster modulo function, only works when v < 2N.
> + */
> +static inline int mod_s(struct bch_control *bch, unsigned int v)
> +{
> +	const unsigned int n = GF_N(bch);
> +	return (v < n) ? v : v-n;
> +}
> +
> +static inline int deg(unsigned int poly)
> +{
> +	/* polynomial degree is the most-significant bit index */
> +	return fls(poly)-1;
> +}
> +
> +/* Galois field basic operations: multiply, divide, inverse, etc. */
> +
> +static inline unsigned int gf_mul(struct bch_control *bch, unsigned int a,
> +				  unsigned int b)
> +{
> +	return (a && b) ? bch->a_pow_tab[mod_s(bch, bch->a_log_tab[a]+
> +					       bch->a_log_tab[b])] : 0;
> +}
> +
> +static inline unsigned int gf_sqr(struct bch_control *bch, unsigned int a)
> +{
> +	return a ? bch->a_pow_tab[mod_s(bch, 2*bch->a_log_tab[a])] : 0;
> +}
> +
> +static inline unsigned int a_pow(struct bch_control *bch, int i)
> +{
> +	return bch->a_pow_tab[modulo(bch, i)];
> +}
> +
> +static inline int a_log(struct bch_control *bch, unsigned int x)
> +{
> +	return bch->a_log_tab[x];
> +}
> +
> +/*
> + * generate Galois field lookup tables
> + */
> +static int build_gf_tables(struct bch_control *bch, unsigned int poly)
> +{
> +	unsigned int i, x = 1;
> +	const unsigned int k = 1 << deg(poly);
> +
> +	/* primitive polynomial must be of degree m */
> +	if (k != (1u << GF_M(bch)))
> +		return -1;
> +
> +	for (i = 0; i < GF_N(bch); i++) {
> +		bch->a_pow_tab[i] = x;
> +		bch->a_log_tab[x] = i;
> +		if (i && (x == 1))
> +			/* polynomial is not primitive (a^i=1 with 0<i<2^m-1) */
> +			return -1;
> +		x <<= 1;
> +		if (x & k)
> +			x ^= poly;
> +	}
> +	bch->a_pow_tab[GF_N(bch)] = 1;
> +	bch->a_log_tab[0] = 0;
> +
> +	return 0;
> +}
> +
> +/*
> + * compute generator polynomial remainder tables for fast encoding
> + */
> +static void build_mod8_tables(struct bch_control *bch, const uint32_t *g)
> +{
> +	int i, j, b, d;
> +	uint32_t data, hi, lo, *tab;
> +	const int l = BCH_ECC_WORDS(bch);
> +	const int plen = DIV_ROUND_UP(bch->ecc_bits+1, 32);
> +	const int ecclen = DIV_ROUND_UP(bch->ecc_bits, 32);
> +
> +	memset(bch->mod8_tab, 0, 4*256*l*sizeof(*bch->mod8_tab));
> +
> +	for (i = 0; i < 256; i++) {
> +		/* p(X)=i is a small polynomial of weight <= 8 */
> +		for (b = 0; b < 4; b++) {
> +			/* we want to compute (p(X).X^(8*b+deg(g))) mod g(X) */
> +			tab = bch->mod8_tab + (b*256+i)*l;
> +			data = i << (8*b);
> +			while (data) {
> +				d = deg(data);
> +				/* subtract X^d.g(X) from p(X).X^(8*b+deg(g)) */
> +				data ^= g[0] >> (31-d);
> +				for (j = 0; j < ecclen; j++) {
> +					hi = (d < 31) ? g[j] << (d+1) : 0;
> +					lo = (j+1 < plen) ?
> +						g[j+1] >> (31-d) : 0;
> +					tab[j] ^= hi|lo;
> +				}
> +			}
> +		}
> +	}
> +}
> +
> +/*
> + * build a base for factoring degree 2 polynomials
> + */
> +static int build_deg2_base(struct bch_control *bch)
> +{
> +	const int m = GF_M(bch);
> +	int i, j, r;
> +	unsigned int sum, x, y, remaining, ak = 0, xi[m];
> +
> +	/* find k s.t. Tr(a^k) = 1 and 0 <= k < m */
> +	for (i = 0; i < m; i++) {
> +		for (j = 0, sum = 0; j < m; j++)
> +			sum ^= a_pow(bch, i*(1 << j));
> +
> +		if (sum) {
> +			ak = bch->a_pow_tab[i];
> +			break;
> +		}
> +	}
> +	/* find xi, i=0..m-1 such that xi^2+xi = a^i+Tr(a^i).a^k */
> +	remaining = m;
> +	memset(xi, 0, sizeof(xi));
> +
> +	for (x = 0; (x <= GF_N(bch)) && remaining; x++) {
> +		y = gf_sqr(bch, x)^x;
> +		for (i = 0; i < 2; i++) {
> +			r = a_log(bch, y);
> +			if (y && (r < m) && !xi[r]) {
> +				bch->xi_tab[r] = x;
> +				xi[r] = 1;
> +				remaining--;
> +				dbg("x%d = %x\n", r, x);
> +				break;
> +			}
> +			y ^= ak;
> +		}
> +	}
> +	/* should not happen but check anyway */
> +	return remaining ? -1 : 0;
> +}
> +
> +static void *bch_alloc(size_t size, int *err)
> +{
> +	void *ptr;
> +
> +	ptr = malloc(size);
> +	if (ptr == NULL)
> +		*err = 1;
> +	return ptr;
> +}
> +
> +/*
> + * compute generator polynomial for given (m,t) parameters.
> + */
> +static uint32_t *compute_generator_polynomial(struct bch_control *bch)
> +{
> +	const unsigned int m = GF_M(bch);
> +	const unsigned int t = GF_T(bch);
> +	int n, err = 0;
> +	unsigned int i, j, nbits, r, word, *roots;
> +	struct gf_poly *g;
> +	uint32_t *genpoly;
> +
> +	g = bch_alloc(GF_POLY_SZ(m*t), &err);
> +	roots = bch_alloc((bch->n+1)*sizeof(*roots), &err);
> +	genpoly = bch_alloc(DIV_ROUND_UP(m*t+1, 32)*sizeof(*genpoly), &err);
> +
> +	if (err) {
> +		kfree(genpoly);
> +		genpoly = NULL;
> +		goto finish;
> +	}
> +
> +	/* enumerate all roots of g(X) */
> +	memset(roots , 0, (bch->n+1)*sizeof(*roots));
> +	for (i = 0; i < t; i++) {
> +		for (j = 0, r = 2*i+1; j < m; j++) {
> +			roots[r] = 1;
> +			r = mod_s(bch, 2*r);
> +		}
> +	}
> +	/* build generator polynomial g(X) */
> +	g->deg = 0;
> +	g->c[0] = 1;
> +	for (i = 0; i < GF_N(bch); i++) {
> +		if (roots[i]) {
> +			/* multiply g(X) by (X+root) */
> +			r = bch->a_pow_tab[i];
> +			g->c[g->deg+1] = 1;
> +			for (j = g->deg; j > 0; j--)
> +				g->c[j] = gf_mul(bch, g->c[j], r)^g->c[j-1];
> +
> +			g->c[0] = gf_mul(bch, g->c[0], r);
> +			g->deg++;
> +		}
> +	}
> +	/* store left-justified binary representation of g(X) */
> +	n = g->deg+1;
> +	i = 0;
> +
> +	while (n > 0) {
> +		nbits = (n > 32) ? 32 : n;
> +		for (j = 0, word = 0; j < nbits; j++) {
> +			if (g->c[n-1-j])
> +				word |= 1u << (31-j);
> +		}
> +		genpoly[i++] = word;
> +		n -= nbits;
> +	}
> +	bch->ecc_bits = g->deg;
> +
> +finish:
> +	kfree(g);
> +	kfree(roots);
> +
> +	return genpoly;
> +}
> +
> +/**
> + *  free_bch - free the BCH control structure
> + *  @bch:    BCH control structure to release
> + */
> +static void free_bch(struct bch_control *bch)
> +{
> +	unsigned int i;
> +
> +	if (bch) {
> +		kfree(bch->a_pow_tab);
> +		kfree(bch->a_log_tab);
> +		kfree(bch->mod8_tab);
> +		kfree(bch->ecc_buf);
> +		kfree(bch->ecc_buf2);
> +		kfree(bch->xi_tab);
> +		kfree(bch->syn);
> +		kfree(bch->cache);
> +		kfree(bch->elp);
> +
> +		for (i = 0; i < ARRAY_SIZE(bch->poly_2t); i++)
> +			kfree(bch->poly_2t[i]);
> +
> +		kfree(bch);
> +	}
> +}
> +
> +/**
> + * init_bch - initialize a BCH encoder/decoder
> + * @m:          Galois field order, should be in the range 5-15
> + * @t:          maximum error correction capability, in bits
> + * @prim_poly:  user-provided primitive polynomial (or 0 to use default)
> + *
> + * Returns:
> + *  a newly allocated BCH control structure if successful, NULL otherwise
> + *
> + * This initialization can take some time, as lookup tables are built for fast
> + * encoding/decoding; make sure not to call this function from a time critical
> + * path. Usually, init_bch() should be called on module/driver init and
> + * free_bch() should be called to release memory on exit.
> + *
> + * You may provide your own primitive polynomial of degree @m in argument
> + * @prim_poly, or let init_bch() use its default polynomial.
> + *
> + * Once init_bch() has successfully returned a pointer to a newly allocated
> + * BCH control structure, ecc length in bytes is given by member @ecc_bytes of
> + * the structure.
> + */
> +static struct bch_control *init_bch(int m, int t, unsigned int prim_poly)
> +{
> +	int err = 0;
> +	unsigned int i, words;
> +	uint32_t *genpoly;
> +	struct bch_control *bch = NULL;
> +
> +	const int min_m = 5;
> +	const int max_m = 15;
> +
> +	/* default primitive polynomials */
> +	static const unsigned int prim_poly_tab[] = {
> +		0x25, 0x43, 0x83, 0x11d, 0x211, 0x409, 0x805, 0x1053, 0x201b,
> +		0x402b, 0x8003,
> +	};
> +
> +#if defined(CONFIG_BCH_CONST_PARAMS)
> +	if ((m != (CONFIG_BCH_CONST_M)) || (t != (CONFIG_BCH_CONST_T))) {
> +		printk(KERN_ERR "bch encoder/decoder was configured to support "
> +		       "parameters m=%d, t=%d only!\n",
> +		       CONFIG_BCH_CONST_M, CONFIG_BCH_CONST_T);
> +		goto fail;
> +	}
> +#endif
> +	if ((m < min_m) || (m > max_m))
> +		/*
> +		 * values of m greater than 15 are not currently supported;
> +		 * supporting m > 15 would require changing table base type
> +		 * (uint16_t) and a small patch in matrix transposition
> +		 */
> +		goto fail;
> +
> +	/* sanity checks */
> +	if ((t < 1) || (m*t >= ((1 << m)-1)))
> +		/* invalid t value */
> +		goto fail;
> +
> +	/* select a primitive polynomial for generating GF(2^m) */
> +	if (prim_poly == 0)
> +		prim_poly = prim_poly_tab[m-min_m];
> +
> +	bch = malloc(sizeof(*bch));
> +	if (bch == NULL)
> +		goto fail;
> +
> +	memset(bch, 0, sizeof(*bch));
> +
> +	bch->m = m;
> +	bch->t = t;
> +	bch->n = (1 << m)-1;
> +	words  = DIV_ROUND_UP(m*t, 32);
> +	bch->ecc_bytes = DIV_ROUND_UP(m*t, 8);
> +	bch->a_pow_tab = bch_alloc((1+bch->n)*sizeof(*bch->a_pow_tab), &err);
> +	bch->a_log_tab = bch_alloc((1+bch->n)*sizeof(*bch->a_log_tab), &err);
> +	bch->mod8_tab  = bch_alloc(words*1024*sizeof(*bch->mod8_tab), &err);
> +	bch->ecc_buf   = bch_alloc(words*sizeof(*bch->ecc_buf), &err);
> +	bch->ecc_buf2  = bch_alloc(words*sizeof(*bch->ecc_buf2), &err);
> +	bch->xi_tab    = bch_alloc(m*sizeof(*bch->xi_tab), &err);
> +	bch->syn       = bch_alloc(2*t*sizeof(*bch->syn), &err);
> +	bch->cache     = bch_alloc(2*t*sizeof(*bch->cache), &err);
> +	bch->elp       = bch_alloc((t+1)*sizeof(struct gf_poly_deg1), &err);
> +
> +	for (i = 0; i < ARRAY_SIZE(bch->poly_2t); i++)
> +		bch->poly_2t[i] = bch_alloc(GF_POLY_SZ(2*t), &err);
> +
> +	if (err)
> +		goto fail;
> +
> +	err = build_gf_tables(bch, prim_poly);
> +	if (err)
> +		goto fail;
> +
> +	/* use generator polynomial for computing encoding tables */
> +	genpoly = compute_generator_polynomial(bch);
> +	if (genpoly == NULL)
> +		goto fail;
> +
> +	build_mod8_tables(bch, genpoly);
> +	kfree(genpoly);
> +
> +	err = build_deg2_base(bch);
> +	if (err)
> +		goto fail;
> +
> +	return bch;
> +
> +fail:
> +	free_bch(bch);
> +	return NULL;
> +}
> +
> +static void swap_bits(uint8_t *buf, int len)
> +{
> +	int i, j;
> +
> +	for (j = 0; j < len; j++) {
> +		uint8_t byte = buf[j];
> +
> +		buf[j] = 0;
> +		for (i = 0; i < 8; i++) {
> +			if (byte & (1 << i))
> +				buf[j] |= (1 << (7 - i));
> +		}
> +	}
> +}
> +
> +static uint16_t lfsr_step(uint16_t state, int count)
> +{
> +	state &= 0x7fff;
> +	while (count--)
> +		state = ((state >> 1) |
> +			 ((((state >> 0) ^ (state >> 1)) & 1) << 14)) & 0x7fff;
> +
> +	return state;
> +}
> +
> +static uint16_t default_scrambler_seeds[] = {
> +	0x2b75, 0x0bd0, 0x5ca3, 0x62d1, 0x1c93, 0x07e9, 0x2162, 0x3a72,
> +	0x0d67, 0x67f9, 0x1be7, 0x077d, 0x032f, 0x0dac, 0x2716, 0x2436,
> +	0x7922, 0x1510, 0x3860, 0x5287, 0x480f, 0x4252, 0x1789, 0x5a2d,
> +	0x2a49, 0x5e10, 0x437f, 0x4b4e, 0x2f45, 0x216e, 0x5cb7, 0x7130,
> +	0x2a3f, 0x60e4, 0x4dc9, 0x0ef0, 0x0f52, 0x1bb9, 0x6211, 0x7a56,
> +	0x226d, 0x4ea7, 0x6f36, 0x3692, 0x38bf, 0x0c62, 0x05eb, 0x4c55,
> +	0x60f4, 0x728c, 0x3b6f, 0x2037, 0x7f69, 0x0936, 0x651a, 0x4ceb,
> +	0x6218, 0x79f3, 0x383f, 0x18d9, 0x4f05, 0x5c82, 0x2912, 0x6f17,
> +	0x6856, 0x5938, 0x1007, 0x61ab, 0x3e7f, 0x57c2, 0x542f, 0x4f62,
> +	0x7454, 0x2eac, 0x7739, 0x42d4, 0x2f90, 0x435a, 0x2e52, 0x2064,
> +	0x637c, 0x66ad, 0x2c90, 0x0bad, 0x759c, 0x0029, 0x0986, 0x7126,
> +	0x1ca7, 0x1605, 0x386a, 0x27f5, 0x1380, 0x6d75, 0x24c3, 0x0f8e,
> +	0x2b7a, 0x1418, 0x1fd1, 0x7dc1, 0x2d8e, 0x43af, 0x2267, 0x7da3,
> +	0x4e3d, 0x1338, 0x50db, 0x454d, 0x764d, 0x40a3, 0x42e6, 0x262b,
> +	0x2d2e, 0x1aea, 0x2e17, 0x173d, 0x3a6e, 0x71bf, 0x25f9, 0x0a5d,
> +	0x7c57, 0x0fbe, 0x46ce, 0x4939, 0x6b17, 0x37bb, 0x3e91, 0x76db,
> +};
> +
> +static uint16_t brom_scrambler_seeds[] = { 0x4a80 };
> +
> +static void scramble(const struct image_info *info,
> +		     int page, uint8_t *data, int datalen)
> +{
> +	uint16_t state;
> +	int i;
> +
> +	/* Boot0 is always scrambled no matter the command line option. */
> +	if (info->boot0) {
> +		state = brom_scrambler_seeds[0];
> +	} else {
> +		unsigned seedmod = info->eraseblock_size / info->page_size;
> +
> +		/* Bail out earlier if the user didn't ask for scrambling. */
> +		if (!info->scramble)
> +			return;
> +
> +		if (seedmod > ARRAY_SIZE(default_scrambler_seeds))
> +			seedmod = ARRAY_SIZE(default_scrambler_seeds);
> +
> +		state = default_scrambler_seeds[page % seedmod];
> +	}
> +
> +	/* Prepare the initial state... */
> +	state = lfsr_step(state, 15);
> +
> +	/* and start scrambling data. */
> +	for (i = 0; i < datalen; i++) {
> +		data[i] ^= state;
> +		state = lfsr_step(state, 8);
> +	}
> +}
> +
> +static int write_page(const struct image_info *info, uint8_t *buffer,
> +		      FILE *src, FILE *rnd, FILE *dst,
> +		      struct bch_control *bch, int page)
> +{
> +	int steps = info->usable_page_size / info->ecc_step_size;
> +	int eccbytes = DIV_ROUND_UP(info->ecc_strength * 14, 8);
> +	off_t pos = ftell(dst);
> +	size_t pad, cnt;
> +	int i;
> +
> +	if (eccbytes % 2)
> +		eccbytes++;
> +
> +	memset(buffer, 0xff, info->page_size + info->oob_size);
> +	cnt = fread(buffer, 1, info->usable_page_size, src);
> +	if (!cnt) {
> +		if (!feof(src)) {
> +			fprintf(stderr,
> +				"Failed to read data from the source\n");
> +			return -1;
> +		} else {
> +			return 0;
> +		}
> +	}
> +
> +	fwrite(buffer, info->page_size + info->oob_size, 1, dst);
> +
> +	for (i = 0; i < info->usable_page_size; i++) {
> +		if (buffer[i] !=  0xff)
> +			break;
> +	}
> +
> +	/* We leave empty pages at 0xff. */
> +	if (i == info->usable_page_size)
> +		return 0;
> +
> +	/* Restore the source pointer to read it again. */
> +	fseek(src, -cnt, SEEK_CUR);
> +
> +	/* Randomize unused space if scrambling is required. */
> +	if (info->scramble) {
> +		int offs;
> +
> +		if (info->boot0) {
> +			offs = steps * (info->ecc_step_size + eccbytes + 4);
> +			cnt = info->page_size + info->oob_size - offs;
> +			fread(buffer + offs, 1, cnt, rnd);
> +		} else {
> +			offs = info->page_size + (steps * (eccbytes + 4));
> +			cnt = info->page_size + info->oob_size - offs;
> +			memset(buffer + offs, 0xff, cnt);
> +			scramble(info, page, buffer + offs, cnt);
> +		}
> +		fseek(dst, pos + offs, SEEK_SET);
> +		fwrite(buffer + offs, cnt, 1, dst);
> +	}
> +
> +	for (i = 0; i < steps; i++) {
> +		int ecc_offs, data_offs;
> +		uint8_t *ecc;
> +
> +		memset(buffer, 0xff, info->ecc_step_size + eccbytes + 4);
> +		ecc = buffer + info->ecc_step_size + 4;
> +		if (info->boot0) {
> +			data_offs = i * (info->ecc_step_size + eccbytes + 4);
> +			ecc_offs = data_offs + info->ecc_step_size + 4;
> +		} else {
> +			data_offs = i * info->ecc_step_size;
> +			ecc_offs = info->page_size + 4 + (i * (eccbytes + 4));
> +		}
> +
> +		cnt = fread(buffer, 1, info->ecc_step_size, src);
> +		if (!cnt && !feof(src)) {
> +			fprintf(stderr,
> +				"Failed to read data from the source\n");
> +			return -1;
> +		}
> +
> +		pad = info->ecc_step_size - cnt;
> +		if (pad) {
> +			if (info->scramble && info->boot0)
> +				fread(buffer + cnt, 1, pad, rnd);
> +			else
> +				memset(buffer + cnt, 0xff, pad);
> +		}
> +
> +		memset(ecc, 0, eccbytes);
> +		swap_bits(buffer, info->ecc_step_size + 4);
> +		encode_bch(bch, buffer, info->ecc_step_size + 4, ecc);
> +		swap_bits(buffer, info->ecc_step_size + 4);
> +		swap_bits(ecc, eccbytes);
> +		scramble(info, page, buffer, info->ecc_step_size + 4 + eccbytes);
> +
> +		fseek(dst, pos + data_offs, SEEK_SET);
> +		fwrite(buffer, info->ecc_step_size, 1, dst);
> +		fseek(dst, pos + ecc_offs - 4, SEEK_SET);
> +		fwrite(ecc - 4, eccbytes + 4, 1, dst);
> +	}
> +
> +	/* Fix BBM. */
> +	fseek(dst, pos + info->page_size, SEEK_SET);
> +	memset(buffer, 0xff, 2);
> +	fwrite(buffer, 2, 1, dst);
> +
> +	/* Make dst pointer point to the next page. */
> +	fseek(dst, pos + info->page_size + info->oob_size, SEEK_SET);
> +
> +	return 0;
> +}
> +
> +static int create_image(const struct image_info *info)
> +{
> +	off_t page = info->offset / info->page_size;
> +	struct bch_control *bch;
> +	FILE *src, *dst, *rnd;
> +	uint8_t *buffer;
> +
> +	bch = init_bch(14, info->ecc_strength, BCH_PRIMITIVE_POLY);
> +	if (!bch) {
> +		fprintf(stderr, "Failed to init the BCH engine\n");
> +		return -1;
> +	}
> +
> +	buffer = malloc(info->page_size + info->oob_size);
> +	if (!buffer) {
> +		fprintf(stderr, "Failed to allocate the NAND page buffer\n");
> +		return -1;
> +	}
> +
> +	memset(buffer, 0xff, info->page_size + info->oob_size);
> +
> +	src = fopen(info->source, "r");
> +	if (!src) {
> +		fprintf(stderr, "Failed to open source file (%s)\n",
> +			info->source);
> +		return -1;
> +	}
> +
> +	dst = fopen(info->dest, "w");
> +	if (!dst) {
> +		fprintf(stderr, "Failed to open dest file (%s)\n", info->dest);
> +		return -1;
> +	}
> +
> +	rnd = fopen("/dev/urandom", "r");
> +	if (!rnd) {
> +		fprintf(stderr, "Failed to open /dev/urandom\n");
> +		return -1;
> +	}
> +
> +	while (!feof(src)) {
> +		int ret;
> +
> +		ret = write_page(info, buffer, src, rnd, dst, bch, page++);
> +		if (ret)
> +			return ret;
> +	}
> +
> +	return 0;
> +}
> +
> +static void display_help(int status)
> +{
> +	fprintf(status == EXIT_SUCCESS ? stdout : stderr,
> +		"sunxi-nand-image-builder %s\n"
> +		"\n"
> +		"Usage: sunxi-nand-image-builder [OPTIONS] source-image output-image\n"
> +		"\n"
> +		"Creates a raw NAND image that can be read by the sunxi NAND controller.\n"
> +		"\n"
> +		"-h               --help               Display this help and exit\n"
> +		"-c <str>/<step>  --ecc=<str>/<step>   ECC config (strength/step-size)\n"
> +		"-p <size>        --page=<size>        Page size\n"
> +		"-o <size>        --oob=<size>         OOB size\n"
> +		"-u <size>        --usable=<size>      Usable page size\n"
> +		"-e <size>        --eraseblock=<size>  Erase block size\n"
> +		"-b               --boot0              Build a boot0 image.\n"
> +		"-s               --scramble           Scramble data\n"
> +		"-a <offset>      --address=<offset>   Where the image will be programmed.\n"
> +		"\n"
> +		"Notes:\n"
> +		"All the information you need to pass to this tool should be part of\n"
> +		"the NAND datasheet.\n"
> +		"\n"
> +		"The NAND controller only supports the following ECC configs\n"
> +		"  Valid ECC strengths: 16, 24, 28, 32, 40, 48, 56, 60 and 64\n"
> +		"  Valid ECC step size: 512 and 1024\n"
> +		"\n"
> +		"If you are building a boot0 image, you'll have specify extra options.\n"
> +		"These options should be chosen based on the layouts described here:\n"
> +		"  http://linux-sunxi.org/NAND#More_information_on_BROM_NAND\n"
> +		"\n"
> +		"  --usable should be assigned the 'Hardware page' value\n"
> +		"  --ecc should be assigned the 'ECC capacity'/'ECC page' values\n"
> +		"  --usable should be smaller than --page\n"
> +		"\n"
> +		"The --address option is only required for non-boot0 images that are \n"
> +		"meant to be programmed at a non eraseblock aligned offset.\n"
> +		"\n"
> +		"Examples:\n"
> +		"  The H27UCG8T2BTR-BC NAND exposes\n"
> +		"  * 16k pages\n"
> +		"  * 1280 OOB bytes per page\n"
> +		"  * 4M eraseblocks\n"
> +		"  * requires data scrambling\n"
> +		"  * expects a minimum ECC of 40bits/1024bytes\n"
> +		"\n"
> +		"  A normal image can be generated with\n"
> +		"    sunxi-nand-image-builder -p 16384 -o 1280 -e 0x400000 -s -c 40/1024\n"
> +		"  A boot0 image can be generated with\n"
> +		"    sunxi-nand-image-builder -p 16384 -o 1280 -e 0x400000 -s -b -u 4096 -c 64/1024\n",
> +		PLAIN_VERSION);
> +	exit(status);
> +}
> +
> +static int check_image_info(struct image_info *info)
> +{
> +	static int valid_ecc_strengths[] = { 16, 24, 28, 32, 40, 48, 56, 60, 64 };
> +	int eccbytes, eccsteps;
> +	unsigned i;
> +
> +	if (!info->page_size) {
> +		fprintf(stderr, "--page is missing\n");
> +		return -EINVAL;
> +	}
> +
> +	if (!info->page_size) {
> +		fprintf(stderr, "--oob is missing\n");
> +		return -EINVAL;
> +	}
> +
> +	if (!info->eraseblock_size) {
> +		fprintf(stderr, "--eraseblock is missing\n");
> +		return -EINVAL;
> +	}
> +
> +	if (info->ecc_step_size != 512 && info->ecc_step_size != 1024) {
> +		fprintf(stderr, "Invalid ECC step argument: %d\n",
> +			info->ecc_step_size);
> +		return -EINVAL;
> +	}
> +
> +	for (i = 0; i < ARRAY_SIZE(valid_ecc_strengths); i++) {
> +		if (valid_ecc_strengths[i] == info->ecc_strength)
> +			break;
> +	}
> +
> +	if (i == ARRAY_SIZE(valid_ecc_strengths)) {
> +		fprintf(stderr, "Invalid ECC strength argument: %d\n",
> +			info->ecc_strength);
> +		return -EINVAL;
> +	}
> +
> +	eccbytes = DIV_ROUND_UP(info->ecc_strength * 14, 8);
> +	if (eccbytes % 2)
> +		eccbytes++;
> +	eccbytes += 4;
> +
> +	eccsteps = info->usable_page_size / info->ecc_step_size;
> +
> +	if (info->page_size + info->oob_size <
> +	    info->usable_page_size + (eccsteps * eccbytes)) {
> +		fprintf(stderr,
> +			"ECC bytes do not fit in the NAND page, choose a weaker ECC\n");
> +		return -EINVAL;
> +	}
> +
> +	return 0;
> +}
> +
> +int main(int argc, char **argv)
> +{
> +	struct image_info info;
> +
> +	memset(&info, 0, sizeof(info));
> +	/*
> +	 * Process user arguments
> +	 */
> +	for (;;) {
> +		int option_index = 0;
> +		char *endptr = NULL;
> +		static const struct option long_options[] = {
> +			{"help", no_argument, 0, 'h'},
> +			{"ecc", required_argument, 0, 'c'},
> +			{"page", required_argument, 0, 'p'},
> +			{"oob", required_argument, 0, 'o'},
> +			{"usable", required_argument, 0, 'u'},
> +			{"eraseblock", required_argument, 0, 'e'},
> +			{"boot0", no_argument, 0, 'b'},
> +			{"scramble", no_argument, 0, 's'},
> +			{"address", required_argument, 0, 'a'},
> +			{0, 0, 0, 0},
> +		};
> +
> +		int c = getopt_long(argc, argv, "c:p:o:u:e:ba:sh",
> +				long_options, &option_index);
> +		if (c == EOF)
> +			break;
> +
> +		switch (c) {
> +		case 'h':
> +			display_help(0);
> +			break;
> +		case 's':
> +			info.scramble = 1;
> +			break;
> +		case 'c':
> +			info.ecc_strength = strtol(optarg, &endptr, 0);
> +			if (endptr || *endptr == '/')
> +				info.ecc_step_size = strtol(endptr + 1, NULL, 0);
> +			break;
> +		case 'p':
> +			info.page_size = strtol(optarg, NULL, 0);
> +			break;
> +		case 'o':
> +			info.oob_size = strtol(optarg, NULL, 0);
> +			break;
> +		case 'u':
> +			info.usable_page_size = strtol(optarg, NULL, 0);
> +			break;
> +		case 'e':
> +			info.eraseblock_size = strtol(optarg, NULL, 0);
> +			break;
> +		case 'b':
> +			info.boot0 = 1;
> +			break;
> +		case 'a':
> +			info.offset = strtoull(optarg, NULL, 0);
> +			break;
> +		case '?':
> +			display_help(-1);
> +			break;
> +		}
> +	}
> +
> +	if ((argc - optind) != 2)
> +		display_help(-1);
> +
> +	info.source = argv[optind];
> +	info.dest = argv[optind + 1];
> +
> +	if (!info.boot0) {
> +		info.usable_page_size = info.page_size;
> +	} else if (!info.usable_page_size) {
> +		if (info.page_size > 8192)
> +			info.usable_page_size = 8192;
> +		else if (info.page_size > 4096)
> +			info.usable_page_size = 4096;
> +		else
> +			info.usable_page_size = 1024;
> +	}
> +
> +	if (check_image_info(&info))
> +		display_help(-1);
> +
> +	return create_image(&info);
> +}

^ permalink raw reply	[flat|nested] 44+ messages in thread

* [U-Boot] [PATCH 5/7] nand: sunxi: Add options for the SPL NAND configuration
  2016-11-08 16:21 ` [U-Boot] [PATCH 5/7] nand: sunxi: Add options for the SPL NAND configuration Maxime Ripard
@ 2016-11-08 16:31   ` Boris Brezillon
  2016-11-14 11:19   ` Hans de Goede
  2016-11-15  5:07   ` Scott Wood
  2 siblings, 0 replies; 44+ messages in thread
From: Boris Brezillon @ 2016-11-08 16:31 UTC (permalink / raw)
  To: u-boot

On Tue,  8 Nov 2016 17:21:15 +0100
Maxime Ripard <maxime.ripard@free-electrons.com> wrote:

> The SPL image needs to be built with a different ECC configuration than the
> U-Boot binary.
> 
> Add Kconfig options with defaults to provide a value that should work for
> anyone, but is still configurable if needs be.
> 
> Signed-off-by: Maxime Ripard <maxime.ripard@free-electrons.com>

Acked-by: Boris Brezillon <boris.brezillon@free-electrons.com>

> ---
>  drivers/mtd/nand/Kconfig | 16 ++++++++++++++++
>  1 file changed, 16 insertions(+), 0 deletions(-)
> 
> diff --git a/drivers/mtd/nand/Kconfig b/drivers/mtd/nand/Kconfig
> index df154bfd32b9..a60abb625ee5 100644
> --- a/drivers/mtd/nand/Kconfig
> +++ b/drivers/mtd/nand/Kconfig
> @@ -73,6 +73,22 @@ config NAND_SUNXI
>  	The SPL driver only supports reading from the NAND using DMA
>  	transfers.
>  
> +if NAND_SUNXI
> +
> +config NAND_SUNXI_SPL_ECC_STRENGTH
> +	int "Allwinner NAND SPL ECC Strength"
> +	default 64
> +
> +config NAND_SUNXI_SPL_ECC_SIZE
> +	int "Allwinner NAND SPL ECC Step Size"
> +	default 1024
> +
> +config NAND_SUNXI_SPL_USABLE_PAGE_SIZE
> +	int "Allwinner NAND SPL Usable Page Size"
> +	default 1024
> +
> +endif
> +
>  config NAND_ARASAN
>  	bool "Configure Arasan Nand"
>  	help

^ permalink raw reply	[flat|nested] 44+ messages in thread

* [U-Boot] [PATCH 6/7] scripts: sunxi: Build an raw SPL image
  2016-11-08 16:21 ` [U-Boot] [PATCH 6/7] scripts: sunxi: Build an raw SPL image Maxime Ripard
@ 2016-11-08 16:33   ` Boris Brezillon
  2016-11-14 11:19   ` Hans de Goede
  1 sibling, 0 replies; 44+ messages in thread
From: Boris Brezillon @ 2016-11-08 16:33 UTC (permalink / raw)
  To: u-boot

On Tue,  8 Nov 2016 17:21:16 +0100
Maxime Ripard <maxime.ripard@free-electrons.com> wrote:

> Introduce a new sunxi-spl-with-ecc.bin image with already the right header,
> ECC, randomizer and padding for the BROM to be able to read it.
> 
> It needs to be flashed using a raw access to the NAND so that the
> controller doesn't change a thing to it, since we already have all the
> right parameters.
> 
> Signed-off-by: Maxime Ripard <maxime.ripard@free-electrons.com>

Acked-by: Boris Brezillon <boris.brezillon@free-electrons.com>

> ---
>  Makefile             |  3 +++
>  scripts/Makefile.spl | 12 ++++++++++++
>  2 files changed, 15 insertions(+), 0 deletions(-)
> 
> diff --git a/Makefile b/Makefile
> index 37cbcb28f75e..12a248e297b5 100644
> --- a/Makefile
> +++ b/Makefile
> @@ -1345,6 +1345,9 @@ spl/u-boot-spl: tools prepare \
>  spl/sunxi-spl.bin: spl/u-boot-spl
>  	@:
>  
> +spl/sunxi-spl-with-ecc.bin: spl/sunxi-spl.bin
> +	@:
> +
>  spl/u-boot-spl.sfp: spl/u-boot-spl
>  	@:
>  
> diff --git a/scripts/Makefile.spl b/scripts/Makefile.spl
> index e0b0117dc9b6..b41b4e427cc5 100644
> --- a/scripts/Makefile.spl
> +++ b/scripts/Makefile.spl
> @@ -168,6 +168,7 @@ endif
>  
>  ifdef CONFIG_ARCH_SUNXI
>  ALL-y	+= $(obj)/sunxi-spl.bin
> +ALL-y	+= $(obj)/sunxi-spl-with-ecc.bin
>  endif
>  
>  ifeq ($(CONFIG_SYS_SOC),"at91")
> @@ -276,6 +277,17 @@ cmd_mksunxiboot = $(objtree)/tools/mksunxiboot $< $@
>  $(obj)/sunxi-spl.bin: $(obj)/$(SPL_BIN).bin FORCE
>  	$(call if_changed,mksunxiboot)
>  
> +quiet_cmd_sunxi_spl_image_builder = SUNXI_SPL_IMAGE_BUILDER $@
> +cmd_sunxi_spl_image_builder = $(objtree)/tools/sunxi-spl-image-builder \
> +				-c $(CONFIG_NAND_SUNXI_SPL_ECC_STRENGTH)/$(CONFIG_NAND_SUNXI_SPL_ECC_SIZE) \
> +				-p $(CONFIG_SYS_NAND_PAGE_SIZE) \
> +				-o $(CONFIG_SYS_NAND_OOBSIZE) \
> +				-u $(CONFIG_NAND_SUNXI_SPL_USABLE_PAGE_SIZE) \
> +				-e $(CONFIG_SYS_NAND_BLOCK_SIZE) \
> +				-s -b $< $@
> +$(obj)/sunxi-spl-with-ecc.bin: $(obj)/sunxi-spl.bin
> +	$(call if_changed,sunxi_spl_image_builder)
> +
>  # Rule to link u-boot-spl
>  # May be overridden by arch/$(ARCH)/config.mk
>  quiet_cmd_u-boot-spl ?= LD      $@

^ permalink raw reply	[flat|nested] 44+ messages in thread

* [U-Boot] [PATCH 4/7] tools: sunxi: Add spl image builder
  2016-11-08 16:29   ` Boris Brezillon
@ 2016-11-08 20:45     ` Maxime Ripard
  0 siblings, 0 replies; 44+ messages in thread
From: Maxime Ripard @ 2016-11-08 20:45 UTC (permalink / raw)
  To: u-boot

On Tue, Nov 08, 2016 at 05:29:47PM +0100, Boris Brezillon wrote:
> On Tue,  8 Nov 2016 17:21:14 +0100
> Maxime Ripard <maxime.ripard@free-electrons.com> wrote:
> 
> > This program generates raw SPL images that can be flashed on the NAND with
> > the ECC and randomizer properly set up.
> > 
> 
> Maybe you should mention that this file has been copied from the
> sunxi-tools project.

Definitely, I've amended my commit log.

> Otherwise,
> 
> Acked-by: Boris Brezillon <boris.brezillon@free-electrons.com>

Thanks!
Maxime

-- 
Maxime Ripard, Free Electrons
Embedded Linux and Kernel engineering
http://free-electrons.com
-------------- next part --------------
A non-text attachment was scrubbed...
Name: signature.asc
Type: application/pgp-signature
Size: 801 bytes
Desc: not available
URL: <http://lists.denx.de/pipermail/u-boot/attachments/20161108/131f809c/attachment.sig>

^ permalink raw reply	[flat|nested] 44+ messages in thread

* [U-Boot] [PATCH 0/7] sunxi: Add support for the CHIP Pro
  2016-11-08 16:21 [U-Boot] [PATCH 0/7] sunxi: Add support for the CHIP Pro Maxime Ripard
                   ` (6 preceding siblings ...)
  2016-11-08 16:21 ` [U-Boot] [PATCH 7/7] sunxi: Add support for the CHIP Pro Maxime Ripard
@ 2016-11-09  7:47 ` Heiko Schocher
  2016-11-09 14:44   ` Maxime Ripard
  7 siblings, 1 reply; 44+ messages in thread
From: Heiko Schocher @ 2016-11-09  7:47 UTC (permalink / raw)
  To: u-boot

Hello Maxime,

Am 08.11.2016 um 17:21 schrieb Maxime Ripard:
> The CHIP Pro is a SoM made by NextThing Co, and that embeds a GR8 SIP, an
> AXP209 PMIC, a WiFi BT chip and a 512MB SLC NAND.
>
> Since the first Allwinner device coming whit an SLC NAND that doesn't have
> the shortcomings (and breakages) the MLC NAND has, we can finally enable
> the NAND support on a board by default.
>
> This is the occasion to introduce a bunch of additions needed imo to be
> able to come up with a sane NAND support for our users.
>
> The biggest pain point is that the BROM uses a different ECC and randomizer
> configuration than for the rest of the NAND. In order to lessen the number
> of bitflips, you also need to pad with random data the SPL image.
>
> Since it's quite tedious to do right (and most users won't be able to
> figure it out) and since if it is not done right, it will eventually turn
> into an unusable system (which is bad UX), we think that the best solution
> is to generate an SPL image that already embeds all this. We'll possible
> have to do the same thing for the U-Boot image (at least for the random
> padding) on MLC NANDs.
>
> The only drawback from that is that you need to flash it raw, instead of
> using the usual nand write, but it's just a different command, nothing
> major anyway.
>
> In order to flash it, from a device switched in FEL, on your host:
> sunxi-fel spl spl/sunxi-spl.bin
> sunxi-fel write 0x4a000000 u-boot-dtb.bin
> sunxi-fel write 0x43000000 spl/sunxi-spl-with-ecc.bin
> sunxi-fel exe 0x4a000000
>
> And on the board, once u-boot is running (assuming the NAND is already
> erased):
>
> nand write.raw.noverify 0x43000000 0 40
> nand write.raw.noverify 0x43000000 0x400000 40
>
> nand write 0x4a000000 0x800000 0xc0000
>
> I also encountered some weird bug in the private libgcc that prevents
> U-Boot from loading. Disabling CONFIG_USE_PRIVATE_LIBGCC fixes that.

What was the problem?

>
> Let me know what you think,
> Maxime
>
> Boris Brezillon (1):
>    mtd: nand: add support for the TC58NVG2S0H chip
>
> Hans de Goede (1):
>    sunxi: Enable UBI and NAND support
>
> Maxime Ripard (5):
>    sunxi: Sync GR8 DTS and AXP209 with the kernel
>    tools: sunxi: Add spl image builder
>    nand: sunxi: Add options for the SPL NAND configuration
>    scripts: sunxi: Build an raw SPL image
>    sunxi: Add support for the CHIP Pro
>
>   Makefile                          |    3 +-
>   arch/arm/dts/Makefile             |    1 +-
>   arch/arm/dts/axp209.dtsi          |    6 +-
>   arch/arm/dts/ntc-gr8-chip-pro.dts |  266 +++++++-
>   arch/arm/dts/ntc-gr8.dtsi         | 1132 ++++++++++++++++++++++++++++++-
>   configs/CHIP_pro_defconfig        |   27 +-
>   drivers/mtd/nand/Kconfig          |   16 +-
>   drivers/mtd/nand/nand_ids.c       |    3 +-
>   include/configs/sunxi-common.h    |   26 +-
>   scripts/Makefile.spl              |   12 +-
>   tools/.gitignore                  |    1 +-
>   tools/Makefile                    |    1 +-
>   tools/sunxi-spl-image-builder.c   | 1113 +++++++++++++++++++++++++++++-
>   13 files changed, 2603 insertions(+), 4 deletions(-)
>   create mode 100644 arch/arm/dts/ntc-gr8-chip-pro.dts
>   create mode 100644 arch/arm/dts/ntc-gr8.dtsi
>   create mode 100644 configs/CHIP_pro_defconfig
>   create mode 100644 tools/sunxi-spl-image-builder.c
>
> base-commit: d8bdfc80da39211d95f10d24e79f2e867305f71b

Can you please add a README file, where the above things are explained?

Thanks!

bye,
Heiko
-- 
DENX Software Engineering GmbH,      Managing Director: Wolfgang Denk
HRB 165235 Munich, Office: Kirchenstr.5, D-82194 Groebenzell, Germany

^ permalink raw reply	[flat|nested] 44+ messages in thread

* [U-Boot] [PATCH 3/7] sunxi: Enable UBI and NAND support
  2016-11-08 16:27   ` Boris Brezillon
@ 2016-11-09 14:32     ` Maxime Ripard
  2016-11-09 14:57       ` Boris Brezillon
  0 siblings, 1 reply; 44+ messages in thread
From: Maxime Ripard @ 2016-11-09 14:32 UTC (permalink / raw)
  To: u-boot

Hi Boris,

On Tue, Nov 08, 2016 at 05:27:48PM +0100, Boris Brezillon wrote:
> On Tue,  8 Nov 2016 17:21:13 +0100
> Maxime Ripard <maxime.ripard@free-electrons.com> wrote:
> 
> > From: Hans de Goede <hdegoede@redhat.com>
> > 
> > Enable the NAND and UBI support in the configuration header so that we can
> > (finally) use it.
> > 
> > Signed-off-by: Hans de Goede <hdegoede@redhat.com>
> > Signed-off-by: Maxime Ripard <maxime.ripard@free-electrons.com>
> > ---
> >  include/configs/sunxi-common.h | 26 ++++++++++++++++++++++----
> >  1 file changed, 22 insertions(+), 4 deletions(-)
> > 
> > diff --git a/include/configs/sunxi-common.h b/include/configs/sunxi-common.h
> > index 8363414828fa..1733767ba53b 100644
> > --- a/include/configs/sunxi-common.h
> > +++ b/include/configs/sunxi-common.h
> > @@ -129,9 +129,23 @@
> >  #define CONFIG_SERIAL_TAG
> >  
> >  #ifdef CONFIG_NAND_SUNXI
> > +#define CONFIG_SYS_NAND_U_BOOT_OFFS	(8 << 20) /* 8 MiB */
> 
> Can we make this configurable through Kconfig?

Is there a need for that? AFAIK, everyone in U-Boot defines it there
(and converting everyone to Kconfig for all the CONFIG_SYS_NAND
options is going to be painful).

Thanks!
Maxime

-- 
Maxime Ripard, Free Electrons
Embedded Linux and Kernel engineering
http://free-electrons.com
-------------- next part --------------
A non-text attachment was scrubbed...
Name: signature.asc
Type: application/pgp-signature
Size: 801 bytes
Desc: not available
URL: <http://lists.denx.de/pipermail/u-boot/attachments/20161109/145628d7/attachment.sig>

^ permalink raw reply	[flat|nested] 44+ messages in thread

* [U-Boot] [PATCH 0/7] sunxi: Add support for the CHIP Pro
  2016-11-09  7:47 ` [U-Boot] [PATCH 0/7] " Heiko Schocher
@ 2016-11-09 14:44   ` Maxime Ripard
  2016-11-10 11:57     ` Heiko Schocher
  0 siblings, 1 reply; 44+ messages in thread
From: Maxime Ripard @ 2016-11-09 14:44 UTC (permalink / raw)
  To: u-boot

Hi Heiko,

On Wed, Nov 09, 2016 at 08:47:12AM +0100, Heiko Schocher wrote:
> Am 08.11.2016 um 17:21 schrieb Maxime Ripard:
> > The CHIP Pro is a SoM made by NextThing Co, and that embeds a GR8 SIP, an
> > AXP209 PMIC, a WiFi BT chip and a 512MB SLC NAND.
> > 
> > Since the first Allwinner device coming whit an SLC NAND that doesn't have
> > the shortcomings (and breakages) the MLC NAND has, we can finally enable
> > the NAND support on a board by default.
> > 
> > This is the occasion to introduce a bunch of additions needed imo to be
> > able to come up with a sane NAND support for our users.
> > 
> > The biggest pain point is that the BROM uses a different ECC and randomizer
> > configuration than for the rest of the NAND. In order to lessen the number
> > of bitflips, you also need to pad with random data the SPL image.
> > 
> > Since it's quite tedious to do right (and most users won't be able to
> > figure it out) and since if it is not done right, it will eventually turn
> > into an unusable system (which is bad UX), we think that the best solution
> > is to generate an SPL image that already embeds all this. We'll possible
> > have to do the same thing for the U-Boot image (at least for the random
> > padding) on MLC NANDs.
> > 
> > The only drawback from that is that you need to flash it raw, instead of
> > using the usual nand write, but it's just a different command, nothing
> > major anyway.
> > 
> > In order to flash it, from a device switched in FEL, on your host:
> > sunxi-fel spl spl/sunxi-spl.bin
> > sunxi-fel write 0x4a000000 u-boot-dtb.bin
> > sunxi-fel write 0x43000000 spl/sunxi-spl-with-ecc.bin
> > sunxi-fel exe 0x4a000000
> > 
> > And on the board, once u-boot is running (assuming the NAND is already
> > erased):
> > 
> > nand write.raw.noverify 0x43000000 0 40
> > nand write.raw.noverify 0x43000000 0x400000 40
> > 
> > nand write 0x4a000000 0x800000 0xc0000
> > 
> > I also encountered some weird bug in the private libgcc that prevents
> > U-Boot from loading. Disabling CONFIG_USE_PRIVATE_LIBGCC fixes that.
> 
> What was the problem?

It has been reported here:
http://lists.denx.de/pipermail/u-boot/2016-August/264513.html

> > 
> > Let me know what you think,
> > Maxime
> > 
> > Boris Brezillon (1):
> >    mtd: nand: add support for the TC58NVG2S0H chip
> > 
> > Hans de Goede (1):
> >    sunxi: Enable UBI and NAND support
> > 
> > Maxime Ripard (5):
> >    sunxi: Sync GR8 DTS and AXP209 with the kernel
> >    tools: sunxi: Add spl image builder
> >    nand: sunxi: Add options for the SPL NAND configuration
> >    scripts: sunxi: Build an raw SPL image
> >    sunxi: Add support for the CHIP Pro
> > 
> >   Makefile                          |    3 +-
> >   arch/arm/dts/Makefile             |    1 +-
> >   arch/arm/dts/axp209.dtsi          |    6 +-
> >   arch/arm/dts/ntc-gr8-chip-pro.dts |  266 +++++++-
> >   arch/arm/dts/ntc-gr8.dtsi         | 1132 ++++++++++++++++++++++++++++++-
> >   configs/CHIP_pro_defconfig        |   27 +-
> >   drivers/mtd/nand/Kconfig          |   16 +-
> >   drivers/mtd/nand/nand_ids.c       |    3 +-
> >   include/configs/sunxi-common.h    |   26 +-
> >   scripts/Makefile.spl              |   12 +-
> >   tools/.gitignore                  |    1 +-
> >   tools/Makefile                    |    1 +-
> >   tools/sunxi-spl-image-builder.c   | 1113 +++++++++++++++++++++++++++++-
> >   13 files changed, 2603 insertions(+), 4 deletions(-)
> >   create mode 100644 arch/arm/dts/ntc-gr8-chip-pro.dts
> >   create mode 100644 arch/arm/dts/ntc-gr8.dtsi
> >   create mode 100644 configs/CHIP_pro_defconfig
> >   create mode 100644 tools/sunxi-spl-image-builder.c
> > 
> > base-commit: d8bdfc80da39211d95f10d24e79f2e867305f71b
> 
> Can you please add a README file, where the above things are explained?

Sure, where do you want me to put it? in doc/README.* or somewhere
else?

Thanks,
Maxime

-- 
Maxime Ripard, Free Electrons
Embedded Linux and Kernel engineering
http://free-electrons.com
-------------- next part --------------
A non-text attachment was scrubbed...
Name: signature.asc
Type: application/pgp-signature
Size: 801 bytes
Desc: not available
URL: <http://lists.denx.de/pipermail/u-boot/attachments/20161109/81e15a11/attachment.sig>

^ permalink raw reply	[flat|nested] 44+ messages in thread

* [U-Boot] [PATCH 3/7] sunxi: Enable UBI and NAND support
  2016-11-09 14:32     ` Maxime Ripard
@ 2016-11-09 14:57       ` Boris Brezillon
  0 siblings, 0 replies; 44+ messages in thread
From: Boris Brezillon @ 2016-11-09 14:57 UTC (permalink / raw)
  To: u-boot

On Wed, 9 Nov 2016 15:32:37 +0100
Maxime Ripard <maxime.ripard@free-electrons.com> wrote:

> Hi Boris,
> 
> On Tue, Nov 08, 2016 at 05:27:48PM +0100, Boris Brezillon wrote:
> > On Tue,  8 Nov 2016 17:21:13 +0100
> > Maxime Ripard <maxime.ripard@free-electrons.com> wrote:
> >   
> > > From: Hans de Goede <hdegoede@redhat.com>
> > > 
> > > Enable the NAND and UBI support in the configuration header so that we can
> > > (finally) use it.
> > > 
> > > Signed-off-by: Hans de Goede <hdegoede@redhat.com>
> > > Signed-off-by: Maxime Ripard <maxime.ripard@free-electrons.com>
> > > ---
> > >  include/configs/sunxi-common.h | 26 ++++++++++++++++++++++----
> > >  1 file changed, 22 insertions(+), 4 deletions(-)
> > > 
> > > diff --git a/include/configs/sunxi-common.h b/include/configs/sunxi-common.h
> > > index 8363414828fa..1733767ba53b 100644
> > > --- a/include/configs/sunxi-common.h
> > > +++ b/include/configs/sunxi-common.h
> > > @@ -129,9 +129,23 @@
> > >  #define CONFIG_SERIAL_TAG
> > >  
> > >  #ifdef CONFIG_NAND_SUNXI
> > > +#define CONFIG_SYS_NAND_U_BOOT_OFFS	(8 << 20) /* 8 MiB */  
> > 
> > Can we make this configurable through Kconfig?  
> 
> Is there a need for that?

Yes, I think so, since each board has a different kind of NAND (with
possibly different eraseblock size) and I'm not sure this is always
acceptable to lose 8MiB of storage for the SPL images (especially for
small SLC NANDs).

> AFAIK, everyone in U-Boot defines it there
> (and converting everyone to Kconfig for all the CONFIG_SYS_NAND
> options is going to be painful).

It already exists: enable the SYS_NAND_U_BOOT_LOCATIONS Kconfig
option, and you should see the SYS_NAND_U_BOOT_OFFS and
SYS_NAND_U_BOOT_OFFS_REDUND ones.

> 
> Thanks!
> Maxime
> 

^ permalink raw reply	[flat|nested] 44+ messages in thread

* [U-Boot] [PATCH 0/7] sunxi: Add support for the CHIP Pro
  2016-11-09 14:44   ` Maxime Ripard
@ 2016-11-10 11:57     ` Heiko Schocher
  2016-11-11 16:24       ` Tom Rini
  0 siblings, 1 reply; 44+ messages in thread
From: Heiko Schocher @ 2016-11-10 11:57 UTC (permalink / raw)
  To: u-boot

Hello Maxime,

Am 09.11.2016 um 15:44 schrieb Maxime Ripard:
> Hi Heiko,
>
> On Wed, Nov 09, 2016 at 08:47:12AM +0100, Heiko Schocher wrote:
>> Am 08.11.2016 um 17:21 schrieb Maxime Ripard:
>>> The CHIP Pro is a SoM made by NextThing Co, and that embeds a GR8 SIP, an
>>> AXP209 PMIC, a WiFi BT chip and a 512MB SLC NAND.
>>>
>>> Since the first Allwinner device coming whit an SLC NAND that doesn't have
>>> the shortcomings (and breakages) the MLC NAND has, we can finally enable
>>> the NAND support on a board by default.
>>>
>>> This is the occasion to introduce a bunch of additions needed imo to be
>>> able to come up with a sane NAND support for our users.
>>>
>>> The biggest pain point is that the BROM uses a different ECC and randomizer
>>> configuration than for the rest of the NAND. In order to lessen the number
>>> of bitflips, you also need to pad with random data the SPL image.
>>>
>>> Since it's quite tedious to do right (and most users won't be able to
>>> figure it out) and since if it is not done right, it will eventually turn
>>> into an unusable system (which is bad UX), we think that the best solution
>>> is to generate an SPL image that already embeds all this. We'll possible
>>> have to do the same thing for the U-Boot image (at least for the random
>>> padding) on MLC NANDs.
>>>
>>> The only drawback from that is that you need to flash it raw, instead of
>>> using the usual nand write, but it's just a different command, nothing
>>> major anyway.
>>>
>>> In order to flash it, from a device switched in FEL, on your host:
>>> sunxi-fel spl spl/sunxi-spl.bin
>>> sunxi-fel write 0x4a000000 u-boot-dtb.bin
>>> sunxi-fel write 0x43000000 spl/sunxi-spl-with-ecc.bin
>>> sunxi-fel exe 0x4a000000
>>>
>>> And on the board, once u-boot is running (assuming the NAND is already
>>> erased):
>>>
>>> nand write.raw.noverify 0x43000000 0 40
>>> nand write.raw.noverify 0x43000000 0x400000 40
>>>
>>> nand write 0x4a000000 0x800000 0xc0000
>>>
>>> I also encountered some weird bug in the private libgcc that prevents
>>> U-Boot from loading. Disabling CONFIG_USE_PRIVATE_LIBGCC fixes that.
>>
>> What was the problem?
>
> It has been reported here:
> http://lists.denx.de/pipermail/u-boot/2016-August/264513.html

Hmm.. could not find, what was the real problem ...

>>> Let me know what you think,
>>> Maxime
>>>
>>> Boris Brezillon (1):
>>>     mtd: nand: add support for the TC58NVG2S0H chip
>>>
>>> Hans de Goede (1):
>>>     sunxi: Enable UBI and NAND support
>>>
>>> Maxime Ripard (5):
>>>     sunxi: Sync GR8 DTS and AXP209 with the kernel
>>>     tools: sunxi: Add spl image builder
>>>     nand: sunxi: Add options for the SPL NAND configuration
>>>     scripts: sunxi: Build an raw SPL image
>>>     sunxi: Add support for the CHIP Pro
>>>
>>>    Makefile                          |    3 +-
>>>    arch/arm/dts/Makefile             |    1 +-
>>>    arch/arm/dts/axp209.dtsi          |    6 +-
>>>    arch/arm/dts/ntc-gr8-chip-pro.dts |  266 +++++++-
>>>    arch/arm/dts/ntc-gr8.dtsi         | 1132 ++++++++++++++++++++++++++++++-
>>>    configs/CHIP_pro_defconfig        |   27 +-
>>>    drivers/mtd/nand/Kconfig          |   16 +-
>>>    drivers/mtd/nand/nand_ids.c       |    3 +-
>>>    include/configs/sunxi-common.h    |   26 +-
>>>    scripts/Makefile.spl              |   12 +-
>>>    tools/.gitignore                  |    1 +-
>>>    tools/Makefile                    |    1 +-
>>>    tools/sunxi-spl-image-builder.c   | 1113 +++++++++++++++++++++++++++++-
>>>    13 files changed, 2603 insertions(+), 4 deletions(-)
>>>    create mode 100644 arch/arm/dts/ntc-gr8-chip-pro.dts
>>>    create mode 100644 arch/arm/dts/ntc-gr8.dtsi
>>>    create mode 100644 configs/CHIP_pro_defconfig
>>>    create mode 100644 tools/sunxi-spl-image-builder.c
>>>
>>> base-commit: d8bdfc80da39211d95f10d24e79f2e867305f71b
>>
>> Can you please add a README file, where the above things are explained?
>
> Sure, where do you want me to put it? in doc/README.* or somewhere
> else?

Yes, may doc/README.sunxi ?

Thanks!

bye,
Heiko
-- 
DENX Software Engineering GmbH,      Managing Director: Wolfgang Denk
HRB 165235 Munich, Office: Kirchenstr.5, D-82194 Groebenzell, Germany

^ permalink raw reply	[flat|nested] 44+ messages in thread

* [U-Boot] [PATCH 4/7] tools: sunxi: Add spl image builder
  2016-11-08 16:21 ` [U-Boot] [PATCH 4/7] tools: sunxi: Add spl image builder Maxime Ripard
  2016-11-08 16:29   ` Boris Brezillon
@ 2016-11-11 16:20   ` Tom Rini
  2016-11-14 15:20     ` Maxime Ripard
  2016-11-14 11:18   ` Hans de Goede
  2 siblings, 1 reply; 44+ messages in thread
From: Tom Rini @ 2016-11-11 16:20 UTC (permalink / raw)
  To: u-boot

On Tue, Nov 08, 2016 at 05:21:14PM +0100, Maxime Ripard wrote:

> This program generates raw SPL images that can be flashed on the NAND with
> the ECC and randomizer properly set up.
> 
> Signed-off-by: Maxime Ripard <maxime.ripard@free-electrons.com>
[snip]
> +++ b/tools/sunxi-spl-image-builder.c
> @@ -0,0 +1,1113 @@
> +/*
> + * Generic binary BCH encoding/decoding library

OK, but this is also lib/bch.c and re-using lib/ code for tools is a
normal best practice.  I'd suggest re-factoring this code in sunxi-tools
sot that it too borrows lib/bch.c from the kernel (and can re-sync
bugfixes if needed).  Thanks!

-- 
Tom
-------------- next part --------------
A non-text attachment was scrubbed...
Name: signature.asc
Type: application/pgp-signature
Size: 819 bytes
Desc: Digital signature
URL: <http://lists.denx.de/pipermail/u-boot/attachments/20161111/2ff002af/attachment.sig>

^ permalink raw reply	[flat|nested] 44+ messages in thread

* [U-Boot] [PATCH 0/7] sunxi: Add support for the CHIP Pro
  2016-11-10 11:57     ` Heiko Schocher
@ 2016-11-11 16:24       ` Tom Rini
  0 siblings, 0 replies; 44+ messages in thread
From: Tom Rini @ 2016-11-11 16:24 UTC (permalink / raw)
  To: u-boot

On Thu, Nov 10, 2016 at 12:57:09PM +0100, Heiko Schocher wrote:
> Hello Maxime,
> 
> Am 09.11.2016 um 15:44 schrieb Maxime Ripard:
> >Hi Heiko,
> >
> >On Wed, Nov 09, 2016 at 08:47:12AM +0100, Heiko Schocher wrote:
> >>Am 08.11.2016 um 17:21 schrieb Maxime Ripard:
> >>>The CHIP Pro is a SoM made by NextThing Co, and that embeds a GR8 SIP, an
> >>>AXP209 PMIC, a WiFi BT chip and a 512MB SLC NAND.
> >>>
> >>>Since the first Allwinner device coming whit an SLC NAND that doesn't have
> >>>the shortcomings (and breakages) the MLC NAND has, we can finally enable
> >>>the NAND support on a board by default.
> >>>
> >>>This is the occasion to introduce a bunch of additions needed imo to be
> >>>able to come up with a sane NAND support for our users.
> >>>
> >>>The biggest pain point is that the BROM uses a different ECC and randomizer
> >>>configuration than for the rest of the NAND. In order to lessen the number
> >>>of bitflips, you also need to pad with random data the SPL image.
> >>>
> >>>Since it's quite tedious to do right (and most users won't be able to
> >>>figure it out) and since if it is not done right, it will eventually turn
> >>>into an unusable system (which is bad UX), we think that the best solution
> >>>is to generate an SPL image that already embeds all this. We'll possible
> >>>have to do the same thing for the U-Boot image (at least for the random
> >>>padding) on MLC NANDs.
> >>>
> >>>The only drawback from that is that you need to flash it raw, instead of
> >>>using the usual nand write, but it's just a different command, nothing
> >>>major anyway.
> >>>
> >>>In order to flash it, from a device switched in FEL, on your host:
> >>>sunxi-fel spl spl/sunxi-spl.bin
> >>>sunxi-fel write 0x4a000000 u-boot-dtb.bin
> >>>sunxi-fel write 0x43000000 spl/sunxi-spl-with-ecc.bin
> >>>sunxi-fel exe 0x4a000000
> >>>
> >>>And on the board, once u-boot is running (assuming the NAND is already
> >>>erased):
> >>>
> >>>nand write.raw.noverify 0x43000000 0 40
> >>>nand write.raw.noverify 0x43000000 0x400000 40
> >>>
> >>>nand write 0x4a000000 0x800000 0xc0000
> >>>
> >>>I also encountered some weird bug in the private libgcc that prevents
> >>>U-Boot from loading. Disabling CONFIG_USE_PRIVATE_LIBGCC fixes that.
> >>
> >>What was the problem?
> >
> >It has been reported here:
> >http://lists.denx.de/pipermail/u-boot/2016-August/264513.html
> 
> Hmm.. could not find, what was the real problem ...

And since it's another area we're just borrowing kernel code for, it'd
be good to figure out what odd corner-case is going wrong somewhere and
what the fix is.

-- 
Tom
-------------- next part --------------
A non-text attachment was scrubbed...
Name: signature.asc
Type: application/pgp-signature
Size: 819 bytes
Desc: Digital signature
URL: <http://lists.denx.de/pipermail/u-boot/attachments/20161111/1cdc6261/attachment.sig>

^ permalink raw reply	[flat|nested] 44+ messages in thread

* [U-Boot] [PATCH 1/7] sunxi: Sync GR8 DTS and AXP209 with the kernel
  2016-11-08 16:21 ` [U-Boot] [PATCH 1/7] sunxi: Sync GR8 DTS and AXP209 with the kernel Maxime Ripard
@ 2016-11-14 11:15   ` Hans de Goede
  0 siblings, 0 replies; 44+ messages in thread
From: Hans de Goede @ 2016-11-14 11:15 UTC (permalink / raw)
  To: u-boot

Hi,

On 08-11-16 17:21, Maxime Ripard wrote:
> Those DT will be part of 4.10, sync them so we can have our own config.
>
> Signed-off-by: Maxime Ripard <maxime.ripard@free-electrons.com>

Looks good to me:

Reviewed-by: Hans de Goede <hdegoede@redhat.com>

Regards,

Hans


> ---
>  arch/arm/dts/Makefile             |    1 +-
>  arch/arm/dts/axp209.dtsi          |    6 +-
>  arch/arm/dts/ntc-gr8-chip-pro.dts |  266 +++++++-
>  arch/arm/dts/ntc-gr8.dtsi         | 1132 ++++++++++++++++++++++++++++++-
>  4 files changed, 1405 insertions(+), 0 deletions(-)
>  create mode 100644 arch/arm/dts/ntc-gr8-chip-pro.dts
>  create mode 100644 arch/arm/dts/ntc-gr8.dtsi
>
> diff --git a/arch/arm/dts/Makefile b/arch/arm/dts/Makefile
> index 836a8c4d1ee2..932dbe07cf14 100644
> --- a/arch/arm/dts/Makefile
> +++ b/arch/arm/dts/Makefile
> @@ -180,6 +180,7 @@ dtb-$(CONFIG_MACH_SUN4I) += \
>  	sun4i-a10-pcduino2.dtb \
>  	sun4i-a10-pov-protab2-ips9.dtb
>  dtb-$(CONFIG_MACH_SUN5I) += \
> +	ntc-gr8-chip-pro.dtb \
>  	sun5i-a10s-auxtek-t003.dtb \
>  	sun5i-a10s-auxtek-t004.dtb \
>  	sun5i-a10s-mk802.dtb \
> diff --git a/arch/arm/dts/axp209.dtsi b/arch/arm/dts/axp209.dtsi
> index afbe89c01df5..675bb0f30825 100644
> --- a/arch/arm/dts/axp209.dtsi
> +++ b/arch/arm/dts/axp209.dtsi
> @@ -53,6 +53,12 @@
>  	interrupt-controller;
>  	#interrupt-cells = <1>;
>
> +	axp_gpio: gpio {
> +		compatible = "x-powers,axp209-gpio";
> +		gpio-controller;
> +		#gpio-cells = <2>;
> +	};
> +
>  	regulators {
>  		/* Default work frequency for buck regulators */
>  		x-powers,dcdc-freq = <1500>;
> diff --git a/arch/arm/dts/ntc-gr8-chip-pro.dts b/arch/arm/dts/ntc-gr8-chip-pro.dts
> new file mode 100644
> index 000000000000..c4be912df481
> --- /dev/null
> +++ b/arch/arm/dts/ntc-gr8-chip-pro.dts
> @@ -0,0 +1,266 @@
> +/*
> + * Copyright 2016 Free Electrons
> + * Copyright 2016 NextThing Co
> + *
> + * Maxime Ripard <maxime.ripard@free-electrons.com>
> + *
> + * This file is dual-licensed: you can use it either under the terms
> + * of the GPL or the X11 license, at your option. Note that this dual
> + * licensing only applies to this file, and not this project as a
> + * whole.
> + *
> + *  a) This file is free software; you can redistribute it and/or
> + *     modify it under the terms of the GNU General Public License as
> + *     published by the Free Software Foundation; either version 2 of the
> + *     License, or (at your option) any later version.
> + *
> + *     This file is distributed in the hope that it will be useful,
> + *     but WITHOUT ANY WARRANTY; without even the implied warranty of
> + *     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
> + *     GNU General Public License for more details.
> + *
> + * Or, alternatively,
> + *
> + *  b) Permission is hereby granted, free of charge, to any person
> + *     obtaining a copy of this software and associated documentation
> + *     files (the "Software"), to deal in the Software without
> + *     restriction, including without limitation the rights to use,
> + *     copy, modify, merge, publish, distribute, sublicense, and/or
> + *     sell copies of the Software, and to permit persons to whom the
> + *     Software is furnished to do so, subject to the following
> + *     conditions:
> + *
> + *     The above copyright notice and this permission notice shall be
> + *     included in all copies or substantial portions of the Software.
> + *
> + *     THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
> + *     EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
> + *     OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
> + *     NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
> + *     HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
> + *     WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
> + *     FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
> + *     OTHER DEALINGS IN THE SOFTWARE.
> + */
> +
> +/dts-v1/;
> +#include "ntc-gr8.dtsi"
> +#include "sunxi-common-regulators.dtsi"
> +
> +#include <dt-bindings/gpio/gpio.h>
> +#include <dt-bindings/input/input.h>
> +#include <dt-bindings/interrupt-controller/irq.h>
> +
> +/ {
> +	model = "NextThing C.H.I.P. Pro";
> +	compatible = "nextthing,chip-pro", "nextthing,gr8";
> +
> +	aliases {
> +		i2c0 = &i2c0;
> +		i2c1 = &i2c1;
> +		serial0 = &uart1;
> +		serial1 = &uart2;
> +		serial2 = &uart3;
> +	};
> +
> +	chosen {
> +		stdout-path = "serial0:115200n8";
> +	};
> +
> +	leds {
> +		compatible = "gpio-leds";
> +
> +		status {
> +			label = "chip-pro:white:status";
> +			gpios = <&axp_gpio 2 GPIO_ACTIVE_HIGH>;
> +			default-state = "on";
> +		};
> +	};
> +
> +	mmc0_pwrseq: mmc0_pwrseq {
> +		compatible = "mmc-pwrseq-simple";
> +		pinctrl-names = "default";
> +		pinctrl-0 = <&wifi_reg_on_pin_chip_pro>;
> +		reset-gpios = <&pio 1 10 GPIO_ACTIVE_LOW>; /* PB10 */
> +	};
> +};
> +
> +&codec {
> +	status = "okay";
> +};
> +
> +&ehci0 {
> +	status = "okay";
> +};
> +
> +&i2c0 {
> +	pinctrl-names = "default";
> +	pinctrl-0 = <&i2c0_pins_a>;
> +	status = "okay";
> +
> +	axp209: pmic at 34 {
> +		reg = <0x34>;
> +
> +		/*
> +		* The interrupt is routed through the "External Fast
> +		* Interrupt Request" pin (ball G13 of the module)
> +		* directly to the main interrupt controller, without
> +		* any other controller interfering.
> +		*/
> +		interrupts = <0>;
> +	};
> +};
> +
> +#include "axp209.dtsi"
> +
> +&i2c1 {
> +	pinctrl-names = "default";
> +	pinctrl-0 = <&i2c1_pins_a>;
> +	status = "disabled";
> +};
> +
> +&i2s0 {
> +	pinctrl-names = "default";
> +	pinctrl-0 = <&i2s0_mclk_pins_a>, <&i2s0_data_pins_a>;
> +	status = "disabled";
> +};
> +
> +&mmc0 {
> +	pinctrl-names = "default";
> +	pinctrl-0 = <&mmc0_pins_a>;
> +	vmmc-supply = <&reg_vcc3v3>;
> +	mmc-pwrseq = <&mmc0_pwrseq>;
> +	bus-width = <4>;
> +	non-removable;
> +	status = "okay";
> +};
> +
> +&nfc {
> +	pinctrl-names = "default";
> +	pinctrl-0 = <&nand_pins_a &nand_cs0_pins_a &nand_rb0_pins_a>;
> +	status = "okay";
> +
> +	nand at 0 {
> +		#address-cells = <2>;
> +		#size-cells = <2>;
> +		reg = <0>;
> +		allwinner,rb = <0>;
> +		nand-ecc-mode = "hw";
> +	};
> +};
> +
> +&ohci0 {
> +	status = "okay";
> +};
> +
> +&otg_sram {
> +	status = "okay";
> +};
> +
> +&pio {
> +	usb0_id_pin_chip_pro: usb0-id-pin at 0 {
> +		allwinner,pins = "PG2";
> +		allwinner,function = "gpio_in";
> +		allwinner,drive = <SUN4I_PINCTRL_10_MA>;
> +		allwinner,pull = <SUN4I_PINCTRL_NO_PULL>;
> +	};
> +
> +	wifi_reg_on_pin_chip_pro: wifi-reg-on-pin at 0 {
> +		allwinner,pins = "PB10";
> +		allwinner,function = "gpio_out";
> +		allwinner,drive = <SUN4I_PINCTRL_10_MA>;
> +		allwinner,pull = <SUN4I_PINCTRL_NO_PULL>;
> +	};
> +};
> +
> +&pwm {
> +	pinctrl-names = "default";
> +	pinctrl-0 = <&pwm0_pins_a>, <&pwm1_pins>;
> +	status = "disabled";
> +};
> +
> +&reg_dcdc2 {
> +	regulator-min-microvolt = <1000000>;
> +	regulator-max-microvolt = <1400000>;
> +	regulator-name = "vdd-cpu";
> +	regulator-always-on;
> +};
> +
> +&reg_dcdc3 {
> +	regulator-min-microvolt = <1000000>;
> +	regulator-max-microvolt = <1300000>;
> +	regulator-name = "vdd-sys";
> +	regulator-always-on;
> +};
> +
> +&reg_ldo1 {
> +	regulator-name = "vdd-rtc";
> +};
> +
> +&reg_ldo2 {
> +	regulator-min-microvolt = <2700000>;
> +	regulator-max-microvolt = <3300000>;
> +	regulator-name = "avcc";
> +	regulator-always-on;
> +};
> +
> +/*
> + * Both LDO3 and LDO4 are used in parallel to power up the
> + * WiFi/BT chip.
> + */
> +&reg_ldo3 {
> +	regulator-min-microvolt = <3300000>;
> +	regulator-max-microvolt = <3300000>;
> +	regulator-name = "vcc-wifi-1";
> +	regulator-always-on;
> +};
> +
> +&reg_ldo4 {
> +	regulator-min-microvolt = <3300000>;
> +	regulator-max-microvolt = <3300000>;
> +	regulator-name = "vcc-wifi-2";
> +	regulator-always-on;
> +};
> +
> +&uart1 {
> +	pinctrl-names = "default";
> +	pinctrl-0 = <&uart1_pins_a>, <&uart1_cts_rts_pins_a>;
> +	status = "okay";
> +};
> +
> +&uart2 {
> +	pinctrl-names = "default";
> +	pinctrl-0 = <&uart2_pins_a>, <&uart2_cts_rts_pins_a>;
> +	status = "disabled";
> +};
> +
> +&uart3 {
> +	pinctrl-names = "default";
> +	pinctrl-0 = <&uart3_pins_a>, <&uart3_cts_rts_pins_a>;
> +	status = "okay";
> +};
> +
> +&usb_otg {
> +	/*
> +	 * The CHIP Pro doesn't have a controllable VBUS, nor does it
> +	 * have any 5v rail on the board itself.
> +	 *
> +	 * If one wants to use it as a true OTG port, it should be
> +	 * done in the baseboard, and its DT / overlay will add it.
> +	 */
> +	dr_mode = "otg";
> +	status = "okay";
> +};
> +
> +&usb_power_supply {
> +	status = "okay";
> +};
> +
> +&usbphy {
> +	pinctrl-names = "default";
> +	pinctrl-0 = <&usb0_id_pin_chip_pro>;
> +	usb0_id_det-gpio = <&pio 6 2 GPIO_ACTIVE_HIGH>; /* PG2 */
> +	usb0_vbus_power-supply = <&usb_power_supply>;
> +	usb1_vbus-supply = <&reg_vcc5v0>;
> +	status = "okay";
> +};
> diff --git a/arch/arm/dts/ntc-gr8.dtsi b/arch/arm/dts/ntc-gr8.dtsi
> new file mode 100644
> index 000000000000..ea86d4d58db6
> --- /dev/null
> +++ b/arch/arm/dts/ntc-gr8.dtsi
> @@ -0,0 +1,1132 @@
> +/*
> + * Copyright 2016 Myl?ne Josserand
> + *
> + * Myl?ne Josserand <mylene.josserand@free-electrons.com>
> + *
> + * This file is dual-licensed: you can use it either under the terms
> + * of the GPL or the X11 license, at your option. Note that this dual
> + * licensing only applies to this file, and not this project as a
> + * whole.
> + *
> + *  a) This library is free software; you can redistribute it and/or
> + *     modify it under the terms of the GNU General Public License as
> + *     published by the Free Software Foundation; either version 2 of the
> + *     License, or (at your option) any later version.
> + *
> + *     This library is distributed in the hope that it will be useful,
> + *     but WITHOUT ANY WARRANTY; without even the implied warranty of
> + *     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
> + *     GNU General Public License for more details.
> + *
> + * Or, alternatively,
> + *
> + *  b) Permission is hereby granted, free of charge, to any person
> + *     obtaining a copy of this software and associated documentation
> + *     files (the "Software"), to deal in the Software without
> + *     restriction, including without limitation the rights to use,
> + *     copy, modify, merge, publish, distribute, sublicense, and/or
> + *     sell copies of the Software, and to permit persons to whom the
> + *     Software is furnished to do so, subject to the following
> + *     conditions:
> + *
> + *     The above copyright notice and this permission notice shall be
> + *     included in all copies or substantial portions of the Software.
> + *
> + *     THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
> + *     EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
> + *     OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
> + *     NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
> + *     HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
> + *     WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
> + *     FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
> + *     OTHER DEALINGS IN THE SOFTWARE.
> + */
> +
> +#include <dt-bindings/clock/sun4i-a10-pll2.h>
> +#include <dt-bindings/dma/sun4i-a10.h>
> +#include <dt-bindings/pinctrl/sun4i-a10.h>
> +
> +/ {
> +	interrupt-parent = <&intc>;
> +	#address-cells = <1>;
> +	#size-cells = <1>;
> +
> +	cpus {
> +		#address-cells = <1>;
> +		#size-cells = <0>;
> +
> +		cpu0: cpu at 0 {
> +			device_type = "cpu";
> +			compatible = "arm,cortex-a8";
> +			reg = <0x0>;
> +			clocks = <&cpu>;
> +		};
> +	};
> +
> +	clocks {
> +		#address-cells = <1>;
> +		#size-cells = <1>;
> +		ranges;
> +
> +		/*
> +		 * This is a dummy clock, to be used as placeholder on
> +		 * other mux clocks when a specific parent clock is not
> +		 * yet implemented. It should be dropped when the driver
> +		 * is complete.
> +		 */
> +		dummy: dummy {
> +			#clock-cells = <0>;
> +			compatible = "fixed-clock";
> +			clock-frequency = <0>;
> +		};
> +
> +		osc24M: clk at 01c20050 {
> +			#clock-cells = <0>;
> +			compatible = "allwinner,sun4i-a10-osc-clk";
> +			reg = <0x01c20050 0x4>;
> +			clock-frequency = <24000000>;
> +			clock-output-names = "osc24M";
> +		};
> +
> +		osc3M: osc3M-clk {
> +			compatible = "fixed-factor-clock";
> +			#clock-cells = <0>;
> +			clock-div = <8>;
> +			clock-mult = <1>;
> +			clocks = <&osc24M>;
> +			clock-output-names = "osc3M";
> +		};
> +
> +		osc32k: clk at 0 {
> +			#clock-cells = <0>;
> +			compatible = "fixed-clock";
> +			clock-frequency = <32768>;
> +			clock-output-names = "osc32k";
> +		};
> +
> +		pll1: clk at 01c20000 {
> +			#clock-cells = <0>;
> +			compatible = "allwinner,sun4i-a10-pll1-clk";
> +			reg = <0x01c20000 0x4>;
> +			clocks = <&osc24M>;
> +			clock-output-names = "pll1";
> +		};
> +
> +		pll2: clk at 01c20008 {
> +			#clock-cells = <1>;
> +			compatible = "allwinner,sun5i-a13-pll2-clk";
> +			reg = <0x01c20008 0x8>;
> +			clocks = <&osc24M>;
> +			clock-output-names = "pll2-1x", "pll2-2x",
> +					     "pll2-4x", "pll2-8x";
> +		};
> +
> +		pll3: clk at 01c20010 {
> +			#clock-cells = <0>;
> +			compatible = "allwinner,sun4i-a10-pll3-clk";
> +			reg = <0x01c20010 0x4>;
> +			clocks = <&osc3M>;
> +			clock-output-names = "pll3";
> +		};
> +
> +		pll3x2: pll3x2-clk {
> +			compatible = "allwinner,sun4i-a10-pll3-2x-clk";
> +			#clock-cells = <0>;
> +			clock-div = <1>;
> +			clock-mult = <2>;
> +			clocks = <&pll3>;
> +			clock-output-names = "pll3-2x";
> +		};
> +
> +		pll4: clk at 01c20018 {
> +			#clock-cells = <0>;
> +			compatible = "allwinner,sun4i-a10-pll1-clk";
> +			reg = <0x01c20018 0x4>;
> +			clocks = <&osc24M>;
> +			clock-output-names = "pll4";
> +		};
> +
> +		pll5: clk at 01c20020 {
> +			#clock-cells = <1>;
> +			compatible = "allwinner,sun4i-a10-pll5-clk";
> +			reg = <0x01c20020 0x4>;
> +			clocks = <&osc24M>;
> +			clock-output-names = "pll5_ddr", "pll5_other";
> +		};
> +
> +		pll6: clk at 01c20028 {
> +			#clock-cells = <1>;
> +			compatible = "allwinner,sun4i-a10-pll6-clk";
> +			reg = <0x01c20028 0x4>;
> +			clocks = <&osc24M>;
> +			clock-output-names = "pll6_sata", "pll6_other", "pll6";
> +		};
> +
> +		pll7: clk at 01c20030 {
> +			#clock-cells = <0>;
> +			compatible = "allwinner,sun4i-a10-pll3-clk";
> +			reg = <0x01c20030 0x4>;
> +			clocks = <&osc3M>;
> +			clock-output-names = "pll7";
> +		};
> +
> +		pll7x2: pll7x2-clk {
> +			compatible = "allwinner,sun4i-a10-pll3-2x-clk";
> +			#clock-cells = <0>;
> +			clock-div = <1>;
> +			clock-mult = <2>;
> +			clocks = <&pll7>;
> +			clock-output-names = "pll7-2x";
> +		};
> +
> +		/* dummy is 200M */
> +		cpu: cpu at 01c20054 {
> +			#clock-cells = <0>;
> +			compatible = "allwinner,sun4i-a10-cpu-clk";
> +			reg = <0x01c20054 0x4>;
> +			clocks = <&osc32k>, <&osc24M>, <&pll1>, <&dummy>;
> +			clock-output-names = "cpu";
> +		};
> +
> +		axi: axi at 01c20054 {
> +			#clock-cells = <0>;
> +			compatible = "allwinner,sun4i-a10-axi-clk";
> +			reg = <0x01c20054 0x4>;
> +			clocks = <&cpu>;
> +			clock-output-names = "axi";
> +		};
> +
> +		ahb: ahb at 01c20054 {
> +			#clock-cells = <0>;
> +			compatible = "allwinner,sun5i-a13-ahb-clk";
> +			reg = <0x01c20054 0x4>;
> +			clocks = <&axi>, <&cpu>, <&pll6 1>;
> +			clock-output-names = "ahb";
> +			/*
> +			 * Use PLL6 as parent, instead of CPU/AXI
> +			 * which has rate changes due to cpufreq
> +			 */
> +			assigned-clocks = <&ahb>;
> +			assigned-clock-parents = <&pll6 1>;
> +		};
> +
> +		apb0: apb0 at 01c20054 {
> +			#clock-cells = <0>;
> +			compatible = "allwinner,sun4i-a10-apb0-clk";
> +			reg = <0x01c20054 0x4>;
> +			clocks = <&ahb>;
> +			clock-output-names = "apb0";
> +		};
> +
> +		apb1: clk at 01c20058 {
> +			#clock-cells = <0>;
> +			compatible = "allwinner,sun4i-a10-apb1-clk";
> +			reg = <0x01c20058 0x4>;
> +			clocks = <&osc24M>, <&pll6 1>, <&osc32k>;
> +			clock-output-names = "apb1";
> +		};
> +
> +		axi_gates: clk at 01c2005c {
> +			#clock-cells = <1>;
> +			compatible = "allwinner,sun4i-a10-gates-clk";
> +			reg = <0x01c2005c 0x4>;
> +			clocks = <&axi>;
> +			clock-indices = <0>;
> +			clock-output-names = "axi_dram";
> +		};
> +
> +		ahb_gates: clk at 01c20060 {
> +			#clock-cells = <1>;
> +			compatible = "allwinner,sun5i-a13-ahb-gates-clk";
> +			reg = <0x01c20060 0x8>;
> +			clocks = <&ahb>;
> +			clock-indices = <0>, <1>,
> +					<2>, <5>, <6>,
> +					<7>, <8>, <9>,
> +					<10>, <13>,
> +					<14>, <17>, <20>,
> +					<21>, <22>,
> +					<28>, <32>, <34>,
> +					<36>, <40>, <44>,
> +					<46>, <51>,
> +					<52>;
> +			clock-output-names = "ahb_usbotg", "ahb_ehci",
> +					     "ahb_ohci", "ahb_ss", "ahb_dma",
> +					     "ahb_bist", "ahb_mmc0", "ahb_mmc1",
> +					     "ahb_mmc2", "ahb_nand",
> +					     "ahb_sdram", "ahb_emac", "ahb_spi0",
> +					     "ahb_spi1", "ahb_spi2",
> +					     "ahb_hstimer", "ahb_ve", "ahb_tve",
> +					     "ahb_lcd", "ahb_csi", "ahb_de_be",
> +					     "ahb_de_fe", "ahb_iep",
> +					     "ahb_mali400";
> +		};
> +
> +		apb0_gates: clk at 01c20068 {
> +			#clock-cells = <1>;
> +			compatible = "allwinner,sun4i-a10-gates-clk";
> +			reg = <0x01c20068 0x4>;
> +			clocks = <&apb0>;
> +			clock-indices = <0>, <3>,
> +					<5>, <6>;
> +			clock-output-names = "apb0_codec", "apb0_i2s0",
> +					     "apb0_pio", "apb0_ir";
> +		};
> +
> +		apb1_gates: clk at 01c2006c {
> +			#clock-cells = <1>;
> +			compatible = "allwinner,sun4i-a10-gates-clk";
> +			reg = <0x01c2006c 0x4>;
> +			clocks = <&apb1>;
> +			clock-indices = <0>, <1>,
> +					<2>, <17>,
> +					<18>, <19>;
> +			clock-output-names = "apb1_i2c0", "apb1_i2c1",
> +					     "apb1_i2c2", "apb1_uart1",
> +					     "apb1_uart2", "apb1_uart3";
> +		};
> +
> +		nand_clk: clk at 01c20080 {
> +			#clock-cells = <0>;
> +			compatible = "allwinner,sun4i-a10-mod0-clk";
> +			reg = <0x01c20080 0x4>;
> +			clocks = <&osc24M>, <&pll6 1>, <&pll5 1>;
> +			clock-output-names = "nand";
> +		};
> +
> +		ms_clk: clk at 01c20084 {
> +			#clock-cells = <0>;
> +			compatible = "allwinner,sun4i-a10-mod0-clk";
> +			reg = <0x01c20084 0x4>;
> +			clocks = <&osc24M>, <&pll6 1>, <&pll5 1>;
> +			clock-output-names = "ms";
> +		};
> +
> +		mmc0_clk: clk at 01c20088 {
> +			#clock-cells = <1>;
> +			compatible = "allwinner,sun4i-a10-mmc-clk";
> +			reg = <0x01c20088 0x4>;
> +			clocks = <&osc24M>, <&pll6 1>, <&pll5 1>;
> +			clock-output-names = "mmc0",
> +					     "mmc0_output",
> +					     "mmc0_sample";
> +		};
> +
> +		mmc1_clk: clk at 01c2008c {
> +			#clock-cells = <1>;
> +			compatible = "allwinner,sun4i-a10-mmc-clk";
> +			reg = <0x01c2008c 0x4>;
> +			clocks = <&osc24M>, <&pll6 1>, <&pll5 1>;
> +			clock-output-names = "mmc1",
> +					     "mmc1_output",
> +					     "mmc1_sample";
> +		};
> +
> +		mmc2_clk: clk at 01c20090 {
> +			#clock-cells = <1>;
> +			compatible = "allwinner,sun4i-a10-mmc-clk";
> +			reg = <0x01c20090 0x4>;
> +			clocks = <&osc24M>, <&pll6 1>, <&pll5 1>;
> +			clock-output-names = "mmc2",
> +					     "mmc2_output",
> +					     "mmc2_sample";
> +		};
> +
> +		ts_clk: clk at 01c20098 {
> +			#clock-cells = <0>;
> +			compatible = "allwinner,sun4i-a10-mod0-clk";
> +			reg = <0x01c20098 0x4>;
> +			clocks = <&osc24M>, <&pll6 1>, <&pll5 1>;
> +			clock-output-names = "ts";
> +		};
> +
> +		ss_clk: clk at 01c2009c {
> +			#clock-cells = <0>;
> +			compatible = "allwinner,sun4i-a10-mod0-clk";
> +			reg = <0x01c2009c 0x4>;
> +			clocks = <&osc24M>, <&pll6 1>, <&pll5 1>;
> +			clock-output-names = "ss";
> +		};
> +
> +		spi0_clk: clk at 01c200a0 {
> +			#clock-cells = <0>;
> +			compatible = "allwinner,sun4i-a10-mod0-clk";
> +			reg = <0x01c200a0 0x4>;
> +			clocks = <&osc24M>, <&pll6 1>, <&pll5 1>;
> +			clock-output-names = "spi0";
> +		};
> +
> +		spi1_clk: clk at 01c200a4 {
> +			#clock-cells = <0>;
> +			compatible = "allwinner,sun4i-a10-mod0-clk";
> +			reg = <0x01c200a4 0x4>;
> +			clocks = <&osc24M>, <&pll6 1>, <&pll5 1>;
> +			clock-output-names = "spi1";
> +		};
> +
> +		spi2_clk: clk at 01c200a8 {
> +			#clock-cells = <0>;
> +			compatible = "allwinner,sun4i-a10-mod0-clk";
> +			reg = <0x01c200a8 0x4>;
> +			clocks = <&osc24M>, <&pll6 1>, <&pll5 1>;
> +			clock-output-names = "spi2";
> +		};
> +
> +		ir0_clk: clk at 01c200b0 {
> +			#clock-cells = <0>;
> +			compatible = "allwinner,sun4i-a10-mod0-clk";
> +			reg = <0x01c200b0 0x4>;
> +			clocks = <&osc24M>, <&pll6 1>, <&pll5 1>;
> +			clock-output-names = "ir0";
> +		};
> +
> +		i2s0_clk: clk at 01c200b8 {
> +			#clock-cells = <0>;
> +			compatible = "allwinner,sun4i-a10-mod1-clk";
> +			reg = <0x01c200b8 0x4>;
> +			clocks = <&pll2 SUN4I_A10_PLL2_8X>,
> +				 <&pll2 SUN4I_A10_PLL2_4X>,
> +				 <&pll2 SUN4I_A10_PLL2_2X>,
> +				 <&pll2 SUN4I_A10_PLL2_1X>;
> +			clock-output-names = "i2s0";
> +		};
> +
> +		spdif_clk: clk at 01c200c0 {
> +			#clock-cells = <0>;
> +			compatible = "allwinner,sun4i-a10-mod1-clk";
> +			reg = <0x01c200c0 0x4>;
> +			clocks = <&pll2 SUN4I_A10_PLL2_8X>,
> +				 <&pll2 SUN4I_A10_PLL2_4X>,
> +				 <&pll2 SUN4I_A10_PLL2_2X>,
> +				 <&pll2 SUN4I_A10_PLL2_1X>;
> +			clock-output-names = "spdif";
> +		};
> +
> +		usb_clk: clk at 01c200cc {
> +			#clock-cells = <1>;
> +			#reset-cells = <1>;
> +			compatible = "allwinner,sun5i-a13-usb-clk";
> +			reg = <0x01c200cc 0x4>;
> +			clocks = <&pll6 1>;
> +			clock-output-names = "usb_ohci0", "usb_phy";
> +		};
> +
> +		dram_gates: clk at 01c20100 {
> +			#clock-cells = <1>;
> +			compatible = "nextthing,gr8-dram-gates-clk",
> +				     "allwinner,sun4i-a10-gates-clk";
> +			reg = <0x01c20100 0x4>;
> +			clocks = <&pll5 0>;
> +			clock-indices = <0>,
> +					<1>,
> +					<25>,
> +					<26>,
> +					<29>,
> +					<31>;
> +			clock-output-names = "dram_ve",
> +					     "dram_csi",
> +					     "dram_de_fe",
> +					     "dram_de_be",
> +					     "dram_ace",
> +					     "dram_iep";
> +		};
> +
> +		de_be_clk: clk at 01c20104 {
> +			#clock-cells = <0>;
> +			#reset-cells = <0>;
> +			compatible = "allwinner,sun4i-a10-display-clk";
> +			reg = <0x01c20104 0x4>;
> +			clocks = <&pll3>, <&pll7>, <&pll5 1>;
> +			clock-output-names = "de-be";
> +		};
> +
> +		de_fe_clk: clk at 01c2010c {
> +			#clock-cells = <0>;
> +			#reset-cells = <0>;
> +			compatible = "allwinner,sun4i-a10-display-clk";
> +			reg = <0x01c2010c 0x4>;
> +			clocks = <&pll3>, <&pll7>, <&pll5 1>;
> +			clock-output-names = "de-fe";
> +		};
> +
> +		tcon_ch0_clk: clk at 01c20118 {
> +			#clock-cells = <0>;
> +			#reset-cells = <1>;
> +			compatible = "allwinner,sun4i-a10-tcon-ch0-clk";
> +			reg = <0x01c20118 0x4>;
> +			clocks = <&pll3>, <&pll7>, <&pll3x2>, <&pll7x2>;
> +			clock-output-names = "tcon-ch0-sclk";
> +		};
> +
> +		tcon_ch1_clk: clk at 01c2012c {
> +			#clock-cells = <0>;
> +			compatible = "allwinner,sun4i-a10-tcon-ch1-clk";
> +			reg = <0x01c2012c 0x4>;
> +			clocks = <&pll3>, <&pll7>, <&pll3x2>, <&pll7x2>;
> +			clock-output-names = "tcon-ch1-sclk";
> +		};
> +
> +		codec_clk: clk at 01c20140 {
> +			#clock-cells = <0>;
> +			compatible = "allwinner,sun4i-a10-codec-clk";
> +			reg = <0x01c20140 0x4>;
> +			clocks = <&pll2 SUN4I_A10_PLL2_1X>;
> +			clock-output-names = "codec";
> +		};
> +
> +		mbus_clk: clk at 01c2015c {
> +			#clock-cells = <0>;
> +			compatible = "allwinner,sun5i-a13-mbus-clk";
> +			reg = <0x01c2015c 0x4>;
> +			clocks = <&osc24M>, <&pll6 1>, <&pll5 1>;
> +			clock-output-names = "mbus";
> +		};
> +	};
> +
> +	display-engine {
> +		compatible = "allwinner,sun5i-a13-display-engine";
> +		allwinner,pipelines = <&fe0>;
> +	};
> +
> +	soc at 01c00000 {
> +		compatible = "simple-bus";
> +		#address-cells = <1>;
> +		#size-cells = <1>;
> +		ranges;
> +
> +		sram-controller at 01c00000 {
> +			compatible = "allwinner,sun4i-a10-sram-controller";
> +			reg = <0x01c00000 0x30>;
> +			#address-cells = <1>;
> +			#size-cells = <1>;
> +			ranges;
> +
> +			sram_a: sram at 00000000 {
> +				compatible = "mmio-sram";
> +				reg = <0x00000000 0xc000>;
> +				#address-cells = <1>;
> +				#size-cells = <1>;
> +				ranges = <0 0x00000000 0xc000>;
> +			};
> +
> +			sram_d: sram at 00010000 {
> +				compatible = "mmio-sram";
> +				reg = <0x00010000 0x1000>;
> +				#address-cells = <1>;
> +				#size-cells = <1>;
> +				ranges = <0 0x00010000 0x1000>;
> +
> +				otg_sram: sram-section at 0000 {
> +					compatible = "allwinner,sun4i-a10-sram-d";
> +					reg = <0x0000 0x1000>;
> +					status = "disabled";
> +				};
> +			};
> +		};
> +
> +		dma: dma-controller at 01c02000 {
> +			compatible = "allwinner,sun4i-a10-dma";
> +			reg = <0x01c02000 0x1000>;
> +			interrupts = <27>;
> +			clocks = <&ahb_gates 6>;
> +			#dma-cells = <2>;
> +		};
> +
> +		nfc: nand at 01c03000 {
> +			compatible = "allwinner,sun4i-a10-nand";
> +			reg = <0x01c03000 0x1000>;
> +			interrupts = <37>;
> +			clocks = <&ahb_gates 13>, <&nand_clk>;
> +			clock-names = "ahb", "mod";
> +			dmas = <&dma SUN4I_DMA_DEDICATED 3>;
> +			dma-names = "rxtx";
> +			status = "disabled";
> +			#address-cells = <1>;
> +			#size-cells = <0>;
> +		};
> +
> +		spi0: spi at 01c05000 {
> +			compatible = "allwinner,sun4i-a10-spi";
> +			reg = <0x01c05000 0x1000>;
> +			interrupts = <10>;
> +			clocks = <&ahb_gates 20>, <&spi0_clk>;
> +			clock-names = "ahb", "mod";
> +			dmas = <&dma SUN4I_DMA_DEDICATED 27>,
> +			       <&dma SUN4I_DMA_DEDICATED 26>;
> +			dma-names = "rx", "tx";
> +			status = "disabled";
> +			#address-cells = <1>;
> +			#size-cells = <0>;
> +		};
> +
> +		spi1: spi at 01c06000 {
> +			compatible = "allwinner,sun4i-a10-spi";
> +			reg = <0x01c06000 0x1000>;
> +			interrupts = <11>;
> +			clocks = <&ahb_gates 21>, <&spi1_clk>;
> +			clock-names = "ahb", "mod";
> +			dmas = <&dma SUN4I_DMA_DEDICATED 9>,
> +			       <&dma SUN4I_DMA_DEDICATED 8>;
> +			dma-names = "rx", "tx";
> +			status = "disabled";
> +			#address-cells = <1>;
> +			#size-cells = <0>;
> +		};
> +
> +		tve0: tv-encoder at 01c0a000 {
> +			compatible = "allwinner,sun4i-a10-tv-encoder";
> +			reg = <0x01c0a000 0x1000>;
> +			clocks = <&ahb_gates 34>;
> +			resets = <&tcon_ch0_clk 0>;
> +			status = "disabled";
> +
> +			port {
> +				#address-cells = <1>;
> +				#size-cells = <0>;
> +
> +				tve0_in_tcon0: endpoint at 0 {
> +					reg = <0>;
> +					remote-endpoint = <&tcon0_out_tve0>;
> +				};
> +			};
> +		};
> +
> +		tcon0: lcd-controller at 01c0c000 {
> +			compatible = "allwinner,sun5i-a13-tcon";
> +			reg = <0x01c0c000 0x1000>;
> +			interrupts = <44>;
> +			resets = <&tcon_ch0_clk 1>;
> +			reset-names = "lcd";
> +			clocks = <&ahb_gates 36>,
> +				 <&tcon_ch0_clk>,
> +				 <&tcon_ch1_clk>;
> +			clock-names = "ahb",
> +				      "tcon-ch0",
> +				      "tcon-ch1";
> +			clock-output-names = "tcon-pixel-clock";
> +			status = "disabled";
> +
> +			ports {
> +				#address-cells = <1>;
> +				#size-cells = <0>;
> +
> +				tcon0_in: port at 0 {
> +					#address-cells = <1>;
> +					#size-cells = <0>;
> +					reg = <0>;
> +
> +					tcon0_in_be0: endpoint at 0 {
> +						reg = <0>;
> +						remote-endpoint = <&be0_out_tcon0>;
> +					};
> +				};
> +
> +				tcon0_out: port at 1 {
> +					#address-cells = <1>;
> +					#size-cells = <0>;
> +					reg = <1>;
> +
> +					tcon0_out_tve0: endpoint at 1 {
> +						reg = <1>;
> +						remote-endpoint = <&tve0_in_tcon0>;
> +					};
> +				};
> +			};
> +		};
> +
> +		mmc0: mmc at 01c0f000 {
> +			compatible = "allwinner,sun5i-a13-mmc";
> +			reg = <0x01c0f000 0x1000>;
> +			clocks = <&ahb_gates 8>,
> +				 <&mmc0_clk 0>,
> +				 <&mmc0_clk 1>,
> +				 <&mmc0_clk 2>;
> +			clock-names = "ahb",
> +				      "mmc",
> +				      "output",
> +				      "sample";
> +			interrupts = <32>;
> +			status = "disabled";
> +			#address-cells = <1>;
> +			#size-cells = <0>;
> +		};
> +
> +		mmc1: mmc at 01c10000 {
> +			compatible = "allwinner,sun5i-a13-mmc";
> +			reg = <0x01c10000 0x1000>;
> +			clocks = <&ahb_gates 9>,
> +				 <&mmc1_clk 0>,
> +				 <&mmc1_clk 1>,
> +				 <&mmc1_clk 2>;
> +			clock-names = "ahb",
> +				      "mmc",
> +				      "output",
> +				      "sample";
> +			interrupts = <33>;
> +			status = "disabled";
> +			#address-cells = <1>;
> +			#size-cells = <0>;
> +		};
> +
> +		mmc2: mmc at 01c11000 {
> +			compatible = "allwinner,sun5i-a13-mmc";
> +			reg = <0x01c11000 0x1000>;
> +			clocks = <&ahb_gates 10>,
> +				 <&mmc2_clk 0>,
> +				 <&mmc2_clk 1>,
> +				 <&mmc2_clk 2>;
> +			clock-names = "ahb",
> +				      "mmc",
> +				      "output",
> +				      "sample";
> +			interrupts = <34>;
> +			status = "disabled";
> +			#address-cells = <1>;
> +			#size-cells = <0>;
> +		};
> +
> +		usb_otg: usb at 01c13000 {
> +			compatible = "allwinner,sun4i-a10-musb";
> +			reg = <0x01c13000 0x0400>;
> +			clocks = <&ahb_gates 0>;
> +			interrupts = <38>;
> +			interrupt-names = "mc";
> +			phys = <&usbphy 0>;
> +			phy-names = "usb";
> +			extcon = <&usbphy 0>;
> +			allwinner,sram = <&otg_sram 1>;
> +			status = "disabled";
> +
> +			dr_mode = "otg";
> +		};
> +
> +		usbphy: phy at 01c13400 {
> +			#phy-cells = <1>;
> +			compatible = "allwinner,sun5i-a13-usb-phy";
> +			reg = <0x01c13400 0x10 0x01c14800 0x4>;
> +			reg-names = "phy_ctrl", "pmu1";
> +			clocks = <&usb_clk 8>;
> +			clock-names = "usb_phy";
> +			resets = <&usb_clk 0>, <&usb_clk 1>;
> +			reset-names = "usb0_reset", "usb1_reset";
> +			status = "disabled";
> +		};
> +
> +		ehci0: usb at 01c14000 {
> +			compatible = "allwinner,sun5i-a13-ehci", "generic-ehci";
> +			reg = <0x01c14000 0x100>;
> +			interrupts = <39>;
> +			clocks = <&ahb_gates 1>;
> +			phys = <&usbphy 1>;
> +			phy-names = "usb";
> +			status = "disabled";
> +		};
> +
> +		ohci0: usb at 01c14400 {
> +			compatible = "allwinner,sun5i-a13-ohci", "generic-ohci";
> +			reg = <0x01c14400 0x100>;
> +			interrupts = <40>;
> +			clocks = <&usb_clk 6>, <&ahb_gates 2>;
> +			phys = <&usbphy 1>;
> +			phy-names = "usb";
> +			status = "disabled";
> +		};
> +
> +		spi2: spi at 01c17000 {
> +			compatible = "allwinner,sun4i-a10-spi";
> +			reg = <0x01c17000 0x1000>;
> +			interrupts = <12>;
> +			clocks = <&ahb_gates 22>, <&spi2_clk>;
> +			clock-names = "ahb", "mod";
> +			dmas = <&dma SUN4I_DMA_DEDICATED 29>,
> +			       <&dma SUN4I_DMA_DEDICATED 28>;
> +			dma-names = "rx", "tx";
> +			status = "disabled";
> +			#address-cells = <1>;
> +			#size-cells = <0>;
> +		};
> +
> +		intc: interrupt-controller at 01c20400 {
> +			compatible = "allwinner,sun4i-a10-ic";
> +			reg = <0x01c20400 0x400>;
> +			interrupt-controller;
> +			#interrupt-cells = <1>;
> +		};
> +
> +		pio: pinctrl at 01c20800 {
> +			compatible = "nextthing,gr8-pinctrl";
> +			reg = <0x01c20800 0x400>;
> +			interrupts = <28>;
> +			clocks = <&apb0_gates 5>;
> +			gpio-controller;
> +			interrupt-controller;
> +			#interrupt-cells = <3>;
> +			#gpio-cells = <3>;
> +
> +			i2c0_pins_a: i2c0 at 0 {
> +				allwinner,pins = "PB0", "PB1";
> +				allwinner,function = "i2c0";
> +				allwinner,drive = <SUN4I_PINCTRL_10_MA>;
> +				allwinner,pull = <SUN4I_PINCTRL_NO_PULL>;
> +			};
> +
> +			i2c1_pins_a: i2c1 at 0 {
> +				allwinner,pins = "PB15", "PB16";
> +				allwinner,function = "i2c1";
> +				allwinner,drive = <SUN4I_PINCTRL_10_MA>;
> +				allwinner,pull = <SUN4I_PINCTRL_NO_PULL>;
> +			};
> +
> +			i2c2_pins_a: i2c2 at 0 {
> +				allwinner,pins = "PB17", "PB18";
> +				allwinner,function = "i2c2";
> +				allwinner,drive = <SUN4I_PINCTRL_10_MA>;
> +				allwinner,pull = <SUN4I_PINCTRL_NO_PULL>;
> +			};
> +
> +			i2s0_data_pins_a: i2s0-data at 0 {
> +				allwinner,pins = "PB6", "PB7", "PB8", "PB9";
> +				allwinner,function = "i2s0";
> +				allwinner,drive = <SUN4I_PINCTRL_10_MA>;
> +				allwinner,pull = <SUN4I_PINCTRL_NO_PULL>;
> +			};
> +
> +			i2s0_mclk_pins_a: i2s0-mclk at 0 {
> +				allwinner,pins = "PB5";
> +				allwinner,function = "i2s0";
> +				allwinner,drive = <SUN4I_PINCTRL_10_MA>;
> +				allwinner,pull = <SUN4I_PINCTRL_NO_PULL>;
> +			};
> +
> +			ir0_rx_pins_a: ir0 at 0 {
> +				allwinner,pins = "PB4";
> +				allwinner,function = "ir0";
> +				allwinner,drive = <SUN4I_PINCTRL_10_MA>;
> +				allwinner,pull = <SUN4I_PINCTRL_NO_PULL>;
> +			};
> +
> +			lcd_rgb666_pins: lcd-rgb666 at 0 {
> +				allwinner,pins = "PD2", "PD3", "PD4", "PD5", "PD6", "PD7",
> +						 "PD10", "PD11", "PD12", "PD13", "PD14", "PD15",
> +						 "PD18", "PD19", "PD20", "PD21", "PD22", "PD23",
> +						 "PD24", "PD25", "PD26", "PD27";
> +				allwinner,function = "lcd0";
> +				allwinner,drive = <SUN4I_PINCTRL_10_MA>;
> +				allwinner,pull = <SUN4I_PINCTRL_NO_PULL>;
> +			};
> +
> +			mmc0_pins_a: mmc0 at 0 {
> +				allwinner,pins = "PF0", "PF1", "PF2", "PF3",
> +						 "PF4", "PF5";
> +				allwinner,function = "mmc0";
> +				allwinner,drive = <SUN4I_PINCTRL_30_MA>;
> +				allwinner,pull = <SUN4I_PINCTRL_NO_PULL>;
> +			};
> +
> +			nand_pins_a: nand-base0 at 0 {
> +				allwinner,pins = "PC0", "PC1", "PC2",
> +						"PC5", "PC8", "PC9", "PC10",
> +						"PC11", "PC12", "PC13", "PC14",
> +						"PC15";
> +				allwinner,function = "nand0";
> +				allwinner,drive = <SUN4I_PINCTRL_10_MA>;
> +				allwinner,pull = <SUN4I_PINCTRL_NO_PULL>;
> +			};
> +
> +			nand_cs0_pins_a: nand-cs at 0 {
> +				allwinner,pins = "PC4";
> +				allwinner,function = "nand0";
> +				allwinner,drive = <SUN4I_PINCTRL_10_MA>;
> +				allwinner,pull = <SUN4I_PINCTRL_NO_PULL>;
> +			};
> +
> +			nand_rb0_pins_a: nand-rb at 0 {
> +				allwinner,pins = "PC6";
> +				allwinner,function = "nand0";
> +				allwinner,drive = <SUN4I_PINCTRL_10_MA>;
> +				allwinner,pull = <SUN4I_PINCTRL_NO_PULL>;
> +			};
> +
> +			pwm0_pins_a: pwm0 at 0 {
> +				allwinner,pins = "PB2";
> +				allwinner,function = "pwm0";
> +				allwinner,drive = <SUN4I_PINCTRL_10_MA>;
> +				allwinner,pull = <SUN4I_PINCTRL_NO_PULL>;
> +			};
> +
> +			pwm1_pins: pwm1 {
> +				allwinner,pins = "PG13";
> +				allwinner,function = "pwm1";
> +				allwinner,drive = <SUN4I_PINCTRL_10_MA>;
> +				allwinner,pull = <SUN4I_PINCTRL_NO_PULL>;
> +			};
> +
> +			spdif_tx_pins_a: spdif at 0 {
> +				allwinner,pins = "PB10";
> +				allwinner,function = "spdif";
> +				allwinner,drive = <SUN4I_PINCTRL_10_MA>;
> +				allwinner,pull = <SUN4I_PINCTRL_PULL_UP>;
> +			};
> +
> +			uart1_pins_a: uart1 at 1 {
> +				allwinner,pins = "PG3", "PG4";
> +				allwinner,function = "uart1";
> +				allwinner,drive = <SUN4I_PINCTRL_10_MA>;
> +				allwinner,pull = <SUN4I_PINCTRL_NO_PULL>;
> +			};
> +
> +			uart1_cts_rts_pins_a: uart1-cts-rts at 0 {
> +				allwinner,pins = "PG5", "PG6";
> +				allwinner,function = "uart1";
> +				allwinner,drive = <SUN4I_PINCTRL_10_MA>;
> +				allwinner,pull = <SUN4I_PINCTRL_NO_PULL>;
> +			};
> +
> +			uart2_pins_a: uart2 at 1 {
> +				allwinner,pins = "PD2", "PD3";
> +				allwinner,function = "uart2";
> +				allwinner,drive = <SUN4I_PINCTRL_10_MA>;
> +				allwinner,pull = <SUN4I_PINCTRL_NO_PULL>;
> +			};
> +
> +			uart2_cts_rts_pins_a: uart2-cts-rts at 0 {
> +				allwinner,pins = "PD4", "PD5";
> +				allwinner,function = "uart2";
> +				allwinner,drive = <SUN4I_PINCTRL_10_MA>;
> +				allwinner,pull = <SUN4I_PINCTRL_NO_PULL>;
> +			};
> +
> +			uart3_pins_a: uart3 at 1 {
> +				allwinner,pins = "PG9", "PG10";
> +				allwinner,function = "uart3";
> +				allwinner,drive = <SUN4I_PINCTRL_10_MA>;
> +				allwinner,pull = <SUN4I_PINCTRL_NO_PULL>;
> +			};
> +
> +			uart3_cts_rts_pins_a: uart3-cts-rts at 0 {
> +				allwinner,pins = "PG11", "PG12";
> +				allwinner,function = "uart3";
> +				allwinner,drive = <SUN4I_PINCTRL_10_MA>;
> +				allwinner,pull = <SUN4I_PINCTRL_NO_PULL>;
> +			};
> +		};
> +
> +		pwm: pwm at 01c20e00 {
> +			compatible = "allwinner,sun5i-a10s-pwm";
> +			reg = <0x01c20e00 0xc>;
> +			clocks = <&osc24M>;
> +			#pwm-cells = <3>;
> +			status = "disabled";
> +		};
> +
> +		timer at 01c20c00 {
> +			compatible = "allwinner,sun4i-a10-timer";
> +			reg = <0x01c20c00 0x90>;
> +			interrupts = <22>;
> +			clocks = <&osc24M>;
> +		};
> +
> +		wdt: watchdog at 01c20c90 {
> +			compatible = "allwinner,sun4i-a10-wdt";
> +			reg = <0x01c20c90 0x10>;
> +		};
> +
> +		spdif: spdif at 01c21000 {
> +			#sound-dai-cells = <0>;
> +			compatible = "allwinner,sun4i-a10-spdif";
> +			reg = <0x01c21000 0x400>;
> +			interrupts = <13>;
> +			clocks = <&apb0_gates 1>, <&spdif_clk>;
> +			clock-names = "apb", "spdif";
> +			dmas = <&dma SUN4I_DMA_NORMAL 2>,
> +			       <&dma SUN4I_DMA_NORMAL 2>;
> +			dma-names = "rx", "tx";
> +			status = "disabled";
> +		};
> +
> +		ir0: ir at 01c21800 {
> +			compatible = "allwinner,sun4i-a10-ir";
> +			clocks = <&apb0_gates 6>, <&ir0_clk>;
> +			clock-names = "apb", "ir";
> +			interrupts = <5>;
> +			reg = <0x01c21800 0x40>;
> +			status = "disabled";
> +		};
> +
> +		i2s0: i2s at 01c22400 {
> +			#sound-dai-cells = <0>;
> +			compatible = "allwinner,sun4i-a10-i2s";
> +			reg = <0x01c22400 0x400>;
> +			interrupts = <16>;
> +			clocks = <&apb0_gates 3>, <&i2s0_clk>;
> +			clock-names = "apb", "mod";
> +			dmas = <&dma SUN4I_DMA_NORMAL 3>,
> +			       <&dma SUN4I_DMA_NORMAL 3>;
> +			dma-names = "rx", "tx";
> +			status = "disabled";
> +		};
> +
> +		lradc: lradc at 01c22800 {
> +			compatible = "allwinner,sun4i-a10-lradc-keys";
> +			reg = <0x01c22800 0x100>;
> +			interrupts = <31>;
> +			status = "disabled";
> +		};
> +
> +		codec: codec at 01c22c00 {
> +			#sound-dai-cells = <0>;
> +			compatible = "allwinner,sun4i-a10-codec";
> +			reg = <0x01c22c00 0x40>;
> +			interrupts = <30>;
> +			clocks = <&apb0_gates 0>, <&codec_clk>;
> +			clock-names = "apb", "codec";
> +			dmas = <&dma SUN4I_DMA_NORMAL 19>,
> +			       <&dma SUN4I_DMA_NORMAL 19>;
> +			dma-names = "rx", "tx";
> +			status = "disabled";
> +		};
> +
> +		rtp: rtp at 01c25000 {
> +			compatible = "allwinner,sun5i-a13-ts";
> +			reg = <0x01c25000 0x100>;
> +			interrupts = <29>;
> +			#thermal-sensor-cells = <0>;
> +		};
> +
> +		uart1: serial at 01c28400 {
> +			compatible = "snps,dw-apb-uart";
> +			reg = <0x01c28400 0x400>;
> +			interrupts = <2>;
> +			reg-shift = <2>;
> +			reg-io-width = <4>;
> +			clocks = <&apb1_gates 17>;
> +			status = "disabled";
> +		};
> +
> +		uart2: serial at 01c28800 {
> +			compatible = "snps,dw-apb-uart";
> +			reg = <0x01c28800 0x400>;
> +			interrupts = <3>;
> +			reg-shift = <2>;
> +			reg-io-width = <4>;
> +			clocks = <&apb1_gates 18>;
> +			status = "disabled";
> +		};
> +
> +		uart3: serial at 01c28c00 {
> +			compatible = "snps,dw-apb-uart";
> +			reg = <0x01c28c00 0x400>;
> +			interrupts = <4>;
> +			reg-shift = <2>;
> +			reg-io-width = <4>;
> +			clocks = <&apb1_gates 19>;
> +			status = "disabled";
> +		};
> +
> +		i2c0: i2c at 01c2ac00 {
> +			compatible = "allwinner,sun4i-a10-i2c";
> +			reg = <0x01c2ac00 0x400>;
> +			interrupts = <7>;
> +			clocks = <&apb1_gates 0>;
> +			status = "disabled";
> +			#address-cells = <1>;
> +			#size-cells = <0>;
> +		};
> +
> +		i2c1: i2c at 01c2b000 {
> +			compatible = "allwinner,sun4i-a10-i2c";
> +			reg = <0x01c2b000 0x400>;
> +			interrupts = <8>;
> +			clocks = <&apb1_gates 1>;
> +			status = "disabled";
> +			#address-cells = <1>;
> +			#size-cells = <0>;
> +		};
> +
> +		i2c2: i2c at 01c2b400 {
> +			compatible = "allwinner,sun4i-a10-i2c";
> +			reg = <0x01c2b400 0x400>;
> +			interrupts = <9>;
> +			clocks = <&apb1_gates 2>;
> +			status = "disabled";
> +			#address-cells = <1>;
> +			#size-cells = <0>;
> +		};
> +
> +		timer at 01c60000 {
> +			compatible = "allwinner,sun5i-a13-hstimer";
> +			reg = <0x01c60000 0x1000>;
> +			interrupts = <82>, <83>;
> +			clocks = <&ahb_gates 28>;
> +		};
> +
> +		fe0: display-frontend at 01e00000 {
> +			compatible = "allwinner,sun5i-a13-display-frontend";
> +			reg = <0x01e00000 0x20000>;
> +			interrupts = <47>;
> +			clocks = <&ahb_gates 46>, <&de_fe_clk>,
> +				 <&dram_gates 25>;
> +			clock-names = "ahb", "mod",
> +				      "ram";
> +			resets = <&de_fe_clk>;
> +			status = "disabled";
> +
> +			ports {
> +				#address-cells = <1>;
> +				#size-cells = <0>;
> +
> +				fe0_out: port at 1 {
> +					#address-cells = <1>;
> +					#size-cells = <0>;
> +					reg = <1>;
> +
> +					fe0_out_be0: endpoint at 0 {
> +						reg = <0>;
> +						remote-endpoint = <&be0_in_fe0>;
> +					};
> +				};
> +			};
> +		};
> +
> +		be0: display-backend at 01e60000 {
> +			compatible = "allwinner,sun5i-a13-display-backend";
> +			reg = <0x01e60000 0x10000>;
> +			clocks = <&ahb_gates 44>, <&de_be_clk>,
> +				 <&dram_gates 26>;
> +			clock-names = "ahb", "mod",
> +				      "ram";
> +			resets = <&de_be_clk>;
> +			status = "disabled";
> +
> +			assigned-clocks = <&de_be_clk>;
> +			assigned-clock-rates = <300000000>;
> +
> +			ports {
> +				#address-cells = <1>;
> +				#size-cells = <0>;
> +
> +				be0_in: port at 0 {
> +					#address-cells = <1>;
> +					#size-cells = <0>;
> +					reg = <0>;
> +
> +					be0_in_fe0: endpoint at 0 {
> +						reg = <0>;
> +						remote-endpoint = <&fe0_out_be0>;
> +					};
> +				};
> +
> +				be0_out: port at 1 {
> +					#address-cells = <1>;
> +					#size-cells = <0>;
> +					reg = <1>;
> +
> +					be0_out_tcon0: endpoint at 0 {
> +						reg = <0>;
> +						remote-endpoint = <&tcon0_in_be0>;
> +					};
> +				};
> +			};
> +		};
> +	};
> +};
>

^ permalink raw reply	[flat|nested] 44+ messages in thread

* [U-Boot] [PATCH 2/7] mtd: nand: add support for the TC58NVG2S0H chip
  2016-11-08 16:21 ` [U-Boot] [PATCH 2/7] mtd: nand: add support for the TC58NVG2S0H chip Maxime Ripard
@ 2016-11-14 11:15   ` Hans de Goede
  2016-11-15  5:04   ` Scott Wood
  1 sibling, 0 replies; 44+ messages in thread
From: Hans de Goede @ 2016-11-14 11:15 UTC (permalink / raw)
  To: u-boot

Hi,

On 08-11-16 17:21, Maxime Ripard wrote:
> From: Boris Brezillon <boris.brezillon@free-electrons.com>
>
> Add the description of the Toshiba TC58NVG2S0H SLC nand to the nand_ids
> table so we can use the NAND ECC infos and the ONFI timings.
>
> Signed-off-by: Boris Brezillon <boris.brezillon@free-electrons.com>
> Signed-off-by: Maxime Ripard <maxime.ripard@free-electrons.com>

Looks good to me:

Reviewed-by: Hans de Goede <hdegoede@redhat.com>

Regards,

Hans



> ---
>  drivers/mtd/nand/nand_ids.c | 3 +++
>  1 file changed, 3 insertions(+), 0 deletions(-)
>
> diff --git a/drivers/mtd/nand/nand_ids.c b/drivers/mtd/nand/nand_ids.c
> index ce0a14e28abb..d36f9006c99d 100644
> --- a/drivers/mtd/nand/nand_ids.c
> +++ b/drivers/mtd/nand/nand_ids.c
> @@ -46,6 +46,9 @@ struct nand_flash_dev nand_flash_ids[] = {
>  	{"TC58NVG2S0F 4G 3.3V 8-bit",
>  		{ .id = {0x98, 0xdc, 0x90, 0x26, 0x76, 0x15, 0x01, 0x08} },
>  		  SZ_4K, SZ_512, SZ_256K, 0, 8, 224, NAND_ECC_INFO(4, SZ_512) },
> +	{"TC58NVG2S0H 4G 3.3V 8-bit",
> +		{ .id = {0x98, 0xdc, 0x90, 0x26, 0x76, 0x16, 0x08, 0x00} },
> +		  SZ_4K, SZ_512, SZ_256K, 0, 8, 256, NAND_ECC_INFO(8, SZ_512) },
>  	{"TC58NVG3S0F 8G 3.3V 8-bit",
>  		{ .id = {0x98, 0xd3, 0x90, 0x26, 0x76, 0x15, 0x02, 0x08} },
>  		  SZ_4K, SZ_1K, SZ_256K, 0, 8, 232, NAND_ECC_INFO(4, SZ_512) },
>

^ permalink raw reply	[flat|nested] 44+ messages in thread

* [U-Boot] [PATCH 3/7] sunxi: Enable UBI and NAND support
  2016-11-08 16:21 ` [U-Boot] [PATCH 3/7] sunxi: Enable UBI and NAND support Maxime Ripard
  2016-11-08 16:27   ` Boris Brezillon
  2016-11-08 16:27   ` Boris Brezillon
@ 2016-11-14 11:18   ` Hans de Goede
  2016-11-14 14:09     ` Maxime Ripard
  2016-11-14 14:12     ` Maxime Ripard
  2 siblings, 2 replies; 44+ messages in thread
From: Hans de Goede @ 2016-11-14 11:18 UTC (permalink / raw)
  To: u-boot

Hi,

On 08-11-16 17:21, Maxime Ripard wrote:
> From: Hans de Goede <hdegoede@redhat.com>
>
> Enable the NAND and UBI support in the configuration header so that we can
> (finally) use it.
>
> Signed-off-by: Hans de Goede <hdegoede@redhat.com>
> Signed-off-by: Maxime Ripard <maxime.ripard@free-electrons.com>
> ---
>  include/configs/sunxi-common.h | 26 ++++++++++++++++++++++----
>  1 file changed, 22 insertions(+), 4 deletions(-)
>
> diff --git a/include/configs/sunxi-common.h b/include/configs/sunxi-common.h
> index 8363414828fa..1733767ba53b 100644
> --- a/include/configs/sunxi-common.h
> +++ b/include/configs/sunxi-common.h
> @@ -129,9 +129,23 @@
>  #define CONFIG_SERIAL_TAG
>
>  #ifdef CONFIG_NAND_SUNXI
> +#define CONFIG_SYS_NAND_U_BOOT_OFFS	(8 << 20) /* 8 MiB */

As Boris already said, please put this in Kconfig.

>  #define CONFIG_SYS_NAND_MAX_ECCPOS 1664
>  #define CONFIG_SYS_NAND_ONFI_DETECTION
>  #define CONFIG_SYS_MAX_NAND_DEVICE 8
> +
> +/* Requirements for UBI */
> +#define CONFIG_RBTREE
> +#define CONFIG_LZO
> +#define CONFIG_CMD_MTDPARTS
> +#define CONFIG_CMD_UBI
> +#define CONFIG_CMD_UBIFS
> +#define CONFIG_MTD_DEVICE
> +
> +#define CONFIG_MTD_PARTITIONS
> +
> +#define CONFIG_CMD_NAND
> +#define CONFIG_CMD_NAND_TRIMFFS
>  #endif
>
>  #ifdef CONFIG_SPL_SPI_SUNXI
> @@ -143,7 +157,14 @@
>  #define CONFIG_GENERIC_MMC
>  #define CONFIG_MMC_SUNXI
>  #define CONFIG_MMC_SUNXI_SLOT		0
> -#define CONFIG_ENV_IS_IN_MMC
> +#endif
> +
> +#if defined(CONFIG_ENV_IS_IN_NAND)
> +#define CONFIG_ENV_OFFSET			0xc00000
> +#define CONFIG_ENV_SIZE				0x400000
> +#elif defined(CONFIG_ENV_IS_IN_MMC)
> +#define CONFIG_ENV_OFFSET			(544 << 10) /* (8 + 24 + 512) KiB */
> +#define CONFIG_ENV_SIZE				(128 << 10) /* 128 KiB */
>  #define CONFIG_SYS_MMC_ENV_DEV		0	/* first detected MMC controller */
>  #endif
>

I would greatly prefer putting the env in an UBI partition,
I thought that we had agreed on doing that ?

Regards,

Hans



> @@ -175,9 +196,6 @@
>
>  #define CONFIG_SYS_MONITOR_LEN		(768 << 10)	/* 768 KiB */
>
> -#define CONFIG_ENV_OFFSET		(544 << 10) /* (8 + 24 + 512) KiB */
> -#define CONFIG_ENV_SIZE			(128 << 10)	/* 128 KiB */
> -
>  #define CONFIG_FAT_WRITE	/* enable write access */
>
>  #define CONFIG_SPL_FRAMEWORK
>

^ permalink raw reply	[flat|nested] 44+ messages in thread

* [U-Boot] [PATCH 4/7] tools: sunxi: Add spl image builder
  2016-11-08 16:21 ` [U-Boot] [PATCH 4/7] tools: sunxi: Add spl image builder Maxime Ripard
  2016-11-08 16:29   ` Boris Brezillon
  2016-11-11 16:20   ` Tom Rini
@ 2016-11-14 11:18   ` Hans de Goede
  2016-11-14 11:29     ` Hans de Goede
  2 siblings, 1 reply; 44+ messages in thread
From: Hans de Goede @ 2016-11-14 11:18 UTC (permalink / raw)
  To: u-boot

Hi,

On 08-11-16 17:21, Maxime Ripard wrote:
> This program generates raw SPL images that can be flashed on the NAND with
> the ECC and randomizer properly set up.
>
> Signed-off-by: Maxime Ripard <maxime.ripard@free-electrons.com>

Looks good to me:

Reviewed-by: Hans de Goede <hdegoede@redhat.com>

Regards,

Hans



> ---
>  tools/.gitignore                |    1 +-
>  tools/Makefile                  |    1 +-
>  tools/sunxi-spl-image-builder.c | 1113 ++++++++++++++++++++++++++++++++-
>  3 files changed, 1115 insertions(+), 0 deletions(-)
>  create mode 100644 tools/sunxi-spl-image-builder.c
>
> diff --git a/tools/.gitignore b/tools/.gitignore
> index cb1e722d4575..16574467544c 100644
> --- a/tools/.gitignore
> +++ b/tools/.gitignore
> @@ -15,6 +15,7 @@
>  /mkexynosspl
>  /mxsboot
>  /mksunxiboot
> +/sunxi-spl-image-builder
>  /ncb
>  /proftool
>  /relocate-rela
> diff --git a/tools/Makefile b/tools/Makefile
> index 400588cf0f5c..dfeeb23484ce 100644
> --- a/tools/Makefile
> +++ b/tools/Makefile
> @@ -171,6 +171,7 @@ hostprogs-$(CONFIG_MX28) += mxsboot
>  HOSTCFLAGS_mxsboot.o := -pedantic
>
>  hostprogs-$(CONFIG_ARCH_SUNXI) += mksunxiboot
> +hostprogs-$(CONFIG_ARCH_SUNXI) += sunxi-spl-image-builder
>
>  hostprogs-$(CONFIG_NETCONSOLE) += ncb
>  hostprogs-$(CONFIG_SHA1_CHECK_UB_IMG) += ubsha1
> diff --git a/tools/sunxi-spl-image-builder.c b/tools/sunxi-spl-image-builder.c
> new file mode 100644
> index 000000000000..0f915eb2bdf5
> --- /dev/null
> +++ b/tools/sunxi-spl-image-builder.c
> @@ -0,0 +1,1113 @@
> +/*
> + * Generic binary BCH encoding/decoding library
> + *
> + * This program is free software; you can redistribute it and/or modify it
> + * under the terms of the GNU General Public License version 2 as published by
> + * the Free Software Foundation.
> + *
> + * This program is distributed in the hope that it will be useful, but WITHOUT
> + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
> + * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
> + * more details.
> + *
> + * You should have received a copy of the GNU General Public License along with
> + * this program; if not, write to the Free Software Foundation, Inc., 51
> + * Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
> + *
> + * For the BCH implementation:
> + *
> + * Copyright ? 2011 Parrot S.A.
> + *
> + * Author: Ivan Djelic <ivan.djelic@parrot.com>
> + *
> + * See also:
> + * http://lxr.free-electrons.com/source/lib/bch.c
> + *
> + * For the randomizer and image builder implementation:
> + *
> + * Copyright ? 2016 NextThing Co.
> + * Copyright ? 2016 Free Electrons
> + *
> + * Author: Boris Brezillon <boris.brezillon@free-electrons.com>
> + *
> + */
> +
> +#include <stdint.h>
> +#include <stdlib.h>
> +#include <string.h>
> +#include <stdio.h>
> +#include <linux/kernel.h>
> +#include <linux/errno.h>
> +#include <asm/byteorder.h>
> +#include <endian.h>
> +#include <getopt.h>
> +#include <version.h>
> +
> +#if defined(CONFIG_BCH_CONST_PARAMS)
> +#define GF_M(_p)               (CONFIG_BCH_CONST_M)
> +#define GF_T(_p)               (CONFIG_BCH_CONST_T)
> +#define GF_N(_p)               ((1 << (CONFIG_BCH_CONST_M))-1)
> +#else
> +#define GF_M(_p)               ((_p)->m)
> +#define GF_T(_p)               ((_p)->t)
> +#define GF_N(_p)               ((_p)->n)
> +#endif
> +
> +#define DIV_ROUND_UP(n,d) (((n) + (d) - 1) / (d))
> +
> +#define BCH_ECC_WORDS(_p)      DIV_ROUND_UP(GF_M(_p)*GF_T(_p), 32)
> +#define BCH_ECC_BYTES(_p)      DIV_ROUND_UP(GF_M(_p)*GF_T(_p), 8)
> +
> +#ifndef dbg
> +#define dbg(_fmt, args...)     do {} while (0)
> +#endif
> +
> +#define cpu_to_be32 htobe32
> +#define kfree free
> +#define ARRAY_SIZE(arr) (sizeof(arr) / sizeof((arr)[0]))
> +
> +#define BCH_PRIMITIVE_POLY	0x5803
> +
> +struct image_info {
> +	int ecc_strength;
> +	int ecc_step_size;
> +	int page_size;
> +	int oob_size;
> +	int usable_page_size;
> +	int eraseblock_size;
> +	int scramble;
> +	int boot0;
> +	off_t offset;
> +	const char *source;
> +	const char *dest;
> +};
> +
> +/**
> + * struct bch_control - BCH control structure
> + * @m:          Galois field order
> + * @n:          maximum codeword size in bits (= 2^m-1)
> + * @t:          error correction capability in bits
> + * @ecc_bits:   ecc exact size in bits, i.e. generator polynomial degree (<=m*t)
> + * @ecc_bytes:  ecc max size (m*t bits) in bytes
> + * @a_pow_tab:  Galois field GF(2^m) exponentiation lookup table
> + * @a_log_tab:  Galois field GF(2^m) log lookup table
> + * @mod8_tab:   remainder generator polynomial lookup tables
> + * @ecc_buf:    ecc parity words buffer
> + * @ecc_buf2:   ecc parity words buffer
> + * @xi_tab:     GF(2^m) base for solving degree 2 polynomial roots
> + * @syn:        syndrome buffer
> + * @cache:      log-based polynomial representation buffer
> + * @elp:        error locator polynomial
> + * @poly_2t:    temporary polynomials of degree 2t
> + */
> +struct bch_control {
> +	unsigned int    m;
> +	unsigned int    n;
> +	unsigned int    t;
> +	unsigned int    ecc_bits;
> +	unsigned int    ecc_bytes;
> +/* private: */
> +	uint16_t       *a_pow_tab;
> +	uint16_t       *a_log_tab;
> +	uint32_t       *mod8_tab;
> +	uint32_t       *ecc_buf;
> +	uint32_t       *ecc_buf2;
> +	unsigned int   *xi_tab;
> +	unsigned int   *syn;
> +	int            *cache;
> +	struct gf_poly *elp;
> +	struct gf_poly *poly_2t[4];
> +};
> +
> +static int fls(int x)
> +{
> +	int r = 32;
> +
> +	if (!x)
> +		return 0;
> +	if (!(x & 0xffff0000u)) {
> +		x <<= 16;
> +		r -= 16;
> +	}
> +	if (!(x & 0xff000000u)) {
> +		x <<= 8;
> +		r -= 8;
> +	}
> +	if (!(x & 0xf0000000u)) {
> +		x <<= 4;
> +		r -= 4;
> +	}
> +	if (!(x & 0xc0000000u)) {
> +		x <<= 2;
> +		r -= 2;
> +	}
> +	if (!(x & 0x80000000u)) {
> +		x <<= 1;
> +		r -= 1;
> +	}
> +	return r;
> +}
> +
> +/*
> + * represent a polynomial over GF(2^m)
> + */
> +struct gf_poly {
> +	unsigned int deg;    /* polynomial degree */
> +	unsigned int c[0];   /* polynomial terms */
> +};
> +
> +/* given its degree, compute a polynomial size in bytes */
> +#define GF_POLY_SZ(_d) (sizeof(struct gf_poly)+((_d)+1)*sizeof(unsigned int))
> +
> +/* polynomial of degree 1 */
> +struct gf_poly_deg1 {
> +	struct gf_poly poly;
> +	unsigned int   c[2];
> +};
> +
> +/*
> + * same as encode_bch(), but process input data one byte at a time
> + */
> +static void encode_bch_unaligned(struct bch_control *bch,
> +				 const unsigned char *data, unsigned int len,
> +				 uint32_t *ecc)
> +{
> +	int i;
> +	const uint32_t *p;
> +	const int l = BCH_ECC_WORDS(bch)-1;
> +
> +	while (len--) {
> +		p = bch->mod8_tab + (l+1)*(((ecc[0] >> 24)^(*data++)) & 0xff);
> +
> +		for (i = 0; i < l; i++)
> +			ecc[i] = ((ecc[i] << 8)|(ecc[i+1] >> 24))^(*p++);
> +
> +		ecc[l] = (ecc[l] << 8)^(*p);
> +	}
> +}
> +
> +/*
> + * convert ecc bytes to aligned, zero-padded 32-bit ecc words
> + */
> +static void load_ecc8(struct bch_control *bch, uint32_t *dst,
> +		      const uint8_t *src)
> +{
> +	uint8_t pad[4] = {0, 0, 0, 0};
> +	unsigned int i, nwords = BCH_ECC_WORDS(bch)-1;
> +
> +	for (i = 0; i < nwords; i++, src += 4)
> +		dst[i] = (src[0] << 24)|(src[1] << 16)|(src[2] << 8)|src[3];
> +
> +	memcpy(pad, src, BCH_ECC_BYTES(bch)-4*nwords);
> +	dst[nwords] = (pad[0] << 24)|(pad[1] << 16)|(pad[2] << 8)|pad[3];
> +}
> +
> +/*
> + * convert 32-bit ecc words to ecc bytes
> + */
> +static void store_ecc8(struct bch_control *bch, uint8_t *dst,
> +		       const uint32_t *src)
> +{
> +	uint8_t pad[4];
> +	unsigned int i, nwords = BCH_ECC_WORDS(bch)-1;
> +
> +	for (i = 0; i < nwords; i++) {
> +		*dst++ = (src[i] >> 24);
> +		*dst++ = (src[i] >> 16) & 0xff;
> +		*dst++ = (src[i] >>  8) & 0xff;
> +		*dst++ = (src[i] >>  0) & 0xff;
> +	}
> +	pad[0] = (src[nwords] >> 24);
> +	pad[1] = (src[nwords] >> 16) & 0xff;
> +	pad[2] = (src[nwords] >>  8) & 0xff;
> +	pad[3] = (src[nwords] >>  0) & 0xff;
> +	memcpy(dst, pad, BCH_ECC_BYTES(bch)-4*nwords);
> +}
> +
> +/**
> + * encode_bch - calculate BCH ecc parity of data
> + * @bch:   BCH control structure
> + * @data:  data to encode
> + * @len:   data length in bytes
> + * @ecc:   ecc parity data, must be initialized by caller
> + *
> + * The @ecc parity array is used both as input and output parameter, in order to
> + * allow incremental computations. It should be of the size indicated by member
> + * @ecc_bytes of @bch, and should be initialized to 0 before the first call.
> + *
> + * The exact number of computed ecc parity bits is given by member @ecc_bits of
> + * @bch; it may be less than m*t for large values of t.
> + */
> +static void encode_bch(struct bch_control *bch, const uint8_t *data,
> +		unsigned int len, uint8_t *ecc)
> +{
> +	const unsigned int l = BCH_ECC_WORDS(bch)-1;
> +	unsigned int i, mlen;
> +	unsigned long m;
> +	uint32_t w, r[l+1];
> +	const uint32_t * const tab0 = bch->mod8_tab;
> +	const uint32_t * const tab1 = tab0 + 256*(l+1);
> +	const uint32_t * const tab2 = tab1 + 256*(l+1);
> +	const uint32_t * const tab3 = tab2 + 256*(l+1);
> +	const uint32_t *pdata, *p0, *p1, *p2, *p3;
> +
> +	if (ecc) {
> +		/* load ecc parity bytes into internal 32-bit buffer */
> +		load_ecc8(bch, bch->ecc_buf, ecc);
> +	} else {
> +		memset(bch->ecc_buf, 0, sizeof(r));
> +	}
> +
> +	/* process first unaligned data bytes */
> +	m = ((uintptr_t)data) & 3;
> +	if (m) {
> +		mlen = (len < (4-m)) ? len : 4-m;
> +		encode_bch_unaligned(bch, data, mlen, bch->ecc_buf);
> +		data += mlen;
> +		len  -= mlen;
> +	}
> +
> +	/* process 32-bit aligned data words */
> +	pdata = (uint32_t *)data;
> +	mlen  = len/4;
> +	data += 4*mlen;
> +	len  -= 4*mlen;
> +	memcpy(r, bch->ecc_buf, sizeof(r));
> +
> +	/*
> +	 * split each 32-bit word into 4 polynomials of weight 8 as follows:
> +	 *
> +	 * 31 ...24  23 ...16  15 ... 8  7 ... 0
> +	 * xxxxxxxx  yyyyyyyy  zzzzzzzz  tttttttt
> +	 *                               tttttttt  mod g = r0 (precomputed)
> +	 *                     zzzzzzzz  00000000  mod g = r1 (precomputed)
> +	 *           yyyyyyyy  00000000  00000000  mod g = r2 (precomputed)
> +	 * xxxxxxxx  00000000  00000000  00000000  mod g = r3 (precomputed)
> +	 * xxxxxxxx  yyyyyyyy  zzzzzzzz  tttttttt  mod g = r0^r1^r2^r3
> +	 */
> +	while (mlen--) {
> +		/* input data is read in big-endian format */
> +		w = r[0]^cpu_to_be32(*pdata++);
> +		p0 = tab0 + (l+1)*((w >>  0) & 0xff);
> +		p1 = tab1 + (l+1)*((w >>  8) & 0xff);
> +		p2 = tab2 + (l+1)*((w >> 16) & 0xff);
> +		p3 = tab3 + (l+1)*((w >> 24) & 0xff);
> +
> +		for (i = 0; i < l; i++)
> +			r[i] = r[i+1]^p0[i]^p1[i]^p2[i]^p3[i];
> +
> +		r[l] = p0[l]^p1[l]^p2[l]^p3[l];
> +	}
> +	memcpy(bch->ecc_buf, r, sizeof(r));
> +
> +	/* process last unaligned bytes */
> +	if (len)
> +		encode_bch_unaligned(bch, data, len, bch->ecc_buf);
> +
> +	/* store ecc parity bytes into original parity buffer */
> +	if (ecc)
> +		store_ecc8(bch, ecc, bch->ecc_buf);
> +}
> +
> +static inline int modulo(struct bch_control *bch, unsigned int v)
> +{
> +	const unsigned int n = GF_N(bch);
> +	while (v >= n) {
> +		v -= n;
> +		v = (v & n) + (v >> GF_M(bch));
> +	}
> +	return v;
> +}
> +
> +/*
> + * shorter and faster modulo function, only works when v < 2N.
> + */
> +static inline int mod_s(struct bch_control *bch, unsigned int v)
> +{
> +	const unsigned int n = GF_N(bch);
> +	return (v < n) ? v : v-n;
> +}
> +
> +static inline int deg(unsigned int poly)
> +{
> +	/* polynomial degree is the most-significant bit index */
> +	return fls(poly)-1;
> +}
> +
> +/* Galois field basic operations: multiply, divide, inverse, etc. */
> +
> +static inline unsigned int gf_mul(struct bch_control *bch, unsigned int a,
> +				  unsigned int b)
> +{
> +	return (a && b) ? bch->a_pow_tab[mod_s(bch, bch->a_log_tab[a]+
> +					       bch->a_log_tab[b])] : 0;
> +}
> +
> +static inline unsigned int gf_sqr(struct bch_control *bch, unsigned int a)
> +{
> +	return a ? bch->a_pow_tab[mod_s(bch, 2*bch->a_log_tab[a])] : 0;
> +}
> +
> +static inline unsigned int a_pow(struct bch_control *bch, int i)
> +{
> +	return bch->a_pow_tab[modulo(bch, i)];
> +}
> +
> +static inline int a_log(struct bch_control *bch, unsigned int x)
> +{
> +	return bch->a_log_tab[x];
> +}
> +
> +/*
> + * generate Galois field lookup tables
> + */
> +static int build_gf_tables(struct bch_control *bch, unsigned int poly)
> +{
> +	unsigned int i, x = 1;
> +	const unsigned int k = 1 << deg(poly);
> +
> +	/* primitive polynomial must be of degree m */
> +	if (k != (1u << GF_M(bch)))
> +		return -1;
> +
> +	for (i = 0; i < GF_N(bch); i++) {
> +		bch->a_pow_tab[i] = x;
> +		bch->a_log_tab[x] = i;
> +		if (i && (x == 1))
> +			/* polynomial is not primitive (a^i=1 with 0<i<2^m-1) */
> +			return -1;
> +		x <<= 1;
> +		if (x & k)
> +			x ^= poly;
> +	}
> +	bch->a_pow_tab[GF_N(bch)] = 1;
> +	bch->a_log_tab[0] = 0;
> +
> +	return 0;
> +}
> +
> +/*
> + * compute generator polynomial remainder tables for fast encoding
> + */
> +static void build_mod8_tables(struct bch_control *bch, const uint32_t *g)
> +{
> +	int i, j, b, d;
> +	uint32_t data, hi, lo, *tab;
> +	const int l = BCH_ECC_WORDS(bch);
> +	const int plen = DIV_ROUND_UP(bch->ecc_bits+1, 32);
> +	const int ecclen = DIV_ROUND_UP(bch->ecc_bits, 32);
> +
> +	memset(bch->mod8_tab, 0, 4*256*l*sizeof(*bch->mod8_tab));
> +
> +	for (i = 0; i < 256; i++) {
> +		/* p(X)=i is a small polynomial of weight <= 8 */
> +		for (b = 0; b < 4; b++) {
> +			/* we want to compute (p(X).X^(8*b+deg(g))) mod g(X) */
> +			tab = bch->mod8_tab + (b*256+i)*l;
> +			data = i << (8*b);
> +			while (data) {
> +				d = deg(data);
> +				/* subtract X^d.g(X) from p(X).X^(8*b+deg(g)) */
> +				data ^= g[0] >> (31-d);
> +				for (j = 0; j < ecclen; j++) {
> +					hi = (d < 31) ? g[j] << (d+1) : 0;
> +					lo = (j+1 < plen) ?
> +						g[j+1] >> (31-d) : 0;
> +					tab[j] ^= hi|lo;
> +				}
> +			}
> +		}
> +	}
> +}
> +
> +/*
> + * build a base for factoring degree 2 polynomials
> + */
> +static int build_deg2_base(struct bch_control *bch)
> +{
> +	const int m = GF_M(bch);
> +	int i, j, r;
> +	unsigned int sum, x, y, remaining, ak = 0, xi[m];
> +
> +	/* find k s.t. Tr(a^k) = 1 and 0 <= k < m */
> +	for (i = 0; i < m; i++) {
> +		for (j = 0, sum = 0; j < m; j++)
> +			sum ^= a_pow(bch, i*(1 << j));
> +
> +		if (sum) {
> +			ak = bch->a_pow_tab[i];
> +			break;
> +		}
> +	}
> +	/* find xi, i=0..m-1 such that xi^2+xi = a^i+Tr(a^i).a^k */
> +	remaining = m;
> +	memset(xi, 0, sizeof(xi));
> +
> +	for (x = 0; (x <= GF_N(bch)) && remaining; x++) {
> +		y = gf_sqr(bch, x)^x;
> +		for (i = 0; i < 2; i++) {
> +			r = a_log(bch, y);
> +			if (y && (r < m) && !xi[r]) {
> +				bch->xi_tab[r] = x;
> +				xi[r] = 1;
> +				remaining--;
> +				dbg("x%d = %x\n", r, x);
> +				break;
> +			}
> +			y ^= ak;
> +		}
> +	}
> +	/* should not happen but check anyway */
> +	return remaining ? -1 : 0;
> +}
> +
> +static void *bch_alloc(size_t size, int *err)
> +{
> +	void *ptr;
> +
> +	ptr = malloc(size);
> +	if (ptr == NULL)
> +		*err = 1;
> +	return ptr;
> +}
> +
> +/*
> + * compute generator polynomial for given (m,t) parameters.
> + */
> +static uint32_t *compute_generator_polynomial(struct bch_control *bch)
> +{
> +	const unsigned int m = GF_M(bch);
> +	const unsigned int t = GF_T(bch);
> +	int n, err = 0;
> +	unsigned int i, j, nbits, r, word, *roots;
> +	struct gf_poly *g;
> +	uint32_t *genpoly;
> +
> +	g = bch_alloc(GF_POLY_SZ(m*t), &err);
> +	roots = bch_alloc((bch->n+1)*sizeof(*roots), &err);
> +	genpoly = bch_alloc(DIV_ROUND_UP(m*t+1, 32)*sizeof(*genpoly), &err);
> +
> +	if (err) {
> +		kfree(genpoly);
> +		genpoly = NULL;
> +		goto finish;
> +	}
> +
> +	/* enumerate all roots of g(X) */
> +	memset(roots , 0, (bch->n+1)*sizeof(*roots));
> +	for (i = 0; i < t; i++) {
> +		for (j = 0, r = 2*i+1; j < m; j++) {
> +			roots[r] = 1;
> +			r = mod_s(bch, 2*r);
> +		}
> +	}
> +	/* build generator polynomial g(X) */
> +	g->deg = 0;
> +	g->c[0] = 1;
> +	for (i = 0; i < GF_N(bch); i++) {
> +		if (roots[i]) {
> +			/* multiply g(X) by (X+root) */
> +			r = bch->a_pow_tab[i];
> +			g->c[g->deg+1] = 1;
> +			for (j = g->deg; j > 0; j--)
> +				g->c[j] = gf_mul(bch, g->c[j], r)^g->c[j-1];
> +
> +			g->c[0] = gf_mul(bch, g->c[0], r);
> +			g->deg++;
> +		}
> +	}
> +	/* store left-justified binary representation of g(X) */
> +	n = g->deg+1;
> +	i = 0;
> +
> +	while (n > 0) {
> +		nbits = (n > 32) ? 32 : n;
> +		for (j = 0, word = 0; j < nbits; j++) {
> +			if (g->c[n-1-j])
> +				word |= 1u << (31-j);
> +		}
> +		genpoly[i++] = word;
> +		n -= nbits;
> +	}
> +	bch->ecc_bits = g->deg;
> +
> +finish:
> +	kfree(g);
> +	kfree(roots);
> +
> +	return genpoly;
> +}
> +
> +/**
> + *  free_bch - free the BCH control structure
> + *  @bch:    BCH control structure to release
> + */
> +static void free_bch(struct bch_control *bch)
> +{
> +	unsigned int i;
> +
> +	if (bch) {
> +		kfree(bch->a_pow_tab);
> +		kfree(bch->a_log_tab);
> +		kfree(bch->mod8_tab);
> +		kfree(bch->ecc_buf);
> +		kfree(bch->ecc_buf2);
> +		kfree(bch->xi_tab);
> +		kfree(bch->syn);
> +		kfree(bch->cache);
> +		kfree(bch->elp);
> +
> +		for (i = 0; i < ARRAY_SIZE(bch->poly_2t); i++)
> +			kfree(bch->poly_2t[i]);
> +
> +		kfree(bch);
> +	}
> +}
> +
> +/**
> + * init_bch - initialize a BCH encoder/decoder
> + * @m:          Galois field order, should be in the range 5-15
> + * @t:          maximum error correction capability, in bits
> + * @prim_poly:  user-provided primitive polynomial (or 0 to use default)
> + *
> + * Returns:
> + *  a newly allocated BCH control structure if successful, NULL otherwise
> + *
> + * This initialization can take some time, as lookup tables are built for fast
> + * encoding/decoding; make sure not to call this function from a time critical
> + * path. Usually, init_bch() should be called on module/driver init and
> + * free_bch() should be called to release memory on exit.
> + *
> + * You may provide your own primitive polynomial of degree @m in argument
> + * @prim_poly, or let init_bch() use its default polynomial.
> + *
> + * Once init_bch() has successfully returned a pointer to a newly allocated
> + * BCH control structure, ecc length in bytes is given by member @ecc_bytes of
> + * the structure.
> + */
> +static struct bch_control *init_bch(int m, int t, unsigned int prim_poly)
> +{
> +	int err = 0;
> +	unsigned int i, words;
> +	uint32_t *genpoly;
> +	struct bch_control *bch = NULL;
> +
> +	const int min_m = 5;
> +	const int max_m = 15;
> +
> +	/* default primitive polynomials */
> +	static const unsigned int prim_poly_tab[] = {
> +		0x25, 0x43, 0x83, 0x11d, 0x211, 0x409, 0x805, 0x1053, 0x201b,
> +		0x402b, 0x8003,
> +	};
> +
> +#if defined(CONFIG_BCH_CONST_PARAMS)
> +	if ((m != (CONFIG_BCH_CONST_M)) || (t != (CONFIG_BCH_CONST_T))) {
> +		printk(KERN_ERR "bch encoder/decoder was configured to support "
> +		       "parameters m=%d, t=%d only!\n",
> +		       CONFIG_BCH_CONST_M, CONFIG_BCH_CONST_T);
> +		goto fail;
> +	}
> +#endif
> +	if ((m < min_m) || (m > max_m))
> +		/*
> +		 * values of m greater than 15 are not currently supported;
> +		 * supporting m > 15 would require changing table base type
> +		 * (uint16_t) and a small patch in matrix transposition
> +		 */
> +		goto fail;
> +
> +	/* sanity checks */
> +	if ((t < 1) || (m*t >= ((1 << m)-1)))
> +		/* invalid t value */
> +		goto fail;
> +
> +	/* select a primitive polynomial for generating GF(2^m) */
> +	if (prim_poly == 0)
> +		prim_poly = prim_poly_tab[m-min_m];
> +
> +	bch = malloc(sizeof(*bch));
> +	if (bch == NULL)
> +		goto fail;
> +
> +	memset(bch, 0, sizeof(*bch));
> +
> +	bch->m = m;
> +	bch->t = t;
> +	bch->n = (1 << m)-1;
> +	words  = DIV_ROUND_UP(m*t, 32);
> +	bch->ecc_bytes = DIV_ROUND_UP(m*t, 8);
> +	bch->a_pow_tab = bch_alloc((1+bch->n)*sizeof(*bch->a_pow_tab), &err);
> +	bch->a_log_tab = bch_alloc((1+bch->n)*sizeof(*bch->a_log_tab), &err);
> +	bch->mod8_tab  = bch_alloc(words*1024*sizeof(*bch->mod8_tab), &err);
> +	bch->ecc_buf   = bch_alloc(words*sizeof(*bch->ecc_buf), &err);
> +	bch->ecc_buf2  = bch_alloc(words*sizeof(*bch->ecc_buf2), &err);
> +	bch->xi_tab    = bch_alloc(m*sizeof(*bch->xi_tab), &err);
> +	bch->syn       = bch_alloc(2*t*sizeof(*bch->syn), &err);
> +	bch->cache     = bch_alloc(2*t*sizeof(*bch->cache), &err);
> +	bch->elp       = bch_alloc((t+1)*sizeof(struct gf_poly_deg1), &err);
> +
> +	for (i = 0; i < ARRAY_SIZE(bch->poly_2t); i++)
> +		bch->poly_2t[i] = bch_alloc(GF_POLY_SZ(2*t), &err);
> +
> +	if (err)
> +		goto fail;
> +
> +	err = build_gf_tables(bch, prim_poly);
> +	if (err)
> +		goto fail;
> +
> +	/* use generator polynomial for computing encoding tables */
> +	genpoly = compute_generator_polynomial(bch);
> +	if (genpoly == NULL)
> +		goto fail;
> +
> +	build_mod8_tables(bch, genpoly);
> +	kfree(genpoly);
> +
> +	err = build_deg2_base(bch);
> +	if (err)
> +		goto fail;
> +
> +	return bch;
> +
> +fail:
> +	free_bch(bch);
> +	return NULL;
> +}
> +
> +static void swap_bits(uint8_t *buf, int len)
> +{
> +	int i, j;
> +
> +	for (j = 0; j < len; j++) {
> +		uint8_t byte = buf[j];
> +
> +		buf[j] = 0;
> +		for (i = 0; i < 8; i++) {
> +			if (byte & (1 << i))
> +				buf[j] |= (1 << (7 - i));
> +		}
> +	}
> +}
> +
> +static uint16_t lfsr_step(uint16_t state, int count)
> +{
> +	state &= 0x7fff;
> +	while (count--)
> +		state = ((state >> 1) |
> +			 ((((state >> 0) ^ (state >> 1)) & 1) << 14)) & 0x7fff;
> +
> +	return state;
> +}
> +
> +static uint16_t default_scrambler_seeds[] = {
> +	0x2b75, 0x0bd0, 0x5ca3, 0x62d1, 0x1c93, 0x07e9, 0x2162, 0x3a72,
> +	0x0d67, 0x67f9, 0x1be7, 0x077d, 0x032f, 0x0dac, 0x2716, 0x2436,
> +	0x7922, 0x1510, 0x3860, 0x5287, 0x480f, 0x4252, 0x1789, 0x5a2d,
> +	0x2a49, 0x5e10, 0x437f, 0x4b4e, 0x2f45, 0x216e, 0x5cb7, 0x7130,
> +	0x2a3f, 0x60e4, 0x4dc9, 0x0ef0, 0x0f52, 0x1bb9, 0x6211, 0x7a56,
> +	0x226d, 0x4ea7, 0x6f36, 0x3692, 0x38bf, 0x0c62, 0x05eb, 0x4c55,
> +	0x60f4, 0x728c, 0x3b6f, 0x2037, 0x7f69, 0x0936, 0x651a, 0x4ceb,
> +	0x6218, 0x79f3, 0x383f, 0x18d9, 0x4f05, 0x5c82, 0x2912, 0x6f17,
> +	0x6856, 0x5938, 0x1007, 0x61ab, 0x3e7f, 0x57c2, 0x542f, 0x4f62,
> +	0x7454, 0x2eac, 0x7739, 0x42d4, 0x2f90, 0x435a, 0x2e52, 0x2064,
> +	0x637c, 0x66ad, 0x2c90, 0x0bad, 0x759c, 0x0029, 0x0986, 0x7126,
> +	0x1ca7, 0x1605, 0x386a, 0x27f5, 0x1380, 0x6d75, 0x24c3, 0x0f8e,
> +	0x2b7a, 0x1418, 0x1fd1, 0x7dc1, 0x2d8e, 0x43af, 0x2267, 0x7da3,
> +	0x4e3d, 0x1338, 0x50db, 0x454d, 0x764d, 0x40a3, 0x42e6, 0x262b,
> +	0x2d2e, 0x1aea, 0x2e17, 0x173d, 0x3a6e, 0x71bf, 0x25f9, 0x0a5d,
> +	0x7c57, 0x0fbe, 0x46ce, 0x4939, 0x6b17, 0x37bb, 0x3e91, 0x76db,
> +};
> +
> +static uint16_t brom_scrambler_seeds[] = { 0x4a80 };
> +
> +static void scramble(const struct image_info *info,
> +		     int page, uint8_t *data, int datalen)
> +{
> +	uint16_t state;
> +	int i;
> +
> +	/* Boot0 is always scrambled no matter the command line option. */
> +	if (info->boot0) {
> +		state = brom_scrambler_seeds[0];
> +	} else {
> +		unsigned seedmod = info->eraseblock_size / info->page_size;
> +
> +		/* Bail out earlier if the user didn't ask for scrambling. */
> +		if (!info->scramble)
> +			return;
> +
> +		if (seedmod > ARRAY_SIZE(default_scrambler_seeds))
> +			seedmod = ARRAY_SIZE(default_scrambler_seeds);
> +
> +		state = default_scrambler_seeds[page % seedmod];
> +	}
> +
> +	/* Prepare the initial state... */
> +	state = lfsr_step(state, 15);
> +
> +	/* and start scrambling data. */
> +	for (i = 0; i < datalen; i++) {
> +		data[i] ^= state;
> +		state = lfsr_step(state, 8);
> +	}
> +}
> +
> +static int write_page(const struct image_info *info, uint8_t *buffer,
> +		      FILE *src, FILE *rnd, FILE *dst,
> +		      struct bch_control *bch, int page)
> +{
> +	int steps = info->usable_page_size / info->ecc_step_size;
> +	int eccbytes = DIV_ROUND_UP(info->ecc_strength * 14, 8);
> +	off_t pos = ftell(dst);
> +	size_t pad, cnt;
> +	int i;
> +
> +	if (eccbytes % 2)
> +		eccbytes++;
> +
> +	memset(buffer, 0xff, info->page_size + info->oob_size);
> +	cnt = fread(buffer, 1, info->usable_page_size, src);
> +	if (!cnt) {
> +		if (!feof(src)) {
> +			fprintf(stderr,
> +				"Failed to read data from the source\n");
> +			return -1;
> +		} else {
> +			return 0;
> +		}
> +	}
> +
> +	fwrite(buffer, info->page_size + info->oob_size, 1, dst);
> +
> +	for (i = 0; i < info->usable_page_size; i++) {
> +		if (buffer[i] !=  0xff)
> +			break;
> +	}
> +
> +	/* We leave empty pages at 0xff. */
> +	if (i == info->usable_page_size)
> +		return 0;
> +
> +	/* Restore the source pointer to read it again. */
> +	fseek(src, -cnt, SEEK_CUR);
> +
> +	/* Randomize unused space if scrambling is required. */
> +	if (info->scramble) {
> +		int offs;
> +
> +		if (info->boot0) {
> +			offs = steps * (info->ecc_step_size + eccbytes + 4);
> +			cnt = info->page_size + info->oob_size - offs;
> +			fread(buffer + offs, 1, cnt, rnd);
> +		} else {
> +			offs = info->page_size + (steps * (eccbytes + 4));
> +			cnt = info->page_size + info->oob_size - offs;
> +			memset(buffer + offs, 0xff, cnt);
> +			scramble(info, page, buffer + offs, cnt);
> +		}
> +		fseek(dst, pos + offs, SEEK_SET);
> +		fwrite(buffer + offs, cnt, 1, dst);
> +	}
> +
> +	for (i = 0; i < steps; i++) {
> +		int ecc_offs, data_offs;
> +		uint8_t *ecc;
> +
> +		memset(buffer, 0xff, info->ecc_step_size + eccbytes + 4);
> +		ecc = buffer + info->ecc_step_size + 4;
> +		if (info->boot0) {
> +			data_offs = i * (info->ecc_step_size + eccbytes + 4);
> +			ecc_offs = data_offs + info->ecc_step_size + 4;
> +		} else {
> +			data_offs = i * info->ecc_step_size;
> +			ecc_offs = info->page_size + 4 + (i * (eccbytes + 4));
> +		}
> +
> +		cnt = fread(buffer, 1, info->ecc_step_size, src);
> +		if (!cnt && !feof(src)) {
> +			fprintf(stderr,
> +				"Failed to read data from the source\n");
> +			return -1;
> +		}
> +
> +		pad = info->ecc_step_size - cnt;
> +		if (pad) {
> +			if (info->scramble && info->boot0)
> +				fread(buffer + cnt, 1, pad, rnd);
> +			else
> +				memset(buffer + cnt, 0xff, pad);
> +		}
> +
> +		memset(ecc, 0, eccbytes);
> +		swap_bits(buffer, info->ecc_step_size + 4);
> +		encode_bch(bch, buffer, info->ecc_step_size + 4, ecc);
> +		swap_bits(buffer, info->ecc_step_size + 4);
> +		swap_bits(ecc, eccbytes);
> +		scramble(info, page, buffer, info->ecc_step_size + 4 + eccbytes);
> +
> +		fseek(dst, pos + data_offs, SEEK_SET);
> +		fwrite(buffer, info->ecc_step_size, 1, dst);
> +		fseek(dst, pos + ecc_offs - 4, SEEK_SET);
> +		fwrite(ecc - 4, eccbytes + 4, 1, dst);
> +	}
> +
> +	/* Fix BBM. */
> +	fseek(dst, pos + info->page_size, SEEK_SET);
> +	memset(buffer, 0xff, 2);
> +	fwrite(buffer, 2, 1, dst);
> +
> +	/* Make dst pointer point to the next page. */
> +	fseek(dst, pos + info->page_size + info->oob_size, SEEK_SET);
> +
> +	return 0;
> +}
> +
> +static int create_image(const struct image_info *info)
> +{
> +	off_t page = info->offset / info->page_size;
> +	struct bch_control *bch;
> +	FILE *src, *dst, *rnd;
> +	uint8_t *buffer;
> +
> +	bch = init_bch(14, info->ecc_strength, BCH_PRIMITIVE_POLY);
> +	if (!bch) {
> +		fprintf(stderr, "Failed to init the BCH engine\n");
> +		return -1;
> +	}
> +
> +	buffer = malloc(info->page_size + info->oob_size);
> +	if (!buffer) {
> +		fprintf(stderr, "Failed to allocate the NAND page buffer\n");
> +		return -1;
> +	}
> +
> +	memset(buffer, 0xff, info->page_size + info->oob_size);
> +
> +	src = fopen(info->source, "r");
> +	if (!src) {
> +		fprintf(stderr, "Failed to open source file (%s)\n",
> +			info->source);
> +		return -1;
> +	}
> +
> +	dst = fopen(info->dest, "w");
> +	if (!dst) {
> +		fprintf(stderr, "Failed to open dest file (%s)\n", info->dest);
> +		return -1;
> +	}
> +
> +	rnd = fopen("/dev/urandom", "r");
> +	if (!rnd) {
> +		fprintf(stderr, "Failed to open /dev/urandom\n");
> +		return -1;
> +	}
> +
> +	while (!feof(src)) {
> +		int ret;
> +
> +		ret = write_page(info, buffer, src, rnd, dst, bch, page++);
> +		if (ret)
> +			return ret;
> +	}
> +
> +	return 0;
> +}
> +
> +static void display_help(int status)
> +{
> +	fprintf(status == EXIT_SUCCESS ? stdout : stderr,
> +		"sunxi-nand-image-builder %s\n"
> +		"\n"
> +		"Usage: sunxi-nand-image-builder [OPTIONS] source-image output-image\n"
> +		"\n"
> +		"Creates a raw NAND image that can be read by the sunxi NAND controller.\n"
> +		"\n"
> +		"-h               --help               Display this help and exit\n"
> +		"-c <str>/<step>  --ecc=<str>/<step>   ECC config (strength/step-size)\n"
> +		"-p <size>        --page=<size>        Page size\n"
> +		"-o <size>        --oob=<size>         OOB size\n"
> +		"-u <size>        --usable=<size>      Usable page size\n"
> +		"-e <size>        --eraseblock=<size>  Erase block size\n"
> +		"-b               --boot0              Build a boot0 image.\n"
> +		"-s               --scramble           Scramble data\n"
> +		"-a <offset>      --address=<offset>   Where the image will be programmed.\n"
> +		"\n"
> +		"Notes:\n"
> +		"All the information you need to pass to this tool should be part of\n"
> +		"the NAND datasheet.\n"
> +		"\n"
> +		"The NAND controller only supports the following ECC configs\n"
> +		"  Valid ECC strengths: 16, 24, 28, 32, 40, 48, 56, 60 and 64\n"
> +		"  Valid ECC step size: 512 and 1024\n"
> +		"\n"
> +		"If you are building a boot0 image, you'll have specify extra options.\n"
> +		"These options should be chosen based on the layouts described here:\n"
> +		"  http://linux-sunxi.org/NAND#More_information_on_BROM_NAND\n"
> +		"\n"
> +		"  --usable should be assigned the 'Hardware page' value\n"
> +		"  --ecc should be assigned the 'ECC capacity'/'ECC page' values\n"
> +		"  --usable should be smaller than --page\n"
> +		"\n"
> +		"The --address option is only required for non-boot0 images that are \n"
> +		"meant to be programmed at a non eraseblock aligned offset.\n"
> +		"\n"
> +		"Examples:\n"
> +		"  The H27UCG8T2BTR-BC NAND exposes\n"
> +		"  * 16k pages\n"
> +		"  * 1280 OOB bytes per page\n"
> +		"  * 4M eraseblocks\n"
> +		"  * requires data scrambling\n"
> +		"  * expects a minimum ECC of 40bits/1024bytes\n"
> +		"\n"
> +		"  A normal image can be generated with\n"
> +		"    sunxi-nand-image-builder -p 16384 -o 1280 -e 0x400000 -s -c 40/1024\n"
> +		"  A boot0 image can be generated with\n"
> +		"    sunxi-nand-image-builder -p 16384 -o 1280 -e 0x400000 -s -b -u 4096 -c 64/1024\n",
> +		PLAIN_VERSION);
> +	exit(status);
> +}
> +
> +static int check_image_info(struct image_info *info)
> +{
> +	static int valid_ecc_strengths[] = { 16, 24, 28, 32, 40, 48, 56, 60, 64 };
> +	int eccbytes, eccsteps;
> +	unsigned i;
> +
> +	if (!info->page_size) {
> +		fprintf(stderr, "--page is missing\n");
> +		return -EINVAL;
> +	}
> +
> +	if (!info->page_size) {
> +		fprintf(stderr, "--oob is missing\n");
> +		return -EINVAL;
> +	}
> +
> +	if (!info->eraseblock_size) {
> +		fprintf(stderr, "--eraseblock is missing\n");
> +		return -EINVAL;
> +	}
> +
> +	if (info->ecc_step_size != 512 && info->ecc_step_size != 1024) {
> +		fprintf(stderr, "Invalid ECC step argument: %d\n",
> +			info->ecc_step_size);
> +		return -EINVAL;
> +	}
> +
> +	for (i = 0; i < ARRAY_SIZE(valid_ecc_strengths); i++) {
> +		if (valid_ecc_strengths[i] == info->ecc_strength)
> +			break;
> +	}
> +
> +	if (i == ARRAY_SIZE(valid_ecc_strengths)) {
> +		fprintf(stderr, "Invalid ECC strength argument: %d\n",
> +			info->ecc_strength);
> +		return -EINVAL;
> +	}
> +
> +	eccbytes = DIV_ROUND_UP(info->ecc_strength * 14, 8);
> +	if (eccbytes % 2)
> +		eccbytes++;
> +	eccbytes += 4;
> +
> +	eccsteps = info->usable_page_size / info->ecc_step_size;
> +
> +	if (info->page_size + info->oob_size <
> +	    info->usable_page_size + (eccsteps * eccbytes)) {
> +		fprintf(stderr,
> +			"ECC bytes do not fit in the NAND page, choose a weaker ECC\n");
> +		return -EINVAL;
> +	}
> +
> +	return 0;
> +}
> +
> +int main(int argc, char **argv)
> +{
> +	struct image_info info;
> +
> +	memset(&info, 0, sizeof(info));
> +	/*
> +	 * Process user arguments
> +	 */
> +	for (;;) {
> +		int option_index = 0;
> +		char *endptr = NULL;
> +		static const struct option long_options[] = {
> +			{"help", no_argument, 0, 'h'},
> +			{"ecc", required_argument, 0, 'c'},
> +			{"page", required_argument, 0, 'p'},
> +			{"oob", required_argument, 0, 'o'},
> +			{"usable", required_argument, 0, 'u'},
> +			{"eraseblock", required_argument, 0, 'e'},
> +			{"boot0", no_argument, 0, 'b'},
> +			{"scramble", no_argument, 0, 's'},
> +			{"address", required_argument, 0, 'a'},
> +			{0, 0, 0, 0},
> +		};
> +
> +		int c = getopt_long(argc, argv, "c:p:o:u:e:ba:sh",
> +				long_options, &option_index);
> +		if (c == EOF)
> +			break;
> +
> +		switch (c) {
> +		case 'h':
> +			display_help(0);
> +			break;
> +		case 's':
> +			info.scramble = 1;
> +			break;
> +		case 'c':
> +			info.ecc_strength = strtol(optarg, &endptr, 0);
> +			if (endptr || *endptr == '/')
> +				info.ecc_step_size = strtol(endptr + 1, NULL, 0);
> +			break;
> +		case 'p':
> +			info.page_size = strtol(optarg, NULL, 0);
> +			break;
> +		case 'o':
> +			info.oob_size = strtol(optarg, NULL, 0);
> +			break;
> +		case 'u':
> +			info.usable_page_size = strtol(optarg, NULL, 0);
> +			break;
> +		case 'e':
> +			info.eraseblock_size = strtol(optarg, NULL, 0);
> +			break;
> +		case 'b':
> +			info.boot0 = 1;
> +			break;
> +		case 'a':
> +			info.offset = strtoull(optarg, NULL, 0);
> +			break;
> +		case '?':
> +			display_help(-1);
> +			break;
> +		}
> +	}
> +
> +	if ((argc - optind) != 2)
> +		display_help(-1);
> +
> +	info.source = argv[optind];
> +	info.dest = argv[optind + 1];
> +
> +	if (!info.boot0) {
> +		info.usable_page_size = info.page_size;
> +	} else if (!info.usable_page_size) {
> +		if (info.page_size > 8192)
> +			info.usable_page_size = 8192;
> +		else if (info.page_size > 4096)
> +			info.usable_page_size = 4096;
> +		else
> +			info.usable_page_size = 1024;
> +	}
> +
> +	if (check_image_info(&info))
> +		display_help(-1);
> +
> +	return create_image(&info);
> +}
>

^ permalink raw reply	[flat|nested] 44+ messages in thread

* [U-Boot] [PATCH 5/7] nand: sunxi: Add options for the SPL NAND configuration
  2016-11-08 16:21 ` [U-Boot] [PATCH 5/7] nand: sunxi: Add options for the SPL NAND configuration Maxime Ripard
  2016-11-08 16:31   ` Boris Brezillon
@ 2016-11-14 11:19   ` Hans de Goede
  2016-11-15  5:07   ` Scott Wood
  2 siblings, 0 replies; 44+ messages in thread
From: Hans de Goede @ 2016-11-14 11:19 UTC (permalink / raw)
  To: u-boot

Hi,

On 08-11-16 17:21, Maxime Ripard wrote:
> The SPL image needs to be built with a different ECC configuration than the
> U-Boot binary.
>
> Add Kconfig options with defaults to provide a value that should work for
> anyone, but is still configurable if needs be.
>
> Signed-off-by: Maxime Ripard <maxime.ripard@free-electrons.com>

Looks good to me:

Reviewed-by: Hans de Goede <hdegoede@redhat.com>

Regards,

Hans



> ---
>  drivers/mtd/nand/Kconfig | 16 ++++++++++++++++
>  1 file changed, 16 insertions(+), 0 deletions(-)
>
> diff --git a/drivers/mtd/nand/Kconfig b/drivers/mtd/nand/Kconfig
> index df154bfd32b9..a60abb625ee5 100644
> --- a/drivers/mtd/nand/Kconfig
> +++ b/drivers/mtd/nand/Kconfig
> @@ -73,6 +73,22 @@ config NAND_SUNXI
>  	The SPL driver only supports reading from the NAND using DMA
>  	transfers.
>
> +if NAND_SUNXI
> +
> +config NAND_SUNXI_SPL_ECC_STRENGTH
> +	int "Allwinner NAND SPL ECC Strength"
> +	default 64
> +
> +config NAND_SUNXI_SPL_ECC_SIZE
> +	int "Allwinner NAND SPL ECC Step Size"
> +	default 1024
> +
> +config NAND_SUNXI_SPL_USABLE_PAGE_SIZE
> +	int "Allwinner NAND SPL Usable Page Size"
> +	default 1024
> +
> +endif
> +
>  config NAND_ARASAN
>  	bool "Configure Arasan Nand"
>  	help
>

^ permalink raw reply	[flat|nested] 44+ messages in thread

* [U-Boot] [PATCH 6/7] scripts: sunxi: Build an raw SPL image
  2016-11-08 16:21 ` [U-Boot] [PATCH 6/7] scripts: sunxi: Build an raw SPL image Maxime Ripard
  2016-11-08 16:33   ` Boris Brezillon
@ 2016-11-14 11:19   ` Hans de Goede
  2016-11-14 11:30     ` Hans de Goede
  1 sibling, 1 reply; 44+ messages in thread
From: Hans de Goede @ 2016-11-14 11:19 UTC (permalink / raw)
  To: u-boot

Hi,

On 08-11-16 17:21, Maxime Ripard wrote:
> Introduce a new sunxi-spl-with-ecc.bin image with already the right header,
> ECC, randomizer and padding for the BROM to be able to read it.
>
> It needs to be flashed using a raw access to the NAND so that the
> controller doesn't change a thing to it, since we already have all the
> right parameters.
>
> Signed-off-by: Maxime Ripard <maxime.ripard@free-electrons.com>

Looks good to me:

Reviewed-by: Hans de Goede <hdegoede@redhat.com>

Regards,

Hans



> ---
>  Makefile             |  3 +++
>  scripts/Makefile.spl | 12 ++++++++++++
>  2 files changed, 15 insertions(+), 0 deletions(-)
>
> diff --git a/Makefile b/Makefile
> index 37cbcb28f75e..12a248e297b5 100644
> --- a/Makefile
> +++ b/Makefile
> @@ -1345,6 +1345,9 @@ spl/u-boot-spl: tools prepare \
>  spl/sunxi-spl.bin: spl/u-boot-spl
>  	@:
>
> +spl/sunxi-spl-with-ecc.bin: spl/sunxi-spl.bin
> +	@:
> +
>  spl/u-boot-spl.sfp: spl/u-boot-spl
>  	@:
>
> diff --git a/scripts/Makefile.spl b/scripts/Makefile.spl
> index e0b0117dc9b6..b41b4e427cc5 100644
> --- a/scripts/Makefile.spl
> +++ b/scripts/Makefile.spl
> @@ -168,6 +168,7 @@ endif
>
>  ifdef CONFIG_ARCH_SUNXI
>  ALL-y	+= $(obj)/sunxi-spl.bin
> +ALL-y	+= $(obj)/sunxi-spl-with-ecc.bin
>  endif
>
>  ifeq ($(CONFIG_SYS_SOC),"at91")
> @@ -276,6 +277,17 @@ cmd_mksunxiboot = $(objtree)/tools/mksunxiboot $< $@
>  $(obj)/sunxi-spl.bin: $(obj)/$(SPL_BIN).bin FORCE
>  	$(call if_changed,mksunxiboot)
>
> +quiet_cmd_sunxi_spl_image_builder = SUNXI_SPL_IMAGE_BUILDER $@
> +cmd_sunxi_spl_image_builder = $(objtree)/tools/sunxi-spl-image-builder \
> +				-c $(CONFIG_NAND_SUNXI_SPL_ECC_STRENGTH)/$(CONFIG_NAND_SUNXI_SPL_ECC_SIZE) \
> +				-p $(CONFIG_SYS_NAND_PAGE_SIZE) \
> +				-o $(CONFIG_SYS_NAND_OOBSIZE) \
> +				-u $(CONFIG_NAND_SUNXI_SPL_USABLE_PAGE_SIZE) \
> +				-e $(CONFIG_SYS_NAND_BLOCK_SIZE) \
> +				-s -b $< $@
> +$(obj)/sunxi-spl-with-ecc.bin: $(obj)/sunxi-spl.bin
> +	$(call if_changed,sunxi_spl_image_builder)
> +
>  # Rule to link u-boot-spl
>  # May be overridden by arch/$(ARCH)/config.mk
>  quiet_cmd_u-boot-spl ?= LD      $@
>

^ permalink raw reply	[flat|nested] 44+ messages in thread

* [U-Boot] [PATCH 7/7] sunxi: Add support for the CHIP Pro
  2016-11-08 16:21 ` [U-Boot] [PATCH 7/7] sunxi: Add support for the CHIP Pro Maxime Ripard
@ 2016-11-14 11:20   ` Hans de Goede
  0 siblings, 0 replies; 44+ messages in thread
From: Hans de Goede @ 2016-11-14 11:20 UTC (permalink / raw)
  To: u-boot

Hi,

On 08-11-16 17:21, Maxime Ripard wrote:
> The CHIP Pro is a SoM that features the GR8 SIP, an AXP209, a BT/WiFi chip
> and a 512MiB SLC NAND.
>
> This it's an SLC NAND, it doesn't suffer the same drawbacks than found on
> the MLC NANDs, and we can enable it right away.
>
> Signed-off-by: Maxime Ripard <maxime.ripard@free-electrons.com>

Patch 3/3 needs a v3 before this can be merged, otherwise this
looks good to me:

Reviewed-by: Hans de Goede <hdegoede@redhat.com>

Regards,

Hans

> ---
>  configs/CHIP_pro_defconfig | 27 +++++++++++++++++++++++++++
>  1 file changed, 27 insertions(+), 0 deletions(-)
>  create mode 100644 configs/CHIP_pro_defconfig
>
> diff --git a/configs/CHIP_pro_defconfig b/configs/CHIP_pro_defconfig
> new file mode 100644
> index 000000000000..6008f44f485c
> --- /dev/null
> +++ b/configs/CHIP_pro_defconfig
> @@ -0,0 +1,27 @@
> +CONFIG_ARM=y
> +CONFIG_ARCH_SUNXI=y
> +CONFIG_SPL_I2C_SUPPORT=y
> +# CONFIG_SPL_MMC_SUPPORT is not set
> +CONFIG_MACH_SUN5I=y
> +CONFIG_DRAM_TIMINGS_DDR3_800E_1066G_1333J=y
> +# CONFIG_MMC is not set
> +CONFIG_USB0_VBUS_PIN="PB10"
> +CONFIG_DEFAULT_DEVICE_TREE="ntc-gr8-chip-pro"
> +CONFIG_SYS_EXTRA_OPTIONS="CONS_INDEX=2,SYS_NAND_BLOCK_SIZE=0x40000,SYS_NAND_PAGE_SIZE=4096,SYS_NAND_OOBSIZE=256,ENV_IS_IN_NAND"
> +CONFIG_SPL=y
> +# CONFIG_CMD_IMLS is not set
> +CONFIG_CMD_DFU=y
> +CONFIG_CMD_USB_MASS_STORAGE=y
> +CONFIG_DFU_RAM=y
> +CONFIG_AXP_ALDO3_VOLT=3300
> +CONFIG_AXP_ALDO4_VOLT=3300
> +CONFIG_USB_EHCI_HCD=y
> +CONFIG_USB_MUSB_GADGET=y
> +CONFIG_USB_GADGET=y
> +CONFIG_USB_GADGET_DOWNLOAD=y
> +CONFIG_G_DNL_MANUFACTURER="Allwinner Technology"
> +CONFIG_G_DNL_VENDOR_NUM=0x1f3a
> +CONFIG_G_DNL_PRODUCT_NUM=0x1010
> +CONFIG_NAND_SUNXI=y
> +CONFIG_SPL_NAND_SUPPORT=y
> +CONFIG_MTD_UBI=y
>

^ permalink raw reply	[flat|nested] 44+ messages in thread

* [U-Boot] [PATCH 4/7] tools: sunxi: Add spl image builder
  2016-11-14 11:18   ` Hans de Goede
@ 2016-11-14 11:29     ` Hans de Goede
  2016-11-14 13:53       ` Maxime Ripard
  0 siblings, 1 reply; 44+ messages in thread
From: Hans de Goede @ 2016-11-14 11:29 UTC (permalink / raw)
  To: u-boot

Hi,

On 14-11-16 12:18, Hans de Goede wrote:
> Hi,
>
> On 08-11-16 17:21, Maxime Ripard wrote:
>> This program generates raw SPL images that can be flashed on the NAND with
>> the ECC and randomizer properly set up.
>>
>> Signed-off-by: Maxime Ripard <maxime.ripard@free-electrons.com>
>
> Looks good to me:
>
> Reviewed-by: Hans de Goede <hdegoede@redhat.com>

Note this causes a cpu_to_be32 redefine compiler warning
I've fixed this up locally.

Regards,

Hans


>
> Regards,
>
> Hans
>
>
>
>> ---
>>  tools/.gitignore                |    1 +-
>>  tools/Makefile                  |    1 +-
>>  tools/sunxi-spl-image-builder.c | 1113 ++++++++++++++++++++++++++++++++-
>>  3 files changed, 1115 insertions(+), 0 deletions(-)
>>  create mode 100644 tools/sunxi-spl-image-builder.c
>>
>> diff --git a/tools/.gitignore b/tools/.gitignore
>> index cb1e722d4575..16574467544c 100644
>> --- a/tools/.gitignore
>> +++ b/tools/.gitignore
>> @@ -15,6 +15,7 @@
>>  /mkexynosspl
>>  /mxsboot
>>  /mksunxiboot
>> +/sunxi-spl-image-builder
>>  /ncb
>>  /proftool
>>  /relocate-rela
>> diff --git a/tools/Makefile b/tools/Makefile
>> index 400588cf0f5c..dfeeb23484ce 100644
>> --- a/tools/Makefile
>> +++ b/tools/Makefile
>> @@ -171,6 +171,7 @@ hostprogs-$(CONFIG_MX28) += mxsboot
>>  HOSTCFLAGS_mxsboot.o := -pedantic
>>
>>  hostprogs-$(CONFIG_ARCH_SUNXI) += mksunxiboot
>> +hostprogs-$(CONFIG_ARCH_SUNXI) += sunxi-spl-image-builder
>>
>>  hostprogs-$(CONFIG_NETCONSOLE) += ncb
>>  hostprogs-$(CONFIG_SHA1_CHECK_UB_IMG) += ubsha1
>> diff --git a/tools/sunxi-spl-image-builder.c b/tools/sunxi-spl-image-builder.c
>> new file mode 100644
>> index 000000000000..0f915eb2bdf5
>> --- /dev/null
>> +++ b/tools/sunxi-spl-image-builder.c
>> @@ -0,0 +1,1113 @@
>> +/*
>> + * Generic binary BCH encoding/decoding library
>> + *
>> + * This program is free software; you can redistribute it and/or modify it
>> + * under the terms of the GNU General Public License version 2 as published by
>> + * the Free Software Foundation.
>> + *
>> + * This program is distributed in the hope that it will be useful, but WITHOUT
>> + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
>> + * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
>> + * more details.
>> + *
>> + * You should have received a copy of the GNU General Public License along with
>> + * this program; if not, write to the Free Software Foundation, Inc., 51
>> + * Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
>> + *
>> + * For the BCH implementation:
>> + *
>> + * Copyright ? 2011 Parrot S.A.
>> + *
>> + * Author: Ivan Djelic <ivan.djelic@parrot.com>
>> + *
>> + * See also:
>> + * http://lxr.free-electrons.com/source/lib/bch.c
>> + *
>> + * For the randomizer and image builder implementation:
>> + *
>> + * Copyright ? 2016 NextThing Co.
>> + * Copyright ? 2016 Free Electrons
>> + *
>> + * Author: Boris Brezillon <boris.brezillon@free-electrons.com>
>> + *
>> + */
>> +
>> +#include <stdint.h>
>> +#include <stdlib.h>
>> +#include <string.h>
>> +#include <stdio.h>
>> +#include <linux/kernel.h>
>> +#include <linux/errno.h>
>> +#include <asm/byteorder.h>
>> +#include <endian.h>
>> +#include <getopt.h>
>> +#include <version.h>
>> +
>> +#if defined(CONFIG_BCH_CONST_PARAMS)
>> +#define GF_M(_p)               (CONFIG_BCH_CONST_M)
>> +#define GF_T(_p)               (CONFIG_BCH_CONST_T)
>> +#define GF_N(_p)               ((1 << (CONFIG_BCH_CONST_M))-1)
>> +#else
>> +#define GF_M(_p)               ((_p)->m)
>> +#define GF_T(_p)               ((_p)->t)
>> +#define GF_N(_p)               ((_p)->n)
>> +#endif
>> +
>> +#define DIV_ROUND_UP(n,d) (((n) + (d) - 1) / (d))
>> +
>> +#define BCH_ECC_WORDS(_p)      DIV_ROUND_UP(GF_M(_p)*GF_T(_p), 32)
>> +#define BCH_ECC_BYTES(_p)      DIV_ROUND_UP(GF_M(_p)*GF_T(_p), 8)
>> +
>> +#ifndef dbg
>> +#define dbg(_fmt, args...)     do {} while (0)
>> +#endif
>> +
>> +#define cpu_to_be32 htobe32
>> +#define kfree free
>> +#define ARRAY_SIZE(arr) (sizeof(arr) / sizeof((arr)[0]))
>> +
>> +#define BCH_PRIMITIVE_POLY    0x5803
>> +
>> +struct image_info {
>> +    int ecc_strength;
>> +    int ecc_step_size;
>> +    int page_size;
>> +    int oob_size;
>> +    int usable_page_size;
>> +    int eraseblock_size;
>> +    int scramble;
>> +    int boot0;
>> +    off_t offset;
>> +    const char *source;
>> +    const char *dest;
>> +};
>> +
>> +/**
>> + * struct bch_control - BCH control structure
>> + * @m:          Galois field order
>> + * @n:          maximum codeword size in bits (= 2^m-1)
>> + * @t:          error correction capability in bits
>> + * @ecc_bits:   ecc exact size in bits, i.e. generator polynomial degree (<=m*t)
>> + * @ecc_bytes:  ecc max size (m*t bits) in bytes
>> + * @a_pow_tab:  Galois field GF(2^m) exponentiation lookup table
>> + * @a_log_tab:  Galois field GF(2^m) log lookup table
>> + * @mod8_tab:   remainder generator polynomial lookup tables
>> + * @ecc_buf:    ecc parity words buffer
>> + * @ecc_buf2:   ecc parity words buffer
>> + * @xi_tab:     GF(2^m) base for solving degree 2 polynomial roots
>> + * @syn:        syndrome buffer
>> + * @cache:      log-based polynomial representation buffer
>> + * @elp:        error locator polynomial
>> + * @poly_2t:    temporary polynomials of degree 2t
>> + */
>> +struct bch_control {
>> +    unsigned int    m;
>> +    unsigned int    n;
>> +    unsigned int    t;
>> +    unsigned int    ecc_bits;
>> +    unsigned int    ecc_bytes;
>> +/* private: */
>> +    uint16_t       *a_pow_tab;
>> +    uint16_t       *a_log_tab;
>> +    uint32_t       *mod8_tab;
>> +    uint32_t       *ecc_buf;
>> +    uint32_t       *ecc_buf2;
>> +    unsigned int   *xi_tab;
>> +    unsigned int   *syn;
>> +    int            *cache;
>> +    struct gf_poly *elp;
>> +    struct gf_poly *poly_2t[4];
>> +};
>> +
>> +static int fls(int x)
>> +{
>> +    int r = 32;
>> +
>> +    if (!x)
>> +        return 0;
>> +    if (!(x & 0xffff0000u)) {
>> +        x <<= 16;
>> +        r -= 16;
>> +    }
>> +    if (!(x & 0xff000000u)) {
>> +        x <<= 8;
>> +        r -= 8;
>> +    }
>> +    if (!(x & 0xf0000000u)) {
>> +        x <<= 4;
>> +        r -= 4;
>> +    }
>> +    if (!(x & 0xc0000000u)) {
>> +        x <<= 2;
>> +        r -= 2;
>> +    }
>> +    if (!(x & 0x80000000u)) {
>> +        x <<= 1;
>> +        r -= 1;
>> +    }
>> +    return r;
>> +}
>> +
>> +/*
>> + * represent a polynomial over GF(2^m)
>> + */
>> +struct gf_poly {
>> +    unsigned int deg;    /* polynomial degree */
>> +    unsigned int c[0];   /* polynomial terms */
>> +};
>> +
>> +/* given its degree, compute a polynomial size in bytes */
>> +#define GF_POLY_SZ(_d) (sizeof(struct gf_poly)+((_d)+1)*sizeof(unsigned int))
>> +
>> +/* polynomial of degree 1 */
>> +struct gf_poly_deg1 {
>> +    struct gf_poly poly;
>> +    unsigned int   c[2];
>> +};
>> +
>> +/*
>> + * same as encode_bch(), but process input data one byte at a time
>> + */
>> +static void encode_bch_unaligned(struct bch_control *bch,
>> +                 const unsigned char *data, unsigned int len,
>> +                 uint32_t *ecc)
>> +{
>> +    int i;
>> +    const uint32_t *p;
>> +    const int l = BCH_ECC_WORDS(bch)-1;
>> +
>> +    while (len--) {
>> +        p = bch->mod8_tab + (l+1)*(((ecc[0] >> 24)^(*data++)) & 0xff);
>> +
>> +        for (i = 0; i < l; i++)
>> +            ecc[i] = ((ecc[i] << 8)|(ecc[i+1] >> 24))^(*p++);
>> +
>> +        ecc[l] = (ecc[l] << 8)^(*p);
>> +    }
>> +}
>> +
>> +/*
>> + * convert ecc bytes to aligned, zero-padded 32-bit ecc words
>> + */
>> +static void load_ecc8(struct bch_control *bch, uint32_t *dst,
>> +              const uint8_t *src)
>> +{
>> +    uint8_t pad[4] = {0, 0, 0, 0};
>> +    unsigned int i, nwords = BCH_ECC_WORDS(bch)-1;
>> +
>> +    for (i = 0; i < nwords; i++, src += 4)
>> +        dst[i] = (src[0] << 24)|(src[1] << 16)|(src[2] << 8)|src[3];
>> +
>> +    memcpy(pad, src, BCH_ECC_BYTES(bch)-4*nwords);
>> +    dst[nwords] = (pad[0] << 24)|(pad[1] << 16)|(pad[2] << 8)|pad[3];
>> +}
>> +
>> +/*
>> + * convert 32-bit ecc words to ecc bytes
>> + */
>> +static void store_ecc8(struct bch_control *bch, uint8_t *dst,
>> +               const uint32_t *src)
>> +{
>> +    uint8_t pad[4];
>> +    unsigned int i, nwords = BCH_ECC_WORDS(bch)-1;
>> +
>> +    for (i = 0; i < nwords; i++) {
>> +        *dst++ = (src[i] >> 24);
>> +        *dst++ = (src[i] >> 16) & 0xff;
>> +        *dst++ = (src[i] >>  8) & 0xff;
>> +        *dst++ = (src[i] >>  0) & 0xff;
>> +    }
>> +    pad[0] = (src[nwords] >> 24);
>> +    pad[1] = (src[nwords] >> 16) & 0xff;
>> +    pad[2] = (src[nwords] >>  8) & 0xff;
>> +    pad[3] = (src[nwords] >>  0) & 0xff;
>> +    memcpy(dst, pad, BCH_ECC_BYTES(bch)-4*nwords);
>> +}
>> +
>> +/**
>> + * encode_bch - calculate BCH ecc parity of data
>> + * @bch:   BCH control structure
>> + * @data:  data to encode
>> + * @len:   data length in bytes
>> + * @ecc:   ecc parity data, must be initialized by caller
>> + *
>> + * The @ecc parity array is used both as input and output parameter, in order to
>> + * allow incremental computations. It should be of the size indicated by member
>> + * @ecc_bytes of @bch, and should be initialized to 0 before the first call.
>> + *
>> + * The exact number of computed ecc parity bits is given by member @ecc_bits of
>> + * @bch; it may be less than m*t for large values of t.
>> + */
>> +static void encode_bch(struct bch_control *bch, const uint8_t *data,
>> +        unsigned int len, uint8_t *ecc)
>> +{
>> +    const unsigned int l = BCH_ECC_WORDS(bch)-1;
>> +    unsigned int i, mlen;
>> +    unsigned long m;
>> +    uint32_t w, r[l+1];
>> +    const uint32_t * const tab0 = bch->mod8_tab;
>> +    const uint32_t * const tab1 = tab0 + 256*(l+1);
>> +    const uint32_t * const tab2 = tab1 + 256*(l+1);
>> +    const uint32_t * const tab3 = tab2 + 256*(l+1);
>> +    const uint32_t *pdata, *p0, *p1, *p2, *p3;
>> +
>> +    if (ecc) {
>> +        /* load ecc parity bytes into internal 32-bit buffer */
>> +        load_ecc8(bch, bch->ecc_buf, ecc);
>> +    } else {
>> +        memset(bch->ecc_buf, 0, sizeof(r));
>> +    }
>> +
>> +    /* process first unaligned data bytes */
>> +    m = ((uintptr_t)data) & 3;
>> +    if (m) {
>> +        mlen = (len < (4-m)) ? len : 4-m;
>> +        encode_bch_unaligned(bch, data, mlen, bch->ecc_buf);
>> +        data += mlen;
>> +        len  -= mlen;
>> +    }
>> +
>> +    /* process 32-bit aligned data words */
>> +    pdata = (uint32_t *)data;
>> +    mlen  = len/4;
>> +    data += 4*mlen;
>> +    len  -= 4*mlen;
>> +    memcpy(r, bch->ecc_buf, sizeof(r));
>> +
>> +    /*
>> +     * split each 32-bit word into 4 polynomials of weight 8 as follows:
>> +     *
>> +     * 31 ...24  23 ...16  15 ... 8  7 ... 0
>> +     * xxxxxxxx  yyyyyyyy  zzzzzzzz  tttttttt
>> +     *                               tttttttt  mod g = r0 (precomputed)
>> +     *                     zzzzzzzz  00000000  mod g = r1 (precomputed)
>> +     *           yyyyyyyy  00000000  00000000  mod g = r2 (precomputed)
>> +     * xxxxxxxx  00000000  00000000  00000000  mod g = r3 (precomputed)
>> +     * xxxxxxxx  yyyyyyyy  zzzzzzzz  tttttttt  mod g = r0^r1^r2^r3
>> +     */
>> +    while (mlen--) {
>> +        /* input data is read in big-endian format */
>> +        w = r[0]^cpu_to_be32(*pdata++);
>> +        p0 = tab0 + (l+1)*((w >>  0) & 0xff);
>> +        p1 = tab1 + (l+1)*((w >>  8) & 0xff);
>> +        p2 = tab2 + (l+1)*((w >> 16) & 0xff);
>> +        p3 = tab3 + (l+1)*((w >> 24) & 0xff);
>> +
>> +        for (i = 0; i < l; i++)
>> +            r[i] = r[i+1]^p0[i]^p1[i]^p2[i]^p3[i];
>> +
>> +        r[l] = p0[l]^p1[l]^p2[l]^p3[l];
>> +    }
>> +    memcpy(bch->ecc_buf, r, sizeof(r));
>> +
>> +    /* process last unaligned bytes */
>> +    if (len)
>> +        encode_bch_unaligned(bch, data, len, bch->ecc_buf);
>> +
>> +    /* store ecc parity bytes into original parity buffer */
>> +    if (ecc)
>> +        store_ecc8(bch, ecc, bch->ecc_buf);
>> +}
>> +
>> +static inline int modulo(struct bch_control *bch, unsigned int v)
>> +{
>> +    const unsigned int n = GF_N(bch);
>> +    while (v >= n) {
>> +        v -= n;
>> +        v = (v & n) + (v >> GF_M(bch));
>> +    }
>> +    return v;
>> +}
>> +
>> +/*
>> + * shorter and faster modulo function, only works when v < 2N.
>> + */
>> +static inline int mod_s(struct bch_control *bch, unsigned int v)
>> +{
>> +    const unsigned int n = GF_N(bch);
>> +    return (v < n) ? v : v-n;
>> +}
>> +
>> +static inline int deg(unsigned int poly)
>> +{
>> +    /* polynomial degree is the most-significant bit index */
>> +    return fls(poly)-1;
>> +}
>> +
>> +/* Galois field basic operations: multiply, divide, inverse, etc. */
>> +
>> +static inline unsigned int gf_mul(struct bch_control *bch, unsigned int a,
>> +                  unsigned int b)
>> +{
>> +    return (a && b) ? bch->a_pow_tab[mod_s(bch, bch->a_log_tab[a]+
>> +                           bch->a_log_tab[b])] : 0;
>> +}
>> +
>> +static inline unsigned int gf_sqr(struct bch_control *bch, unsigned int a)
>> +{
>> +    return a ? bch->a_pow_tab[mod_s(bch, 2*bch->a_log_tab[a])] : 0;
>> +}
>> +
>> +static inline unsigned int a_pow(struct bch_control *bch, int i)
>> +{
>> +    return bch->a_pow_tab[modulo(bch, i)];
>> +}
>> +
>> +static inline int a_log(struct bch_control *bch, unsigned int x)
>> +{
>> +    return bch->a_log_tab[x];
>> +}
>> +
>> +/*
>> + * generate Galois field lookup tables
>> + */
>> +static int build_gf_tables(struct bch_control *bch, unsigned int poly)
>> +{
>> +    unsigned int i, x = 1;
>> +    const unsigned int k = 1 << deg(poly);
>> +
>> +    /* primitive polynomial must be of degree m */
>> +    if (k != (1u << GF_M(bch)))
>> +        return -1;
>> +
>> +    for (i = 0; i < GF_N(bch); i++) {
>> +        bch->a_pow_tab[i] = x;
>> +        bch->a_log_tab[x] = i;
>> +        if (i && (x == 1))
>> +            /* polynomial is not primitive (a^i=1 with 0<i<2^m-1) */
>> +            return -1;
>> +        x <<= 1;
>> +        if (x & k)
>> +            x ^= poly;
>> +    }
>> +    bch->a_pow_tab[GF_N(bch)] = 1;
>> +    bch->a_log_tab[0] = 0;
>> +
>> +    return 0;
>> +}
>> +
>> +/*
>> + * compute generator polynomial remainder tables for fast encoding
>> + */
>> +static void build_mod8_tables(struct bch_control *bch, const uint32_t *g)
>> +{
>> +    int i, j, b, d;
>> +    uint32_t data, hi, lo, *tab;
>> +    const int l = BCH_ECC_WORDS(bch);
>> +    const int plen = DIV_ROUND_UP(bch->ecc_bits+1, 32);
>> +    const int ecclen = DIV_ROUND_UP(bch->ecc_bits, 32);
>> +
>> +    memset(bch->mod8_tab, 0, 4*256*l*sizeof(*bch->mod8_tab));
>> +
>> +    for (i = 0; i < 256; i++) {
>> +        /* p(X)=i is a small polynomial of weight <= 8 */
>> +        for (b = 0; b < 4; b++) {
>> +            /* we want to compute (p(X).X^(8*b+deg(g))) mod g(X) */
>> +            tab = bch->mod8_tab + (b*256+i)*l;
>> +            data = i << (8*b);
>> +            while (data) {
>> +                d = deg(data);
>> +                /* subtract X^d.g(X) from p(X).X^(8*b+deg(g)) */
>> +                data ^= g[0] >> (31-d);
>> +                for (j = 0; j < ecclen; j++) {
>> +                    hi = (d < 31) ? g[j] << (d+1) : 0;
>> +                    lo = (j+1 < plen) ?
>> +                        g[j+1] >> (31-d) : 0;
>> +                    tab[j] ^= hi|lo;
>> +                }
>> +            }
>> +        }
>> +    }
>> +}
>> +
>> +/*
>> + * build a base for factoring degree 2 polynomials
>> + */
>> +static int build_deg2_base(struct bch_control *bch)
>> +{
>> +    const int m = GF_M(bch);
>> +    int i, j, r;
>> +    unsigned int sum, x, y, remaining, ak = 0, xi[m];
>> +
>> +    /* find k s.t. Tr(a^k) = 1 and 0 <= k < m */
>> +    for (i = 0; i < m; i++) {
>> +        for (j = 0, sum = 0; j < m; j++)
>> +            sum ^= a_pow(bch, i*(1 << j));
>> +
>> +        if (sum) {
>> +            ak = bch->a_pow_tab[i];
>> +            break;
>> +        }
>> +    }
>> +    /* find xi, i=0..m-1 such that xi^2+xi = a^i+Tr(a^i).a^k */
>> +    remaining = m;
>> +    memset(xi, 0, sizeof(xi));
>> +
>> +    for (x = 0; (x <= GF_N(bch)) && remaining; x++) {
>> +        y = gf_sqr(bch, x)^x;
>> +        for (i = 0; i < 2; i++) {
>> +            r = a_log(bch, y);
>> +            if (y && (r < m) && !xi[r]) {
>> +                bch->xi_tab[r] = x;
>> +                xi[r] = 1;
>> +                remaining--;
>> +                dbg("x%d = %x\n", r, x);
>> +                break;
>> +            }
>> +            y ^= ak;
>> +        }
>> +    }
>> +    /* should not happen but check anyway */
>> +    return remaining ? -1 : 0;
>> +}
>> +
>> +static void *bch_alloc(size_t size, int *err)
>> +{
>> +    void *ptr;
>> +
>> +    ptr = malloc(size);
>> +    if (ptr == NULL)
>> +        *err = 1;
>> +    return ptr;
>> +}
>> +
>> +/*
>> + * compute generator polynomial for given (m,t) parameters.
>> + */
>> +static uint32_t *compute_generator_polynomial(struct bch_control *bch)
>> +{
>> +    const unsigned int m = GF_M(bch);
>> +    const unsigned int t = GF_T(bch);
>> +    int n, err = 0;
>> +    unsigned int i, j, nbits, r, word, *roots;
>> +    struct gf_poly *g;
>> +    uint32_t *genpoly;
>> +
>> +    g = bch_alloc(GF_POLY_SZ(m*t), &err);
>> +    roots = bch_alloc((bch->n+1)*sizeof(*roots), &err);
>> +    genpoly = bch_alloc(DIV_ROUND_UP(m*t+1, 32)*sizeof(*genpoly), &err);
>> +
>> +    if (err) {
>> +        kfree(genpoly);
>> +        genpoly = NULL;
>> +        goto finish;
>> +    }
>> +
>> +    /* enumerate all roots of g(X) */
>> +    memset(roots , 0, (bch->n+1)*sizeof(*roots));
>> +    for (i = 0; i < t; i++) {
>> +        for (j = 0, r = 2*i+1; j < m; j++) {
>> +            roots[r] = 1;
>> +            r = mod_s(bch, 2*r);
>> +        }
>> +    }
>> +    /* build generator polynomial g(X) */
>> +    g->deg = 0;
>> +    g->c[0] = 1;
>> +    for (i = 0; i < GF_N(bch); i++) {
>> +        if (roots[i]) {
>> +            /* multiply g(X) by (X+root) */
>> +            r = bch->a_pow_tab[i];
>> +            g->c[g->deg+1] = 1;
>> +            for (j = g->deg; j > 0; j--)
>> +                g->c[j] = gf_mul(bch, g->c[j], r)^g->c[j-1];
>> +
>> +            g->c[0] = gf_mul(bch, g->c[0], r);
>> +            g->deg++;
>> +        }
>> +    }
>> +    /* store left-justified binary representation of g(X) */
>> +    n = g->deg+1;
>> +    i = 0;
>> +
>> +    while (n > 0) {
>> +        nbits = (n > 32) ? 32 : n;
>> +        for (j = 0, word = 0; j < nbits; j++) {
>> +            if (g->c[n-1-j])
>> +                word |= 1u << (31-j);
>> +        }
>> +        genpoly[i++] = word;
>> +        n -= nbits;
>> +    }
>> +    bch->ecc_bits = g->deg;
>> +
>> +finish:
>> +    kfree(g);
>> +    kfree(roots);
>> +
>> +    return genpoly;
>> +}
>> +
>> +/**
>> + *  free_bch - free the BCH control structure
>> + *  @bch:    BCH control structure to release
>> + */
>> +static void free_bch(struct bch_control *bch)
>> +{
>> +    unsigned int i;
>> +
>> +    if (bch) {
>> +        kfree(bch->a_pow_tab);
>> +        kfree(bch->a_log_tab);
>> +        kfree(bch->mod8_tab);
>> +        kfree(bch->ecc_buf);
>> +        kfree(bch->ecc_buf2);
>> +        kfree(bch->xi_tab);
>> +        kfree(bch->syn);
>> +        kfree(bch->cache);
>> +        kfree(bch->elp);
>> +
>> +        for (i = 0; i < ARRAY_SIZE(bch->poly_2t); i++)
>> +            kfree(bch->poly_2t[i]);
>> +
>> +        kfree(bch);
>> +    }
>> +}
>> +
>> +/**
>> + * init_bch - initialize a BCH encoder/decoder
>> + * @m:          Galois field order, should be in the range 5-15
>> + * @t:          maximum error correction capability, in bits
>> + * @prim_poly:  user-provided primitive polynomial (or 0 to use default)
>> + *
>> + * Returns:
>> + *  a newly allocated BCH control structure if successful, NULL otherwise
>> + *
>> + * This initialization can take some time, as lookup tables are built for fast
>> + * encoding/decoding; make sure not to call this function from a time critical
>> + * path. Usually, init_bch() should be called on module/driver init and
>> + * free_bch() should be called to release memory on exit.
>> + *
>> + * You may provide your own primitive polynomial of degree @m in argument
>> + * @prim_poly, or let init_bch() use its default polynomial.
>> + *
>> + * Once init_bch() has successfully returned a pointer to a newly allocated
>> + * BCH control structure, ecc length in bytes is given by member @ecc_bytes of
>> + * the structure.
>> + */
>> +static struct bch_control *init_bch(int m, int t, unsigned int prim_poly)
>> +{
>> +    int err = 0;
>> +    unsigned int i, words;
>> +    uint32_t *genpoly;
>> +    struct bch_control *bch = NULL;
>> +
>> +    const int min_m = 5;
>> +    const int max_m = 15;
>> +
>> +    /* default primitive polynomials */
>> +    static const unsigned int prim_poly_tab[] = {
>> +        0x25, 0x43, 0x83, 0x11d, 0x211, 0x409, 0x805, 0x1053, 0x201b,
>> +        0x402b, 0x8003,
>> +    };
>> +
>> +#if defined(CONFIG_BCH_CONST_PARAMS)
>> +    if ((m != (CONFIG_BCH_CONST_M)) || (t != (CONFIG_BCH_CONST_T))) {
>> +        printk(KERN_ERR "bch encoder/decoder was configured to support "
>> +               "parameters m=%d, t=%d only!\n",
>> +               CONFIG_BCH_CONST_M, CONFIG_BCH_CONST_T);
>> +        goto fail;
>> +    }
>> +#endif
>> +    if ((m < min_m) || (m > max_m))
>> +        /*
>> +         * values of m greater than 15 are not currently supported;
>> +         * supporting m > 15 would require changing table base type
>> +         * (uint16_t) and a small patch in matrix transposition
>> +         */
>> +        goto fail;
>> +
>> +    /* sanity checks */
>> +    if ((t < 1) || (m*t >= ((1 << m)-1)))
>> +        /* invalid t value */
>> +        goto fail;
>> +
>> +    /* select a primitive polynomial for generating GF(2^m) */
>> +    if (prim_poly == 0)
>> +        prim_poly = prim_poly_tab[m-min_m];
>> +
>> +    bch = malloc(sizeof(*bch));
>> +    if (bch == NULL)
>> +        goto fail;
>> +
>> +    memset(bch, 0, sizeof(*bch));
>> +
>> +    bch->m = m;
>> +    bch->t = t;
>> +    bch->n = (1 << m)-1;
>> +    words  = DIV_ROUND_UP(m*t, 32);
>> +    bch->ecc_bytes = DIV_ROUND_UP(m*t, 8);
>> +    bch->a_pow_tab = bch_alloc((1+bch->n)*sizeof(*bch->a_pow_tab), &err);
>> +    bch->a_log_tab = bch_alloc((1+bch->n)*sizeof(*bch->a_log_tab), &err);
>> +    bch->mod8_tab  = bch_alloc(words*1024*sizeof(*bch->mod8_tab), &err);
>> +    bch->ecc_buf   = bch_alloc(words*sizeof(*bch->ecc_buf), &err);
>> +    bch->ecc_buf2  = bch_alloc(words*sizeof(*bch->ecc_buf2), &err);
>> +    bch->xi_tab    = bch_alloc(m*sizeof(*bch->xi_tab), &err);
>> +    bch->syn       = bch_alloc(2*t*sizeof(*bch->syn), &err);
>> +    bch->cache     = bch_alloc(2*t*sizeof(*bch->cache), &err);
>> +    bch->elp       = bch_alloc((t+1)*sizeof(struct gf_poly_deg1), &err);
>> +
>> +    for (i = 0; i < ARRAY_SIZE(bch->poly_2t); i++)
>> +        bch->poly_2t[i] = bch_alloc(GF_POLY_SZ(2*t), &err);
>> +
>> +    if (err)
>> +        goto fail;
>> +
>> +    err = build_gf_tables(bch, prim_poly);
>> +    if (err)
>> +        goto fail;
>> +
>> +    /* use generator polynomial for computing encoding tables */
>> +    genpoly = compute_generator_polynomial(bch);
>> +    if (genpoly == NULL)
>> +        goto fail;
>> +
>> +    build_mod8_tables(bch, genpoly);
>> +    kfree(genpoly);
>> +
>> +    err = build_deg2_base(bch);
>> +    if (err)
>> +        goto fail;
>> +
>> +    return bch;
>> +
>> +fail:
>> +    free_bch(bch);
>> +    return NULL;
>> +}
>> +
>> +static void swap_bits(uint8_t *buf, int len)
>> +{
>> +    int i, j;
>> +
>> +    for (j = 0; j < len; j++) {
>> +        uint8_t byte = buf[j];
>> +
>> +        buf[j] = 0;
>> +        for (i = 0; i < 8; i++) {
>> +            if (byte & (1 << i))
>> +                buf[j] |= (1 << (7 - i));
>> +        }
>> +    }
>> +}
>> +
>> +static uint16_t lfsr_step(uint16_t state, int count)
>> +{
>> +    state &= 0x7fff;
>> +    while (count--)
>> +        state = ((state >> 1) |
>> +             ((((state >> 0) ^ (state >> 1)) & 1) << 14)) & 0x7fff;
>> +
>> +    return state;
>> +}
>> +
>> +static uint16_t default_scrambler_seeds[] = {
>> +    0x2b75, 0x0bd0, 0x5ca3, 0x62d1, 0x1c93, 0x07e9, 0x2162, 0x3a72,
>> +    0x0d67, 0x67f9, 0x1be7, 0x077d, 0x032f, 0x0dac, 0x2716, 0x2436,
>> +    0x7922, 0x1510, 0x3860, 0x5287, 0x480f, 0x4252, 0x1789, 0x5a2d,
>> +    0x2a49, 0x5e10, 0x437f, 0x4b4e, 0x2f45, 0x216e, 0x5cb7, 0x7130,
>> +    0x2a3f, 0x60e4, 0x4dc9, 0x0ef0, 0x0f52, 0x1bb9, 0x6211, 0x7a56,
>> +    0x226d, 0x4ea7, 0x6f36, 0x3692, 0x38bf, 0x0c62, 0x05eb, 0x4c55,
>> +    0x60f4, 0x728c, 0x3b6f, 0x2037, 0x7f69, 0x0936, 0x651a, 0x4ceb,
>> +    0x6218, 0x79f3, 0x383f, 0x18d9, 0x4f05, 0x5c82, 0x2912, 0x6f17,
>> +    0x6856, 0x5938, 0x1007, 0x61ab, 0x3e7f, 0x57c2, 0x542f, 0x4f62,
>> +    0x7454, 0x2eac, 0x7739, 0x42d4, 0x2f90, 0x435a, 0x2e52, 0x2064,
>> +    0x637c, 0x66ad, 0x2c90, 0x0bad, 0x759c, 0x0029, 0x0986, 0x7126,
>> +    0x1ca7, 0x1605, 0x386a, 0x27f5, 0x1380, 0x6d75, 0x24c3, 0x0f8e,
>> +    0x2b7a, 0x1418, 0x1fd1, 0x7dc1, 0x2d8e, 0x43af, 0x2267, 0x7da3,
>> +    0x4e3d, 0x1338, 0x50db, 0x454d, 0x764d, 0x40a3, 0x42e6, 0x262b,
>> +    0x2d2e, 0x1aea, 0x2e17, 0x173d, 0x3a6e, 0x71bf, 0x25f9, 0x0a5d,
>> +    0x7c57, 0x0fbe, 0x46ce, 0x4939, 0x6b17, 0x37bb, 0x3e91, 0x76db,
>> +};
>> +
>> +static uint16_t brom_scrambler_seeds[] = { 0x4a80 };
>> +
>> +static void scramble(const struct image_info *info,
>> +             int page, uint8_t *data, int datalen)
>> +{
>> +    uint16_t state;
>> +    int i;
>> +
>> +    /* Boot0 is always scrambled no matter the command line option. */
>> +    if (info->boot0) {
>> +        state = brom_scrambler_seeds[0];
>> +    } else {
>> +        unsigned seedmod = info->eraseblock_size / info->page_size;
>> +
>> +        /* Bail out earlier if the user didn't ask for scrambling. */
>> +        if (!info->scramble)
>> +            return;
>> +
>> +        if (seedmod > ARRAY_SIZE(default_scrambler_seeds))
>> +            seedmod = ARRAY_SIZE(default_scrambler_seeds);
>> +
>> +        state = default_scrambler_seeds[page % seedmod];
>> +    }
>> +
>> +    /* Prepare the initial state... */
>> +    state = lfsr_step(state, 15);
>> +
>> +    /* and start scrambling data. */
>> +    for (i = 0; i < datalen; i++) {
>> +        data[i] ^= state;
>> +        state = lfsr_step(state, 8);
>> +    }
>> +}
>> +
>> +static int write_page(const struct image_info *info, uint8_t *buffer,
>> +              FILE *src, FILE *rnd, FILE *dst,
>> +              struct bch_control *bch, int page)
>> +{
>> +    int steps = info->usable_page_size / info->ecc_step_size;
>> +    int eccbytes = DIV_ROUND_UP(info->ecc_strength * 14, 8);
>> +    off_t pos = ftell(dst);
>> +    size_t pad, cnt;
>> +    int i;
>> +
>> +    if (eccbytes % 2)
>> +        eccbytes++;
>> +
>> +    memset(buffer, 0xff, info->page_size + info->oob_size);
>> +    cnt = fread(buffer, 1, info->usable_page_size, src);
>> +    if (!cnt) {
>> +        if (!feof(src)) {
>> +            fprintf(stderr,
>> +                "Failed to read data from the source\n");
>> +            return -1;
>> +        } else {
>> +            return 0;
>> +        }
>> +    }
>> +
>> +    fwrite(buffer, info->page_size + info->oob_size, 1, dst);
>> +
>> +    for (i = 0; i < info->usable_page_size; i++) {
>> +        if (buffer[i] !=  0xff)
>> +            break;
>> +    }
>> +
>> +    /* We leave empty pages at 0xff. */
>> +    if (i == info->usable_page_size)
>> +        return 0;
>> +
>> +    /* Restore the source pointer to read it again. */
>> +    fseek(src, -cnt, SEEK_CUR);
>> +
>> +    /* Randomize unused space if scrambling is required. */
>> +    if (info->scramble) {
>> +        int offs;
>> +
>> +        if (info->boot0) {
>> +            offs = steps * (info->ecc_step_size + eccbytes + 4);
>> +            cnt = info->page_size + info->oob_size - offs;
>> +            fread(buffer + offs, 1, cnt, rnd);
>> +        } else {
>> +            offs = info->page_size + (steps * (eccbytes + 4));
>> +            cnt = info->page_size + info->oob_size - offs;
>> +            memset(buffer + offs, 0xff, cnt);
>> +            scramble(info, page, buffer + offs, cnt);
>> +        }
>> +        fseek(dst, pos + offs, SEEK_SET);
>> +        fwrite(buffer + offs, cnt, 1, dst);
>> +    }
>> +
>> +    for (i = 0; i < steps; i++) {
>> +        int ecc_offs, data_offs;
>> +        uint8_t *ecc;
>> +
>> +        memset(buffer, 0xff, info->ecc_step_size + eccbytes + 4);
>> +        ecc = buffer + info->ecc_step_size + 4;
>> +        if (info->boot0) {
>> +            data_offs = i * (info->ecc_step_size + eccbytes + 4);
>> +            ecc_offs = data_offs + info->ecc_step_size + 4;
>> +        } else {
>> +            data_offs = i * info->ecc_step_size;
>> +            ecc_offs = info->page_size + 4 + (i * (eccbytes + 4));
>> +        }
>> +
>> +        cnt = fread(buffer, 1, info->ecc_step_size, src);
>> +        if (!cnt && !feof(src)) {
>> +            fprintf(stderr,
>> +                "Failed to read data from the source\n");
>> +            return -1;
>> +        }
>> +
>> +        pad = info->ecc_step_size - cnt;
>> +        if (pad) {
>> +            if (info->scramble && info->boot0)
>> +                fread(buffer + cnt, 1, pad, rnd);
>> +            else
>> +                memset(buffer + cnt, 0xff, pad);
>> +        }
>> +
>> +        memset(ecc, 0, eccbytes);
>> +        swap_bits(buffer, info->ecc_step_size + 4);
>> +        encode_bch(bch, buffer, info->ecc_step_size + 4, ecc);
>> +        swap_bits(buffer, info->ecc_step_size + 4);
>> +        swap_bits(ecc, eccbytes);
>> +        scramble(info, page, buffer, info->ecc_step_size + 4 + eccbytes);
>> +
>> +        fseek(dst, pos + data_offs, SEEK_SET);
>> +        fwrite(buffer, info->ecc_step_size, 1, dst);
>> +        fseek(dst, pos + ecc_offs - 4, SEEK_SET);
>> +        fwrite(ecc - 4, eccbytes + 4, 1, dst);
>> +    }
>> +
>> +    /* Fix BBM. */
>> +    fseek(dst, pos + info->page_size, SEEK_SET);
>> +    memset(buffer, 0xff, 2);
>> +    fwrite(buffer, 2, 1, dst);
>> +
>> +    /* Make dst pointer point to the next page. */
>> +    fseek(dst, pos + info->page_size + info->oob_size, SEEK_SET);
>> +
>> +    return 0;
>> +}
>> +
>> +static int create_image(const struct image_info *info)
>> +{
>> +    off_t page = info->offset / info->page_size;
>> +    struct bch_control *bch;
>> +    FILE *src, *dst, *rnd;
>> +    uint8_t *buffer;
>> +
>> +    bch = init_bch(14, info->ecc_strength, BCH_PRIMITIVE_POLY);
>> +    if (!bch) {
>> +        fprintf(stderr, "Failed to init the BCH engine\n");
>> +        return -1;
>> +    }
>> +
>> +    buffer = malloc(info->page_size + info->oob_size);
>> +    if (!buffer) {
>> +        fprintf(stderr, "Failed to allocate the NAND page buffer\n");
>> +        return -1;
>> +    }
>> +
>> +    memset(buffer, 0xff, info->page_size + info->oob_size);
>> +
>> +    src = fopen(info->source, "r");
>> +    if (!src) {
>> +        fprintf(stderr, "Failed to open source file (%s)\n",
>> +            info->source);
>> +        return -1;
>> +    }
>> +
>> +    dst = fopen(info->dest, "w");
>> +    if (!dst) {
>> +        fprintf(stderr, "Failed to open dest file (%s)\n", info->dest);
>> +        return -1;
>> +    }
>> +
>> +    rnd = fopen("/dev/urandom", "r");
>> +    if (!rnd) {
>> +        fprintf(stderr, "Failed to open /dev/urandom\n");
>> +        return -1;
>> +    }
>> +
>> +    while (!feof(src)) {
>> +        int ret;
>> +
>> +        ret = write_page(info, buffer, src, rnd, dst, bch, page++);
>> +        if (ret)
>> +            return ret;
>> +    }
>> +
>> +    return 0;
>> +}
>> +
>> +static void display_help(int status)
>> +{
>> +    fprintf(status == EXIT_SUCCESS ? stdout : stderr,
>> +        "sunxi-nand-image-builder %s\n"
>> +        "\n"
>> +        "Usage: sunxi-nand-image-builder [OPTIONS] source-image output-image\n"
>> +        "\n"
>> +        "Creates a raw NAND image that can be read by the sunxi NAND controller.\n"
>> +        "\n"
>> +        "-h               --help               Display this help and exit\n"
>> +        "-c <str>/<step>  --ecc=<str>/<step>   ECC config (strength/step-size)\n"
>> +        "-p <size>        --page=<size>        Page size\n"
>> +        "-o <size>        --oob=<size>         OOB size\n"
>> +        "-u <size>        --usable=<size>      Usable page size\n"
>> +        "-e <size>        --eraseblock=<size>  Erase block size\n"
>> +        "-b               --boot0              Build a boot0 image.\n"
>> +        "-s               --scramble           Scramble data\n"
>> +        "-a <offset>      --address=<offset>   Where the image will be programmed.\n"
>> +        "\n"
>> +        "Notes:\n"
>> +        "All the information you need to pass to this tool should be part of\n"
>> +        "the NAND datasheet.\n"
>> +        "\n"
>> +        "The NAND controller only supports the following ECC configs\n"
>> +        "  Valid ECC strengths: 16, 24, 28, 32, 40, 48, 56, 60 and 64\n"
>> +        "  Valid ECC step size: 512 and 1024\n"
>> +        "\n"
>> +        "If you are building a boot0 image, you'll have specify extra options.\n"
>> +        "These options should be chosen based on the layouts described here:\n"
>> +        "  http://linux-sunxi.org/NAND#More_information_on_BROM_NAND\n"
>> +        "\n"
>> +        "  --usable should be assigned the 'Hardware page' value\n"
>> +        "  --ecc should be assigned the 'ECC capacity'/'ECC page' values\n"
>> +        "  --usable should be smaller than --page\n"
>> +        "\n"
>> +        "The --address option is only required for non-boot0 images that are \n"
>> +        "meant to be programmed at a non eraseblock aligned offset.\n"
>> +        "\n"
>> +        "Examples:\n"
>> +        "  The H27UCG8T2BTR-BC NAND exposes\n"
>> +        "  * 16k pages\n"
>> +        "  * 1280 OOB bytes per page\n"
>> +        "  * 4M eraseblocks\n"
>> +        "  * requires data scrambling\n"
>> +        "  * expects a minimum ECC of 40bits/1024bytes\n"
>> +        "\n"
>> +        "  A normal image can be generated with\n"
>> +        "    sunxi-nand-image-builder -p 16384 -o 1280 -e 0x400000 -s -c 40/1024\n"
>> +        "  A boot0 image can be generated with\n"
>> +        "    sunxi-nand-image-builder -p 16384 -o 1280 -e 0x400000 -s -b -u 4096 -c 64/1024\n",
>> +        PLAIN_VERSION);
>> +    exit(status);
>> +}
>> +
>> +static int check_image_info(struct image_info *info)
>> +{
>> +    static int valid_ecc_strengths[] = { 16, 24, 28, 32, 40, 48, 56, 60, 64 };
>> +    int eccbytes, eccsteps;
>> +    unsigned i;
>> +
>> +    if (!info->page_size) {
>> +        fprintf(stderr, "--page is missing\n");
>> +        return -EINVAL;
>> +    }
>> +
>> +    if (!info->page_size) {
>> +        fprintf(stderr, "--oob is missing\n");
>> +        return -EINVAL;
>> +    }
>> +
>> +    if (!info->eraseblock_size) {
>> +        fprintf(stderr, "--eraseblock is missing\n");
>> +        return -EINVAL;
>> +    }
>> +
>> +    if (info->ecc_step_size != 512 && info->ecc_step_size != 1024) {
>> +        fprintf(stderr, "Invalid ECC step argument: %d\n",
>> +            info->ecc_step_size);
>> +        return -EINVAL;
>> +    }
>> +
>> +    for (i = 0; i < ARRAY_SIZE(valid_ecc_strengths); i++) {
>> +        if (valid_ecc_strengths[i] == info->ecc_strength)
>> +            break;
>> +    }
>> +
>> +    if (i == ARRAY_SIZE(valid_ecc_strengths)) {
>> +        fprintf(stderr, "Invalid ECC strength argument: %d\n",
>> +            info->ecc_strength);
>> +        return -EINVAL;
>> +    }
>> +
>> +    eccbytes = DIV_ROUND_UP(info->ecc_strength * 14, 8);
>> +    if (eccbytes % 2)
>> +        eccbytes++;
>> +    eccbytes += 4;
>> +
>> +    eccsteps = info->usable_page_size / info->ecc_step_size;
>> +
>> +    if (info->page_size + info->oob_size <
>> +        info->usable_page_size + (eccsteps * eccbytes)) {
>> +        fprintf(stderr,
>> +            "ECC bytes do not fit in the NAND page, choose a weaker ECC\n");
>> +        return -EINVAL;
>> +    }
>> +
>> +    return 0;
>> +}
>> +
>> +int main(int argc, char **argv)
>> +{
>> +    struct image_info info;
>> +
>> +    memset(&info, 0, sizeof(info));
>> +    /*
>> +     * Process user arguments
>> +     */
>> +    for (;;) {
>> +        int option_index = 0;
>> +        char *endptr = NULL;
>> +        static const struct option long_options[] = {
>> +            {"help", no_argument, 0, 'h'},
>> +            {"ecc", required_argument, 0, 'c'},
>> +            {"page", required_argument, 0, 'p'},
>> +            {"oob", required_argument, 0, 'o'},
>> +            {"usable", required_argument, 0, 'u'},
>> +            {"eraseblock", required_argument, 0, 'e'},
>> +            {"boot0", no_argument, 0, 'b'},
>> +            {"scramble", no_argument, 0, 's'},
>> +            {"address", required_argument, 0, 'a'},
>> +            {0, 0, 0, 0},
>> +        };
>> +
>> +        int c = getopt_long(argc, argv, "c:p:o:u:e:ba:sh",
>> +                long_options, &option_index);
>> +        if (c == EOF)
>> +            break;
>> +
>> +        switch (c) {
>> +        case 'h':
>> +            display_help(0);
>> +            break;
>> +        case 's':
>> +            info.scramble = 1;
>> +            break;
>> +        case 'c':
>> +            info.ecc_strength = strtol(optarg, &endptr, 0);
>> +            if (endptr || *endptr == '/')
>> +                info.ecc_step_size = strtol(endptr + 1, NULL, 0);
>> +            break;
>> +        case 'p':
>> +            info.page_size = strtol(optarg, NULL, 0);
>> +            break;
>> +        case 'o':
>> +            info.oob_size = strtol(optarg, NULL, 0);
>> +            break;
>> +        case 'u':
>> +            info.usable_page_size = strtol(optarg, NULL, 0);
>> +            break;
>> +        case 'e':
>> +            info.eraseblock_size = strtol(optarg, NULL, 0);
>> +            break;
>> +        case 'b':
>> +            info.boot0 = 1;
>> +            break;
>> +        case 'a':
>> +            info.offset = strtoull(optarg, NULL, 0);
>> +            break;
>> +        case '?':
>> +            display_help(-1);
>> +            break;
>> +        }
>> +    }
>> +
>> +    if ((argc - optind) != 2)
>> +        display_help(-1);
>> +
>> +    info.source = argv[optind];
>> +    info.dest = argv[optind + 1];
>> +
>> +    if (!info.boot0) {
>> +        info.usable_page_size = info.page_size;
>> +    } else if (!info.usable_page_size) {
>> +        if (info.page_size > 8192)
>> +            info.usable_page_size = 8192;
>> +        else if (info.page_size > 4096)
>> +            info.usable_page_size = 4096;
>> +        else
>> +            info.usable_page_size = 1024;
>> +    }
>> +
>> +    if (check_image_info(&info))
>> +        display_help(-1);
>> +
>> +    return create_image(&info);
>> +}
>>

^ permalink raw reply	[flat|nested] 44+ messages in thread

* [U-Boot] [PATCH 6/7] scripts: sunxi: Build an raw SPL image
  2016-11-14 11:19   ` Hans de Goede
@ 2016-11-14 11:30     ` Hans de Goede
  0 siblings, 0 replies; 44+ messages in thread
From: Hans de Goede @ 2016-11-14 11:30 UTC (permalink / raw)
  To: u-boot

Hi,

On 14-11-16 12:19, Hans de Goede wrote:
> Hi,
>
> On 08-11-16 17:21, Maxime Ripard wrote:
>> Introduce a new sunxi-spl-with-ecc.bin image with already the right header,
>> ECC, randomizer and padding for the BROM to be able to read it.
>>
>> It needs to be flashed using a raw access to the NAND so that the
>> controller doesn't change a thing to it, since we already have all the
>> right parameters.
>>
>> Signed-off-by: Maxime Ripard <maxime.ripard@free-electrons.com>
>
> Looks good to me:
>
> Reviewed-by: Hans de Goede <hdegoede@redhat.com>

Scrap that, this causes all sunxi boars to fail to build:

+--page is missing
+sunxi-nand-image-builder 2016.11-rc3-00069-gabe4d57
+Usage: sunxi-nand-image-builder [OPTIONS] source-image output-image
+Creates a raw NAND image that can be read by the sunxi NAND controller.
+-h               --help               Display this help and exit
+-c <str>/<step>  --ecc=<str>/<step>   ECC config (strength/step-size)
+-p <size>        --page=<size>        Page size
+-o <size>        --oob=<size>         OOB size
+-u <size>        --usable=<size>      Usable page size
+-e <size>        --eraseblock=<size>  Erase block size
+-b               --boot0              Build a boot0 image.
+-s               --scramble           Scramble data
+  Valid ECC strengths: 16, 24, 28, 32, 40, 48, 56, 60 and 64
+  Valid ECC step size: 512 and 1024
+If you are building a boot0 image, you'll have specify extra options.
+These options should be chosen based on the layouts described here:
+  http://linux-sunxi.org/NAND#More_information_on_BROM_NAND
+  --usable should be assigned the 'Hardware page' value
+  --ecc should be assigned the 'ECC capacity'/'ECC page' values
+  --usable should be smaller than --page
+The --address option is only required for non-boot0 images that are
+meant to be programmed at a non eraseblock aligned offset.
+Examples:
+  The H27UCG8T2BTR-BC NAND exposes
+  * 16k pages
+  * 1280 OOB bytes per page
+  * 4M eraseblocks
+  * requires data scrambling
+  * expects a minimum ECC of 40bits/1024bytes
+  A normal image can be generated with
+    sunxi-nand-image-builder -p 16384 -o 1280 -e 0x400000 -s -c 40/1024
+  A boot0 image can be generated with
+    sunxi-nand-image-builder -p 16384 -o 1280 -e 0x400000 -s -b -u 4096 -c 64/1024
+make[2]: *** [spl/sunxi-spl-with-ecc.bin] Error 255
+make[1]: *** [spl/u-boot-spl] Error 2

I've dropped this patch.


Regards,

Hans


>
> Regards,
>
> Hans
>
>
>
>> ---
>>  Makefile             |  3 +++
>>  scripts/Makefile.spl | 12 ++++++++++++
>>  2 files changed, 15 insertions(+), 0 deletions(-)
>>
>> diff --git a/Makefile b/Makefile
>> index 37cbcb28f75e..12a248e297b5 100644
>> --- a/Makefile
>> +++ b/Makefile
>> @@ -1345,6 +1345,9 @@ spl/u-boot-spl: tools prepare \
>>  spl/sunxi-spl.bin: spl/u-boot-spl
>>      @:
>>
>> +spl/sunxi-spl-with-ecc.bin: spl/sunxi-spl.bin
>> +    @:
>> +
>>  spl/u-boot-spl.sfp: spl/u-boot-spl
>>      @:
>>
>> diff --git a/scripts/Makefile.spl b/scripts/Makefile.spl
>> index e0b0117dc9b6..b41b4e427cc5 100644
>> --- a/scripts/Makefile.spl
>> +++ b/scripts/Makefile.spl
>> @@ -168,6 +168,7 @@ endif
>>
>>  ifdef CONFIG_ARCH_SUNXI
>>  ALL-y    += $(obj)/sunxi-spl.bin
>> +ALL-y    += $(obj)/sunxi-spl-with-ecc.bin
>>  endif
>>
>>  ifeq ($(CONFIG_SYS_SOC),"at91")
>> @@ -276,6 +277,17 @@ cmd_mksunxiboot = $(objtree)/tools/mksunxiboot $< $@
>>  $(obj)/sunxi-spl.bin: $(obj)/$(SPL_BIN).bin FORCE
>>      $(call if_changed,mksunxiboot)
>>
>> +quiet_cmd_sunxi_spl_image_builder = SUNXI_SPL_IMAGE_BUILDER $@
>> +cmd_sunxi_spl_image_builder = $(objtree)/tools/sunxi-spl-image-builder \
>> +                -c $(CONFIG_NAND_SUNXI_SPL_ECC_STRENGTH)/$(CONFIG_NAND_SUNXI_SPL_ECC_SIZE) \
>> +                -p $(CONFIG_SYS_NAND_PAGE_SIZE) \
>> +                -o $(CONFIG_SYS_NAND_OOBSIZE) \
>> +                -u $(CONFIG_NAND_SUNXI_SPL_USABLE_PAGE_SIZE) \
>> +                -e $(CONFIG_SYS_NAND_BLOCK_SIZE) \
>> +                -s -b $< $@
>> +$(obj)/sunxi-spl-with-ecc.bin: $(obj)/sunxi-spl.bin
>> +    $(call if_changed,sunxi_spl_image_builder)
>> +
>>  # Rule to link u-boot-spl
>>  # May be overridden by arch/$(ARCH)/config.mk
>>  quiet_cmd_u-boot-spl ?= LD      $@
>>

^ permalink raw reply	[flat|nested] 44+ messages in thread

* [U-Boot] [PATCH 4/7] tools: sunxi: Add spl image builder
  2016-11-14 11:29     ` Hans de Goede
@ 2016-11-14 13:53       ` Maxime Ripard
  2016-11-14 14:01         ` Hans de Goede
  0 siblings, 1 reply; 44+ messages in thread
From: Maxime Ripard @ 2016-11-14 13:53 UTC (permalink / raw)
  To: u-boot

On Mon, Nov 14, 2016 at 12:29:25PM +0100, Hans de Goede wrote:
> Hi,
> 
> On 14-11-16 12:18, Hans de Goede wrote:
> > Hi,
> > 
> > On 08-11-16 17:21, Maxime Ripard wrote:
> > > This program generates raw SPL images that can be flashed on the NAND with
> > > the ECC and randomizer properly set up.
> > > 
> > > Signed-off-by: Maxime Ripard <maxime.ripard@free-electrons.com>
> > 
> > Looks good to me:
> > 
> > Reviewed-by: Hans de Goede <hdegoede@redhat.com>
> 
> Note this causes a cpu_to_be32 redefine compiler warning
> I've fixed this up locally.

I'll have to send a v2 based on Tom's comments. How did you fix this?

Thanks,
Maxime

-- 
Maxime Ripard, Free Electrons
Embedded Linux and Kernel engineering
http://free-electrons.com
-------------- next part --------------
A non-text attachment was scrubbed...
Name: signature.asc
Type: application/pgp-signature
Size: 801 bytes
Desc: not available
URL: <http://lists.denx.de/pipermail/u-boot/attachments/20161114/99402243/attachment.sig>

^ permalink raw reply	[flat|nested] 44+ messages in thread

* [U-Boot] [PATCH 4/7] tools: sunxi: Add spl image builder
  2016-11-14 13:53       ` Maxime Ripard
@ 2016-11-14 14:01         ` Hans de Goede
  0 siblings, 0 replies; 44+ messages in thread
From: Hans de Goede @ 2016-11-14 14:01 UTC (permalink / raw)
  To: u-boot

Hi,

On 14-11-16 14:53, Maxime Ripard wrote:
> On Mon, Nov 14, 2016 at 12:29:25PM +0100, Hans de Goede wrote:
>> Hi,
>>
>> On 14-11-16 12:18, Hans de Goede wrote:
>>> Hi,
>>>
>>> On 08-11-16 17:21, Maxime Ripard wrote:
>>>> This program generates raw SPL images that can be flashed on the NAND with
>>>> the ECC and randomizer properly set up.
>>>>
>>>> Signed-off-by: Maxime Ripard <maxime.ripard@free-electrons.com>
>>>
>>> Looks good to me:
>>>
>>> Reviewed-by: Hans de Goede <hdegoede@redhat.com>
>>
>> Note this causes a cpu_to_be32 redefine compiler warning
>> I've fixed this up locally.
>
> I'll have to send a v2 based on Tom's comments. How did you fix this?

I added an undef above the define, if you use the
pre-existing macro you get problems later
because it gets called as cpu_to_be32(*addr++)
and the pre-existing macro references its argument
multiple times.

Regards,

Hans

^ permalink raw reply	[flat|nested] 44+ messages in thread

* [U-Boot] [PATCH 3/7] sunxi: Enable UBI and NAND support
  2016-11-14 11:18   ` Hans de Goede
@ 2016-11-14 14:09     ` Maxime Ripard
  2016-11-14 14:12       ` Hans de Goede
  2016-11-14 14:12     ` Maxime Ripard
  1 sibling, 1 reply; 44+ messages in thread
From: Maxime Ripard @ 2016-11-14 14:09 UTC (permalink / raw)
  To: u-boot

Hi,

On Mon, Nov 14, 2016 at 12:18:06PM +0100, Hans de Goede wrote:
> >  #ifdef CONFIG_SPL_SPI_SUNXI
> > @@ -143,7 +157,14 @@
> >  #define CONFIG_GENERIC_MMC
> >  #define CONFIG_MMC_SUNXI
> >  #define CONFIG_MMC_SUNXI_SLOT		0
> > -#define CONFIG_ENV_IS_IN_MMC
> > +#endif
> > +
> > +#if defined(CONFIG_ENV_IS_IN_NAND)
> > +#define CONFIG_ENV_OFFSET			0xc00000
> > +#define CONFIG_ENV_SIZE				0x400000
> > +#elif defined(CONFIG_ENV_IS_IN_MMC)
> > +#define CONFIG_ENV_OFFSET			(544 << 10) /* (8 + 24 + 512) KiB */
> > +#define CONFIG_ENV_SIZE				(128 << 10) /* 128 KiB */
> >  #define CONFIG_SYS_MMC_ENV_DEV		0	/* first detected MMC controller */
> >  #endif
> > 
> 
> I would greatly prefer putting the env in an UBI partition,
> I thought that we had agreed on doing that ?

That was mentionned a few times, but I didn't remember having a final
decision. I'm not really sure that putting the environment in UBI
would be a good idea.

Attaching the UBI volume takes a very significant time. Doing so
before the user can see that something is happening in the system
feels pretty bad.

Maxime

-- 
Maxime Ripard, Free Electrons
Embedded Linux and Kernel engineering
http://free-electrons.com
-------------- next part --------------
A non-text attachment was scrubbed...
Name: signature.asc
Type: application/pgp-signature
Size: 801 bytes
Desc: not available
URL: <http://lists.denx.de/pipermail/u-boot/attachments/20161114/06e665bf/attachment.sig>

^ permalink raw reply	[flat|nested] 44+ messages in thread

* [U-Boot] [PATCH 3/7] sunxi: Enable UBI and NAND support
  2016-11-14 14:09     ` Maxime Ripard
@ 2016-11-14 14:12       ` Hans de Goede
  0 siblings, 0 replies; 44+ messages in thread
From: Hans de Goede @ 2016-11-14 14:12 UTC (permalink / raw)
  To: u-boot

Hi,

On 14-11-16 15:09, Maxime Ripard wrote:
> Hi,
>
> On Mon, Nov 14, 2016 at 12:18:06PM +0100, Hans de Goede wrote:
>>>  #ifdef CONFIG_SPL_SPI_SUNXI
>>> @@ -143,7 +157,14 @@
>>>  #define CONFIG_GENERIC_MMC
>>>  #define CONFIG_MMC_SUNXI
>>>  #define CONFIG_MMC_SUNXI_SLOT		0
>>> -#define CONFIG_ENV_IS_IN_MMC
>>> +#endif
>>> +
>>> +#if defined(CONFIG_ENV_IS_IN_NAND)
>>> +#define CONFIG_ENV_OFFSET			0xc00000
>>> +#define CONFIG_ENV_SIZE				0x400000
>>> +#elif defined(CONFIG_ENV_IS_IN_MMC)
>>> +#define CONFIG_ENV_OFFSET			(544 << 10) /* (8 + 24 + 512) KiB */
>>> +#define CONFIG_ENV_SIZE				(128 << 10) /* 128 KiB */
>>>  #define CONFIG_SYS_MMC_ENV_DEV		0	/* first detected MMC controller */
>>>  #endif
>>>
>>
>> I would greatly prefer putting the env in an UBI partition,
>> I thought that we had agreed on doing that ?
>
> That was mentionned a few times, but I didn't remember having a final
> decision. I'm not really sure that putting the environment in UBI
> would be a good idea.
>
> Attaching the UBI volume takes a very significant time. Doing so
> before the user can see that something is happening in the system
> feels pretty bad.

So maybe we need to print a message before doing so ?

We really need bad-block management for the environment, AFAICT
the current non UBI implementation does not even have a backup ?

Regards,

Hans

^ permalink raw reply	[flat|nested] 44+ messages in thread

* [U-Boot] [PATCH 3/7] sunxi: Enable UBI and NAND support
  2016-11-14 11:18   ` Hans de Goede
  2016-11-14 14:09     ` Maxime Ripard
@ 2016-11-14 14:12     ` Maxime Ripard
  2016-11-14 14:21       ` Hans de Goede
  1 sibling, 1 reply; 44+ messages in thread
From: Maxime Ripard @ 2016-11-14 14:12 UTC (permalink / raw)
  To: u-boot

On Mon, Nov 14, 2016 at 12:18:06PM +0100, Hans de Goede wrote:
> >  #ifdef CONFIG_SPL_SPI_SUNXI
> > @@ -143,7 +157,14 @@
> >  #define CONFIG_GENERIC_MMC
> >  #define CONFIG_MMC_SUNXI
> >  #define CONFIG_MMC_SUNXI_SLOT		0
> > -#define CONFIG_ENV_IS_IN_MMC
> > +#endif
> > +
> > +#if defined(CONFIG_ENV_IS_IN_NAND)
> > +#define CONFIG_ENV_OFFSET			0xc00000
> > +#define CONFIG_ENV_SIZE				0x400000
> > +#elif defined(CONFIG_ENV_IS_IN_MMC)
> > +#define CONFIG_ENV_OFFSET			(544 << 10) /* (8 + 24 + 512) KiB */
> > +#define CONFIG_ENV_SIZE				(128 << 10) /* 128 KiB */
> >  #define CONFIG_SYS_MMC_ENV_DEV		0	/* first detected MMC controller */
> >  #endif

Oh, and this part is broken. It relies on the fact that all board
define ENV_IS_IN_MMC (which they should), while obviously they
don't. I'm not exactly sure about what the proper fix would be.

Maxime

-- 
Maxime Ripard, Free Electrons
Embedded Linux and Kernel engineering
http://free-electrons.com
-------------- next part --------------
A non-text attachment was scrubbed...
Name: signature.asc
Type: application/pgp-signature
Size: 801 bytes
Desc: not available
URL: <http://lists.denx.de/pipermail/u-boot/attachments/20161114/84fe1854/attachment.sig>

^ permalink raw reply	[flat|nested] 44+ messages in thread

* [U-Boot] [PATCH 3/7] sunxi: Enable UBI and NAND support
  2016-11-14 14:12     ` Maxime Ripard
@ 2016-11-14 14:21       ` Hans de Goede
  2016-11-14 17:03         ` Tom Rini
  2016-11-17 22:27         ` Maxime Ripard
  0 siblings, 2 replies; 44+ messages in thread
From: Hans de Goede @ 2016-11-14 14:21 UTC (permalink / raw)
  To: u-boot

Hi,

On 14-11-16 15:12, Maxime Ripard wrote:
> On Mon, Nov 14, 2016 at 12:18:06PM +0100, Hans de Goede wrote:
>>>  #ifdef CONFIG_SPL_SPI_SUNXI
>>> @@ -143,7 +157,14 @@
>>>  #define CONFIG_GENERIC_MMC
>>>  #define CONFIG_MMC_SUNXI
>>>  #define CONFIG_MMC_SUNXI_SLOT		0
>>> -#define CONFIG_ENV_IS_IN_MMC
>>> +#endif
>>> +
>>> +#if defined(CONFIG_ENV_IS_IN_NAND)
>>> +#define CONFIG_ENV_OFFSET			0xc00000
>>> +#define CONFIG_ENV_SIZE				0x400000
>>> +#elif defined(CONFIG_ENV_IS_IN_MMC)
>>> +#define CONFIG_ENV_OFFSET			(544 << 10) /* (8 + 24 + 512) KiB */
>>> +#define CONFIG_ENV_SIZE				(128 << 10) /* 128 KiB */
>>>  #define CONFIG_SYS_MMC_ENV_DEV		0	/* first detected MMC controller */
>>>  #endif
>
> Oh, and this part is broken. It relies on the fact that all board
> define ENV_IS_IN_MMC (which they should), while obviously they
> don't. I'm not exactly sure about what the proper fix would be.

Yes, this has been a known problem for a while, but never
became an issue due to lack of NAND support.

My preferred way for dealing with this be would for the
environment code in u-boot allowing to build in multiple
back-ends and use spl_boot_device() which then would need
to loose its spl prefix. For the CHIP devices I'm sure
you can come up with a simpler fix since those don't
have an sdcard-slot. But for other boards this will be
necessary as we really don't want to have separate
nand and mmc u-boot.bin files.

Anyways this is something for whomever will take over
as sunxi custodian from me. Maybe someone from free-electrons
can co-maintain with Jagan ?

Regards,

Hans

^ permalink raw reply	[flat|nested] 44+ messages in thread

* [U-Boot] [PATCH 4/7] tools: sunxi: Add spl image builder
  2016-11-11 16:20   ` Tom Rini
@ 2016-11-14 15:20     ` Maxime Ripard
  2016-11-14 15:25       ` Tom Rini
  0 siblings, 1 reply; 44+ messages in thread
From: Maxime Ripard @ 2016-11-14 15:20 UTC (permalink / raw)
  To: u-boot

On Fri, Nov 11, 2016 at 11:20:47AM -0500, Tom Rini wrote:
> On Tue, Nov 08, 2016 at 05:21:14PM +0100, Maxime Ripard wrote:
> 
> > This program generates raw SPL images that can be flashed on the NAND with
> > the ECC and randomizer properly set up.
> > 
> > Signed-off-by: Maxime Ripard <maxime.ripard@free-electrons.com>
> [snip]
> > +++ b/tools/sunxi-spl-image-builder.c
> > @@ -0,0 +1,1113 @@
> > +/*
> > + * Generic binary BCH encoding/decoding library
> 
> OK, but this is also lib/bch.c and re-using lib/ code for tools is a
> normal best practice.  I'd suggest re-factoring this code in sunxi-tools
> sot that it too borrows lib/bch.c from the kernel (and can re-sync
> bugfixes if needed).  Thanks!

I finally figured that out.

It turns out that the driver was doing a modulo by 0. I guess gcc's
and our libgcc don't have the same behaviour in this case, but in
U-boot's case, the function was simply returning (which is kind of
odd).

I'll send a fix for the driver.

Maxime

-- 
Maxime Ripard, Free Electrons
Embedded Linux and Kernel engineering
http://free-electrons.com
-------------- next part --------------
A non-text attachment was scrubbed...
Name: signature.asc
Type: application/pgp-signature
Size: 801 bytes
Desc: not available
URL: <http://lists.denx.de/pipermail/u-boot/attachments/20161114/e54db4c2/attachment.sig>

^ permalink raw reply	[flat|nested] 44+ messages in thread

* [U-Boot] [PATCH 4/7] tools: sunxi: Add spl image builder
  2016-11-14 15:20     ` Maxime Ripard
@ 2016-11-14 15:25       ` Tom Rini
  2016-11-14 18:58         ` Maxime Ripard
  0 siblings, 1 reply; 44+ messages in thread
From: Tom Rini @ 2016-11-14 15:25 UTC (permalink / raw)
  To: u-boot

On Mon, Nov 14, 2016 at 04:20:49PM +0100, Maxime Ripard wrote:
> On Fri, Nov 11, 2016 at 11:20:47AM -0500, Tom Rini wrote:
> > On Tue, Nov 08, 2016 at 05:21:14PM +0100, Maxime Ripard wrote:
> > 
> > > This program generates raw SPL images that can be flashed on the NAND with
> > > the ECC and randomizer properly set up.
> > > 
> > > Signed-off-by: Maxime Ripard <maxime.ripard@free-electrons.com>
> > [snip]
> > > +++ b/tools/sunxi-spl-image-builder.c
> > > @@ -0,0 +1,1113 @@
> > > +/*
> > > + * Generic binary BCH encoding/decoding library
> > 
> > OK, but this is also lib/bch.c and re-using lib/ code for tools is a
> > normal best practice.  I'd suggest re-factoring this code in sunxi-tools
> > sot that it too borrows lib/bch.c from the kernel (and can re-sync
> > bugfixes if needed).  Thanks!
> 
> I finally figured that out.
> 
> It turns out that the driver was doing a modulo by 0. I guess gcc's
> and our libgcc don't have the same behaviour in this case, but in
> U-boot's case, the function was simply returning (which is kind of
> odd).
> 
> I'll send a fix for the driver.

So it's something in how lib/bch.c and lib1funcs.S interact?  Please CC
me on these when fixing whatever side of this it is in the kernel,
thanks!

-- 
Tom
-------------- next part --------------
A non-text attachment was scrubbed...
Name: signature.asc
Type: application/pgp-signature
Size: 819 bytes
Desc: Digital signature
URL: <http://lists.denx.de/pipermail/u-boot/attachments/20161114/68184623/attachment.sig>

^ permalink raw reply	[flat|nested] 44+ messages in thread

* [U-Boot] [PATCH 3/7] sunxi: Enable UBI and NAND support
  2016-11-14 14:21       ` Hans de Goede
@ 2016-11-14 17:03         ` Tom Rini
  2016-11-17 22:27         ` Maxime Ripard
  1 sibling, 0 replies; 44+ messages in thread
From: Tom Rini @ 2016-11-14 17:03 UTC (permalink / raw)
  To: u-boot

On Mon, Nov 14, 2016 at 03:21:41PM +0100, Hans de Goede wrote:
> Hi,
> 
> On 14-11-16 15:12, Maxime Ripard wrote:
> >On Mon, Nov 14, 2016 at 12:18:06PM +0100, Hans de Goede wrote:
> >>> #ifdef CONFIG_SPL_SPI_SUNXI
> >>>@@ -143,7 +157,14 @@
> >>> #define CONFIG_GENERIC_MMC
> >>> #define CONFIG_MMC_SUNXI
> >>> #define CONFIG_MMC_SUNXI_SLOT		0
> >>>-#define CONFIG_ENV_IS_IN_MMC
> >>>+#endif
> >>>+
> >>>+#if defined(CONFIG_ENV_IS_IN_NAND)
> >>>+#define CONFIG_ENV_OFFSET			0xc00000
> >>>+#define CONFIG_ENV_SIZE				0x400000
> >>>+#elif defined(CONFIG_ENV_IS_IN_MMC)
> >>>+#define CONFIG_ENV_OFFSET			(544 << 10) /* (8 + 24 + 512) KiB */
> >>>+#define CONFIG_ENV_SIZE				(128 << 10) /* 128 KiB */
> >>> #define CONFIG_SYS_MMC_ENV_DEV		0	/* first detected MMC controller */
> >>> #endif
> >
> >Oh, and this part is broken. It relies on the fact that all board
> >define ENV_IS_IN_MMC (which they should), while obviously they
> >don't. I'm not exactly sure about what the proper fix would be.
> 
> Yes, this has been a known problem for a while, but never
> became an issue due to lack of NAND support.
> 
> My preferred way for dealing with this be would for the
> environment code in u-boot allowing to build in multiple
> back-ends and use spl_boot_device() which then would need
> to loose its spl prefix. For the CHIP devices I'm sure
> you can come up with a simpler fix since those don't
> have an sdcard-slot. But for other boards this will be
> necessary as we really don't want to have separate
> nand and mmc u-boot.bin files.
> 
> Anyways this is something for whomever will take over
> as sunxi custodian from me. Maybe someone from free-electrons
> can co-maintain with Jagan ?

I would really like to see the co-maintainer model continue here, if
possible, yes.  Thanks!

-- 
Tom
-------------- next part --------------
A non-text attachment was scrubbed...
Name: signature.asc
Type: application/pgp-signature
Size: 819 bytes
Desc: Digital signature
URL: <http://lists.denx.de/pipermail/u-boot/attachments/20161114/26d75453/attachment.sig>

^ permalink raw reply	[flat|nested] 44+ messages in thread

* [U-Boot] [PATCH 4/7] tools: sunxi: Add spl image builder
  2016-11-14 15:25       ` Tom Rini
@ 2016-11-14 18:58         ` Maxime Ripard
  2016-11-14 18:59           ` Tom Rini
  0 siblings, 1 reply; 44+ messages in thread
From: Maxime Ripard @ 2016-11-14 18:58 UTC (permalink / raw)
  To: u-boot

Hi,

On Mon, Nov 14, 2016 at 10:25:27AM -0500, Tom Rini wrote:
> On Mon, Nov 14, 2016 at 04:20:49PM +0100, Maxime Ripard wrote:
> > On Fri, Nov 11, 2016 at 11:20:47AM -0500, Tom Rini wrote:
> > > On Tue, Nov 08, 2016 at 05:21:14PM +0100, Maxime Ripard wrote:
> > > 
> > > > This program generates raw SPL images that can be flashed on the NAND with
> > > > the ECC and randomizer properly set up.
> > > > 
> > > > Signed-off-by: Maxime Ripard <maxime.ripard@free-electrons.com>
> > > [snip]
> > > > +++ b/tools/sunxi-spl-image-builder.c
> > > > @@ -0,0 +1,1113 @@
> > > > +/*
> > > > + * Generic binary BCH encoding/decoding library
> > > 
> > > OK, but this is also lib/bch.c and re-using lib/ code for tools is a
> > > normal best practice.  I'd suggest re-factoring this code in sunxi-tools
> > > sot that it too borrows lib/bch.c from the kernel (and can re-sync
> > > bugfixes if needed).  Thanks!
> > 
> > I finally figured that out.
> > 
> > It turns out that the driver was doing a modulo by 0. I guess gcc's
> > and our libgcc don't have the same behaviour in this case, but in
> > U-boot's case, the function was simply returning (which is kind of
> > odd).
> > 
> > I'll send a fix for the driver.
> 
> So it's something in how lib/bch.c and lib1funcs.S interact?  Please CC
> me on these when fixing whatever side of this it is in the kernel,
> thanks!

Hmm, no, sorry, I meant to reply on the cover letter. The issue isn't
in lib/bch.c, it was really in our NAND driver. No changes required in
the kernel, just an extra patch in this serie :)

Maxime

-- 
Maxime Ripard, Free Electrons
Embedded Linux and Kernel engineering
http://free-electrons.com
-------------- next part --------------
A non-text attachment was scrubbed...
Name: signature.asc
Type: application/pgp-signature
Size: 801 bytes
Desc: not available
URL: <http://lists.denx.de/pipermail/u-boot/attachments/20161114/e0591a6e/attachment.sig>

^ permalink raw reply	[flat|nested] 44+ messages in thread

* [U-Boot] [PATCH 4/7] tools: sunxi: Add spl image builder
  2016-11-14 18:58         ` Maxime Ripard
@ 2016-11-14 18:59           ` Tom Rini
  0 siblings, 0 replies; 44+ messages in thread
From: Tom Rini @ 2016-11-14 18:59 UTC (permalink / raw)
  To: u-boot

On Mon, Nov 14, 2016 at 07:58:03PM +0100, Maxime Ripard wrote:
> Hi,
> 
> On Mon, Nov 14, 2016 at 10:25:27AM -0500, Tom Rini wrote:
> > On Mon, Nov 14, 2016 at 04:20:49PM +0100, Maxime Ripard wrote:
> > > On Fri, Nov 11, 2016 at 11:20:47AM -0500, Tom Rini wrote:
> > > > On Tue, Nov 08, 2016 at 05:21:14PM +0100, Maxime Ripard wrote:
> > > > 
> > > > > This program generates raw SPL images that can be flashed on the NAND with
> > > > > the ECC and randomizer properly set up.
> > > > > 
> > > > > Signed-off-by: Maxime Ripard <maxime.ripard@free-electrons.com>
> > > > [snip]
> > > > > +++ b/tools/sunxi-spl-image-builder.c
> > > > > @@ -0,0 +1,1113 @@
> > > > > +/*
> > > > > + * Generic binary BCH encoding/decoding library
> > > > 
> > > > OK, but this is also lib/bch.c and re-using lib/ code for tools is a
> > > > normal best practice.  I'd suggest re-factoring this code in sunxi-tools
> > > > sot that it too borrows lib/bch.c from the kernel (and can re-sync
> > > > bugfixes if needed).  Thanks!
> > > 
> > > I finally figured that out.
> > > 
> > > It turns out that the driver was doing a modulo by 0. I guess gcc's
> > > and our libgcc don't have the same behaviour in this case, but in
> > > U-boot's case, the function was simply returning (which is kind of
> > > odd).
> > > 
> > > I'll send a fix for the driver.
> > 
> > So it's something in how lib/bch.c and lib1funcs.S interact?  Please CC
> > me on these when fixing whatever side of this it is in the kernel,
> > thanks!
> 
> Hmm, no, sorry, I meant to reply on the cover letter. The issue isn't
> in lib/bch.c, it was really in our NAND driver. No changes required in
> the kernel, just an extra patch in this serie :)

Ah-ah! OK, thanks for clarifying.

-- 
Tom
-------------- next part --------------
A non-text attachment was scrubbed...
Name: signature.asc
Type: application/pgp-signature
Size: 819 bytes
Desc: Digital signature
URL: <http://lists.denx.de/pipermail/u-boot/attachments/20161114/36f010bd/attachment.sig>

^ permalink raw reply	[flat|nested] 44+ messages in thread

* [U-Boot] [PATCH 2/7] mtd: nand: add support for the TC58NVG2S0H chip
  2016-11-08 16:21 ` [U-Boot] [PATCH 2/7] mtd: nand: add support for the TC58NVG2S0H chip Maxime Ripard
  2016-11-14 11:15   ` Hans de Goede
@ 2016-11-15  5:04   ` Scott Wood
  1 sibling, 0 replies; 44+ messages in thread
From: Scott Wood @ 2016-11-15  5:04 UTC (permalink / raw)
  To: u-boot

On Tue, 2016-11-08 at 17:21 +0100, Maxime Ripard wrote:
> From: Boris Brezillon <boris.brezillon@free-electrons.com>
> 
> Add the description of the Toshiba TC58NVG2S0H SLC nand to the nand_ids
> table so we can use the NAND ECC infos and the ONFI timings.
> 
> Signed-off-by: Boris Brezillon <boris.brezillon@free-electrons.com>
> Signed-off-by: Maxime Ripard <maxime.ripard@free-electrons.com>
> ---
> ?drivers/mtd/nand/nand_ids.c | 3 +++
> ?1 file changed, 3 insertions(+), 0 deletions(-)

Acked-by: Scott Wood <oss@buserror.net>

-Scott

^ permalink raw reply	[flat|nested] 44+ messages in thread

* [U-Boot] [PATCH 5/7] nand: sunxi: Add options for the SPL NAND configuration
  2016-11-08 16:21 ` [U-Boot] [PATCH 5/7] nand: sunxi: Add options for the SPL NAND configuration Maxime Ripard
  2016-11-08 16:31   ` Boris Brezillon
  2016-11-14 11:19   ` Hans de Goede
@ 2016-11-15  5:07   ` Scott Wood
  2 siblings, 0 replies; 44+ messages in thread
From: Scott Wood @ 2016-11-15  5:07 UTC (permalink / raw)
  To: u-boot

On Tue, 2016-11-08 at 17:21 +0100, Maxime Ripard wrote:
> The SPL image needs to be built with a different ECC configuration than the
> U-Boot binary.
> 
> Add Kconfig options with defaults to provide a value that should work for
> anyone, but is still configurable if needs be.
> 
> Signed-off-by: Maxime Ripard <maxime.ripard@free-electrons.com>
> ---
> ?drivers/mtd/nand/Kconfig | 16 ++++++++++++++++
> ?1 file changed, 16 insertions(+), 0 deletions(-)

Acked-by: Scott Wood <oss@buserror.net>

-Scott

^ permalink raw reply	[flat|nested] 44+ messages in thread

* [U-Boot] [PATCH 3/7] sunxi: Enable UBI and NAND support
  2016-11-14 14:21       ` Hans de Goede
  2016-11-14 17:03         ` Tom Rini
@ 2016-11-17 22:27         ` Maxime Ripard
  1 sibling, 0 replies; 44+ messages in thread
From: Maxime Ripard @ 2016-11-17 22:27 UTC (permalink / raw)
  To: u-boot

On Mon, Nov 14, 2016 at 03:21:41PM +0100, Hans de Goede wrote:
> Hi,
> 
> On 14-11-16 15:12, Maxime Ripard wrote:
> > On Mon, Nov 14, 2016 at 12:18:06PM +0100, Hans de Goede wrote:
> > > >  #ifdef CONFIG_SPL_SPI_SUNXI
> > > > @@ -143,7 +157,14 @@
> > > >  #define CONFIG_GENERIC_MMC
> > > >  #define CONFIG_MMC_SUNXI
> > > >  #define CONFIG_MMC_SUNXI_SLOT		0
> > > > -#define CONFIG_ENV_IS_IN_MMC
> > > > +#endif
> > > > +
> > > > +#if defined(CONFIG_ENV_IS_IN_NAND)
> > > > +#define CONFIG_ENV_OFFSET			0xc00000
> > > > +#define CONFIG_ENV_SIZE				0x400000
> > > > +#elif defined(CONFIG_ENV_IS_IN_MMC)
> > > > +#define CONFIG_ENV_OFFSET			(544 << 10) /* (8 + 24 + 512) KiB */
> > > > +#define CONFIG_ENV_SIZE				(128 << 10) /* 128 KiB */
> > > >  #define CONFIG_SYS_MMC_ENV_DEV		0	/* first detected MMC controller */
> > > >  #endif
> > 
> > Oh, and this part is broken. It relies on the fact that all board
> > define ENV_IS_IN_MMC (which they should), while obviously they
> > don't. I'm not exactly sure about what the proper fix would be.
> 
> Yes, this has been a known problem for a while, but never
> became an issue due to lack of NAND support.
> 
> My preferred way for dealing with this be would for the
> environment code in u-boot allowing to build in multiple
> back-ends and use spl_boot_device() which then would need
> to loose its spl prefix. For the CHIP devices I'm sure
> you can come up with a simpler fix since those don't
> have an sdcard-slot. But for other boards this will be
> necessary as we really don't want to have separate
> nand and mmc u-boot.bin files.

Ack, thanks.

> Anyways this is something for whomever will take over as sunxi
> custodian from me. Maybe someone from free-electrons can co-maintain
> with Jagan ?

Yes, that would make a lot of sense. I'll discuss this internally, and
do the interim while we come up with someone.

Maxime

-- 
Maxime Ripard, Free Electrons
Embedded Linux and Kernel engineering
http://free-electrons.com
-------------- next part --------------
A non-text attachment was scrubbed...
Name: signature.asc
Type: application/pgp-signature
Size: 801 bytes
Desc: not available
URL: <http://lists.denx.de/pipermail/u-boot/attachments/20161117/01d9f4ae/attachment.sig>

^ permalink raw reply	[flat|nested] 44+ messages in thread

end of thread, other threads:[~2016-11-17 22:27 UTC | newest]

Thread overview: 44+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2016-11-08 16:21 [U-Boot] [PATCH 0/7] sunxi: Add support for the CHIP Pro Maxime Ripard
2016-11-08 16:21 ` [U-Boot] [PATCH 1/7] sunxi: Sync GR8 DTS and AXP209 with the kernel Maxime Ripard
2016-11-14 11:15   ` Hans de Goede
2016-11-08 16:21 ` [U-Boot] [PATCH 2/7] mtd: nand: add support for the TC58NVG2S0H chip Maxime Ripard
2016-11-14 11:15   ` Hans de Goede
2016-11-15  5:04   ` Scott Wood
2016-11-08 16:21 ` [U-Boot] [PATCH 3/7] sunxi: Enable UBI and NAND support Maxime Ripard
2016-11-08 16:27   ` Boris Brezillon
2016-11-08 16:27   ` Boris Brezillon
2016-11-09 14:32     ` Maxime Ripard
2016-11-09 14:57       ` Boris Brezillon
2016-11-14 11:18   ` Hans de Goede
2016-11-14 14:09     ` Maxime Ripard
2016-11-14 14:12       ` Hans de Goede
2016-11-14 14:12     ` Maxime Ripard
2016-11-14 14:21       ` Hans de Goede
2016-11-14 17:03         ` Tom Rini
2016-11-17 22:27         ` Maxime Ripard
2016-11-08 16:21 ` [U-Boot] [PATCH 4/7] tools: sunxi: Add spl image builder Maxime Ripard
2016-11-08 16:29   ` Boris Brezillon
2016-11-08 20:45     ` Maxime Ripard
2016-11-11 16:20   ` Tom Rini
2016-11-14 15:20     ` Maxime Ripard
2016-11-14 15:25       ` Tom Rini
2016-11-14 18:58         ` Maxime Ripard
2016-11-14 18:59           ` Tom Rini
2016-11-14 11:18   ` Hans de Goede
2016-11-14 11:29     ` Hans de Goede
2016-11-14 13:53       ` Maxime Ripard
2016-11-14 14:01         ` Hans de Goede
2016-11-08 16:21 ` [U-Boot] [PATCH 5/7] nand: sunxi: Add options for the SPL NAND configuration Maxime Ripard
2016-11-08 16:31   ` Boris Brezillon
2016-11-14 11:19   ` Hans de Goede
2016-11-15  5:07   ` Scott Wood
2016-11-08 16:21 ` [U-Boot] [PATCH 6/7] scripts: sunxi: Build an raw SPL image Maxime Ripard
2016-11-08 16:33   ` Boris Brezillon
2016-11-14 11:19   ` Hans de Goede
2016-11-14 11:30     ` Hans de Goede
2016-11-08 16:21 ` [U-Boot] [PATCH 7/7] sunxi: Add support for the CHIP Pro Maxime Ripard
2016-11-14 11:20   ` Hans de Goede
2016-11-09  7:47 ` [U-Boot] [PATCH 0/7] " Heiko Schocher
2016-11-09 14:44   ` Maxime Ripard
2016-11-10 11:57     ` Heiko Schocher
2016-11-11 16:24       ` Tom Rini

This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.