summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--MAINTAINERS3
-rw-r--r--Makefile3
-rw-r--r--arch/arm/dts/Makefile7
-rw-r--r--arch/arm/dts/axp209.dtsi6
-rw-r--r--arch/arm/dts/sun5i-gr8-chip-pro.dts266
-rw-r--r--arch/arm/dts/sun5i-gr8.dtsi1132
-rw-r--r--arch/arm/dts/sun8i-h3-nanopi-neo-air.dts97
-rw-r--r--arch/arm/dts/sun9i-a80-cx-a99.dts380
-rw-r--r--arch/arm/dts/sun9i-a80.dtsi8
-rw-r--r--board/sunxi/MAINTAINERS6
-rw-r--r--board/sunxi/README.nand54
-rw-r--r--cmd/Kconfig51
-rw-r--r--cmd/mtdparts.c8
-rw-r--r--common/Kconfig69
-rw-r--r--configs/CHIP_pro_defconfig33
-rw-r--r--configs/Sunchip_CX-A99_defconfig22
-rw-r--r--configs/nanopi_neo_air_defconfig17
-rw-r--r--configs/sun8i_a23_evb_defconfig19
-rw-r--r--drivers/mtd/nand/Kconfig19
-rw-r--r--drivers/mtd/nand/sunxi_nand_spl.c7
-rw-r--r--drivers/mtd/ubi/Kconfig1
-rw-r--r--drivers/net/sun8i_emac.c86
-rw-r--r--include/configs/sunxi-common.h35
-rw-r--r--include/environment.h2
-rw-r--r--lib/Kconfig5
-rw-r--r--lib/bch.c48
-rw-r--r--scripts/Makefile.spl15
-rw-r--r--tools/.gitignore1
-rw-r--r--tools/Makefile2
-rw-r--r--tools/sunxi-spl-image-builder.c484
30 files changed, 2863 insertions, 23 deletions
diff --git a/MAINTAINERS b/MAINTAINERS
index 9c88ff2b17..6c702f2ff2 100644
--- a/MAINTAINERS
+++ b/MAINTAINERS
@@ -174,9 +174,12 @@ F: arch/arm/include/asm/arch-sti*/
ARM SUNXI
M: Jagan Teki <jagan@openedev.com>
M: Maxime Ripard <maxime.ripard@free-electrons.com>
+S: Maintained
T: git git://git.denx.de/u-boot-sunxi.git
F: arch/arm/cpu/armv7/sunxi/
F: arch/arm/include/asm/arch-sunxi/
+F: arch/arm/mach-sunxi/
+F: board/sunxi/
ARM TEGRA
M: Tom Warren <twarren@nvidia.com>
diff --git a/Makefile b/Makefile
index 2638acf838..ca7d60d610 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/arch/arm/dts/Makefile b/arch/arm/dts/Makefile
index 7378c88431..a2c0717f07 100644
--- a/arch/arm/dts/Makefile
+++ b/arch/arm/dts/Makefile
@@ -228,6 +228,7 @@ dtb-$(CONFIG_MACH_SUN5I) += \
sun5i-a13-olinuxino-micro.dtb \
sun5i-a13-q8-tablet.dtb \
sun5i-a13-utoo-p66.dtb \
+ sun5i-gr8-chip-pro.dtb \
sun5i-r8-chip.dtb
dtb-$(CONFIG_MACH_SUN6I) += \
sun6i-a31-app4-evb1.dtb \
@@ -301,7 +302,8 @@ dtb-$(CONFIG_MACH_SUN8I_H3) += \
sun8i-h3-orangepi-pc-plus.dtb \
sun8i-h3-orangepi-plus.dtb \
sun8i-h3-orangepi-plus2e.dtb \
- sun8i-h3-nanopi-neo.dtb
+ sun8i-h3-nanopi-neo.dtb \
+ sun8i-h3-nanopi-neo-air.dtb
dtb-$(CONFIG_MACH_SUN50I_H5) += \
sun50i-h5-orangepi-pc2.dtb
dtb-$(CONFIG_MACH_SUN50I) += \
@@ -309,7 +311,8 @@ dtb-$(CONFIG_MACH_SUN50I) += \
sun50i-a64-pine64.dtb
dtb-$(CONFIG_MACH_SUN9I) += \
sun9i-a80-optimus.dtb \
- sun9i-a80-cubieboard4.dtb
+ sun9i-a80-cubieboard4.dtb \
+ sun9i-a80-cx-a99.dtb
dtb-$(CONFIG_VF610) += vf500-colibri.dtb \
vf610-colibri.dtb \
diff --git a/arch/arm/dts/axp209.dtsi b/arch/arm/dts/axp209.dtsi
index afbe89c01d..675bb0f308 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/sun5i-gr8-chip-pro.dts b/arch/arm/dts/sun5i-gr8-chip-pro.dts
new file mode 100644
index 0000000000..92a2dc6250
--- /dev/null
+++ b/arch/arm/dts/sun5i-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 "sun5i-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@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@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@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@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/sun5i-gr8.dtsi b/arch/arm/dts/sun5i-gr8.dtsi
new file mode 100644
index 0000000000..ea86d4d58d
--- /dev/null
+++ b/arch/arm/dts/sun5i-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@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@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@0 {
+ #clock-cells = <0>;
+ compatible = "fixed-clock";
+ clock-frequency = <32768>;
+ clock-output-names = "osc32k";
+ };
+
+ pll1: clk@01c20000 {
+ #clock-cells = <0>;
+ compatible = "allwinner,sun4i-a10-pll1-clk";
+ reg = <0x01c20000 0x4>;
+ clocks = <&osc24M>;
+ clock-output-names = "pll1";
+ };
+
+ pll2: clk@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@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@01c20018 {
+ #clock-cells = <0>;
+ compatible = "allwinner,sun4i-a10-pll1-clk";
+ reg = <0x01c20018 0x4>;
+ clocks = <&osc24M>;
+ clock-output-names = "pll4";
+ };
+
+ pll5: clk@01c20020 {
+ #clock-cells = <1>;
+ compatible = "allwinner,sun4i-a10-pll5-clk";
+ reg = <0x01c20020 0x4>;
+ clocks = <&osc24M>;
+ clock-output-names = "pll5_ddr", "pll5_other";
+ };
+
+ pll6: clk@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@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@01c20054 {
+ #clock-cells = <0>;
+ compatible = "allwinner,sun4i-a10-cpu-clk";
+ reg = <0x01c20054 0x4>;
+ clocks = <&osc32k>, <&osc24M>, <&pll1>, <&dummy>;
+ clock-output-names = "cpu";
+ };
+
+ axi: axi@01c20054 {
+ #clock-cells = <0>;
+ compatible = "allwinner,sun4i-a10-axi-clk";
+ reg = <0x01c20054 0x4>;
+ clocks = <&cpu>;
+ clock-output-names = "axi";
+ };
+
+ ahb: ahb@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@01c20054 {
+ #clock-cells = <0>;
+ compatible = "allwinner,sun4i-a10-apb0-clk";
+ reg = <0x01c20054 0x4>;
+ clocks = <&ahb>;
+ clock-output-names = "apb0";
+ };
+
+ apb1: clk@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@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@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@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@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@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@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@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@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@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@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@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@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@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@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@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@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@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@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@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@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@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@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@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@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@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@01c00000 {
+ compatible = "simple-bus";
+ #address-cells = <1>;
+ #size-cells = <1>;
+ ranges;
+
+ sram-controller@01c00000 {
+ compatible = "allwinner,sun4i-a10-sram-controller";
+ reg = <0x01c00000 0x30>;
+ #address-cells = <1>;
+ #size-cells = <1>;
+ ranges;
+
+ sram_a: sram@00000000 {
+ compatible = "mmio-sram";
+ reg = <0x00000000 0xc000>;
+ #address-cells = <1>;
+ #size-cells = <1>;
+ ranges = <0 0x00000000 0xc000>;
+ };
+
+ sram_d: sram@00010000 {
+ compatible = "mmio-sram";
+ reg = <0x00010000 0x1000>;
+ #address-cells = <1>;
+ #size-cells = <1>;
+ ranges = <0 0x00010000 0x1000>;
+
+ otg_sram: sram-section@0000 {
+ compatible = "allwinner,sun4i-a10-sram-d";
+ reg = <0x0000 0x1000>;
+ status = "disabled";
+ };
+ };
+ };
+
+ dma: dma-controller@01c02000 {
+ compatible = "allwinner,sun4i-a10-dma";
+ reg = <0x01c02000 0x1000>;
+ interrupts = <27>;
+ clocks = <&ahb_gates 6>;
+ #dma-cells = <2>;
+ };
+
+ nfc: nand@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@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@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@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@0 {
+ reg = <0>;
+ remote-endpoint = <&tcon0_out_tve0>;
+ };
+ };
+ };
+
+ tcon0: lcd-controller@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@0 {
+ #address-cells = <1>;
+ #size-cells = <0>;
+ reg = <0>;
+
+ tcon0_in_be0: endpoint@0 {
+ reg = <0>;
+ remote-endpoint = <&be0_out_tcon0>;
+ };
+ };
+
+ tcon0_out: port@1 {
+ #address-cells = <1>;
+ #size-cells = <0>;
+ reg = <1>;
+
+ tcon0_out_tve0: endpoint@1 {
+ reg = <1>;
+ remote-endpoint = <&tve0_in_tcon0>;
+ };
+ };
+ };
+ };
+
+ mmc0: mmc@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@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@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@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@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@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@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@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@01c20400 {
+ compatible = "allwinner,sun4i-a10-ic";
+ reg = <0x01c20400 0x400>;
+ interrupt-controller;
+ #interrupt-cells = <1>;
+ };
+
+ pio: pinctrl@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@0 {
+ allwinner,pins = "PB0", "PB1";
+ allwinner,function = "i2c0";
+ allwinner,drive = <SUN4I_PINCTRL_10_MA>;
+ allwinner,pull = <SUN4I_PINCTRL_NO_PULL>;
+ };
+
+ i2c1_pins_a: i2c1@0 {
+ allwinner,pins = "PB15", "PB16";
+ allwinner,function = "i2c1";
+ allwinner,drive = <SUN4I_PINCTRL_10_MA>;
+ allwinner,pull = <SUN4I_PINCTRL_NO_PULL>;
+ };
+
+ i2c2_pins_a: i2c2@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@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@0 {
+ allwinner,pins = "PB5";
+ allwinner,function = "i2s0";
+ allwinner,drive = <SUN4I_PINCTRL_10_MA>;
+ allwinner,pull = <SUN4I_PINCTRL_NO_PULL>;
+ };
+
+ ir0_rx_pins_a: ir0@0 {
+ allwinner,pins = "PB4";
+ allwinner,function = "ir0";
+ allwinner,drive = <SUN4I_PINCTRL_10_MA>;
+ allwinner,pull = <SUN4I_PINCTRL_NO_PULL>;
+ };
+
+ lcd_rgb666_pins: lcd-rgb666@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@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@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@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@0 {
+ allwinner,pins = "PC6";
+ allwinner,function = "nand0";
+ allwinner,drive = <SUN4I_PINCTRL_10_MA>;
+ allwinner,pull = <SUN4I_PINCTRL_NO_PULL>;
+ };
+
+ pwm0_pins_a: pwm0@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@0 {
+ allwinner,pins = "PB10";
+ allwinner,function = "spdif";
+ allwinner,drive = <SUN4I_PINCTRL_10_MA>;
+ allwinner,pull = <SUN4I_PINCTRL_PULL_UP>;
+ };
+
+ uart1_pins_a: uart1@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@0 {
+ allwinner,pins = "PG5", "PG6";
+ allwinner,function = "uart1";
+ allwinner,drive = <SUN4I_PINCTRL_10_MA>;
+ allwinner,pull = <SUN4I_PINCTRL_NO_PULL>;
+ };
+
+ uart2_pins_a: uart2@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@0 {
+ allwinner,pins = "PD4", "PD5";
+ allwinner,function = "uart2";
+ allwinner,drive = <SUN4I_PINCTRL_10_MA>;
+ allwinner,pull = <SUN4I_PINCTRL_NO_PULL>;
+ };
+
+ uart3_pins_a: uart3@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@0 {
+ allwinner,pins = "PG11", "PG12";
+ allwinner,function = "uart3";
+ allwinner,drive = <SUN4I_PINCTRL_10_MA>;
+ allwinner,pull = <SUN4I_PINCTRL_NO_PULL>;
+ };
+ };
+
+ pwm: pwm@01c20e00 {
+ compatible = "allwinner,sun5i-a10s-pwm";
+ reg = <0x01c20e00 0xc>;
+ clocks = <&osc24M>;
+ #pwm-cells = <3>;
+ status = "disabled";
+ };
+
+ timer@01c20c00 {
+ compatible = "allwinner,sun4i-a10-timer";
+ reg = <0x01c20c00 0x90>;
+ interrupts = <22>;
+ clocks = <&osc24M>;
+ };
+
+ wdt: watchdog@01c20c90 {
+ compatible = "allwinner,sun4i-a10-wdt";
+ reg = <0x01c20c90 0x10>;
+ };
+
+ spdif: spdif@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@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@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@01c22800 {
+ compatible = "allwinner,sun4i-a10-lradc-keys";
+ reg = <0x01c22800 0x100>;
+ interrupts = <31>;
+ status = "disabled";
+ };
+
+ codec: codec@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@01c25000 {
+ compatible = "allwinner,sun5i-a13-ts";
+ reg = <0x01c25000 0x100>;
+ interrupts = <29>;
+ #thermal-sensor-cells = <0>;
+ };
+
+ uart1: serial@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@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@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@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@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@01c2b400 {
+ compatible = "allwinner,sun4i-a10-i2c";
+ reg = <0x01c2b400 0x400>;
+ interrupts = <9>;
+ clocks = <&apb1_gates 2>;
+ status = "disabled";
+ #address-cells = <1>;
+ #size-cells = <0>;
+ };
+
+ timer@01c60000 {
+ compatible = "allwinner,sun5i-a13-hstimer";
+ reg = <0x01c60000 0x1000>;
+ interrupts = <82>, <83>;
+ clocks = <&ahb_gates 28>;
+ };
+
+ fe0: display-frontend@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@1 {
+ #address-cells = <1>;
+ #size-cells = <0>;
+ reg = <1>;
+
+ fe0_out_be0: endpoint@0 {
+ reg = <0>;
+ remote-endpoint = <&be0_in_fe0>;
+ };
+ };
+ };
+ };
+
+ be0: display-backend@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@0 {
+ #address-cells = <1>;
+ #size-cells = <0>;
+ reg = <0>;
+
+ be0_in_fe0: endpoint@0 {
+ reg = <0>;
+ remote-endpoint = <&fe0_out_be0>;
+ };
+ };
+
+ be0_out: port@1 {
+ #address-cells = <1>;
+ #size-cells = <0>;
+ reg = <1>;
+
+ be0_out_tcon0: endpoint@0 {
+ reg = <0>;
+ remote-endpoint = <&tcon0_in_be0>;
+ };
+ };
+ };
+ };
+ };
+};
diff --git a/arch/arm/dts/sun8i-h3-nanopi-neo-air.dts b/arch/arm/dts/sun8i-h3-nanopi-neo-air.dts
new file mode 100644
index 0000000000..3ba081c1f5
--- /dev/null
+++ b/arch/arm/dts/sun8i-h3-nanopi-neo-air.dts
@@ -0,0 +1,97 @@
+/*
+ * Copyright (C) 2017 Jelle van der Waa <jelle@vdwaa.nl>
+ *
+ * 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 "sun8i-h3.dtsi"
+#include "sunxi-common-regulators.dtsi"
+
+#include <dt-bindings/gpio/gpio.h>
+#include <dt-bindings/pinctrl/sun4i-a10.h>
+
+/ {
+ model = "FriendlyARM NanoPi NEO Air";
+ compatible = "friendlyarm,nanopi-neo-air", "allwinner,sun8i-h3";
+
+ aliases {
+ serial0 = &uart0;
+ };
+
+ chosen {
+ stdout-path = "serial0:115200n8";
+ };
+
+ leds {
+ compatible = "gpio-leds";
+
+ pwr {
+ label = "nanopi:green:pwr";
+ gpios = <&r_pio 0 10 GPIO_ACTIVE_HIGH>; /* PL10 */
+ default-state = "on";
+ };
+
+ status {
+ label = "nanopi:blue:status";
+ gpios = <&pio 0 10 GPIO_ACTIVE_HIGH>; /* PA10 */
+ };
+ };
+};
+
+&mmc0 {
+ pinctrl-names = "default";
+ pinctrl-0 = <&mmc0_pins_a>, <&mmc0_cd_pin>;
+ vmmc-supply = <&reg_vcc3v3>;
+ bus-width = <4>;
+ cd-gpios = <&pio 5 6 GPIO_ACTIVE_HIGH>; /* PF6 */
+ cd-inverted;
+ status = "okay";
+};
+
+&uart0 {
+ pinctrl-names = "default";
+ pinctrl-0 = <&uart0_pins_a>;
+ status = "okay";
+};
+
+&usbphy {
+ /* USB VBUS is always on */
+ status = "okay";
+};
diff --git a/arch/arm/dts/sun9i-a80-cx-a99.dts b/arch/arm/dts/sun9i-a80-cx-a99.dts
new file mode 100644
index 0000000000..a30b6fec56
--- /dev/null
+++ b/arch/arm/dts/sun9i-a80-cx-a99.dts
@@ -0,0 +1,380 @@
+/*
+ * sun9i-a80-cx-a99.dts - Device Tree file for the Sunchip CX-A99 board.
+ *
+ * Copyright (C) 2017 Rask Ingemann Lambertsen <rask@formelder.dk>
+ *
+ * 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.
+ */
+
+/*
+ * The Sunchip CX-A99 board is found in several similar Android media
+ * players, such as:
+ *
+ * Instabox Fantasy A8 (no external antenna)
+ * Jesurun CS-Q8 (ships with larger remote control)
+ * Jesurun Maxone
+ * Rikomagic (RKM) MK80/MK80LE
+ * Tronsmart Draco AW80 Meta/Telos
+ *
+ * See the Sunchip CX-A99 page on the Linux-sunxi wiki for more information.
+ */
+
+/dts-v1/;
+#include "sun9i-a80.dtsi"
+
+#include <dt-bindings/gpio/gpio.h>
+
+/ {
+ model = "Sunchip CX-A99";
+ compatible = "sunchip,cx-a99", "allwinner,sun9i-a80";
+
+ aliases {
+ serial0 = &uart0;
+ };
+
+ chosen {
+ stdout-path = "serial0:115200n8";
+ };
+
+ leds {
+ compatible = "gpio-leds";
+
+ blue {
+ gpios = <&pio 6 10 GPIO_ACTIVE_HIGH>; /* PG10 */
+ label = "cx-a99:blue:status";
+ };
+
+ red {
+ gpios = <&pio 6 11 GPIO_ACTIVE_HIGH>; /* PG11 */
+ label = "cx-a99:red:status";
+ };
+ };
+
+ powerseq_wifi: powerseq-wifi {
+ compatible = "mmc-pwrseq-simple";
+ clocks = <&ac100_rtc 1>;
+ clock-names = "ext_clock";
+ reset-gpios = <&r_pio 1 0 GPIO_ACTIVE_LOW>; /* PM0 */
+ post-power-on-delay-ms = <1>; /* Minimum 2 cycles. */
+ };
+
+ /* USB 2.0 connector closest to the 12 V power connector. */
+ reg_usb1_vbus: regulator-usb1-vbus {
+ compatible = "regulator-fixed";
+ regulator-name = "usb1-vbus";
+ regulator-min-microvolt = <5000000>;
+ regulator-max-microvolt = <5000000>;
+ gpio = <&r_pio 0 7 /* no flag support */ 0>; /* PL7 */
+ enable-active-high;
+ };
+
+ /* USB 2.0 connector next to the SD card slot. */
+ reg_usb3_vbus: regulator-usb3-vbus {
+ compatible = "regulator-fixed";
+ regulator-name = "usb3-vbus";
+ regulator-min-microvolt = <5000000>;
+ regulator-max-microvolt = <5000000>;
+ gpio = <&r_pio 0 8 /* no flag support */ 0>; /* PL8 */
+ enable-active-high;
+ };
+
+ /*
+ * OZ80120 voltage regulator for the four Cortex-A15 CPU cores.
+ * Although the regulator can output 750 - 1200 mV, the permissible
+ * range for the CPU cores is only 800 - 1100 mV.
+ */
+ reg_vdd_cpub: regulator-vdd-cpub {
+ compatible = "regulator-gpio";
+
+ regulator-always-on;
+ regulator-min-microvolt = < 800000>;
+ regulator-max-microvolt = <1100000>;
+ regulator-name = "vdd-cpub";
+
+ /* Note: GPIO flags are not supported here . */
+ enable-gpio = <&r_pio 0 2 /* flags n/a */ 0>; /* PL2 */
+ enable-active-high;
+ gpios = <&r_pio 0 3 /* no flag support */ 0>, /* PL3 */
+ <&r_pio 0 4 /* no flag support */ 0>, /* PL4 */
+ <&r_pio 0 5 /* no flag support */ 0>; /* PL5 */
+
+ gpios-states = <1 0 0>;
+ states = < 750000 0x7
+ 800000 0x3
+ 850000 0x5
+ 900000 0x1
+ 950000 0x6
+ 1000000 0x2
+ 1100000 0x4
+ 1200000 0x0>;
+ };
+};
+
+&ehci0 {
+ status = "okay";
+};
+
+&ehci2 {
+ status = "okay";
+};
+
+/*
+ * SD card slot. Although the GPIO pin for card detection is listed as capable
+ * of generating interrupts in the "A80 User Manual", this doesn't work for
+ * some unknown reason, so poll the GPIO for card detection. This is also what
+ * the vendor sys_config.fex file specifies.
+ */
+&mmc0 {
+ bus-width = <4>;
+ cd-gpios = <&pio 7 17 GPIO_ACTIVE_LOW>; /* PH17 */
+ broken-cd; /* Poll. */
+ pinctrl-names = "default";
+ pinctrl-0 = <&mmc0_pins>;
+ vmmc-supply = <&reg_dcdce>;
+ status = "okay";
+};
+
+/* Ampak AP6335 IEEE 802.11 a/b/g/n/ac Wifi. */
+&mmc1 {
+ bus-width = <4>;
+ non-removable;
+ pinctrl-names = "default";
+ pinctrl-0 = <&mmc1_pins>;
+ vmmc-supply = <&reg_cldo3>; /* See cldo2,cldo3 note. */
+ vqmmc-supply = <&reg_aldo2>;
+ mmc-pwrseq = <&powerseq_wifi>;
+ status = "okay";
+};
+
+/* On-board eMMC card. */
+&mmc2 {
+ bus-width = <8>;
+ non-removable;
+ pinctrl-names = "default";
+ pinctrl-0 = <&mmc2_8bit_pins>;
+ vmmc-supply = <&reg_dcdce>;
+ status = "okay";
+};
+
+&osc32k {
+ clocks = <&ac100_rtc 0>;
+};
+
+&r_ir {
+ status = "okay";
+};
+
+&r_rsb {
+ status = "okay";
+
+ ac100: codec@e89 {
+ compatible = "x-powers,ac100";
+ reg = <0xe89>;
+
+ ac100_codec: codec {
+ compatible = "x-powers,ac100-codec";
+ interrupt-parent = <&r_pio>;
+ interrupts = <0 9 IRQ_TYPE_LEVEL_LOW>; /* PL9 */
+ #clock-cells = <0>;
+ clock-output-names = "4M_adda";
+ };
+
+ ac100_rtc: rtc {
+ compatible = "x-powers,ac100-rtc";
+ interrupt-parent = <&nmi_intc>;
+ interrupts = <0 IRQ_TYPE_LEVEL_LOW>;
+ clocks = <&ac100_codec>;
+ #clock-cells = <1>;
+ clock-output-names = "cko1_rtc",
+ "cko2_rtc",
+ "cko3_rtc";
+ };
+ };
+
+ pmic@745 {
+ compatible = "x-powers,axp808", "x-powers,axp806";
+ x-powers,master-mode;
+ reg = <0x745>;
+ interrupt-parent = <&nmi_intc>;
+ interrupts = <0 IRQ_TYPE_LEVEL_LOW>;
+ interrupt-controller;
+ #interrupt-cells = <1>;
+
+ swin-supply = <&reg_dcdce>;
+
+ regulators {
+ reg_aldo1: aldo1 {
+ regulator-boot-on;
+ regulator-min-microvolt = <3000000>;
+ regulator-max-microvolt = <3000000>;
+ regulator-name = "vcc-3v0";
+ };
+
+ /* Supplies pin groups G and M. */
+ reg_aldo2: aldo2 {
+ regulator-boot-on;
+ regulator-min-microvolt = <1800000>;
+ regulator-max-microvolt = <3600000>;
+ regulator-name = "vddio-wifi-codec";
+ };
+
+ reg_aldo3: aldo3 {
+ regulator-boot-on;
+ regulator-min-microvolt = <2500000>;
+ regulator-max-microvolt = <2500000>;
+ regulator-name = "vddio-gmac";
+ };
+
+ reg_bldo1: bldo1 {
+ regulator-always-on; /* Hang if disabled */
+ regulator-min-microvolt = <1700000>;
+ regulator-max-microvolt = <1900000>;
+ regulator-name = "vdd18-dll-vcc18-pll";
+ };
+
+ reg_bldo2: bldo2 {
+ regulator-always-on; /* Hang if disabled */
+ regulator-min-microvolt = < 800000>;
+ regulator-max-microvolt = <1100000>;
+ regulator-name = "vdd-cpus";
+ };
+
+ reg_bldo3: bldo3 {
+ regulator-min-microvolt = <1100000>;
+ regulator-max-microvolt = <1300000>;
+ regulator-name = "vcc12-hsic";
+ };
+
+ reg_bldo4: bldo4 {
+ regulator-boot-on;
+ regulator-min-microvolt = < 800000>;
+ regulator-max-microvolt = <1100000>;
+ regulator-name = "vdd09-hdmi";
+ };
+
+ /* Supplies PLx pins which control some regulators. */
+ reg_cldo1: cldo1 {
+ regulator-always-on;
+ regulator-min-microvolt = <3300000>;
+ regulator-max-microvolt = <3300000>;
+ regulator-name = "vcc-pl-led";
+ };
+
+ /*
+ * cldo2 and cldo3 are connected in parallel.
+ * There is currently no way to express that.
+ * For now, use regulator-always-on on cldo2 and lock
+ * the voltage on both to 3.3 V.
+ */
+ reg_cldo2: cldo2 {
+ regulator-always-on;
+ regulator-min-microvolt = <3300000>;
+ regulator-max-microvolt = <3300000>;
+ regulator-name = "vbat2-wifi+bt";
+ };
+
+ reg_cldo3: cldo3 {
+ regulator-min-microvolt = <3300000>;
+ regulator-max-microvolt = <3300000>;
+ regulator-name = "vbat1-wifi+bt";
+ };
+
+ reg_dcdca: dcdca {
+ regulator-always-on;
+ regulator-min-microvolt = < 800000>;
+ regulator-max-microvolt = <1100000>;
+ regulator-name = "vdd-cpua";
+ };
+
+ reg_dcdcb: dcdcb {
+ regulator-always-on;
+ regulator-min-microvolt = <1450000>;
+ regulator-max-microvolt = <1550000>;
+ regulator-name = "vcc-dram";
+ };
+
+ reg_dcdcc: dcdcc {
+ regulator-min-microvolt = < 800000>;
+ regulator-max-microvolt = <1100000>;
+ regulator-name = "vdd-gpu";
+ };
+
+ reg_dcdcd: dcdcd {
+ regulator-always-on; /* Hang if disabled. */
+ regulator-min-microvolt = < 800000>;
+ regulator-max-microvolt = <1100000>;
+ regulator-name = "vdd-sys";
+ };
+
+ /* Supplies pin groups B-F and H. */
+ reg_dcdce: dcdce {
+ regulator-always-on;
+ regulator-min-microvolt = <3300000>;
+ regulator-max-microvolt = <3300000>;
+ regulator-name = "vcc-io-mmc-spdif";
+ };
+
+ reg_sw: sw {
+ regulator-min-microvolt = <3300000>;
+ regulator-max-microvolt = <3300000>;
+ regulator-name = "vcc-gmac-codec";
+ };
+ };
+ };
+};
+
+/*
+ * 5-pin connector opposite of the SD card slot:
+ * 1 = GND (pointed to by small triangle), 2 = GND, 3 = 3.3 V, 4 = RX, 5 = TX.
+ */
+&uart0 {
+ pinctrl-names = "default";
+ pinctrl-0 = <&uart0_pins_a>;
+ status = "okay";
+};
+
+&usbphy1 {
+ phy-supply = <&reg_usb1_vbus>;
+ status = "okay";
+};
+
+&usbphy3 {
+ phy-supply = <&reg_usb3_vbus>;
+ status = "okay";
+};
diff --git a/arch/arm/dts/sun9i-a80.dtsi b/arch/arm/dts/sun9i-a80.dtsi
index f68b3242b3..92412b2ac1 100644
--- a/arch/arm/dts/sun9i-a80.dtsi
+++ b/arch/arm/dts/sun9i-a80.dtsi
@@ -701,6 +701,14 @@
allwinner,pull = <SUN4I_PINCTRL_NO_PULL>;
};
+ mmc1_pins: mmc1 {
+ allwinner,pins = "PG0", "PG1" ,"PG2", "PG3",
+ "PG4", "PG5";
+ allwinner,function = "mmc1";
+ allwinner,drive = <SUN4I_PINCTRL_30_MA>;
+ allwinner,pull = <SUN4I_PINCTRL_NO_PULL>;
+ };
+
mmc2_8bit_pins: mmc2_8bit {
allwinner,pins = "PC6", "PC7", "PC8", "PC9",
"PC10", "PC11", "PC12",
diff --git a/board/sunxi/MAINTAINERS b/board/sunxi/MAINTAINERS
index 3f211293fe..91ca6eaf7a 100644
--- a/board/sunxi/MAINTAINERS
+++ b/board/sunxi/MAINTAINERS
@@ -269,6 +269,12 @@ M: VishnuPatekar <vishnupatekar0510@gmail.com>
S: Maintained
F: configs/Sinovoip_BPI_M3_defconfig
+SUNCHIP CX-A99 BOARD
+M: Rask Ingemann Lambertsen <rask@formelder.dk>
+S: Maintained
+F: configs/Sunchip_CX-A99_defconfig
+W: https://linux-sunxi.org/Sunchip_CX-A99
+
WEXLER-TAB7200 BOARD
M: Aleksei Mamlin <mamlinav@gmail.com>
S: Maintained
diff --git a/board/sunxi/README.nand b/board/sunxi/README.nand
new file mode 100644
index 0000000000..a5d4ff0e90
--- /dev/null
+++ b/board/sunxi/README.nand
@@ -0,0 +1,54 @@
+Allwinner NAND flashing
+=======================
+
+A lot of Allwinner devices, especially the older ones (pre-H3 era),
+comes with a NAND. NANDs storages are a pretty weak choice when it
+comes to the reliability, and it comes with a number of flaws like
+read and write disturbs, data retention issues, bloks becoming
+unusable, etc.
+
+In order to mitigate that, various strategies have been found to be
+able to recover from those issues like ECC, hardware randomization,
+and of course, redundancy for the critical parts.
+
+This is obviously something that we will take into account when
+creating our images. However, the BROM will use a quite weird pattern
+when accessing the NAND, and will access only at most 4kB per page,
+which means that we also have to split that binary accross several
+pages.
+
+In order to accomodate that, we create a tool that will generate an
+SPL image that is ready to be programmed directly embedding the ECCs,
+randomized, and with the necessary bits needed to reduce the number of
+bitflips. The U-Boot build system, when configured for the NAND will
+also generate the image sunxi-spl-with-ecc.bin that will have been
+generated by that tool.
+
+In order to flash your U-Boot image onto a board, assuming that the
+board is in FEL mode, you'll need the sunxi-tools that you can find at
+this repository: https://github.com/linux-sunxi/sunxi-tools
+
+Then, you'll need to first load an SPL to initialise the RAM:
+sunxi-fel spl spl/sunxi-spl.bin
+
+Load the binaries we'll flash into RAM:
+sunxi-fel write 0x4a000000 u-boot-dtb.bin
+sunxi-fel write 0x43000000 spl/sunxi-spl-with-ecc.bin
+
+And execute U-Boot
+sunxi-fel exe 0x4a000000
+
+On your board, you'll now have all the needed binaries into RAM, so
+you only need to erase the NAND...
+
+nand erase.chip
+
+Then write the SPL and its backup:
+
+nand write.raw.noverify 0x43000000 0 40
+nand write.raw.noverify 0x43000000 0x400000 40
+
+And finally write the U-Boot binary:
+nand write 0x4a000000 0x800000 0xc0000
+
+You can now reboot and enjoy your NAND. \ No newline at end of file
diff --git a/cmd/Kconfig b/cmd/Kconfig
index 4b152f8222..661ae7a98c 100644
--- a/cmd/Kconfig
+++ b/cmd/Kconfig
@@ -452,9 +452,29 @@ config CMD_MMC
config CMD_NAND
bool "nand"
+ default y if NAND_SUNXI
help
NAND support.
+if CMD_NAND
+config CMD_NAND_TRIMFFS
+ bool "nand write.trimffs"
+ default y if ARCH_SUNXI
+ help
+ Allows one to skip empty pages when flashing something on a NAND.
+
+config CMD_NAND_LOCK_UNLOCK
+ bool "nand lock/unlock"
+ help
+ NAND locking support.
+
+config CMD_NAND_TORTURE
+ bool "nand torture"
+ help
+ NAND torture support.
+
+endif # CMD_NAND
+
config CMD_PART
bool "part"
select PARTITION_UUIDS
@@ -801,12 +821,33 @@ config CMD_FS_GENERIC
help
Enables filesystem commands (e.g. load, ls) that work for multiple
fs types.
+
+config CMD_MTDPARTS
+ depends on ARCH_SUNXI
+ bool "MTD partition support"
+ help
+ MTD partition support
+
+config MTDIDS_DEFAULT
+ string "Default MTD IDs"
+ depends on CMD_MTDPARTS
+ help
+ Defines a default MTD ID
+
+config MTDPARTS_DEFAULT
+ string "Default MTD partition scheme"
+ depends on CMD_MTDPARTS
+ help
+ Defines a default MTD partitioning scheme in the Linux MTD command
+ line partitions format
+
endmenu
config CMD_UBI
tristate "Enable UBI - Unsorted block images commands"
select CRC32
select MTD_UBI
+ default y if NAND_SUNXI
help
UBI is a software layer above MTD layer which admits use of LVM-like
logical volumes on top of MTD devices, hides some complexities of
@@ -815,4 +856,14 @@ config CMD_UBI
(www.linux-mtd.infradead.org). Activate this option if you want
to use U-Boot UBI commands.
+config CMD_UBIFS
+ tristate "Enable UBIFS - Unsorted block images filesystem commands"
+ depends on CMD_UBI
+ select CRC32
+ select RBTREE if ARCH_SUNXI
+ select LZO if ARCH_SUNXI
+ default y if NAND_SUNXI
+ help
+ UBIFS is a file system for flash devices which works on top of UBI.
+
endmenu
diff --git a/cmd/mtdparts.c b/cmd/mtdparts.c
index b9b160dc1e..112bf1f3e3 100644
--- a/cmd/mtdparts.c
+++ b/cmd/mtdparts.c
@@ -110,11 +110,19 @@ DECLARE_GLOBAL_DATA_PTR;
/* default values for mtdids and mtdparts variables */
#if !defined(MTDIDS_DEFAULT)
+#ifdef CONFIG_MTDIDS_DEFAULT
+#define MTDIDS_DEFAULT CONFIG_MTDIDS_DEFAULT
+#else
#define MTDIDS_DEFAULT NULL
#endif
+#endif
#if !defined(MTDPARTS_DEFAULT)
+#ifdef CONFIG_MTDPARTS_DEFAULT
+#define MTDPARTS_DEFAULT CONFIG_MTDPARTS_DEFAULT
+#else
#define MTDPARTS_DEFAULT NULL
#endif
+#endif
#if defined(CONFIG_SYS_MTDPARTS_RUNTIME)
extern void board_mtdparts_default(const char **mtdids, const char **mtdparts);
#endif
diff --git a/common/Kconfig b/common/Kconfig
index ec519d07cc..1879aefaf8 100644
--- a/common/Kconfig
+++ b/common/Kconfig
@@ -158,6 +158,75 @@ config SPI_BOOT
endmenu
+menu "Environment"
+
+if ARCH_SUNXI
+
+choice
+ prompt "Environment Device"
+ default ENV_IS_IN_MMC if ARCH_SUNXI
+
+config ENV_IS_IN_MMC
+ bool "Environment in an MMC device"
+ depends on CMD_MMC
+ help
+ Define this if you have an MMC device which you want to use for the
+ environment.
+
+config ENV_IS_IN_NAND
+ bool "Environment in a NAND device"
+ depends on CMD_NAND
+ help
+ Define this if you have a NAND device which you want to use for the
+ environment.
+
+config ENV_IS_IN_UBI
+ bool "Environment in a UBI volume"
+ depends on CMD_UBI
+ depends on CMD_MTDPARTS
+ help
+ Define this if you have a UBI volume which you want to use for the
+ environment.
+
+config ENV_IS_NOWHERE
+ bool "Environment is not stored"
+ help
+ Define this if you don't want to or can't have an environment stored
+ on a storage medium
+
+endchoice
+
+config ENV_OFFSET
+ hex "Environment Offset"
+ depends on !ENV_IS_IN_UBI
+ depends on !ENV_IS_NOWHERE
+ default 0x88000 if ARCH_SUNXI
+ help
+ Offset from the start of the device (or partition)
+
+config ENV_SIZE
+ hex "Environment Size"
+ depends on !ENV_IS_NOWHERE
+ default 0x20000 if ARCH_SUNXI
+ help
+ Size of the environment storage area
+
+config ENV_UBI_PART
+ string "UBI partition name"
+ depends on ENV_IS_IN_UBI
+ help
+ MTD partition containing the UBI device
+
+config ENV_UBI_VOLUME
+ string "UBI volume name"
+ depends on ENV_IS_IN_UBI
+ help
+ Name of the volume that you want to store the environment in.
+
+endif
+
+endmenu
+
config BOOTDELAY
int "delay in seconds before automatically booting"
default 2
diff --git a/configs/CHIP_pro_defconfig b/configs/CHIP_pro_defconfig
new file mode 100644
index 0000000000..df43e5a12d
--- /dev/null
+++ b/configs/CHIP_pro_defconfig
@@ -0,0 +1,33 @@
+CONFIG_ARM=y
+CONFIG_ARCH_SUNXI=y
+CONFIG_SPL_I2C_SUPPORT=y
+# CONFIG_SPL_MMC_SUPPORT is not set
+CONFIG_SPL_NAND_SUPPORT=y
+CONFIG_MACH_SUN5I=y
+CONFIG_DRAM_TIMINGS_DDR3_800E_1066G_1333J=y
+CONFIG_USB0_VBUS_PIN="PB10"
+CONFIG_DEFAULT_DEVICE_TREE="sun5i-gr8-chip-pro"
+CONFIG_SYS_EXTRA_OPTIONS="CONS_INDEX=2,SYS_NAND_BLOCK_SIZE=0x40000,SYS_NAND_PAGE_SIZE=4096,SYS_NAND_OOBSIZE=256"
+CONFIG_ENV_IS_IN_UBI=y
+CONFIG_ENV_UBI_PART="UBI"
+CONFIG_ENV_UBI_VOLUME="uboot-env"
+CONFIG_SPL=y
+# CONFIG_CMD_IMLS is not set
+# CONFIG_CMD_LOADB is not set
+# CONFIG_CMD_LOADS is not set
+# CONFIG_CMD_FLASH is not set
+# CONFIG_CMD_FPGA is not set
+CONFIG_CMD_MTDPARTS=y
+CONFIG_MTDIDS_DEFAULT="nand0=sunxi-nand.0"
+CONFIG_MTDPARTS_DEFAULT="mtdparts=sunxi-nand.0:256k(spl),256k(spl-backup),2m(uboot),2m(uboot-backup),-(UBI)"
+# CONFIG_MMC is not set
+CONFIG_NAND_SUNXI=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
diff --git a/configs/Sunchip_CX-A99_defconfig b/configs/Sunchip_CX-A99_defconfig
new file mode 100644
index 0000000000..7530d7db20
--- /dev/null
+++ b/configs/Sunchip_CX-A99_defconfig
@@ -0,0 +1,22 @@
+CONFIG_ARM=y
+CONFIG_ARCH_SUNXI=y
+CONFIG_MACH_SUN9I=y
+CONFIG_DRAM_CLK=600
+CONFIG_DRAM_ZQ=3881915
+CONFIG_DRAM_ODT_EN=y
+CONFIG_MMC0_CD_PIN="PH17"
+CONFIG_MMC_SUNXI_SLOT_EXTRA=2
+CONFIG_USB0_VBUS_PIN="PH15"
+CONFIG_USB0_VBUS_DET=""
+CONFIG_USB0_ID_DET=""
+CONFIG_USB1_VBUS_PIN="PL7"
+CONFIG_USB3_VBUS_PIN="PL8"
+CONFIG_DEFAULT_DEVICE_TREE="sun9i-a80-cx-a99"
+# CONFIG_SYS_MALLOC_CLEAR_ON_INIT is not set
+CONFIG_SPL=y
+# CONFIG_CMD_IMLS is not set
+# CONFIG_CMD_FLASH is not set
+# CONFIG_CMD_FPGA is not set
+# CONFIG_SPL_DOS_PARTITION is not set
+# CONFIG_SPL_ISO_PARTITION is not set
+# CONFIG_SPL_EFI_PARTITION is not set
diff --git a/configs/nanopi_neo_air_defconfig b/configs/nanopi_neo_air_defconfig
new file mode 100644
index 0000000000..9598bd5cd5
--- /dev/null
+++ b/configs/nanopi_neo_air_defconfig
@@ -0,0 +1,17 @@
+CONFIG_ARM=y
+CONFIG_ARCH_SUNXI=y
+CONFIG_MACH_SUN8I_H3=y
+CONFIG_DRAM_CLK=408
+CONFIG_DRAM_ZQ=3881979
+CONFIG_DRAM_ODT_EN=y
+CONFIG_DEFAULT_DEVICE_TREE="sun8i-h3-nanopi-neo-air"
+# CONFIG_SYS_MALLOC_CLEAR_ON_INIT is not set
+CONFIG_CONSOLE_MUX=y
+CONFIG_SPL=y
+# CONFIG_CMD_IMLS is not set
+# CONFIG_CMD_FLASH is not set
+# CONFIG_CMD_FPGA is not set
+# CONFIG_SPL_DOS_PARTITION is not set
+# CONFIG_SPL_ISO_PARTITION is not set
+# CONFIG_SPL_EFI_PARTITION is not set
+CONFIG_USB_EHCI_HCD=y
diff --git a/configs/sun8i_a23_evb_defconfig b/configs/sun8i_a23_evb_defconfig
new file mode 100644
index 0000000000..296df00043
--- /dev/null
+++ b/configs/sun8i_a23_evb_defconfig
@@ -0,0 +1,19 @@
+CONFIG_ARM=y
+CONFIG_ARCH_SUNXI=y
+CONFIG_MACH_SUN8I_A23=y
+CONFIG_DRAM_CLK=552
+CONFIG_DRAM_ZQ=63351
+CONFIG_USB0_VBUS_PIN="axp_drivebus"
+CONFIG_USB0_VBUS_DET="axp_vbus_detect"
+CONFIG_USB1_VBUS_PIN="PH7"
+CONFIG_DEFAULT_DEVICE_TREE="sun8i-a23-evb"
+# CONFIG_SYS_MALLOC_CLEAR_ON_INIT is not set
+CONFIG_SYS_EXTRA_OPTIONS="CONS_INDEX=5"
+CONFIG_SPL=y
+# CONFIG_CMD_IMLS is not set
+# CONFIG_CMD_FLASH is not set
+# CONFIG_CMD_FPGA is not set
+# CONFIG_SPL_DOS_PARTITION is not set
+# CONFIG_SPL_ISO_PARTITION is not set
+# CONFIG_SPL_EFI_PARTITION is not set
+CONFIG_USB_EHCI_HCD=y
diff --git a/drivers/mtd/nand/Kconfig b/drivers/mtd/nand/Kconfig
index a2ea9b1b6d..a7b76f4218 100644
--- a/drivers/mtd/nand/Kconfig
+++ b/drivers/mtd/nand/Kconfig
@@ -67,12 +67,29 @@ config NAND_SUNXI
bool "Support for NAND on Allwinner SoCs"
depends on MACH_SUN4I || MACH_SUN5I || MACH_SUN7I
select SYS_NAND_SELF_INIT
+ select SYS_NAND_U_BOOT_LOCATIONS
---help---
Enable support for NAND. This option enables the standard and
SPL drivers.
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
@@ -127,7 +144,7 @@ config SYS_NAND_U_BOOT_LOCATIONS
config SYS_NAND_U_BOOT_OFFS
hex "Location in NAND to read U-Boot from"
- default 0x8000 if NAND_SUNXI
+ default 0x800000 if NAND_SUNXI
depends on SYS_NAND_U_BOOT_LOCATIONS
help
Set the offset from the start of the nand where u-boot should be
diff --git a/drivers/mtd/nand/sunxi_nand_spl.c b/drivers/mtd/nand/sunxi_nand_spl.c
index 1ef7366d4c..eed4472bdc 100644
--- a/drivers/mtd/nand/sunxi_nand_spl.c
+++ b/drivers/mtd/nand/sunxi_nand_spl.c
@@ -245,7 +245,7 @@ static int nand_read_page(const struct nfc_config *conf, u32 offs,
{
dma_addr_t dst = (dma_addr_t)dest;
int nsectors = len / conf->ecc_size;
- u16 rand_seed;
+ u16 rand_seed = 0;
u32 val;
int page;
@@ -258,8 +258,9 @@ static int nand_read_page(const struct nfc_config *conf, u32 offs,
/* clear ecc status */
writel(0, SUNXI_NFC_BASE + NFC_ECC_ST);
- /* Choose correct seed */
- rand_seed = random_seed[page % conf->nseeds];
+ /* Choose correct seed if randomized */
+ if (conf->randomize)
+ rand_seed = random_seed[page % conf->nseeds];
writel((rand_seed << 16) | (conf->ecc_strength << 12) |
(conf->randomize ? NFC_ECC_RANDOM_EN : 0) |
diff --git a/drivers/mtd/ubi/Kconfig b/drivers/mtd/ubi/Kconfig
index 0c82395317..cb9ba78681 100644
--- a/drivers/mtd/ubi/Kconfig
+++ b/drivers/mtd/ubi/Kconfig
@@ -3,6 +3,7 @@ menu "UBI support"
config MTD_UBI
bool "Enable UBI - Unsorted block images"
select CRC32
+ select RBTREE if ARCH_SUNXI
help
UBI is a software layer above MTD layer which admits of LVM-like
logical volumes on top of MTD devices, hides some complexities of
diff --git a/drivers/net/sun8i_emac.c b/drivers/net/sun8i_emac.c
index abdfada646..a3dbe2823b 100644
--- a/drivers/net/sun8i_emac.c
+++ b/drivers/net/sun8i_emac.c
@@ -21,6 +21,9 @@
#include <malloc.h>
#include <miiphy.h>
#include <net.h>
+#ifdef CONFIG_DM_GPIO
+#include <asm-generic/gpio.h>
+#endif
#define MDIO_CMD_MII_BUSY BIT(0)
#define MDIO_CMD_MII_WRITE BIT(1)
@@ -128,11 +131,22 @@ struct emac_eth_dev {
phys_addr_t sysctl_reg;
struct phy_device *phydev;
struct mii_dev *bus;
+#ifdef CONFIG_DM_GPIO
+ struct gpio_desc reset_gpio;
+#endif
+};
+
+
+struct sun8i_eth_pdata {
+ struct eth_pdata eth_pdata;
+ u32 reset_delays[3];
};
+
static int sun8i_mdio_read(struct mii_dev *bus, int addr, int devad, int reg)
{
- struct emac_eth_dev *priv = bus->priv;
+ struct udevice *dev = bus->priv;
+ struct emac_eth_dev *priv = dev_get_priv(dev);
ulong start;
u32 miiaddr = 0;
int timeout = CONFIG_MDIO_TIMEOUT;
@@ -164,7 +178,8 @@ static int sun8i_mdio_read(struct mii_dev *bus, int addr, int devad, int reg)
static int sun8i_mdio_write(struct mii_dev *bus, int addr, int devad, int reg,
u16 val)
{
- struct emac_eth_dev *priv = bus->priv;
+ struct udevice *dev = bus->priv;
+ struct emac_eth_dev *priv = dev_get_priv(dev);
ulong start;
u32 miiaddr = 0;
int ret = -1, timeout = CONFIG_MDIO_TIMEOUT;
@@ -604,7 +619,41 @@ static void sun8i_emac_board_setup(struct emac_eth_dev *priv)
setbits_le32(&ccm->ahb_reset0_cfg, BIT(AHB_RESET_OFFSET_GMAC));
}
-static int sun8i_mdio_init(const char *name, struct emac_eth_dev *priv)
+#if defined(CONFIG_DM_GPIO)
+static int sun8i_mdio_reset(struct mii_dev *bus)
+{
+ struct udevice *dev = bus->priv;
+ struct emac_eth_dev *priv = dev_get_priv(dev);
+ struct sun8i_eth_pdata *pdata = dev_get_platdata(dev);
+ int ret;
+
+ if (!dm_gpio_is_valid(&priv->reset_gpio))
+ return 0;
+
+ /* reset the phy */
+ ret = dm_gpio_set_value(&priv->reset_gpio, 0);
+ if (ret)
+ return ret;
+
+ udelay(pdata->reset_delays[0]);
+
+ ret = dm_gpio_set_value(&priv->reset_gpio, 1);
+ if (ret)
+ return ret;
+
+ udelay(pdata->reset_delays[1]);
+
+ ret = dm_gpio_set_value(&priv->reset_gpio, 0);
+ if (ret)
+ return ret;
+
+ udelay(pdata->reset_delays[2]);
+
+ return 0;
+}
+#endif
+
+static int sun8i_mdio_init(const char *name, struct udevice *priv)
{
struct mii_dev *bus = mdio_alloc();
@@ -617,6 +666,9 @@ static int sun8i_mdio_init(const char *name, struct emac_eth_dev *priv)
bus->write = sun8i_mdio_write;
snprintf(bus->name, sizeof(bus->name), name);
bus->priv = (void *)priv;
+#if defined(CONFIG_DM_GPIO)
+ bus->reset = sun8i_mdio_reset;
+#endif
return mdio_register(bus);
}
@@ -696,7 +748,7 @@ static int sun8i_emac_eth_probe(struct udevice *dev)
sun8i_emac_board_setup(priv);
sun8i_emac_set_syscon(priv);
- sun8i_mdio_init(dev->name, priv);
+ sun8i_mdio_init(dev->name, dev);
priv->bus = miiphy_get_dev_by_name(dev->name);
return sun8i_phy_init(priv, dev);
@@ -713,11 +765,16 @@ static const struct eth_ops sun8i_emac_eth_ops = {
static int sun8i_emac_eth_ofdata_to_platdata(struct udevice *dev)
{
- struct eth_pdata *pdata = dev_get_platdata(dev);
+ struct sun8i_eth_pdata *sun8i_pdata = dev_get_platdata(dev);
+ struct eth_pdata *pdata = &sun8i_pdata->eth_pdata;
struct emac_eth_dev *priv = dev_get_priv(dev);
const char *phy_mode;
int node = dev_of_offset(dev);
int offset = 0;
+#ifdef CONFIG_DM_GPIO
+ int reset_flags = GPIOD_IS_OUT;
+ int ret = 0;
+#endif
pdata->iobase = dev_get_addr_name(dev, "emac");
priv->sysctl_reg = dev_get_addr_name(dev, "syscon");
@@ -762,6 +819,23 @@ static int sun8i_emac_eth_ofdata_to_platdata(struct udevice *dev)
if (!priv->use_internal_phy)
parse_phy_pins(dev);
+#ifdef CONFIG_DM_GPIO
+ if (fdtdec_get_bool(gd->fdt_blob, dev->of_offset,
+ "snps,reset-active-low"))
+ reset_flags |= GPIOD_ACTIVE_LOW;
+
+ ret = gpio_request_by_name(dev, "snps,reset-gpio", 0,
+ &priv->reset_gpio, reset_flags);
+
+ if (ret == 0) {
+ ret = fdtdec_get_int_array(gd->fdt_blob, dev->of_offset,
+ "snps,reset-delays-us",
+ sun8i_pdata->reset_delays, 3);
+ } else if (ret == -ENOENT) {
+ ret = 0;
+ }
+#endif
+
return 0;
}
@@ -782,6 +856,6 @@ U_BOOT_DRIVER(eth_sun8i_emac) = {
.probe = sun8i_emac_eth_probe,
.ops = &sun8i_emac_eth_ops,
.priv_auto_alloc_size = sizeof(struct emac_eth_dev),
- .platdata_auto_alloc_size = sizeof(struct eth_pdata),
+ .platdata_auto_alloc_size = sizeof(struct sun8i_eth_pdata),
.flags = DM_FLAG_ALLOC_PRIV_DMA,
};
diff --git a/include/configs/sunxi-common.h b/include/configs/sunxi-common.h
index cda2fec519..1d475b10dd 100644
--- a/include/configs/sunxi-common.h
+++ b/include/configs/sunxi-common.h
@@ -125,6 +125,9 @@
#define CONFIG_SYS_NAND_MAX_ECCPOS 1664
#define CONFIG_SYS_NAND_ONFI_DETECTION
#define CONFIG_SYS_MAX_NAND_DEVICE 8
+
+#define CONFIG_MTD_DEVICE
+#define CONFIG_MTD_PARTITIONS
#endif
#ifdef CONFIG_SPL_SPI_SUNXI
@@ -134,9 +137,13 @@
/* mmc config */
#ifdef CONFIG_MMC
#define CONFIG_MMC_SUNXI_SLOT 0
-#define CONFIG_ENV_IS_IN_MMC
+#endif
+
+#if defined(CONFIG_ENV_IS_IN_MMC)
#define CONFIG_SYS_MMC_ENV_DEV 0 /* first detected MMC controller */
#define CONFIG_SYS_MMC_MAX_DEVICE 4
+#elif defined(CONFIG_ENV_IS_NOWHERE)
+#define CONFIG_ENV_SIZE (128 << 10)
#endif
/* 64MB of malloc() pool */
@@ -159,9 +166,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
@@ -325,13 +329,6 @@ extern int soft_i2c_gpio_scl;
#define CONFIG_SYS_USB_EVENT_POLL_VIA_INT_QUEUE
#endif
-#if !defined CONFIG_ENV_IS_IN_MMC && \
- !defined CONFIG_ENV_IS_IN_NAND && \
- !defined CONFIG_ENV_IS_IN_FAT && \
- !defined CONFIG_ENV_IS_IN_SPI_FLASH
-#define CONFIG_ENV_IS_NOWHERE
-#endif
-
#define CONFIG_MISC_INIT_R
#ifndef CONFIG_SPL_BUILD
@@ -461,6 +458,20 @@ extern int soft_i2c_gpio_scl;
"stderr=serial\0"
#endif
+#ifdef CONFIG_MTDIDS_DEFAULT
+#define SUNXI_MTDIDS_DEFAULT \
+ "mtdids=" CONFIG_MTDIDS_DEFAULT "\0"
+#else
+#define SUNXI_MTDIDS_DEFAULT
+#endif
+
+#ifdef CONFIG_MTDPARTS_DEFAULT
+#define SUNXI_MTDPARTS_DEFAULT \
+ "mtdparts=" CONFIG_MTDPARTS_DEFAULT "\0"
+#else
+#define SUNXI_MTDPARTS_DEFAULT
+#endif
+
#define CONSOLE_ENV_SETTINGS \
CONSOLE_STDIN_SETTINGS \
CONSOLE_STDOUT_SETTINGS
@@ -471,6 +482,8 @@ extern int soft_i2c_gpio_scl;
DFU_ALT_INFO_RAM \
"fdtfile=" CONFIG_DEFAULT_DEVICE_TREE ".dtb\0" \
"console=ttyS0,115200\0" \
+ SUNXI_MTDIDS_DEFAULT \
+ SUNXI_MTDPARTS_DEFAULT \
BOOTCMD_SUNXI_COMPAT \
BOOTENV
diff --git a/include/environment.h b/include/environment.h
index b602e8ac46..6f94986c6b 100644
--- a/include/environment.h
+++ b/include/environment.h
@@ -8,6 +8,8 @@
#ifndef _ENVIRONMENT_H_
#define _ENVIRONMENT_H_
+#include <linux/kconfig.h>
+
/**************************************************************************
*
* The "environment" is stored as a list of '\0' terminated
diff --git a/lib/Kconfig b/lib/Kconfig
index 5115d047f8..a0d5d926eb 100644
--- a/lib/Kconfig
+++ b/lib/Kconfig
@@ -61,6 +61,9 @@ config SPL_TINY_MEMSET
size-constrained envrionments even this may be too big. Enable this
option to reduce code size slightly at the cost of some speed.
+config RBTREE
+ bool
+
source lib/dhry/Kconfig
source lib/rsa/Kconfig
@@ -132,6 +135,8 @@ config LZ4
frame format currently (2015) implemented in the Linux kernel
(generated by 'lz4 -l'). The two formats are incompatible.
+config LZO
+ bool
endmenu
config ERRNO_STR
diff --git a/lib/bch.c b/lib/bch.c
index 147715afd0..ec53483774 100644
--- a/lib/bch.c
+++ b/lib/bch.c
@@ -54,10 +54,27 @@
* finite fields GF(2^q). In Rapport de recherche INRIA no 2829, 1996.
*/
+#ifndef USE_HOSTCC
#include <common.h>
#include <ubi_uboot.h>
#include <linux/bitops.h>
+#else
+#include <errno.h>
+#include <endian.h>
+#include <stdint.h>
+#include <stdlib.h>
+#include <string.h>
+
+#undef cpu_to_be32
+#define cpu_to_be32 htobe32
+#define DIV_ROUND_UP(n,d) (((n) + (d) - 1) / (d))
+#define kmalloc(size, flags) malloc(size)
+#define kzalloc(size, flags) calloc(1, size)
+#define kfree free
+#define ARRAY_SIZE(arr) (sizeof(arr) / sizeof((arr)[0]))
+#endif
+
#include <asm/byteorder.h>
#include <linux/bch.h>
@@ -95,6 +112,37 @@ struct gf_poly_deg1 {
unsigned int c[2];
};
+#ifdef USE_HOSTCC
+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;
+}
+#endif
+
/*
* same as encode_bch(), but process input data one byte at a time
*/
diff --git a/scripts/Makefile.spl b/scripts/Makefile.spl
index 4485ea8812..760aceea63 100644
--- a/scripts/Makefile.spl
+++ b/scripts/Makefile.spl
@@ -179,6 +179,10 @@ endif
ifdef CONFIG_ARCH_SUNXI
ALL-y += $(obj)/sunxi-spl.bin
+
+ifdef CONFIG_NAND_SUNXI
+ALL-y += $(obj)/sunxi-spl-with-ecc.bin
+endif
endif
ifeq ($(CONFIG_SYS_SOC),"at91")
@@ -300,6 +304,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 $@
diff --git a/tools/.gitignore b/tools/.gitignore
index 0d1f076d78..6ec71f5c7f 100644
--- a/tools/.gitignore
+++ b/tools/.gitignore
@@ -16,6 +16,7 @@
/mkexynosspl
/mxsboot
/mksunxiboot
+/sunxi-spl-image-builder
/ncb
/proftool
/relocate-rela
diff --git a/tools/Makefile b/tools/Makefile
index e9cde02c90..fa1b85bdae 100644
--- a/tools/Makefile
+++ b/tools/Makefile
@@ -179,6 +179,8 @@ hostprogs-$(CONFIG_MX28) += mxsboot
HOSTCFLAGS_mxsboot.o := -pedantic
hostprogs-$(CONFIG_ARCH_SUNXI) += mksunxiboot
+hostprogs-$(CONFIG_ARCH_SUNXI) += sunxi-spl-image-builder
+sunxi-spl-image-builder-objs := sunxi-spl-image-builder.o lib/bch.o
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 0000000000..d538a38813
--- /dev/null
+++ b/tools/sunxi-spl-image-builder.c
@@ -0,0 +1,484 @@
+/*
+ * Allwinner NAND randomizer and image builder implementation:
+ *
+ * Copyright © 2016 NextThing Co.
+ * Copyright © 2016 Free Electrons
+ *
+ * Author: Boris Brezillon <boris.brezillon@free-electrons.com>
+ *
+ */
+
+#include <linux/bch.h>
+
+#include <getopt.h>
+#include <version.h>
+
+#define BCH_PRIMITIVE_POLY 0x5803
+
+#define ARRAY_SIZE(arr) (sizeof(arr) / sizeof((arr)[0]))
+#define DIV_ROUND_UP(n,d) (((n) + (d) - 1) / (d))
+
+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;
+};
+
+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) {
+ size_t ret;
+
+ offs = steps * (info->ecc_step_size + eccbytes + 4);
+ cnt = info->page_size + info->oob_size - offs;
+ ret = fread(buffer + offs, 1, cnt, rnd);
+ if (!ret && !feof(rnd)) {
+ fprintf(stderr,
+ "Failed to read random data\n");
+ return -1;
+ }
+ } 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) {
+ size_t ret;
+
+ ret = fread(buffer + cnt, 1, pad, rnd);
+ if (!ret && !feof(rnd)) {
+ fprintf(stderr,
+ "Failed to read random data\n");
+ return -1;
+ }
+ } 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);
+}