commit
089795090a
@ -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 = <®_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"; |
||||
}; |
||||
|
||||
®_dcdc2 { |
||||
regulator-min-microvolt = <1000000>; |
||||
regulator-max-microvolt = <1400000>; |
||||
regulator-name = "vdd-cpu"; |
||||
regulator-always-on; |
||||
}; |
||||
|
||||
®_dcdc3 { |
||||
regulator-min-microvolt = <1000000>; |
||||
regulator-max-microvolt = <1300000>; |
||||
regulator-name = "vdd-sys"; |
||||
regulator-always-on; |
||||
}; |
||||
|
||||
®_ldo1 { |
||||
regulator-name = "vdd-rtc"; |
||||
}; |
||||
|
||||
®_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. |
||||
*/ |
||||
®_ldo3 { |
||||
regulator-min-microvolt = <3300000>; |
||||
regulator-max-microvolt = <3300000>; |
||||
regulator-name = "vcc-wifi-1"; |
||||
regulator-always-on; |
||||
}; |
||||
|
||||
®_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 = <®_vcc5v0>; |
||||
status = "okay"; |
||||
}; |
File diff suppressed because it is too large
Load Diff
@ -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 = <®_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"; |
||||
}; |
@ -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 = <®_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 = <®_cldo3>; /* See cldo2,cldo3 note. */ |
||||
vqmmc-supply = <®_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 = <®_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 = <®_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 = <®_usb1_vbus>; |
||||
status = "okay"; |
||||
}; |
||||
|
||||
&usbphy3 { |
||||
phy-supply = <®_usb3_vbus>; |
||||
status = "okay"; |
||||
}; |
@ -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. |
@ -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 |
@ -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 |
@ -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 |
@ -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 |
@ -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); |
||||
} |
Loading…
Reference in new issue