diff mbox series

rk3399: Add basic support for helios64

Message ID 20210225211315.157694-1-uwe@kleine-koenig.org
State Changes Requested
Delegated to: Kever Yang
Headers show
Series rk3399: Add basic support for helios64 | expand

Commit Message

Uwe Kleine-König Feb. 25, 2021, 9:13 p.m. UTC
This is a stripped down version of the vendor U-Boot patch by Aditya
Prayoga found in the armbian repository. This patch is enough to have
the 1G ethernet port, the micro SD card, eMMC and UART operational and
let it boot a Debian netboot installer.

The device tree is contained in Linux v5.11-rc1. During my work on
U-Boot I noticed a wrong pull setting, the corresponding patch is still
in linux-next and already applied in the copy that is added by this
patch.

Signed-off-by: Uwe Kleine-König <uwe@kleine-koenig.org>
---
Hello,

@Aditya: I kept you as maintainer in MAINTAINERS, is this ok for you?
I doubt that I'm qualified enough for that.

So please wait for this question to be resolved before you apply this
patch.

Best regards
Uwe

 arch/arm/dts/Makefile                         |   1 +
 .../arm/dts/rk3399-kobol-helios64-u-boot.dtsi | 266 +++++++++++++
 arch/arm/dts/rk3399-kobol-helios64.dts        | 372 ++++++++++++++++++
 arch/arm/mach-rockchip/rk3399/Kconfig         |  17 +
 board/kobol/helios64/Kconfig                  |  24 ++
 board/kobol/helios64/MAINTAINERS              |   6 +
 board/kobol/helios64/Makefile                 |   5 +
 board/kobol/helios64/helios64.c               | 262 ++++++++++++
 board/kobol/helios64/sys_otp.c                | 248 ++++++++++++
 board/kobol/helios64/sys_otp.h                |  10 +
 configs/helios64-rk3399_defconfig             | 142 +++++++
 include/configs/helios64.h                    |  47 +++
 12 files changed, 1400 insertions(+)
 create mode 100644 arch/arm/dts/rk3399-kobol-helios64-u-boot.dtsi
 create mode 100644 arch/arm/dts/rk3399-kobol-helios64.dts
 create mode 100644 board/kobol/helios64/Kconfig
 create mode 100644 board/kobol/helios64/MAINTAINERS
 create mode 100644 board/kobol/helios64/Makefile
 create mode 100644 board/kobol/helios64/helios64.c
 create mode 100644 board/kobol/helios64/sys_otp.c
 create mode 100644 board/kobol/helios64/sys_otp.h
 create mode 100644 configs/helios64-rk3399_defconfig
 create mode 100644 include/configs/helios64.h

Comments

Dennis Gilmore Feb. 25, 2021, 11:23 p.m. UTC | #1
Thanks for submitting, I have been meaning to do so myself, I have
been meaning to go through and try get the dts files in a decent
shape. I think that most of what is in
arch/arm/dts/rk3399-kobol-helios64-u-boot.dtsi  belongs in
arch/arm/dts/rk3399-kobol-helios64.dts I also wonder if we shouldn't
default to building an image for use in the SPI flash since the system
has it available.

Dennis



On Thu, Feb 25, 2021 at 3:14 PM Uwe Kleine-König <uwe@kleine-koenig.org> wrote:
>
> This is a stripped down version of the vendor U-Boot patch by Aditya
> Prayoga found in the armbian repository. This patch is enough to have
> the 1G ethernet port, the micro SD card, eMMC and UART operational and
> let it boot a Debian netboot installer.
>
> The device tree is contained in Linux v5.11-rc1. During my work on
> U-Boot I noticed a wrong pull setting, the corresponding patch is still
> in linux-next and already applied in the copy that is added by this
> patch.
>
> Signed-off-by: Uwe Kleine-König <uwe@kleine-koenig.org>
> ---
> Hello,
>
> @Aditya: I kept you as maintainer in MAINTAINERS, is this ok for you?
> I doubt that I'm qualified enough for that.
>
> So please wait for this question to be resolved before you apply this
> patch.
>
> Best regards
> Uwe
>
>  arch/arm/dts/Makefile                         |   1 +
>  .../arm/dts/rk3399-kobol-helios64-u-boot.dtsi | 266 +++++++++++++
>  arch/arm/dts/rk3399-kobol-helios64.dts        | 372 ++++++++++++++++++
>  arch/arm/mach-rockchip/rk3399/Kconfig         |  17 +
>  board/kobol/helios64/Kconfig                  |  24 ++
>  board/kobol/helios64/MAINTAINERS              |   6 +
>  board/kobol/helios64/Makefile                 |   5 +
>  board/kobol/helios64/helios64.c               | 262 ++++++++++++
>  board/kobol/helios64/sys_otp.c                | 248 ++++++++++++
>  board/kobol/helios64/sys_otp.h                |  10 +
>  configs/helios64-rk3399_defconfig             | 142 +++++++
>  include/configs/helios64.h                    |  47 +++
>  12 files changed, 1400 insertions(+)
>  create mode 100644 arch/arm/dts/rk3399-kobol-helios64-u-boot.dtsi
>  create mode 100644 arch/arm/dts/rk3399-kobol-helios64.dts
>  create mode 100644 board/kobol/helios64/Kconfig
>  create mode 100644 board/kobol/helios64/MAINTAINERS
>  create mode 100644 board/kobol/helios64/Makefile
>  create mode 100644 board/kobol/helios64/helios64.c
>  create mode 100644 board/kobol/helios64/sys_otp.c
>  create mode 100644 board/kobol/helios64/sys_otp.h
>  create mode 100644 configs/helios64-rk3399_defconfig
>  create mode 100644 include/configs/helios64.h
>
> diff --git a/arch/arm/dts/Makefile b/arch/arm/dts/Makefile
> index fd47e408f826..752ba4fd8b35 100644
> --- a/arch/arm/dts/Makefile
> +++ b/arch/arm/dts/Makefile
> @@ -125,6 +125,7 @@ dtb-$(CONFIG_ROCKCHIP_RK3399) += \
>         rk3399-ficus.dtb \
>         rk3399-firefly.dtb \
>         rk3399-gru-bob.dtb \
> +       rk3399-kobol-helios64.dtb \
>         rk3399-khadas-edge.dtb \
>         rk3399-khadas-edge-captain.dtb \
>         rk3399-khadas-edge-v.dtb \
> diff --git a/arch/arm/dts/rk3399-kobol-helios64-u-boot.dtsi b/arch/arm/dts/rk3399-kobol-helios64-u-boot.dtsi
> new file mode 100644
> index 000000000000..84a27548a08d
> --- /dev/null
> +++ b/arch/arm/dts/rk3399-kobol-helios64-u-boot.dtsi
> @@ -0,0 +1,266 @@
> +// SPDX-License-Identifier: GPL-2.0+
> +/*
> + * Copyright (c) 2020 Aditya Prayoga (aditya@kobol.io)
> + */
> +
> +#include "rk3399-u-boot.dtsi"
> +#include "rk3399-sdram-lpddr4-100.dtsi"
> +
> +/ {
> +       aliases {
> +               spi0 = &spi1;
> +               ethernet0 = &gmac;
> +       };
> +
> +       chosen {
> +               bootargs = "earlycon=uart8250,mmio32,0xff1a0000 earlyprintk";
> +               stdout-path = "serial2:1500000n8";
> +               u-boot,spl-boot-order = "same-as-spl", &spiflash, &sdmmc, &sdhci;
> +       };
> +
> +       config {
> +               u-boot,spl-payload-offset = <0x80000>; /* @ 512KB */
> +       };
> +
> +       leds {
> +               led-1 {
> +                       linux,default-trigger = "panic";
> +               };
> +       };
> +
> +       vcc3v0_sd: vcc3v0-sd {
> +               startup-delay-us = <20000>;
> +       };
> +};
> +
> +&cpu_alert0 {
> +       temperature = <80000>;
> +};
> +
> +&cpu_alert1 {
> +       temperature = <95000>;
> +};
> +
> +&cpu_crit {
> +       temperature = <100000>;
> +};
> +
> +&i2c0 {
> +       rk808: pmic@1b {
> +               rockchip,system-power-controller;
> +
> +               regulators {
> +                       vdd_center: DCDC_REG1 {
> +                               regulator-name = "vdd_center";
> +                               regulator-always-on;
> +                               regulator-boot-on;
> +                               regulator-min-microvolt = <950000>;
> +                               regulator-max-microvolt = <950000>;
> +                               regulator-init-microvolt = <950000>;
> +                               regulator-ramp-delay = <6001>;
> +                               regulator-state-mem {
> +                                       regulator-on-in-suspend;
> +                                       regulator-suspend-microvolt = <950000>;
> +                               };
> +                       };
> +
> +                       vcc_ddr_s3: DCDC_REG3 {
> +                               regulator-name = "vcc_ddr_s3";
> +                               regulator-always-on;
> +                               regulator-boot-on;
> +                               regulator-state-mem {
> +                                       regulator-on-in-suspend;
> +                               };
> +                       };
> +
> +                       /* not used */
> +                       vcc1v8_dvp: LDO_REG1 {
> +                               regulator-name = "vcc1v8_dvp";
> +                       };
> +
> +                       /* not used */
> +                       vcc3v0_touch: LDO_REG2 {
> +                               regulator-name = "vcc3v0_touch";
> +                       };
> +
> +                       vcc1v8_s3: LDO_REG3 {
> +                               regulator-name = "vcc1v8_s3";
> +                               regulator-always-on;
> +                               regulator-boot-on;
> +                               regulator-min-microvolt = <1800000>;
> +                               regulator-max-microvolt = <1800000>;
> +                               regulator-state-mem {
> +                                       regulator-on-in-suspend;
> +                                       regulator-suspend-microvolt = <1800000>;
> +                               };
> +                       };
> +
> +                       /* not used */
> +                       vcca3v0_codec: LDO_REG5 {
> +                               regulator-name = "vcca3v0_codec";
> +                       };
> +
> +                       vcc1v5_s3: LDO_REG6 {
> +                               regulator-name = "vcc1v5_s3";
> +                               regulator-always-on;
> +                               regulator-boot-on;
> +                               regulator-min-microvolt = <1500000>;
> +                               regulator-max-microvolt = <1500000>;
> +                               regulator-state-mem {
> +                                       regulator-on-in-suspend;
> +                                       regulator-suspend-microvolt = <1500000>;
> +                               };
> +                       };
> +
> +                       /* not used */
> +                       vcca1v8_codec: LDO_REG7 {
> +                               regulator-name = "vcca1v8_codec";
> +                       };
> +
> +                       vcc3v3_sys_s0: SWITCH_REG1 {
> +                               regulator-name = "vcc3v3_sys_s0";
> +                               regulator-always-on;
> +                               regulator-boot-on;
> +                               regulator-state-mem {
> +                                       regulator-off-in-suspend;
> +                               };
> +                       };
> +
> +                       vcc3v3_s0: SWITCH_REG2 {
> +                               regulator-name = "vcc3v3_s0";
> +                       };
> +               };
> +       };
> +
> +       vdd_cpu_b: regulator@40 {
> +               pinctrl-names = "default";
> +               pinctrl-0 = <&vsel1_gpio>;
> +               vsel-gpios = <&gpio1 RK_PC1 GPIO_ACTIVE_HIGH>;
> +               regulator-compatible = "fan53555-reg";
> +       };
> +
> +       vdd_gpu: regulator@41 {
> +               compatible = "silergy,syr828";
> +               reg = <0x41>;
> +               fcs,suspend-voltage-selector = <1>;
> +               pinctrl-names = "default";
> +               pinctrl-0 = <&vsel2_gpio>;
> +               vsel-gpios = <&gpio1 RK_PB6 GPIO_ACTIVE_HIGH>;
> +               regulator-compatible = "fan53555-reg";
> +               regulator-name = "vdd_gpu";
> +               regulator-min-microvolt = <712500>;
> +               regulator-max-microvolt = <1500000>;
> +               regulator-ramp-delay = <1000>;
> +               regulator-always-on;
> +               regulator-boot-on;
> +               vin-supply = <&vcc5v0_sys>;
> +
> +               regulator-state-mem {
> +                       regulator-off-in-suspend;
> +               };
> +       };
> +};
> +
> +&pinctrl {
> +       pmic {
> +               vsel1_gpio: vsel1-gpio {
> +                       rockchip,pins =
> +                               <1 RK_PC1 RK_FUNC_GPIO &pcfg_pull_down>;
> +               };
> +
> +               vsel2_gpio: vsel2-gpio {
> +                       rockchip,pins =
> +                               <1 RK_PB6 RK_FUNC_GPIO &pcfg_pull_down>;
> +               };
> +       };
> +};
> +
> +&pmu_io_domains {
> +       pmu1830-supply = <&vcc3v0_s3>;
> +       status = "okay";
> +};
> +
> +&sdmmc {
> +       sd-uhs-sdr104;
> +};
> +
> +&tsadc {
> +       /* tshut mode 0:CRU 1:GPIO */
> +       rockchip,hw-tshut-mode = <1>;
> +       /* tshut polarity 0:LOW 1:HIGH */
> +       rockchip,hw-tshut-polarity = <1>;
> +       status = "okay";
> +};
> +
> +&gpio1 {
> +       usb-mux-hs {
> +               gpio-hog;
> +               gpios = <RK_PA4 GPIO_ACTIVE_HIGH>;
> +               output-low;
> +               line-name = "USB_MUX_HS";
> +       };
> +
> +       usb-mux-oe {
> +               gpio-hog;
> +               gpios = <RK_PB5 GPIO_ACTIVE_LOW>;
> +               output-high;
> +               line-name = "USB_MUX_OE#";
> +       };
> +
> +       soc-flash-wp {
> +               gpio-hog;
> +               gpios = <RK_PC2 GPIO_ACTIVE_LOW>;
> +               output-low;
> +               line-name = "SOC_WP#";
> +       };
> +};
> +
> +&gpio2 {
> +       sata-flash-wp {
> +               gpio-hog;
> +               gpios = <RK_PD0 GPIO_ACTIVE_LOW>;
> +               output-high;
> +               line-name = "SATA_WP#_LV";
> +       };
> +};
> +
> +&gpio4 {
> +       auto-on-en-d {
> +               gpio-hog;
> +               gpios = <RK_PD1 GPIO_ACTIVE_HIGH>;
> +               output-low;
> +               line-name = "AUTO_ON_EN_D";
> +       };
> +
> +       auto-on-en-clk {
> +               gpio-hog;
> +               gpios = <RK_PD2 GPIO_ACTIVE_HIGH>;
> +               output-low;
> +               line-name = "AUTO_ON_EN_CLK";
> +       };
> +
> +       board-rev-id-0 {
> +               gpio-hog;
> +               gpios = <RK_PD5 GPIO_ACTIVE_HIGH>;
> +               input;
> +       };
> +
> +       board-rev-id-1 {
> +               gpio-hog;
> +               gpios = <RK_PD6 GPIO_ACTIVE_HIGH>;
> +               input;
> +       };
> +};
> +
> +&spi1 {
> +       status = "okay";
> +
> +       spiflash: flash@0 {
> +               compatible = "jedec,spi-nor";
> +               reg = <0x0>;
> +               spi-max-frequency = <25000000>;
> +               status = "okay";
> +               m25p,fast-read;
> +               u-boot,dm-pre-reloc;
> +       };
> +};
> diff --git a/arch/arm/dts/rk3399-kobol-helios64.dts b/arch/arm/dts/rk3399-kobol-helios64.dts
> new file mode 100644
> index 000000000000..66c725a34220
> --- /dev/null
> +++ b/arch/arm/dts/rk3399-kobol-helios64.dts
> @@ -0,0 +1,372 @@
> +// SPDX-License-Identifier: (GPL-2.0+ OR MIT)
> +/*
> + * Copyright (c) 2020 Aditya Prayoga <aditya@kobol.io>
> + */
> +
> +/*
> + * The Kobol Helios64 is a board designed to operate as a NAS and optionally
> + * ships with an enclosing that can host five 2.5" hard disks.
> + *
> + * See https://wiki.kobol.io/helios64/intro/ for further details.
> + */
> +
> +/dts-v1/;
> +#include "rk3399.dtsi"
> +#include "rk3399-opp.dtsi"
> +
> +/ {
> +       model = "Kobol Helios64";
> +       compatible = "kobol,helios64", "rockchip,rk3399";
> +
> +       avdd_1v8_s0: avdd-1v8-s0 {
> +               compatible = "regulator-fixed";
> +               regulator-name = "avdd_1v8_s0";
> +               regulator-always-on;
> +               regulator-boot-on;
> +               regulator-min-microvolt = <1800000>;
> +               regulator-max-microvolt = <1800000>;
> +               vin-supply = <&vcc3v3_sys_s3>;
> +       };
> +
> +       clkin_gmac: external-gmac-clock {
> +               compatible = "fixed-clock";
> +               clock-frequency = <125000000>;
> +               clock-output-names = "clkin_gmac";
> +               #clock-cells = <0>;
> +       };
> +
> +       leds {
> +               compatible = "gpio-leds";
> +               pinctrl-names = "default";
> +               pinctrl-0 = <&sys_grn_led_on &sys_red_led_on>;
> +
> +               led-0 {
> +                       label = "helios64:green:status";
> +                       gpios = <&gpio0 RK_PB4 GPIO_ACTIVE_HIGH>;
> +                       default-state = "on";
> +               };
> +
> +               led-1 {
> +                       label = "helios64:red:fault";
> +                       gpios = <&gpio0 RK_PB5 GPIO_ACTIVE_HIGH>;
> +                       default-state = "keep";
> +               };
> +       };
> +
> +       vcc1v8_sys_s0: vcc1v8-sys-s0 {
> +               compatible = "regulator-fixed";
> +               regulator-name = "vcc1v8_sys_s0";
> +               regulator-always-on;
> +               regulator-boot-on;
> +               regulator-min-microvolt = <1800000>;
> +               regulator-max-microvolt = <1800000>;
> +               vin-supply = <&vcc1v8_sys_s3>;
> +       };
> +
> +       vcc3v0_sd: vcc3v0-sd {
> +               compatible = "regulator-fixed";
> +               enable-active-high;
> +               gpio = <&gpio0 RK_PA1 GPIO_ACTIVE_HIGH>;
> +               regulator-name = "vcc3v0_sd";
> +               regulator-boot-on;
> +               regulator-min-microvolt = <3000000>;
> +               regulator-max-microvolt = <3000000>;
> +               pinctrl-names = "default";
> +               pinctrl-0 = <&sdmmc0_pwr_h>;
> +               vin-supply = <&vcc3v3_sys_s3>;
> +       };
> +
> +       vcc3v3_sys_s3: vcc_lan: vcc3v3-sys-s3 {
> +               compatible = "regulator-fixed";
> +               regulator-name = "vcc3v3_sys_s3";
> +               regulator-always-on;
> +               regulator-boot-on;
> +               regulator-min-microvolt = <3300000>;
> +               regulator-max-microvolt = <3300000>;
> +               vin-supply = <&vcc5v0_sys>;
> +
> +               regulator-state-mem {
> +                       regulator-on-in-suspend;
> +               };
> +       };
> +
> +       vcc5v0_sys: vcc5v0-sys {
> +               compatible = "regulator-fixed";
> +               regulator-name = "vcc5v0_sys";
> +               regulator-always-on;
> +               regulator-boot-on;
> +               regulator-min-microvolt = <5000000>;
> +               regulator-max-microvolt = <5000000>;
> +               vin-supply = <&vcc12v_dcin_bkup>;
> +
> +               regulator-state-mem {
> +                       regulator-on-in-suspend;
> +               };
> +       };
> +
> +       vcc12v_dcin: vcc12v-dcin {
> +               compatible = "regulator-fixed";
> +               regulator-name = "vcc12v_dcin";
> +               regulator-always-on;
> +               regulator-boot-on;
> +               regulator-min-microvolt = <12000000>;
> +               regulator-max-microvolt = <12000000>;
> +       };
> +
> +       vcc12v_dcin_bkup: vcc12v-dcin-bkup {
> +               compatible = "regulator-fixed";
> +               regulator-name = "vcc12v_dcin_bkup";
> +               regulator-always-on;
> +               regulator-boot-on;
> +               regulator-min-microvolt = <12000000>;
> +               regulator-max-microvolt = <12000000>;
> +               vin-supply = <&vcc12v_dcin>;
> +       };
> +};
> +
> +/*
> + * The system doesn't run stable with cpu freq enabled, so disallow the lower
> + * frequencies until this problem is properly understood and resolved.
> + */
> +&cluster0_opp {
> +       /delete-node/ opp00;
> +       /delete-node/ opp01;
> +       /delete-node/ opp02;
> +       /delete-node/ opp03;
> +       /delete-node/ opp04;
> +};
> +
> +&cluster1_opp {
> +       /delete-node/ opp00;
> +       /delete-node/ opp01;
> +       /delete-node/ opp02;
> +       /delete-node/ opp03;
> +       /delete-node/ opp04;
> +       /delete-node/ opp05;
> +       /delete-node/ opp06;
> +};
> +
> +&cpu_b0 {
> +       cpu-supply = <&vdd_cpu_b>;
> +};
> +
> +&cpu_b1 {
> +       cpu-supply = <&vdd_cpu_b>;
> +};
> +
> +&cpu_l0 {
> +       cpu-supply = <&vdd_cpu_l>;
> +};
> +
> +&cpu_l1 {
> +       cpu-supply = <&vdd_cpu_l>;
> +};
> +
> +&cpu_l2 {
> +       cpu-supply = <&vdd_cpu_l>;
> +};
> +
> +&cpu_l3 {
> +       cpu-supply = <&vdd_cpu_l>;
> +};
> +
> +&emmc_phy {
> +       status = "okay";
> +};
> +
> +&gmac {
> +       assigned-clock-parents = <&clkin_gmac>;
> +       assigned-clocks = <&cru SCLK_RMII_SRC>;
> +       clock_in_out = "input";
> +       phy-mode = "rgmii";
> +       phy-supply = <&vcc_lan>;
> +       pinctrl-names = "default";
> +       pinctrl-0 = <&rgmii_pins &gphy_reset>;
> +       rx_delay = <0x20>;
> +       tx_delay = <0x28>;
> +       snps,reset-active-low;
> +       snps,reset-delays-us = <0 10000 50000>;
> +       snps,reset-gpio = <&gpio3 RK_PB7 GPIO_ACTIVE_LOW>;
> +       status = "okay";
> +};
> +
> +&i2c0 {
> +       clock-frequency = <400000>;
> +       i2c-scl-rising-time-ns = <168>;
> +       i2c-scl-falling-time-ns = <4>;
> +       status = "okay";
> +
> +       rk808: pmic@1b {
> +               compatible = "rockchip,rk808";
> +               reg = <0x1b>;
> +               interrupt-parent = <&gpio0>;
> +               interrupts = <10 IRQ_TYPE_LEVEL_LOW>;
> +               clock-output-names = "xin32k", "rk808-clkout2";
> +               pinctrl-names = "default";
> +               pinctrl-0 = <&pmic_int_l>;
> +               vcc1-supply = <&vcc5v0_sys>;
> +               vcc2-supply = <&vcc5v0_sys>;
> +               vcc3-supply = <&vcc5v0_sys>;
> +               vcc4-supply = <&vcc5v0_sys>;
> +               vcc6-supply = <&vcc5v0_sys>;
> +               vcc7-supply = <&vcc5v0_sys>;
> +               vcc8-supply = <&vcc3v3_sys_s3>;
> +               vcc9-supply = <&vcc5v0_sys>;
> +               vcc10-supply = <&vcc5v0_sys>;
> +               vcc11-supply = <&vcc5v0_sys>;
> +               vcc12-supply = <&vcc3v3_sys_s3>;
> +               vddio-supply = <&vcc3v0_s3>;
> +               wakeup-source;
> +               #clock-cells = <1>;
> +
> +               regulators {
> +                       vdd_cpu_l: DCDC_REG2 {
> +                               regulator-name = "vdd_cpu_l";
> +                               regulator-always-on;
> +                               regulator-boot-on;
> +                               regulator-min-microvolt = <750000>;
> +                               regulator-max-microvolt = <1350000>;
> +                               regulator-ramp-delay = <6001>;
> +
> +                               regulator-state-mem {
> +                                       regulator-off-in-suspend;
> +                               };
> +                       };
> +
> +                       vcc1v8_sys_s3: DCDC_REG4 {
> +                               regulator-name = "vcc1v8_sys_s3";
> +                               regulator-always-on;
> +                               regulator-boot-on;
> +                               regulator-min-microvolt = <1800000>;
> +                               regulator-max-microvolt = <1800000>;
> +
> +                               regulator-state-mem {
> +                                       regulator-on-in-suspend;
> +                                       regulator-suspend-microvolt = <1800000>;
> +                               };
> +                       };
> +
> +                       vcc_sdio_s0: LDO_REG4 {
> +                               regulator-name = "vcc_sdio_s0";
> +                               regulator-always-on;
> +                               regulator-boot-on;
> +                               regulator-min-microvolt = <1800000>;
> +                               regulator-max-microvolt = <3000000>;
> +
> +                               regulator-state-mem {
> +                                       regulator-on-in-suspend;
> +                                       regulator-suspend-microvolt = <3000000>;
> +                               };
> +                       };
> +
> +                       vcc3v0_s3: LDO_REG8 {
> +                               regulator-name = "vcc3v0_s3";
> +                               regulator-always-on;
> +                               regulator-boot-on;
> +                               regulator-min-microvolt = <3000000>;
> +                               regulator-max-microvolt = <3000000>;
> +
> +                               regulator-state-mem {
> +                                       regulator-on-in-suspend;
> +                                       regulator-suspend-microvolt = <3000000>;
> +                               };
> +                       };
> +               };
> +       };
> +
> +       vdd_cpu_b: regulator@40 {
> +               compatible = "silergy,syr827";
> +               reg = <0x40>;
> +               fcs,suspend-voltage-selector = <1>;
> +               regulator-name = "vdd_cpu_b";
> +               regulator-always-on;
> +               regulator-boot-on;
> +               regulator-min-microvolt = <712500>;
> +               regulator-max-microvolt = <1500000>;
> +               regulator-ramp-delay = <1000>;
> +               vin-supply = <&vcc5v0_sys>;
> +
> +               regulator-state-mem {
> +                       regulator-off-in-suspend;
> +               };
> +       };
> +};
> +
> +&i2c2 {
> +       clock-frequency = <400000>;
> +       i2c-scl-rising-time-ns = <160>;
> +       i2c-scl-falling-time-ns = <30>;
> +       status = "okay";
> +
> +       temp@4c {
> +               compatible = "national,lm75";
> +               reg = <0x4c>;
> +       };
> +};
> +
> +&io_domains {
> +       audio-supply = <&vcc1v8_sys_s0>;
> +       bt656-supply = <&vcc1v8_sys_s0>;
> +       gpio1830-supply = <&vcc3v0_s3>;
> +       sdmmc-supply = <&vcc_sdio_s0>;
> +       status = "okay";
> +};
> +
> +&pinctrl {
> +       gmac {
> +               gphy_reset: gphy-reset {
> +                       rockchip,pins = <3 RK_PB7 RK_FUNC_GPIO &pcfg_output_low>;
> +               };
> +       };
> +
> +       leds {
> +               sys_grn_led_on: sys-grn-led-on {
> +                       rockchip,pins = <0 RK_PB4 RK_FUNC_GPIO &pcfg_pull_down>;
> +               };
> +
> +               sys_red_led_on: sys-red-led-on {
> +                       rockchip,pins = <0 RK_PB5 RK_FUNC_GPIO &pcfg_pull_down>;
> +               };
> +       };
> +
> +       pmic {
> +               pmic_int_l: pmic-int-l {
> +                       rockchip,pins = <0 RK_PB2 RK_FUNC_GPIO &pcfg_pull_none>;
> +               };
> +       };
> +
> +       vcc3v0-sd {
> +               sdmmc0_pwr_h: sdmmc0-pwr-h {
> +                       rockchip,pins = <0 RK_PA1 RK_FUNC_GPIO &pcfg_pull_up>;
> +               };
> +       };
> +};
> +
> +&pmu_io_domains {
> +       pmu1830-supply = <&vcc3v0_s3>;
> +       status = "okay";
> +};
> +
> +&sdhci {
> +       bus-width = <8>;
> +       mmc-hs200-1_8v;
> +       non-removable;
> +       vqmmc-supply = <&vcc1v8_sys_s0>;
> +       status = "okay";
> +};
> +
> +&sdmmc {
> +       bus-width = <4>;
> +       cap-sd-highspeed;
> +       cd-gpios = <&gpio0 RK_PA7 GPIO_ACTIVE_LOW>;
> +       disable-wp;
> +       pinctrl-names = "default";
> +       pinctrl-0 = <&sdmmc_clk &sdmmc_cmd &sdmmc_cd &sdmmc_bus4>;
> +       vmmc-supply = <&vcc3v0_sd>;
> +       vqmmc-supply = <&vcc_sdio_s0>;
> +       status = "okay";
> +};
> +
> +&uart2 {
> +       status = "okay";
> +};
> diff --git a/arch/arm/mach-rockchip/rk3399/Kconfig b/arch/arm/mach-rockchip/rk3399/Kconfig
> index 17628f917127..7890bafe5618 100644
> --- a/arch/arm/mach-rockchip/rk3399/Kconfig
> +++ b/arch/arm/mach-rockchip/rk3399/Kconfig
> @@ -28,6 +28,22 @@ config TARGET_PINEBOOK_PRO_RK3399
>           with 4Gb RAM, onboard eMMC, USB-C, a USB3 and USB2 port,
>           1920*1080 screen and all the usual laptop features.
>
> +config TARGET_HELIOS64
> +       bool "Kobol Innovations Helios64"
> +       select BOARD_LATE_INIT
> +       help
> +         Helios64 is a Network Attached Storage board based on Rockchip RK3399.
> +
> +         Key features of the Helios64 include:
> +          * on-board PCIe to 5 Ports SATA Controller JMB585
> +          * on-board USB 3.0 hub (3x USB 3.0 host)
> +          * USB Type-C (Support DisplayPort Alt Mode)
> +          * on-board 1 Gigabit Ethernet
> +          * on-board 2.5 Gigabit Ethernet (Realtek RTL8156)
> +          * on-board eMMC
> +          * on-board LPDDR4
> +          * SPI, I2C, UART, GPIO
> +
>  config TARGET_PUMA_RK3399
>         bool "Theobroma Systems RK3399-Q7 (Puma)"
>         help
> @@ -153,6 +169,7 @@ endif # BOOTCOUNT_LIMIT
>
>  source "board/firefly/roc-pc-rk3399/Kconfig"
>  source "board/google/gru/Kconfig"
> +source "board/kobol/helios64/Kconfig"
>  source "board/pine64/pinebook-pro-rk3399/Kconfig"
>  source "board/pine64/rockpro64_rk3399/Kconfig"
>  source "board/rockchip/evb_rk3399/Kconfig"
> diff --git a/board/kobol/helios64/Kconfig b/board/kobol/helios64/Kconfig
> new file mode 100644
> index 000000000000..644cdbd8f314
> --- /dev/null
> +++ b/board/kobol/helios64/Kconfig
> @@ -0,0 +1,24 @@
> +if TARGET_HELIOS64
> +
> +config SYS_BOARD
> +       default "helios64"
> +
> +config SYS_VENDOR
> +       default "kobol"
> +
> +config SYS_CONFIG_NAME
> +       default "helios64"
> +
> +config BOARD_SPECIFIC_OPTIONS # dummy
> +       def_bool y
> +
> +config ENV_SECT_SIZE
> +       default 0x1000 if ENV_IS_IN_SPI_FLASH
> +
> +config ENV_SIZE
> +       default 0x8000
> +
> +config ENV_OFFSET
> +       default 0x460000 if ENV_IS_IN_SPI_FLASH
> +
> +endif
> diff --git a/board/kobol/helios64/MAINTAINERS b/board/kobol/helios64/MAINTAINERS
> new file mode 100644
> index 000000000000..a9c88c79e331
> --- /dev/null
> +++ b/board/kobol/helios64/MAINTAINERS
> @@ -0,0 +1,6 @@
> +HELIOS64 BOARD
> +M:     Aditya Prayoga <aditya@kobol.io>
> +S:     Maintained
> +F:     board/kobol/helios64/
> +F:     include/configs/helios64.h
> +F:     configs/helios64_defconfig
> diff --git a/board/kobol/helios64/Makefile b/board/kobol/helios64/Makefile
> new file mode 100644
> index 000000000000..ab34245a6d6a
> --- /dev/null
> +++ b/board/kobol/helios64/Makefile
> @@ -0,0 +1,5 @@
> +# SPDX-License-Identifier: GPL-2.0+
> +#
> +# Copyright (C) 2020 Aditya Prayoga <aditya@kobol.io>
> +
> +obj-y  := helios64.o sys_otp.o
> diff --git a/board/kobol/helios64/helios64.c b/board/kobol/helios64/helios64.c
> new file mode 100644
> index 000000000000..1fe948eec4ee
> --- /dev/null
> +++ b/board/kobol/helios64/helios64.c
> @@ -0,0 +1,262 @@
> +// SPDX-License-Identifier: GPL-2.0+
> +/*
> + * (C) Copyright 2020 Aditya Prayoga (aditya@kobol.io)
> + */
> +
> +#include <common.h>
> +#include <dm.h>
> +#include <env.h>
> +#include <log.h>
> +#include <led.h>
> +#include <pci.h>
> +#include <power/regulator.h>
> +#include <scsi.h>
> +#include <spl_gpio.h>
> +#include <syscon.h>
> +#include <usb.h>
> +#include <linux/delay.h>
> +#include <asm/io.h>
> +#include <asm/gpio.h>
> +#include <asm/arch-rockchip/clock.h>
> +#include <asm/arch-rockchip/gpio.h>
> +#include <asm/arch-rockchip/grf_rk3399.h>
> +#include <asm/arch-rockchip/hardware.h>
> +#include <asm/arch-rockchip/misc.h>
> +#include <asm/arch-rockchip/periph.h>
> +
> +#include "sys_otp.h"
> +
> +#ifndef CONFIG_TPL_BUILD
> +int board_early_init_f(void)
> +{
> +#ifdef CONFIG_SPL_BUILD
> +#define GPIO0_BASE      0xff720000
> +#define GRF_BASE               0xff770000
> +       struct rk3399_grf_regs * const grf = (void *)GRF_BASE;
> +       struct rockchip_gpio_regs * const gpio = (void *)GPIO0_BASE;
> +
> +       /* Turn ON status LED. At this stage, FDT & DM is not initialized yet */
> +       spl_gpio_output(gpio, GPIO(BANK_B, 4), 1);
> +#endif
> +       return 0;
> +}
> +#endif
> +
> +#ifndef CONFIG_SPL_BUILD
> +int board_early_init_r(void)
> +{
> +       read_otp_data();
> +       return 0;
> +}
> +#endif
> +
> +#ifdef CONFIG_MISC_INIT_R
> +#define GRF_IO_VSEL_BT565_SHIFT                0
> +#define GRF_IO_VSEL_AUDIO_SHIFT                1
> +#define GRF_IO_VSEL_SDMMC_SHIFT                2
> +#define GRF_IO_VSEL_GPIO1830_SHIFT     3
> +
> +#define PMUGRF_CON0_VSEL_SHIFT         8
> +#define PMUGRF_CON0_PMU1830_VOL_SHIFT   9
> +static void setup_iodomain(void)
> +{
> +       struct rk3399_grf_regs *grf =
> +               syscon_get_first_range(ROCKCHIP_SYSCON_GRF);
> +       struct rk3399_pmugrf_regs *pmugrf =
> +               syscon_get_first_range(ROCKCHIP_SYSCON_PMUGRF);
> +
> +       /* BT565 is in 1.8v domain */
> +       rk_setreg(&grf->io_vsel, 1 << GRF_IO_VSEL_BT565_SHIFT);
> +
> +       /* AUDIO is in 1.8v domain */
> +       rk_setreg(&grf->io_vsel, 1 << GRF_IO_VSEL_AUDIO_SHIFT);
> +
> +       /* SDMMC is in 3.0v domain */
> +       rk_setreg(&grf->io_vsel, 0 << GRF_IO_VSEL_SDMMC_SHIFT);
> +
> +       /* GPIO1830 is in 3.0v domain */
> +       rk_setreg(&grf->io_vsel, 0 << GRF_IO_VSEL_GPIO1830_SHIFT);
> +
> +       /* Set GPIO1 1.8v/3.0v source select to PMU1830_VOL */
> +       rk_setreg(&pmugrf->soc_con0, 1 << PMUGRF_CON0_VSEL_SHIFT);
> +       rk_setreg(&pmugrf->soc_con0, 0 << PMUGRF_CON0_PMU1830_VOL_SHIFT);
> +}
> +
> +/*
> + * Swap mmc0 and mmc1 in boot_targets if booted from SD-Card.
> + *
> + * If bootsource is uSD-card we can assume that we want to use the
> + * SD-Card instead of the eMMC as first boot_target for distroboot.
> + * We only want to swap the defaults and not any custom environment a
> + * user has set. We exit early if a changed boot_targets environment
> + * is detected.
> + */
> +static int setup_boottargets(void)
> +{
> +       const char *boot_device =
> +               ofnode_read_chosen_string("u-boot,spl-boot-device");
> +       char *env_default, *env;
> +
> +       if (!boot_device) {
> +               debug("%s: /chosen/u-boot,spl-boot-device not set\n",
> +                     __func__);
> +               return -1;
> +       }
> +       debug("%s: booted from %s\n", __func__, boot_device);
> +
> +       env_default = env_get_default("boot_targets");
> +       env = env_get("boot_targets");
> +       if (!env) {
> +               debug("%s: boot_targets does not exist\n", __func__);
> +               return -1;
> +       }
> +       debug("%s: boot_targets current: %s - default: %s\n",
> +               __func__, env, env_default);
> +
> +       if (strcmp(env_default, env) != 0) {
> +               debug("%s: boot_targets not default, don't change it\n",
> +                       __func__);
> +               return 0;
> +       }
> +
> +       /*
> +        * Only run, if booting from mmc1 (i.e. /mmc@fe320000) and
> +        * only consider cases where the default boot-order first
> +        * tries to boot from mmc0 (eMMC) and then from mmc1
> +        * (i.e. external SD).
> +        *
> +        * In other words: the SD card will be moved to earlier in the
> +        * order, if U-Boot was also loaded from the SD-card.
> +        */
> +       if (!strcmp(boot_device, "/mmc@fe320000")) {
> +               char *mmc0, *mmc1;
> +
> +               debug("%s: booted from SD-Card\n", __func__);
> +               mmc0 = strstr(env, "mmc0");
> +               mmc1 = strstr(env, "mmc1");
> +
> +               if (!mmc0 || !mmc1) {
> +                       debug("%s: only one mmc boot_target found\n", __func__);
> +                       return -1;
> +               }
> +
> +               /*
> +                * If mmc0 comes first in the boot order, we need to change
> +                * the strings to make mmc1 first.
> +                */
> +               if (mmc0 < mmc1) {
> +                       mmc0[3] = '1';
> +                       mmc1[3] = '0';
> +                       debug("%s: set boot_targets to: %s\n", __func__, env);
> +                       env_set("boot_targets", env);
> +               }
> +       }
> +
> +       return 0;
> +}
> +
> +static void setup_leds(void)
> +{
> +       struct udevice *dev;
> +
> +       led_get_by_label("helios64:green:status", &dev);
> +       led_set_state(dev, LEDST_OFF);
> +       mdelay(250);
> +       led_set_state(dev, LEDST_ON);
> +}
> +
> +int misc_init_r(void)
> +{
> +       const u32 cpuid_offset = 0x7;
> +       const u32 cpuid_length = 0x10;
> +       u8 cpuid[cpuid_length];
> +       int ret;
> +
> +       setup_iodomain();
> +       set_board_info();
> +
> +       ret = rockchip_cpuid_from_efuse(cpuid_offset, cpuid_length, cpuid);
> +       if (ret)
> +               return ret;
> +
> +       ret = rockchip_cpuid_set(cpuid, cpuid_length);
> +       if (ret)
> +               return ret;
> +
> +       if (mac_read_from_otp())
> +               ret = rockchip_setup_macaddr();
> +
> +       setup_boottargets();
> +       setup_leds();
> +
> +       return ret;
> +}
> +#endif
> +
> +#ifdef CONFIG_LAST_STAGE_INIT
> +static void auto_power_enable(void)
> +{
> +       struct gpio_desc *enable, *clock;
> +
> +       if (gpio_hog_lookup_name("AUTO_ON_EN_D", &enable)) {
> +               debug("Fail to get AUTO_ON_EN_D\n");
> +               return;
> +       }
> +
> +       if (gpio_hog_lookup_name("AUTO_ON_EN_CLK", &clock)) {
> +               debug("Fail to get AUTO_ON_EN_CLK\n");
> +               return;
> +       }
> +
> +       dm_gpio_set_value(enable, 1);
> +       dm_gpio_set_value(clock, 1);
> +       mdelay(10);
> +       dm_gpio_set_value(clock, 0);
> +}
> +
> +int last_stage_init(void)
> +{
> +       auto_power_enable();
> +
> +#ifdef CONFIG_PCI
> +       scsi_scan(true);
> +#endif
> +
> +       return 0;
> +}
> +#endif
> +
> +#if defined(CONFIG_DISPLAY_BOARDINFO_LATE)
> +int checkboard(void)
> +{
> +       int major, minor;
> +
> +       printf("Revision: ");
> +
> +       if (!get_revision(&major, &minor))
> +               printf("%i.%i - %s\n", major, minor, get_variant());
> +       else
> +               printf("UNKNOWN\n");
> +
> +       return 0;
> +}
> +#endif
> +
> +#if defined(CONFIG_OF_LIBFDT) && defined(CONFIG_OF_BOARD_SETUP)
> +int ft_board_setup(void *blob, struct bd_info *bd)
> +{
> +       char *env;
> +
> +       env = env_get("board_rev");
> +       if (env)
> +               fdt_setprop_string(blob, fdt_path_offset(blob, "/"),
> +                       "kobol,board-rev", env);
> +
> +       env = env_get("cpuid#");
> +       if (env)
> +               fdt_setprop_string(blob, fdt_path_offset(blob, "/"),
> +                       "kobol,cpu-id", env);
> +
> +       return 0;
> +}
> +#endif
> diff --git a/board/kobol/helios64/sys_otp.c b/board/kobol/helios64/sys_otp.c
> new file mode 100644
> index 000000000000..3a27834641bd
> --- /dev/null
> +++ b/board/kobol/helios64/sys_otp.c
> @@ -0,0 +1,248 @@
> +#include <linux/types.h>
> +#include <dm.h>
> +#include <spi.h>
> +#include <log.h>
> +#include <net.h>
> +#include <u-boot/crc.h>
> +
> +#include "sys_otp.h"
> +
> +#define OTP_DEVICE_BUS  0
> +#define OTP_DEVICE_CS   0
> +#define MAX_NUM_PORTS  2
> +
> +enum board_variant {
> +       BOARD_VARIANT_INVALID = 0,
> +       BOARD_VARIANT_ENG_SAMPLE,
> +       BOARD_VARIANT_4G_PROD_NO_ECC,
> +       BOARD_VARIANT_MAX
> +};
> +
> +struct  __attribute__ ((__packed__)) otp_data_t {
> +       u8 magic[8];
> +       u8 part_num[16];
> +       u8 variant;
> +       u8 revision;
> +       u8 serial_num[6];
> +       u8 mfg_year[2];
> +       u8 mfg_month;
> +       u8 mfg_day;
> +       u8 mac_addr[MAX_NUM_PORTS][6];
> +       u8 reserved[204];
> +       u32 checksum;
> +} otp;
> +
> +static struct spi_slave *slave;
> +static int has_been_read = 0;
> +static int data_valid = 0;
> +
> +static inline int is_data_valid(void)
> +{
> +       return data_valid;
> +}
> +
> +static inline int is_valid_header(void)
> +{
> +       if ((otp.magic[0] == 'H') || (otp.magic[1] == '6') ||
> +               (otp.magic[2] == '4') || (otp.magic[3] == 'N') ||
> +               (otp.magic[4] == 'P') || (otp.magic[5] == 'V') ||
> +               (otp.magic[6] == '1') || (otp.magic[7] == 0))
> +
> +               return 1;
> +
> +       return 0;
> +}
> +
> +static int init_system_otp(int bus, int cs)
> +{
> +       int ret;
> +       char name[30], *str;
> +       struct udevice *dev;
> +
> +       snprintf(name, sizeof(name), "generic_%d:%d", bus, cs);
> +       str = strdup(name);
> +       if (!str)
> +               return -ENOMEM;
> +       ret = spi_get_bus_and_cs(bus, cs, 25000000, CONFIG_DEFAULT_SPI_MODE, "spi_generic_drv",
> +                                str, &dev, &slave);
> +       return ret;
> +}
> +
> +#ifdef DEBUG
> +/**
> + * show_otp_data - display the contents of the OTP register
> + */
> +static void show_otp_data(void)
> +{
> +       u32 i;
> +       u32 crc;
> +
> +       const char* var_str[BOARD_VARIANT_MAX] = {
> +                       "Invalid variant",
> +                       "Engineering Sample",
> +                       "Production - 4GB non ECC"
> +       };
> +
> +       printf("\n");
> +       printf("Register dump: (%lu bytes)\n", sizeof(otp));
> +       for (i = 0; i < sizeof(otp); i++) {
> +               if ((i % 16) == 0)
> +                       printf("%02X: ", i);
> +               printf("%02X ", ((u8 *)&otp)[i]);
> +               if (((i % 16) == 15) || (i == sizeof(otp) - 1))
> +                       printf("\n");
> +       }
> +
> +       if (!is_valid_header())
> +               return;
> +
> +       printf("Part Number: %s\n", otp.part_num);
> +       printf("Variant: %s\n", var_str[otp.variant]);
> +       printf("Revision: %x.%x\n", (otp.revision & 0xf0) >> 4, otp.revision & 0x0f);
> +       printf("Serial Number: %012llx\n", *((uint64_t*) otp.serial_num) &
> +               0xFFFFFFFFFFFF);
> +       printf("Manufacturing Date: %02X-%02X-%04X (DD-MM-YYYY)\n", otp.mfg_day,
> +               otp.mfg_month, *(u16*) otp.mfg_year);
> +
> +       printf("1GbE MAC Address:   %02X:%02X:%02X:%02X:%02X:%02X\n",
> +               otp.mac_addr[0][0], otp.mac_addr[0][1], otp.mac_addr[0][2],
> +               otp.mac_addr[0][3], otp.mac_addr[0][4], otp.mac_addr[0][5]);
> +
> +       printf("2.5GbE MAC Address: %02X:%02X:%02X:%02X:%02X:%02X\n",
> +               otp.mac_addr[1][0], otp.mac_addr[1][1], otp.mac_addr[1][2],
> +               otp.mac_addr[1][3], otp.mac_addr[1][4], otp.mac_addr[1][5]);
> +
> +       crc = crc32(0, (void *)&otp, sizeof(otp) - 4);
> +
> +       if (crc == le32_to_cpu(otp.checksum))
> +               printf("CRC: %08x\n\n", le32_to_cpu(otp.checksum));
> +       else
> +               printf("CRC: %08x (should be %08x)\n\n",
> +                          le32_to_cpu(otp.checksum), crc);
> +
> +}
> +#endif
> +
> +int read_otp_data(void)
> +{
> +       int ret;
> +       u8 dout[5];
> +
> +       if (has_been_read) {
> +               if (is_data_valid())
> +                       return 0;
> +               else
> +                       goto data_invalid;
> +       }
> +
> +       ret = init_system_otp(OTP_DEVICE_BUS, OTP_DEVICE_CS);
> +       if (ret)
> +               return ret;
> +
> +       ret = spi_claim_bus(slave);
> +       if (ret) {
> +               debug("SPI: Failed to claim SPI bus: %d\n", ret);
> +               return ret;
> +       }
> +
> +       dout[0] = 0x48;
> +       dout[1] = 0x00;
> +       dout[2] = 0x10; /* Security Register #1 */
> +       dout[3] = 0x00;
> +       dout[4] = 0x00; /* Dummy Byte */
> +
> +       ret = spi_write_then_read(slave, dout, sizeof(dout), NULL, (u8 *)&otp,
> +                       sizeof(otp));
> +
> +       spi_release_bus(slave);
> +#ifdef DEBUG
> +       show_otp_data();
> +#endif
> +
> +       has_been_read = (ret == 0) ? 1 : 0;
> +       if (!is_valid_header())
> +               goto data_invalid;
> +
> +       if (crc32(0, (void *)&otp, sizeof(otp) - 4) ==
> +               le32_to_cpu(otp.checksum))
> +               data_valid = 1;
> +
> +       if (!is_data_valid())
> +               goto data_invalid;
> +
> +       return 0;
> +
> +data_invalid:
> +       printf("Invalid board ID data!\n");
> +       return -1;
> +}
> +
> +int get_revision(int *major, int *minor)
> +{
> +       if (!is_data_valid())
> +               return -1;
> +
> +       *major = (otp.revision & 0xf0) >> 4;
> +       *minor = otp.revision & 0x0f;
> +
> +       return 0;
> +}
> +
> +const char *get_variant(void)
> +{
> +       const char* var_str[BOARD_VARIANT_MAX] = {
> +               "Unknown",
> +               "Engineering Sample",
> +               "4GB non ECC"
> +       };
> +
> +       if ((otp.variant < BOARD_VARIANT_ENG_SAMPLE) ||
> +               (otp.variant >= BOARD_VARIANT_MAX))
> +               return var_str[0];
> +
> +       return var_str[otp.variant];
> +}
> +
> +void set_board_info(void)
> +{
> +       char env_str[13];
> +
> +       if (!is_data_valid())
> +               return;
> +
> +       snprintf(env_str, sizeof(env_str), "%i.%i", (otp.revision & 0xf0) >> 4, otp.revision & 0x0f);
> +       env_set("board_rev", env_str);
> +
> +       sprintf(env_str, "%012llx", *((uint64_t*) otp.serial_num) &
> +               0xFFFFFFFFFFFF);
> +
> +       env_set("serial#", env_str);
> +}
> +
> +int mac_read_from_otp(void)
> +{
> +       unsigned int i;
> +       int ret;
> +
> +       if (!is_data_valid())
> +               return -1;
> +
> +       for (i = 0; i < MAX_NUM_PORTS; i++) {
> +               char enetvar[9];
> +
> +               sprintf(enetvar, i ? "eth%daddr" : "ethaddr", i);
> +
> +               if (!is_valid_ethaddr(otp.mac_addr[i])) {
> +                       debug("Not valid %s!\n", enetvar);
> +                       continue;
> +               }
> +
> +               /* Only initialize environment variables that are blank
> +                * (i.e. have not yet been set)
> +                */
> +               if (!env_get(enetvar))
> +                       eth_env_set_enetaddr(enetvar, otp.mac_addr[i]);
> +       }
> +
> +       return ret;
> +}
> diff --git a/board/kobol/helios64/sys_otp.h b/board/kobol/helios64/sys_otp.h
> new file mode 100644
> index 000000000000..61f6f3b3809a
> --- /dev/null
> +++ b/board/kobol/helios64/sys_otp.h
> @@ -0,0 +1,10 @@
> +#ifndef __HELIOS64_SYS_OTP_H
> +#define __HELIOS64_SYS_OTP_H
> +
> +int read_otp_data(void);
> +void set_board_info(void);
> +int get_revision(int *major, int *minor);
> +const char *get_variant(void);
> +int mac_read_from_otp(void);
> +
> +#endif
> diff --git a/configs/helios64-rk3399_defconfig b/configs/helios64-rk3399_defconfig
> new file mode 100644
> index 000000000000..6aee24011e45
> --- /dev/null
> +++ b/configs/helios64-rk3399_defconfig
> @@ -0,0 +1,142 @@
> +CONFIG_ARM=y
> +CONFIG_ARCH_ROCKCHIP=y
> +CONFIG_SYS_TEXT_BASE=0x00200000
> +CONFIG_SPL_GPIO_SUPPORT=y
> +CONFIG_ENV_OFFSET=0x3F8000
> +CONFIG_ROCKCHIP_RK3399=y
> +CONFIG_TARGET_HELIOS64=y
> +CONFIG_NR_DRAM_BANKS=1
> +CONFIG_DEBUG_UART_BASE=0xFF1A0000
> +CONFIG_DEBUG_UART_CLOCK=24000000
> +CONFIG_SPL_SPI_FLASH_SUPPORT=y
> +CONFIG_SPL_SPI_SUPPORT=y
> +CONFIG_DEBUG_UART=y
> +CONFIG_AHCI=y
> +# CONFIG_ANDROID_BOOT_IMAGE is not set
> +CONFIG_OF_BOARD_SETUP=y
> +CONFIG_USE_PREBOOT=y
> +CONFIG_CONSOLE_MUX=y
> +CONFIG_SYS_CONSOLE_ENV_OVERWRITE=y
> +CONFIG_DEFAULT_FDT_FILE="rockchip/rk3399-kobol-helios64.dtb"
> +CONFIG_MISC_INIT_R=y
> +CONFIG_VERSION_VARIABLE=y
> +# CONFIG_DISPLAY_BOARDINFO is not set
> +CONFIG_DISPLAY_BOARDINFO_LATE=y
> +CONFIG_BOARD_TYPES=y
> +CONFIG_BOARD_EARLY_INIT_F=y
> +CONFIG_BOARD_EARLY_INIT_R=y
> +CONFIG_LAST_STAGE_INIT=y
> +# CONFIG_SPL_RAW_IMAGE_SUPPORT is not set
> +CONFIG_SPL_STACK_R=y
> +CONFIG_SPL_STACK_R_MALLOC_SIMPLE_LEN=0x10000
> +CONFIG_SPL_I2C_SUPPORT=y
> +CONFIG_SPL_POWER_SUPPORT=y
> +CONFIG_SPL_SPI_LOAD=y
> +CONFIG_TPL=y
> +CONFIG_CMD_CONFIG=y
> +CONFIG_CMD_BOOTZ=y
> +# CONFIG_BOOTM_PLAN9 is not set
> +# CONFIG_BOOTM_RTEMS is not set
> +# CONFIG_BOOTM_VXWORKS is not set
> +CONFIG_CMD_BOOTEFI_HELLO=y
> +CONFIG_CMD_BOOTMENU=y
> +CONFIG_CRC32_VERIFY=y
> +CONFIG_CMD_MD5SUM=y
> +CONFIG_MD5SUM_VERIFY=y
> +CONFIG_CMD_MEMINFO=y
> +CONFIG_CMD_MX_CYCLIC=y
> +CONFIG_CMD_SHA1SUM=y
> +CONFIG_SHA1SUM_VERIFY=y
> +CONFIG_CMD_STRINGS=y
> +CONFIG_CMD_ADC=y
> +CONFIG_CMD_GPIO=y
> +CONFIG_CMD_GPT=y
> +CONFIG_CMD_I2C=y
> +CONFIG_CMD_MMC=y
> +CONFIG_CMD_PCI=y
> +CONFIG_CMD_POWEROFF=y
> +CONFIG_CMD_READ=y
> +CONFIG_CMD_SPI=y
> +CONFIG_CMD_USB=y
> +CONFIG_CMD_ROCKUSB=y
> +CONFIG_CMD_USB_MASS_STORAGE=y
> +CONFIG_CMD_EFIDEBUG=y
> +CONFIG_CMD_EXCEPTION=y
> +CONFIG_CMD_TIME=y
> +CONFIG_CMD_PMIC=y
> +CONFIG_CMD_REGULATOR=y
> +CONFIG_CMD_FS_UUID=y
> +CONFIG_PARTITION_TYPE_GUID=y
> +CONFIG_SPL_OF_CONTROL=y
> +CONFIG_OF_LIVE=y
> +CONFIG_DEFAULT_DEVICE_TREE="rk3399-kobol-helios64"
> +CONFIG_OF_SPL_REMOVE_PROPS="pinctrl-0 pinctrl-names clock-names interrupt-parent assigned-clocks assigned-clock-rates assigned-clock-parents"
> +CONFIG_ENV_IS_IN_MMC=y
> +CONFIG_SYS_RELOC_GD_ENV_ADDR=y
> +CONFIG_ENV_VARS_UBOOT_RUNTIME_CONFIG=y
> +CONFIG_IP_DEFRAG=y
> +# CONFIG_DM_DEVICE_REMOVE is not set
> +CONFIG_SCSI_AHCI=y
> +CONFIG_AHCI_PCI=y
> +CONFIG_SPL_FIRMWARE=y
> +CONFIG_GPIO_HOG=y
> +CONFIG_ROCKCHIP_GPIO=y
> +CONFIG_DM_PCA953X=y
> +CONFIG_I2C_SET_DEFAULT_BUS_NUM=y
> +CONFIG_I2C_DEFAULT_BUS_NUMBER=0x8
> +CONFIG_SYS_I2C_ROCKCHIP=y
> +CONFIG_LED=y
> +CONFIG_LED_GPIO=y
> +CONFIG_MISC=y
> +CONFIG_ROCKCHIP_EFUSE=y
> +CONFIG_ROCKCHIP_OTP=y
> +CONFIG_MMC_DW=y
> +CONFIG_MMC_DW_ROCKCHIP=y
> +CONFIG_MMC_SDHCI=y
> +CONFIG_MMC_SDHCI_ROCKCHIP=y
> +CONFIG_SPI_FLASH_WINBOND=y
> +CONFIG_PHY_REALTEK=y
> +CONFIG_DM_ETH=y
> +CONFIG_DM_MDIO=y
> +CONFIG_PHY_GIGE=y
> +CONFIG_ETH_DESIGNWARE=y
> +CONFIG_RGMII=y
> +CONFIG_MII=y
> +CONFIG_GMAC_ROCKCHIP=y
> +CONFIG_PCI=y
> +CONFIG_PHY_ROCKCHIP_INNO_USB2=y
> +CONFIG_PHY_ROCKCHIP_TYPEC=y
> +CONFIG_DM_PMIC_FAN53555=y
> +CONFIG_PMIC_RK8XX=y
> +CONFIG_SPL_DM_REGULATOR=y
> +CONFIG_REGULATOR_PWM=y
> +CONFIG_SPL_DM_REGULATOR_FIXED=y
> +CONFIG_DM_REGULATOR_GPIO=y
> +CONFIG_SPL_DM_REGULATOR_GPIO=y
> +CONFIG_REGULATOR_RK8XX=y
> +CONFIG_PWM_ROCKCHIP=y
> +CONFIG_RAM_RK3399_LPDDR4=y
> +CONFIG_DM_RESET=y
> +CONFIG_SCSI=y
> +CONFIG_DM_SCSI=y
> +CONFIG_BAUDRATE=1500000
> +CONFIG_DEBUG_UART_SHIFT=2
> +CONFIG_ROCKCHIP_SPI=y
> +CONFIG_SYSRESET=y
> +CONFIG_SYSRESET_SYSCON=y
> +CONFIG_DM_THERMAL=y
> +CONFIG_USB=y
> +# CONFIG_SPL_DM_USB is not set
> +CONFIG_USB_XHCI_HCD=y
> +CONFIG_USB_XHCI_DWC3=y
> +CONFIG_USB_EHCI_HCD=y
> +CONFIG_USB_EHCI_GENERIC=y
> +CONFIG_USB_DWC3=y
> +CONFIG_USB_DWC3_GENERIC=y
> +CONFIG_USB_GADGET=y
> +CONFIG_USB_FUNCTION_ROCKUSB=y
> +CONFIG_USB_HOST_ETHER=y
> +CONFIG_USB_ETHER_RTL8152=y
> +CONFIG_SPL_TINY_MEMSET=y
> +CONFIG_ERRNO_STR=y
> +CONFIG_HEXDUMP=y
> diff --git a/include/configs/helios64.h b/include/configs/helios64.h
> new file mode 100644
> index 000000000000..6fca9a6be0ab
> --- /dev/null
> +++ b/include/configs/helios64.h
> @@ -0,0 +1,47 @@
> +/* SPDX-License-Identifier: GPL-2.0+ */
> +/*
> + * (C) Copyright 2020 Aditya Prayoga <aditya@kobol.io>
> + */
> +
> +#ifndef __HELIOS64_H
> +#define __HELIOS64_H
> +
> +#include <configs/rk3399_common.h>
> +
> +#define SDRAM_BANK_SIZE                        (2UL << 30)
> +
> +#if defined(CONFIG_ENV_IS_IN_MMC)
> +       #define CONFIG_SYS_MMC_ENV_DEV 0
> +#elif defined(CONFIG_ENV_IS_IN_SPI_FLASH)
> +       #define CONFIG_ENV_SPI_BUS              CONFIG_SF_DEFAULT_BUS
> +       #define CONFIG_ENV_SPI_CS               CONFIG_SF_DEFAULT_CS
> +       #define CONFIG_ENV_SPI_MODE             CONFIG_SF_DEFAULT_MODE
> +       #define CONFIG_ENV_SPI_MAX_HZ   CONFIG_SF_DEFAULT_SPEED
> +#endif
> +
> +
> +#ifndef CONFIG_SPL_BUILD
> +#if CONFIG_IS_ENABLED(SCSI)
> +
> +       #define CONFIG_SYS_SCSI_MAX_SCSI_ID     5
> +       #define CONFIG_SYS_SCSI_MAX_LUN         1
> +       #define CONFIG_SYS_SCSI_MAX_DEVICE      (CONFIG_SYS_SCSI_MAX_SCSI_ID * \
> +                                               CONFIG_SYS_SCSI_MAX_LUN)
> +
> +       #define BOOT_TARGET_SCSI(func) \
> +           func(SCSI, scsi, 0)
> +#else
> +       #define BOOT_TARGET_SCSI(func)
> +#endif
> +
> +#undef BOOT_TARGET_DEVICES
> +#define BOOT_TARGET_DEVICES(func) \
> +       BOOT_TARGET_MMC(func) \
> +       BOOT_TARGET_USB(func) \
> +       BOOT_TARGET_SCSI(func) \
> +       BOOT_TARGET_PXE(func) \
> +       BOOT_TARGET_DHCP(func)
> +
> +#endif
> +
> +#endif
> --
> 2.30.0
>
Uwe Kleine-König Feb. 26, 2021, 6:56 a.m. UTC | #2
Hi Dennis,

thanks for your feedback.

On 2/26/21 12:23 AM, Dennis Gilmore wrote:
> Thanks for submitting, I have been meaning to do so myself, I have
> been meaning to go through and try get the dts files in a decent
> shape. I think that most of what is in
> arch/arm/dts/rk3399-kobol-helios64-u-boot.dtsi  belongs in
> arch/arm/dts/rk3399-kobol-helios64.dts

I understood that the intention of the separation into two files is that 
the one should track the Linux dts. Is that wrong?

> I also wonder if we shouldn't
> default to building an image for use in the SPI flash since the system
> has it available.

I didn't test that but expected that I can write the resulting image to 
the spi flash and it works just fine. If you want something else here I 
need some direction about what to change.

Best regards
Uwe
Peter Robinson Feb. 26, 2021, 2:56 p.m. UTC | #3
On Fri, Feb 26, 2021 at 1:45 PM Uwe Kleine-König <uwe@kleine-koenig.org> wrote:
>
> Hi Dennis,
>
> thanks for your feedback.
>
> On 2/26/21 12:23 AM, Dennis Gilmore wrote:
> > Thanks for submitting, I have been meaning to do so myself, I have
> > been meaning to go through and try get the dts files in a decent
> > shape. I think that most of what is in
> > arch/arm/dts/rk3399-kobol-helios64-u-boot.dtsi  belongs in
> > arch/arm/dts/rk3399-kobol-helios64.dts
>
> I understood that the intention of the separation into two files is that
> the one should track the Linux dts. Is that wrong?

No, that's correct, but it should also likely then be submitted for
upstream Linux inclusion.

> > I also wonder if we shouldn't
> > default to building an image for use in the SPI flash since the system
> > has it available.
>
> I didn't test that but expected that I can write the resulting image to
> the spi flash and it works just fine. If you want something else here I
> need some direction about what to change.
>
> Best regards
> Uwe
>
Uwe Kleine-König Feb. 26, 2021, 5:20 p.m. UTC | #4
Hi Peter,

On 2/26/21 3:56 PM, Peter Robinson wrote:
> On Fri, Feb 26, 2021 at 1:45 PM Uwe Kleine-König <uwe@kleine-koenig.org> wrote:
>> On 2/26/21 12:23 AM, Dennis Gilmore wrote:
>>> Thanks for submitting, I have been meaning to do so myself, I have
>>> been meaning to go through and try get the dts files in a decent
>>> shape. I think that most of what is in
>>> arch/arm/dts/rk3399-kobol-helios64-u-boot.dtsi  belongs in
>>> arch/arm/dts/rk3399-kobol-helios64.dts
>>
>> I understood that the intention of the separation into two files is that
>> the one should track the Linux dts. Is that wrong?
> 
> No, that's correct, but it should also likely then be submitted for
> upstream Linux inclusion.

Yeah, that's the eventual plan. For now I want to get a booting system 
into Debian and so several interfaces are not included. After that I 
intend to improve the support in both Linux and U-Boot.

Best regards
Uwe
Dennis Gilmore Feb. 28, 2021, 3:32 a.m. UTC | #5
On Fri, Feb 26, 2021 at 12:57 AM Uwe Kleine-König <uwe@kleine-koenig.org> wrote:
>
> Hi Dennis,
>
> thanks for your feedback.
>
> On 2/26/21 12:23 AM, Dennis Gilmore wrote:
> > Thanks for submitting, I have been meaning to do so myself, I have
> > been meaning to go through and try get the dts files in a decent
> > shape. I think that most of what is in
> > arch/arm/dts/rk3399-kobol-helios64-u-boot.dtsi  belongs in
> > arch/arm/dts/rk3399-kobol-helios64.dts
>
> I understood that the intention of the separation into two files is that
> the one should track the Linux dts. Is that wrong?

That is not wrong, however the only things that should be in the
-u-boot.dtsi files are the things that are u-boot specific and needed
to make u-boot work. everything else should go into Linux also


>
> > I also wonder if we shouldn't
> > default to building an image for use in the SPI flash since the system
> > has it available.
>
> I didn't test that but expected that I can write the resulting image to
> the spi flash and it works just fine. If you want something else here I
> need some direction about what to change.

at the least the env should be in spi. there may be some things I am missing

Dennis

>
> Best regards
> Uwe
>
Dennis Gilmore March 5, 2021, 6:08 p.m. UTC | #6
Hi Uwe,

Not all of the new files have SPDX headers as well. There was a second
submission of this patch set this week. Perhaps you can work with
Christian on the support?

Dennis

On Sat, Feb 27, 2021 at 9:32 PM Dennis Gilmore
<dgilmore@fedoraproject.org> wrote:
>
> On Fri, Feb 26, 2021 at 12:57 AM Uwe Kleine-König <uwe@kleine-koenig.org> wrote:
> >
> > Hi Dennis,
> >
> > thanks for your feedback.
> >
> > On 2/26/21 12:23 AM, Dennis Gilmore wrote:
> > > Thanks for submitting, I have been meaning to do so myself, I have
> > > been meaning to go through and try get the dts files in a decent
> > > shape. I think that most of what is in
> > > arch/arm/dts/rk3399-kobol-helios64-u-boot.dtsi  belongs in
> > > arch/arm/dts/rk3399-kobol-helios64.dts
> >
> > I understood that the intention of the separation into two files is that
> > the one should track the Linux dts. Is that wrong?
>
> That is not wrong, however the only things that should be in the
> -u-boot.dtsi files are the things that are u-boot specific and needed
> to make u-boot work. everything else should go into Linux also
>
>
> >
> > > I also wonder if we shouldn't
> > > default to building an image for use in the SPI flash since the system
> > > has it available.
> >
> > I didn't test that but expected that I can write the resulting image to
> > the spi flash and it works just fine. If you want something else here I
> > need some direction about what to change.
>
> at the least the env should be in spi. there may be some things I am missing
>
> Dennis
>
> >
> > Best regards
> > Uwe
> >
Christian Glombek March 8, 2021, 4:29 p.m. UTC | #7
I've looked into this a bit over the weekend - my current WIP patch can be
found here:
https://src.fedoraproject.org/fork/lorbus/rpms/uboot-tools/blob/helios64/f/0001-arm-Add-support-for-Kobol-Helios64-board.patch

It's essentially the entire devicetree used in Armbian, only that I had to
remove the gpio{1,2,4} initialization since `gpio-hog` doesn't appear to
work with upstream u-boot.
It boots fine with current Fedora IoT 34 nightlies, but kernel crashes are
very regular (sometimes recoverable, sometimes not), which looks to me like
the same problem that Armbian builds have, logs seem to point to an issue
with the dmc frequency.
I've compiled an excerpt of interesting looking logs from a couple of boots
here (you should be able to comment on the doc as well):
https://hackmd.io/@lorbus/SyXTj0lXu

Please take a look and let me know what you think.

Best regards,
Christian
Kever Yang March 30, 2021, 7:21 a.m. UTC | #8
Hi

Could you send new patch set if everything is ready.


Thanks,

- Kever

On 2021/3/9 上午12:29, Christian Glombek wrote:
> I've looked into this a bit over the weekend - my current WIP patch 
> can be found here:
> https://src.fedoraproject.org/fork/lorbus/rpms/uboot-tools/blob/helios64/f/0001-arm-Add-support-for-Kobol-Helios64-board.patch
>
> It's essentially the entire devicetree used in Armbian, only that I 
> had to remove the gpio{1,2,4} initialization since `gpio-hog` doesn't 
> appear to work with upstream u-boot.
> It boots fine with current Fedora IoT 34 nightlies, but kernel crashes 
> are very regular (sometimes recoverable, sometimes not), which looks 
> to me like the same problem that Armbian builds have, logs seem to 
> point to an issue with the dmc frequency.
> I've compiled an excerpt of interesting looking logs from a couple of 
> boots here (you should be able to comment on the doc as well):
> https://hackmd.io/@lorbus/SyXTj0lXu
>
> Please take a look and let me know what you think.
>
> Best regards,
> Christian
diff mbox series

Patch

diff --git a/arch/arm/dts/Makefile b/arch/arm/dts/Makefile
index fd47e408f826..752ba4fd8b35 100644
--- a/arch/arm/dts/Makefile
+++ b/arch/arm/dts/Makefile
@@ -125,6 +125,7 @@  dtb-$(CONFIG_ROCKCHIP_RK3399) += \
 	rk3399-ficus.dtb \
 	rk3399-firefly.dtb \
 	rk3399-gru-bob.dtb \
+	rk3399-kobol-helios64.dtb \
 	rk3399-khadas-edge.dtb \
 	rk3399-khadas-edge-captain.dtb \
 	rk3399-khadas-edge-v.dtb \
diff --git a/arch/arm/dts/rk3399-kobol-helios64-u-boot.dtsi b/arch/arm/dts/rk3399-kobol-helios64-u-boot.dtsi
new file mode 100644
index 000000000000..84a27548a08d
--- /dev/null
+++ b/arch/arm/dts/rk3399-kobol-helios64-u-boot.dtsi
@@ -0,0 +1,266 @@ 
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * Copyright (c) 2020 Aditya Prayoga (aditya@kobol.io)
+ */
+
+#include "rk3399-u-boot.dtsi"
+#include "rk3399-sdram-lpddr4-100.dtsi"
+
+/ {
+	aliases {
+		spi0 = &spi1;
+		ethernet0 = &gmac;
+	};
+
+	chosen {
+		bootargs = "earlycon=uart8250,mmio32,0xff1a0000 earlyprintk";
+		stdout-path = "serial2:1500000n8";
+		u-boot,spl-boot-order = "same-as-spl", &spiflash, &sdmmc, &sdhci;
+	};
+
+	config {
+		u-boot,spl-payload-offset = <0x80000>; /* @ 512KB */
+	};
+
+	leds {
+		led-1 {
+			linux,default-trigger = "panic";
+		};
+	};
+
+	vcc3v0_sd: vcc3v0-sd {
+		startup-delay-us = <20000>;
+	};
+};
+
+&cpu_alert0 {
+	temperature = <80000>;
+};
+
+&cpu_alert1 {
+	temperature = <95000>;
+};
+
+&cpu_crit {
+	temperature = <100000>;
+};
+
+&i2c0 {
+	rk808: pmic@1b {
+		rockchip,system-power-controller;
+
+		regulators {
+			vdd_center: DCDC_REG1 {
+				regulator-name = "vdd_center";
+				regulator-always-on;
+				regulator-boot-on;
+				regulator-min-microvolt = <950000>;
+				regulator-max-microvolt = <950000>;
+				regulator-init-microvolt = <950000>;
+				regulator-ramp-delay = <6001>;
+				regulator-state-mem {
+					regulator-on-in-suspend;
+					regulator-suspend-microvolt = <950000>;
+				};
+			};
+
+			vcc_ddr_s3: DCDC_REG3 {
+				regulator-name = "vcc_ddr_s3";
+				regulator-always-on;
+				regulator-boot-on;
+				regulator-state-mem {
+					regulator-on-in-suspend;
+				};
+			};
+
+			/* not used */
+			vcc1v8_dvp: LDO_REG1 {
+				regulator-name = "vcc1v8_dvp";
+			};
+
+			/* not used */
+			vcc3v0_touch: LDO_REG2 {
+				regulator-name = "vcc3v0_touch";
+			};
+
+			vcc1v8_s3: LDO_REG3 {
+				regulator-name = "vcc1v8_s3";
+				regulator-always-on;
+				regulator-boot-on;
+				regulator-min-microvolt = <1800000>;
+				regulator-max-microvolt = <1800000>;
+				regulator-state-mem {
+					regulator-on-in-suspend;
+					regulator-suspend-microvolt = <1800000>;
+				};
+			};
+
+			/* not used */
+			vcca3v0_codec: LDO_REG5 {
+				regulator-name = "vcca3v0_codec";
+			};
+
+			vcc1v5_s3: LDO_REG6 {
+				regulator-name = "vcc1v5_s3";
+				regulator-always-on;
+				regulator-boot-on;
+				regulator-min-microvolt = <1500000>;
+				regulator-max-microvolt = <1500000>;
+				regulator-state-mem {
+					regulator-on-in-suspend;
+					regulator-suspend-microvolt = <1500000>;
+				};
+			};
+
+			/* not used */
+			vcca1v8_codec: LDO_REG7 {
+				regulator-name = "vcca1v8_codec";
+			};
+
+			vcc3v3_sys_s0: SWITCH_REG1 {
+				regulator-name = "vcc3v3_sys_s0";
+				regulator-always-on;
+				regulator-boot-on;
+				regulator-state-mem {
+					regulator-off-in-suspend;
+				};
+			};
+
+			vcc3v3_s0: SWITCH_REG2 {
+				regulator-name = "vcc3v3_s0";
+			};
+		};
+	};
+
+	vdd_cpu_b: regulator@40 {
+		pinctrl-names = "default";
+		pinctrl-0 = <&vsel1_gpio>;
+		vsel-gpios = <&gpio1 RK_PC1 GPIO_ACTIVE_HIGH>;
+		regulator-compatible = "fan53555-reg";
+	};
+
+	vdd_gpu: regulator@41 {
+		compatible = "silergy,syr828";
+		reg = <0x41>;
+		fcs,suspend-voltage-selector = <1>;
+		pinctrl-names = "default";
+		pinctrl-0 = <&vsel2_gpio>;
+		vsel-gpios = <&gpio1 RK_PB6 GPIO_ACTIVE_HIGH>;
+		regulator-compatible = "fan53555-reg";
+		regulator-name = "vdd_gpu";
+		regulator-min-microvolt = <712500>;
+		regulator-max-microvolt = <1500000>;
+		regulator-ramp-delay = <1000>;
+		regulator-always-on;
+		regulator-boot-on;
+		vin-supply = <&vcc5v0_sys>;
+
+		regulator-state-mem {
+			regulator-off-in-suspend;
+		};
+	};
+};
+
+&pinctrl {
+	pmic {
+		vsel1_gpio: vsel1-gpio {
+			rockchip,pins =
+				<1 RK_PC1 RK_FUNC_GPIO &pcfg_pull_down>;
+		};
+
+		vsel2_gpio: vsel2-gpio {
+			rockchip,pins =
+				<1 RK_PB6 RK_FUNC_GPIO &pcfg_pull_down>;
+		};
+	};
+};
+
+&pmu_io_domains {
+	pmu1830-supply = <&vcc3v0_s3>;
+	status = "okay";
+};
+
+&sdmmc {
+	sd-uhs-sdr104;
+};
+
+&tsadc {
+	/* tshut mode 0:CRU 1:GPIO */
+	rockchip,hw-tshut-mode = <1>;
+	/* tshut polarity 0:LOW 1:HIGH */
+	rockchip,hw-tshut-polarity = <1>;
+	status = "okay";
+};
+
+&gpio1 {
+	usb-mux-hs {
+		gpio-hog;
+		gpios = <RK_PA4 GPIO_ACTIVE_HIGH>;
+		output-low;
+		line-name = "USB_MUX_HS";
+	};
+
+	usb-mux-oe {
+		gpio-hog;
+		gpios = <RK_PB5 GPIO_ACTIVE_LOW>;
+		output-high;
+		line-name = "USB_MUX_OE#";
+	};
+
+	soc-flash-wp {
+		gpio-hog;
+		gpios = <RK_PC2 GPIO_ACTIVE_LOW>;
+		output-low;
+		line-name = "SOC_WP#";
+	};
+};
+
+&gpio2 {
+	sata-flash-wp {
+		gpio-hog;
+		gpios = <RK_PD0 GPIO_ACTIVE_LOW>;
+		output-high;
+		line-name = "SATA_WP#_LV";
+	};
+};
+
+&gpio4 {
+	auto-on-en-d {
+		gpio-hog;
+		gpios = <RK_PD1 GPIO_ACTIVE_HIGH>;
+		output-low;
+		line-name = "AUTO_ON_EN_D";
+	};
+
+	auto-on-en-clk {
+		gpio-hog;
+		gpios = <RK_PD2 GPIO_ACTIVE_HIGH>;
+		output-low;
+		line-name = "AUTO_ON_EN_CLK";
+	};
+
+	board-rev-id-0 {
+		gpio-hog;
+		gpios = <RK_PD5 GPIO_ACTIVE_HIGH>;
+		input;
+	};
+
+	board-rev-id-1 {
+		gpio-hog;
+		gpios = <RK_PD6 GPIO_ACTIVE_HIGH>;
+		input;
+	};
+};
+
+&spi1 {
+	status = "okay";
+
+	spiflash: flash@0 {
+		compatible = "jedec,spi-nor";
+		reg = <0x0>;
+		spi-max-frequency = <25000000>;
+		status = "okay";
+		m25p,fast-read;
+		u-boot,dm-pre-reloc;
+	};
+};
diff --git a/arch/arm/dts/rk3399-kobol-helios64.dts b/arch/arm/dts/rk3399-kobol-helios64.dts
new file mode 100644
index 000000000000..66c725a34220
--- /dev/null
+++ b/arch/arm/dts/rk3399-kobol-helios64.dts
@@ -0,0 +1,372 @@ 
+// SPDX-License-Identifier: (GPL-2.0+ OR MIT)
+/*
+ * Copyright (c) 2020 Aditya Prayoga <aditya@kobol.io>
+ */
+
+/*
+ * The Kobol Helios64 is a board designed to operate as a NAS and optionally
+ * ships with an enclosing that can host five 2.5" hard disks.
+ *
+ * See https://wiki.kobol.io/helios64/intro/ for further details.
+ */
+
+/dts-v1/;
+#include "rk3399.dtsi"
+#include "rk3399-opp.dtsi"
+
+/ {
+	model = "Kobol Helios64";
+	compatible = "kobol,helios64", "rockchip,rk3399";
+
+	avdd_1v8_s0: avdd-1v8-s0 {
+		compatible = "regulator-fixed";
+		regulator-name = "avdd_1v8_s0";
+		regulator-always-on;
+		regulator-boot-on;
+		regulator-min-microvolt = <1800000>;
+		regulator-max-microvolt = <1800000>;
+		vin-supply = <&vcc3v3_sys_s3>;
+	};
+
+	clkin_gmac: external-gmac-clock {
+		compatible = "fixed-clock";
+		clock-frequency = <125000000>;
+		clock-output-names = "clkin_gmac";
+		#clock-cells = <0>;
+	};
+
+	leds {
+		compatible = "gpio-leds";
+		pinctrl-names = "default";
+		pinctrl-0 = <&sys_grn_led_on &sys_red_led_on>;
+
+		led-0 {
+			label = "helios64:green:status";
+			gpios = <&gpio0 RK_PB4 GPIO_ACTIVE_HIGH>;
+			default-state = "on";
+		};
+
+		led-1 {
+			label = "helios64:red:fault";
+			gpios = <&gpio0 RK_PB5 GPIO_ACTIVE_HIGH>;
+			default-state = "keep";
+		};
+	};
+
+	vcc1v8_sys_s0: vcc1v8-sys-s0 {
+		compatible = "regulator-fixed";
+		regulator-name = "vcc1v8_sys_s0";
+		regulator-always-on;
+		regulator-boot-on;
+		regulator-min-microvolt = <1800000>;
+		regulator-max-microvolt = <1800000>;
+		vin-supply = <&vcc1v8_sys_s3>;
+	};
+
+	vcc3v0_sd: vcc3v0-sd {
+		compatible = "regulator-fixed";
+		enable-active-high;
+		gpio = <&gpio0 RK_PA1 GPIO_ACTIVE_HIGH>;
+		regulator-name = "vcc3v0_sd";
+		regulator-boot-on;
+		regulator-min-microvolt = <3000000>;
+		regulator-max-microvolt = <3000000>;
+		pinctrl-names = "default";
+		pinctrl-0 = <&sdmmc0_pwr_h>;
+		vin-supply = <&vcc3v3_sys_s3>;
+	};
+
+	vcc3v3_sys_s3: vcc_lan: vcc3v3-sys-s3 {
+		compatible = "regulator-fixed";
+		regulator-name = "vcc3v3_sys_s3";
+		regulator-always-on;
+		regulator-boot-on;
+		regulator-min-microvolt = <3300000>;
+		regulator-max-microvolt = <3300000>;
+		vin-supply = <&vcc5v0_sys>;
+
+		regulator-state-mem {
+			regulator-on-in-suspend;
+		};
+	};
+
+	vcc5v0_sys: vcc5v0-sys {
+		compatible = "regulator-fixed";
+		regulator-name = "vcc5v0_sys";
+		regulator-always-on;
+		regulator-boot-on;
+		regulator-min-microvolt = <5000000>;
+		regulator-max-microvolt = <5000000>;
+		vin-supply = <&vcc12v_dcin_bkup>;
+
+		regulator-state-mem {
+			regulator-on-in-suspend;
+		};
+	};
+
+	vcc12v_dcin: vcc12v-dcin {
+		compatible = "regulator-fixed";
+		regulator-name = "vcc12v_dcin";
+		regulator-always-on;
+		regulator-boot-on;
+		regulator-min-microvolt = <12000000>;
+		regulator-max-microvolt = <12000000>;
+	};
+
+	vcc12v_dcin_bkup: vcc12v-dcin-bkup {
+		compatible = "regulator-fixed";
+		regulator-name = "vcc12v_dcin_bkup";
+		regulator-always-on;
+		regulator-boot-on;
+		regulator-min-microvolt = <12000000>;
+		regulator-max-microvolt = <12000000>;
+		vin-supply = <&vcc12v_dcin>;
+	};
+};
+
+/*
+ * The system doesn't run stable with cpu freq enabled, so disallow the lower
+ * frequencies until this problem is properly understood and resolved.
+ */
+&cluster0_opp {
+	/delete-node/ opp00;
+	/delete-node/ opp01;
+	/delete-node/ opp02;
+	/delete-node/ opp03;
+	/delete-node/ opp04;
+};
+
+&cluster1_opp {
+	/delete-node/ opp00;
+	/delete-node/ opp01;
+	/delete-node/ opp02;
+	/delete-node/ opp03;
+	/delete-node/ opp04;
+	/delete-node/ opp05;
+	/delete-node/ opp06;
+};
+
+&cpu_b0 {
+	cpu-supply = <&vdd_cpu_b>;
+};
+
+&cpu_b1 {
+	cpu-supply = <&vdd_cpu_b>;
+};
+
+&cpu_l0 {
+	cpu-supply = <&vdd_cpu_l>;
+};
+
+&cpu_l1 {
+	cpu-supply = <&vdd_cpu_l>;
+};
+
+&cpu_l2 {
+	cpu-supply = <&vdd_cpu_l>;
+};
+
+&cpu_l3 {
+	cpu-supply = <&vdd_cpu_l>;
+};
+
+&emmc_phy {
+	status = "okay";
+};
+
+&gmac {
+	assigned-clock-parents = <&clkin_gmac>;
+	assigned-clocks = <&cru SCLK_RMII_SRC>;
+	clock_in_out = "input";
+	phy-mode = "rgmii";
+	phy-supply = <&vcc_lan>;
+	pinctrl-names = "default";
+	pinctrl-0 = <&rgmii_pins &gphy_reset>;
+	rx_delay = <0x20>;
+	tx_delay = <0x28>;
+	snps,reset-active-low;
+	snps,reset-delays-us = <0 10000 50000>;
+	snps,reset-gpio = <&gpio3 RK_PB7 GPIO_ACTIVE_LOW>;
+	status = "okay";
+};
+
+&i2c0 {
+	clock-frequency = <400000>;
+	i2c-scl-rising-time-ns = <168>;
+	i2c-scl-falling-time-ns = <4>;
+	status = "okay";
+
+	rk808: pmic@1b {
+		compatible = "rockchip,rk808";
+		reg = <0x1b>;
+		interrupt-parent = <&gpio0>;
+		interrupts = <10 IRQ_TYPE_LEVEL_LOW>;
+		clock-output-names = "xin32k", "rk808-clkout2";
+		pinctrl-names = "default";
+		pinctrl-0 = <&pmic_int_l>;
+		vcc1-supply = <&vcc5v0_sys>;
+		vcc2-supply = <&vcc5v0_sys>;
+		vcc3-supply = <&vcc5v0_sys>;
+		vcc4-supply = <&vcc5v0_sys>;
+		vcc6-supply = <&vcc5v0_sys>;
+		vcc7-supply = <&vcc5v0_sys>;
+		vcc8-supply = <&vcc3v3_sys_s3>;
+		vcc9-supply = <&vcc5v0_sys>;
+		vcc10-supply = <&vcc5v0_sys>;
+		vcc11-supply = <&vcc5v0_sys>;
+		vcc12-supply = <&vcc3v3_sys_s3>;
+		vddio-supply = <&vcc3v0_s3>;
+		wakeup-source;
+		#clock-cells = <1>;
+
+		regulators {
+			vdd_cpu_l: DCDC_REG2 {
+				regulator-name = "vdd_cpu_l";
+				regulator-always-on;
+				regulator-boot-on;
+				regulator-min-microvolt = <750000>;
+				regulator-max-microvolt = <1350000>;
+				regulator-ramp-delay = <6001>;
+
+				regulator-state-mem {
+					regulator-off-in-suspend;
+				};
+			};
+
+			vcc1v8_sys_s3: DCDC_REG4 {
+				regulator-name = "vcc1v8_sys_s3";
+				regulator-always-on;
+				regulator-boot-on;
+				regulator-min-microvolt = <1800000>;
+				regulator-max-microvolt = <1800000>;
+
+				regulator-state-mem {
+					regulator-on-in-suspend;
+					regulator-suspend-microvolt = <1800000>;
+				};
+			};
+
+			vcc_sdio_s0: LDO_REG4 {
+				regulator-name = "vcc_sdio_s0";
+				regulator-always-on;
+				regulator-boot-on;
+				regulator-min-microvolt = <1800000>;
+				regulator-max-microvolt = <3000000>;
+
+				regulator-state-mem {
+					regulator-on-in-suspend;
+					regulator-suspend-microvolt = <3000000>;
+				};
+			};
+
+			vcc3v0_s3: LDO_REG8 {
+				regulator-name = "vcc3v0_s3";
+				regulator-always-on;
+				regulator-boot-on;
+				regulator-min-microvolt = <3000000>;
+				regulator-max-microvolt = <3000000>;
+
+				regulator-state-mem {
+					regulator-on-in-suspend;
+					regulator-suspend-microvolt = <3000000>;
+				};
+			};
+		};
+	};
+
+	vdd_cpu_b: regulator@40 {
+		compatible = "silergy,syr827";
+		reg = <0x40>;
+		fcs,suspend-voltage-selector = <1>;
+		regulator-name = "vdd_cpu_b";
+		regulator-always-on;
+		regulator-boot-on;
+		regulator-min-microvolt = <712500>;
+		regulator-max-microvolt = <1500000>;
+		regulator-ramp-delay = <1000>;
+		vin-supply = <&vcc5v0_sys>;
+
+		regulator-state-mem {
+			regulator-off-in-suspend;
+		};
+	};
+};
+
+&i2c2 {
+	clock-frequency = <400000>;
+	i2c-scl-rising-time-ns = <160>;
+	i2c-scl-falling-time-ns = <30>;
+	status = "okay";
+
+	temp@4c {
+		compatible = "national,lm75";
+		reg = <0x4c>;
+	};
+};
+
+&io_domains {
+	audio-supply = <&vcc1v8_sys_s0>;
+	bt656-supply = <&vcc1v8_sys_s0>;
+	gpio1830-supply = <&vcc3v0_s3>;
+	sdmmc-supply = <&vcc_sdio_s0>;
+	status = "okay";
+};
+
+&pinctrl {
+	gmac {
+		gphy_reset: gphy-reset {
+			rockchip,pins = <3 RK_PB7 RK_FUNC_GPIO &pcfg_output_low>;
+		};
+	};
+
+	leds {
+		sys_grn_led_on: sys-grn-led-on {
+			rockchip,pins = <0 RK_PB4 RK_FUNC_GPIO &pcfg_pull_down>;
+		};
+
+		sys_red_led_on: sys-red-led-on {
+			rockchip,pins = <0 RK_PB5 RK_FUNC_GPIO &pcfg_pull_down>;
+		};
+	};
+
+	pmic {
+		pmic_int_l: pmic-int-l {
+			rockchip,pins = <0 RK_PB2 RK_FUNC_GPIO &pcfg_pull_none>;
+		};
+	};
+
+	vcc3v0-sd {
+		sdmmc0_pwr_h: sdmmc0-pwr-h {
+			rockchip,pins = <0 RK_PA1 RK_FUNC_GPIO &pcfg_pull_up>;
+		};
+	};
+};
+
+&pmu_io_domains {
+	pmu1830-supply = <&vcc3v0_s3>;
+	status = "okay";
+};
+
+&sdhci {
+	bus-width = <8>;
+	mmc-hs200-1_8v;
+	non-removable;
+	vqmmc-supply = <&vcc1v8_sys_s0>;
+	status = "okay";
+};
+
+&sdmmc {
+	bus-width = <4>;
+	cap-sd-highspeed;
+	cd-gpios = <&gpio0 RK_PA7 GPIO_ACTIVE_LOW>;
+	disable-wp;
+	pinctrl-names = "default";
+	pinctrl-0 = <&sdmmc_clk &sdmmc_cmd &sdmmc_cd &sdmmc_bus4>;
+	vmmc-supply = <&vcc3v0_sd>;
+	vqmmc-supply = <&vcc_sdio_s0>;
+	status = "okay";
+};
+
+&uart2 {
+	status = "okay";
+};
diff --git a/arch/arm/mach-rockchip/rk3399/Kconfig b/arch/arm/mach-rockchip/rk3399/Kconfig
index 17628f917127..7890bafe5618 100644
--- a/arch/arm/mach-rockchip/rk3399/Kconfig
+++ b/arch/arm/mach-rockchip/rk3399/Kconfig
@@ -28,6 +28,22 @@  config TARGET_PINEBOOK_PRO_RK3399
 	  with 4Gb RAM, onboard eMMC, USB-C, a USB3 and USB2 port,
 	  1920*1080 screen and all the usual laptop features.
 
+config TARGET_HELIOS64
+	bool "Kobol Innovations Helios64"
+	select BOARD_LATE_INIT
+	help
+	  Helios64 is a Network Attached Storage board based on Rockchip RK3399.
+
+	  Key features of the Helios64 include:
+	   * on-board PCIe to 5 Ports SATA Controller JMB585
+	   * on-board USB 3.0 hub (3x USB 3.0 host)
+	   * USB Type-C (Support DisplayPort Alt Mode)
+	   * on-board 1 Gigabit Ethernet
+	   * on-board 2.5 Gigabit Ethernet (Realtek RTL8156)
+	   * on-board eMMC
+	   * on-board LPDDR4
+	   * SPI, I2C, UART, GPIO
+
 config TARGET_PUMA_RK3399
 	bool "Theobroma Systems RK3399-Q7 (Puma)"
 	help
@@ -153,6 +169,7 @@  endif # BOOTCOUNT_LIMIT
 
 source "board/firefly/roc-pc-rk3399/Kconfig"
 source "board/google/gru/Kconfig"
+source "board/kobol/helios64/Kconfig"
 source "board/pine64/pinebook-pro-rk3399/Kconfig"
 source "board/pine64/rockpro64_rk3399/Kconfig"
 source "board/rockchip/evb_rk3399/Kconfig"
diff --git a/board/kobol/helios64/Kconfig b/board/kobol/helios64/Kconfig
new file mode 100644
index 000000000000..644cdbd8f314
--- /dev/null
+++ b/board/kobol/helios64/Kconfig
@@ -0,0 +1,24 @@ 
+if TARGET_HELIOS64
+
+config SYS_BOARD
+	default "helios64"
+
+config SYS_VENDOR
+	default "kobol"
+
+config SYS_CONFIG_NAME
+	default "helios64"
+
+config BOARD_SPECIFIC_OPTIONS # dummy
+	def_bool y
+
+config ENV_SECT_SIZE
+	default 0x1000 if ENV_IS_IN_SPI_FLASH
+
+config ENV_SIZE
+	default 0x8000
+
+config ENV_OFFSET
+	default 0x460000 if ENV_IS_IN_SPI_FLASH
+
+endif
diff --git a/board/kobol/helios64/MAINTAINERS b/board/kobol/helios64/MAINTAINERS
new file mode 100644
index 000000000000..a9c88c79e331
--- /dev/null
+++ b/board/kobol/helios64/MAINTAINERS
@@ -0,0 +1,6 @@ 
+HELIOS64 BOARD
+M:	Aditya Prayoga <aditya@kobol.io>
+S:	Maintained
+F:	board/kobol/helios64/
+F:	include/configs/helios64.h
+F:	configs/helios64_defconfig
diff --git a/board/kobol/helios64/Makefile b/board/kobol/helios64/Makefile
new file mode 100644
index 000000000000..ab34245a6d6a
--- /dev/null
+++ b/board/kobol/helios64/Makefile
@@ -0,0 +1,5 @@ 
+# SPDX-License-Identifier: GPL-2.0+
+#
+# Copyright (C) 2020 Aditya Prayoga <aditya@kobol.io>
+
+obj-y	:= helios64.o sys_otp.o
diff --git a/board/kobol/helios64/helios64.c b/board/kobol/helios64/helios64.c
new file mode 100644
index 000000000000..1fe948eec4ee
--- /dev/null
+++ b/board/kobol/helios64/helios64.c
@@ -0,0 +1,262 @@ 
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * (C) Copyright 2020 Aditya Prayoga (aditya@kobol.io)
+ */
+
+#include <common.h>
+#include <dm.h>
+#include <env.h>
+#include <log.h>
+#include <led.h>
+#include <pci.h>
+#include <power/regulator.h>
+#include <scsi.h>
+#include <spl_gpio.h>
+#include <syscon.h>
+#include <usb.h>
+#include <linux/delay.h>
+#include <asm/io.h>
+#include <asm/gpio.h>
+#include <asm/arch-rockchip/clock.h>
+#include <asm/arch-rockchip/gpio.h>
+#include <asm/arch-rockchip/grf_rk3399.h>
+#include <asm/arch-rockchip/hardware.h>
+#include <asm/arch-rockchip/misc.h>
+#include <asm/arch-rockchip/periph.h>
+
+#include "sys_otp.h"
+
+#ifndef CONFIG_TPL_BUILD
+int board_early_init_f(void)
+{
+#ifdef CONFIG_SPL_BUILD
+#define GPIO0_BASE      0xff720000
+#define GRF_BASE		0xff770000
+	struct rk3399_grf_regs * const grf = (void *)GRF_BASE;
+	struct rockchip_gpio_regs * const gpio = (void *)GPIO0_BASE;
+
+	/* Turn ON status LED. At this stage, FDT & DM is not initialized yet */
+	spl_gpio_output(gpio, GPIO(BANK_B, 4), 1);
+#endif
+	return 0;
+}
+#endif
+
+#ifndef CONFIG_SPL_BUILD
+int board_early_init_r(void)
+{
+	read_otp_data();
+	return 0;
+}
+#endif
+
+#ifdef CONFIG_MISC_INIT_R
+#define GRF_IO_VSEL_BT565_SHIFT		0
+#define GRF_IO_VSEL_AUDIO_SHIFT		1
+#define GRF_IO_VSEL_SDMMC_SHIFT		2
+#define GRF_IO_VSEL_GPIO1830_SHIFT	3
+
+#define PMUGRF_CON0_VSEL_SHIFT		8
+#define PMUGRF_CON0_PMU1830_VOL_SHIFT   9
+static void setup_iodomain(void)
+{
+	struct rk3399_grf_regs *grf =
+		syscon_get_first_range(ROCKCHIP_SYSCON_GRF);
+	struct rk3399_pmugrf_regs *pmugrf =
+		syscon_get_first_range(ROCKCHIP_SYSCON_PMUGRF);
+
+	/* BT565 is in 1.8v domain */
+	rk_setreg(&grf->io_vsel, 1 << GRF_IO_VSEL_BT565_SHIFT);
+
+	/* AUDIO is in 1.8v domain */
+	rk_setreg(&grf->io_vsel, 1 << GRF_IO_VSEL_AUDIO_SHIFT);
+
+	/* SDMMC is in 3.0v domain */
+	rk_setreg(&grf->io_vsel, 0 << GRF_IO_VSEL_SDMMC_SHIFT);
+
+	/* GPIO1830 is in 3.0v domain */
+	rk_setreg(&grf->io_vsel, 0 << GRF_IO_VSEL_GPIO1830_SHIFT);
+
+	/* Set GPIO1 1.8v/3.0v source select to PMU1830_VOL */
+	rk_setreg(&pmugrf->soc_con0, 1 << PMUGRF_CON0_VSEL_SHIFT);
+	rk_setreg(&pmugrf->soc_con0, 0 << PMUGRF_CON0_PMU1830_VOL_SHIFT);
+}
+
+/*
+ * Swap mmc0 and mmc1 in boot_targets if booted from SD-Card.
+ *
+ * If bootsource is uSD-card we can assume that we want to use the
+ * SD-Card instead of the eMMC as first boot_target for distroboot.
+ * We only want to swap the defaults and not any custom environment a
+ * user has set. We exit early if a changed boot_targets environment
+ * is detected.
+ */
+static int setup_boottargets(void)
+{
+	const char *boot_device =
+		ofnode_read_chosen_string("u-boot,spl-boot-device");
+	char *env_default, *env;
+
+	if (!boot_device) {
+		debug("%s: /chosen/u-boot,spl-boot-device not set\n",
+		      __func__);
+		return -1;
+	}
+	debug("%s: booted from %s\n", __func__, boot_device);
+
+	env_default = env_get_default("boot_targets");
+	env = env_get("boot_targets");
+	if (!env) {
+		debug("%s: boot_targets does not exist\n", __func__);
+		return -1;
+	}
+	debug("%s: boot_targets current: %s - default: %s\n",
+		__func__, env, env_default);
+
+	if (strcmp(env_default, env) != 0) {
+		debug("%s: boot_targets not default, don't change it\n",
+			__func__);
+		return 0;
+	}
+
+	/*
+	 * Only run, if booting from mmc1 (i.e. /mmc@fe320000) and
+	 * only consider cases where the default boot-order first
+	 * tries to boot from mmc0 (eMMC) and then from mmc1
+	 * (i.e. external SD).
+	 *
+	 * In other words: the SD card will be moved to earlier in the
+	 * order, if U-Boot was also loaded from the SD-card.
+	 */
+	if (!strcmp(boot_device, "/mmc@fe320000")) {
+		char *mmc0, *mmc1;
+
+		debug("%s: booted from SD-Card\n", __func__);
+		mmc0 = strstr(env, "mmc0");
+		mmc1 = strstr(env, "mmc1");
+
+		if (!mmc0 || !mmc1) {
+			debug("%s: only one mmc boot_target found\n", __func__);
+			return -1;
+		}
+
+		/*
+		 * If mmc0 comes first in the boot order, we need to change
+		 * the strings to make mmc1 first.
+		 */
+		if (mmc0 < mmc1) {
+			mmc0[3] = '1';
+			mmc1[3] = '0';
+			debug("%s: set boot_targets to: %s\n", __func__, env);
+			env_set("boot_targets", env);
+		}
+	}
+
+	return 0;
+}
+
+static void setup_leds(void)
+{
+	struct udevice *dev;
+
+	led_get_by_label("helios64:green:status", &dev);
+	led_set_state(dev, LEDST_OFF);
+	mdelay(250);
+	led_set_state(dev, LEDST_ON);
+}
+
+int misc_init_r(void)
+{
+	const u32 cpuid_offset = 0x7;
+	const u32 cpuid_length = 0x10;
+	u8 cpuid[cpuid_length];
+	int ret;
+
+	setup_iodomain();
+	set_board_info();
+
+	ret = rockchip_cpuid_from_efuse(cpuid_offset, cpuid_length, cpuid);
+	if (ret)
+		return ret;
+
+	ret = rockchip_cpuid_set(cpuid, cpuid_length);
+	if (ret)
+		return ret;
+
+	if (mac_read_from_otp())
+		ret = rockchip_setup_macaddr();
+
+	setup_boottargets();
+	setup_leds();
+
+	return ret;
+}
+#endif
+
+#ifdef CONFIG_LAST_STAGE_INIT
+static void auto_power_enable(void)
+{
+	struct gpio_desc *enable, *clock;
+
+	if (gpio_hog_lookup_name("AUTO_ON_EN_D", &enable)) {
+		debug("Fail to get AUTO_ON_EN_D\n");
+		return;
+	}
+
+	if (gpio_hog_lookup_name("AUTO_ON_EN_CLK", &clock)) {
+		debug("Fail to get AUTO_ON_EN_CLK\n");
+		return;
+	}
+
+	dm_gpio_set_value(enable, 1);
+	dm_gpio_set_value(clock, 1);
+	mdelay(10);
+	dm_gpio_set_value(clock, 0);
+}
+
+int last_stage_init(void)
+{
+	auto_power_enable();
+
+#ifdef CONFIG_PCI
+	scsi_scan(true);
+#endif
+
+	return 0;
+}
+#endif
+
+#if defined(CONFIG_DISPLAY_BOARDINFO_LATE)
+int checkboard(void)
+{
+	int major, minor;
+
+	printf("Revision: ");
+
+	if (!get_revision(&major, &minor))
+		printf("%i.%i - %s\n", major, minor, get_variant());
+	else
+		printf("UNKNOWN\n");
+
+	return 0;
+}
+#endif
+
+#if defined(CONFIG_OF_LIBFDT) && defined(CONFIG_OF_BOARD_SETUP)
+int ft_board_setup(void *blob, struct bd_info *bd)
+{
+	char *env;
+
+	env = env_get("board_rev");
+	if (env)
+		fdt_setprop_string(blob, fdt_path_offset(blob, "/"),
+			"kobol,board-rev", env);
+
+	env = env_get("cpuid#");
+	if (env)
+		fdt_setprop_string(blob, fdt_path_offset(blob, "/"),
+			"kobol,cpu-id", env);
+
+	return 0;
+}
+#endif
diff --git a/board/kobol/helios64/sys_otp.c b/board/kobol/helios64/sys_otp.c
new file mode 100644
index 000000000000..3a27834641bd
--- /dev/null
+++ b/board/kobol/helios64/sys_otp.c
@@ -0,0 +1,248 @@ 
+#include <linux/types.h>
+#include <dm.h>
+#include <spi.h>
+#include <log.h>
+#include <net.h>
+#include <u-boot/crc.h>
+
+#include "sys_otp.h"
+
+#define OTP_DEVICE_BUS  0
+#define OTP_DEVICE_CS   0
+#define MAX_NUM_PORTS	2
+
+enum board_variant {
+	BOARD_VARIANT_INVALID = 0,
+	BOARD_VARIANT_ENG_SAMPLE,
+	BOARD_VARIANT_4G_PROD_NO_ECC,
+	BOARD_VARIANT_MAX
+};
+
+struct  __attribute__ ((__packed__)) otp_data_t {
+	u8 magic[8];
+	u8 part_num[16];
+	u8 variant;
+	u8 revision;
+	u8 serial_num[6];
+	u8 mfg_year[2];
+	u8 mfg_month;
+	u8 mfg_day;
+	u8 mac_addr[MAX_NUM_PORTS][6];
+	u8 reserved[204];
+	u32 checksum;
+} otp;
+
+static struct spi_slave *slave;
+static int has_been_read = 0;
+static int data_valid = 0;
+
+static inline int is_data_valid(void)
+{
+	return data_valid;
+}
+
+static inline int is_valid_header(void)
+{
+	if ((otp.magic[0] == 'H') || (otp.magic[1] == '6') ||
+		(otp.magic[2] == '4') || (otp.magic[3] == 'N') ||
+		(otp.magic[4] == 'P') || (otp.magic[5] == 'V') ||
+		(otp.magic[6] == '1') || (otp.magic[7] == 0))
+
+		return 1;
+
+	return 0;
+}
+
+static int init_system_otp(int bus, int cs)
+{
+	int ret;
+	char name[30], *str;
+	struct udevice *dev;
+
+	snprintf(name, sizeof(name), "generic_%d:%d", bus, cs);
+	str = strdup(name);
+	if (!str)
+		return -ENOMEM;
+	ret = spi_get_bus_and_cs(bus, cs, 25000000, CONFIG_DEFAULT_SPI_MODE, "spi_generic_drv",
+				 str, &dev, &slave);
+	return ret;
+}
+
+#ifdef DEBUG
+/**
+ * show_otp_data - display the contents of the OTP register
+ */
+static void show_otp_data(void)
+{
+	u32 i;
+	u32 crc;
+
+	const char* var_str[BOARD_VARIANT_MAX] = {
+			"Invalid variant",
+			"Engineering Sample",
+			"Production - 4GB non ECC"
+	};
+
+	printf("\n");
+	printf("Register dump: (%lu bytes)\n", sizeof(otp));
+	for (i = 0; i < sizeof(otp); i++) {
+		if ((i % 16) == 0)
+			printf("%02X: ", i);
+		printf("%02X ", ((u8 *)&otp)[i]);
+		if (((i % 16) == 15) || (i == sizeof(otp) - 1))
+			printf("\n");
+	}
+
+	if (!is_valid_header())
+		return;
+
+	printf("Part Number: %s\n", otp.part_num);
+	printf("Variant: %s\n", var_str[otp.variant]);
+	printf("Revision: %x.%x\n", (otp.revision & 0xf0) >> 4, otp.revision & 0x0f);
+	printf("Serial Number: %012llx\n", *((uint64_t*) otp.serial_num) &
+		0xFFFFFFFFFFFF);
+	printf("Manufacturing Date: %02X-%02X-%04X (DD-MM-YYYY)\n", otp.mfg_day,
+		otp.mfg_month, *(u16*) otp.mfg_year);
+
+	printf("1GbE MAC Address:   %02X:%02X:%02X:%02X:%02X:%02X\n",
+		otp.mac_addr[0][0], otp.mac_addr[0][1], otp.mac_addr[0][2],
+		otp.mac_addr[0][3], otp.mac_addr[0][4], otp.mac_addr[0][5]);
+
+	printf("2.5GbE MAC Address: %02X:%02X:%02X:%02X:%02X:%02X\n",
+		otp.mac_addr[1][0], otp.mac_addr[1][1], otp.mac_addr[1][2],
+		otp.mac_addr[1][3], otp.mac_addr[1][4], otp.mac_addr[1][5]);
+
+	crc = crc32(0, (void *)&otp, sizeof(otp) - 4);
+
+	if (crc == le32_to_cpu(otp.checksum))
+		printf("CRC: %08x\n\n", le32_to_cpu(otp.checksum));
+	else
+		printf("CRC: %08x (should be %08x)\n\n",
+			   le32_to_cpu(otp.checksum), crc);
+
+}
+#endif
+
+int read_otp_data(void)
+{
+	int ret;
+	u8 dout[5];
+
+	if (has_been_read) {
+		if (is_data_valid())
+			return 0;
+		else
+			goto data_invalid;
+	}
+
+	ret = init_system_otp(OTP_DEVICE_BUS, OTP_DEVICE_CS);
+	if (ret)
+		return ret;
+
+	ret = spi_claim_bus(slave);
+	if (ret) {
+		debug("SPI: Failed to claim SPI bus: %d\n", ret);
+		return ret;
+	}
+
+	dout[0] = 0x48;
+	dout[1] = 0x00;
+	dout[2] = 0x10; /* Security Register #1 */
+	dout[3] = 0x00;
+	dout[4] = 0x00; /* Dummy Byte */
+
+	ret = spi_write_then_read(slave, dout, sizeof(dout), NULL, (u8 *)&otp,
+			sizeof(otp));
+
+	spi_release_bus(slave);
+#ifdef DEBUG
+	show_otp_data();
+#endif
+
+	has_been_read = (ret == 0) ? 1 : 0;
+	if (!is_valid_header())
+		goto data_invalid;
+
+	if (crc32(0, (void *)&otp, sizeof(otp) - 4) ==
+		le32_to_cpu(otp.checksum))
+		data_valid = 1;
+
+	if (!is_data_valid())
+		goto data_invalid;
+
+	return 0;
+
+data_invalid:
+	printf("Invalid board ID data!\n");
+	return -1;
+}
+
+int get_revision(int *major, int *minor)
+{
+	if (!is_data_valid())
+		return -1;
+
+	*major = (otp.revision & 0xf0) >> 4;
+	*minor = otp.revision & 0x0f;
+
+	return 0;
+}
+
+const char *get_variant(void)
+{
+	const char* var_str[BOARD_VARIANT_MAX] = {
+		"Unknown",
+		"Engineering Sample",
+		"4GB non ECC"
+	};
+
+	if ((otp.variant < BOARD_VARIANT_ENG_SAMPLE) ||
+		(otp.variant >= BOARD_VARIANT_MAX))
+		return var_str[0];
+
+	return var_str[otp.variant];
+}
+
+void set_board_info(void)
+{
+	char env_str[13];
+
+	if (!is_data_valid())
+		return;
+
+	snprintf(env_str, sizeof(env_str), "%i.%i", (otp.revision & 0xf0) >> 4, otp.revision & 0x0f);
+	env_set("board_rev", env_str);
+
+	sprintf(env_str, "%012llx", *((uint64_t*) otp.serial_num) &
+		0xFFFFFFFFFFFF);
+
+	env_set("serial#", env_str);
+}
+
+int mac_read_from_otp(void)
+{
+	unsigned int i;
+	int ret;
+
+	if (!is_data_valid())
+		return -1;
+
+	for (i = 0; i < MAX_NUM_PORTS; i++) {
+		char enetvar[9];
+
+		sprintf(enetvar, i ? "eth%daddr" : "ethaddr", i);
+
+		if (!is_valid_ethaddr(otp.mac_addr[i])) {
+			debug("Not valid %s!\n", enetvar);
+			continue;
+		}
+
+		/* Only initialize environment variables that are blank
+		 * (i.e. have not yet been set)
+		 */
+		if (!env_get(enetvar))
+			eth_env_set_enetaddr(enetvar, otp.mac_addr[i]);
+	}
+
+	return ret;
+}
diff --git a/board/kobol/helios64/sys_otp.h b/board/kobol/helios64/sys_otp.h
new file mode 100644
index 000000000000..61f6f3b3809a
--- /dev/null
+++ b/board/kobol/helios64/sys_otp.h
@@ -0,0 +1,10 @@ 
+#ifndef __HELIOS64_SYS_OTP_H
+#define __HELIOS64_SYS_OTP_H
+
+int read_otp_data(void);
+void set_board_info(void);
+int get_revision(int *major, int *minor);
+const char *get_variant(void);
+int mac_read_from_otp(void);
+
+#endif
diff --git a/configs/helios64-rk3399_defconfig b/configs/helios64-rk3399_defconfig
new file mode 100644
index 000000000000..6aee24011e45
--- /dev/null
+++ b/configs/helios64-rk3399_defconfig
@@ -0,0 +1,142 @@ 
+CONFIG_ARM=y
+CONFIG_ARCH_ROCKCHIP=y
+CONFIG_SYS_TEXT_BASE=0x00200000
+CONFIG_SPL_GPIO_SUPPORT=y
+CONFIG_ENV_OFFSET=0x3F8000
+CONFIG_ROCKCHIP_RK3399=y
+CONFIG_TARGET_HELIOS64=y
+CONFIG_NR_DRAM_BANKS=1
+CONFIG_DEBUG_UART_BASE=0xFF1A0000
+CONFIG_DEBUG_UART_CLOCK=24000000
+CONFIG_SPL_SPI_FLASH_SUPPORT=y
+CONFIG_SPL_SPI_SUPPORT=y
+CONFIG_DEBUG_UART=y
+CONFIG_AHCI=y
+# CONFIG_ANDROID_BOOT_IMAGE is not set
+CONFIG_OF_BOARD_SETUP=y
+CONFIG_USE_PREBOOT=y
+CONFIG_CONSOLE_MUX=y
+CONFIG_SYS_CONSOLE_ENV_OVERWRITE=y
+CONFIG_DEFAULT_FDT_FILE="rockchip/rk3399-kobol-helios64.dtb"
+CONFIG_MISC_INIT_R=y
+CONFIG_VERSION_VARIABLE=y
+# CONFIG_DISPLAY_BOARDINFO is not set
+CONFIG_DISPLAY_BOARDINFO_LATE=y
+CONFIG_BOARD_TYPES=y
+CONFIG_BOARD_EARLY_INIT_F=y
+CONFIG_BOARD_EARLY_INIT_R=y
+CONFIG_LAST_STAGE_INIT=y
+# CONFIG_SPL_RAW_IMAGE_SUPPORT is not set
+CONFIG_SPL_STACK_R=y
+CONFIG_SPL_STACK_R_MALLOC_SIMPLE_LEN=0x10000
+CONFIG_SPL_I2C_SUPPORT=y
+CONFIG_SPL_POWER_SUPPORT=y
+CONFIG_SPL_SPI_LOAD=y
+CONFIG_TPL=y
+CONFIG_CMD_CONFIG=y
+CONFIG_CMD_BOOTZ=y
+# CONFIG_BOOTM_PLAN9 is not set
+# CONFIG_BOOTM_RTEMS is not set
+# CONFIG_BOOTM_VXWORKS is not set
+CONFIG_CMD_BOOTEFI_HELLO=y
+CONFIG_CMD_BOOTMENU=y
+CONFIG_CRC32_VERIFY=y
+CONFIG_CMD_MD5SUM=y
+CONFIG_MD5SUM_VERIFY=y
+CONFIG_CMD_MEMINFO=y
+CONFIG_CMD_MX_CYCLIC=y
+CONFIG_CMD_SHA1SUM=y
+CONFIG_SHA1SUM_VERIFY=y
+CONFIG_CMD_STRINGS=y
+CONFIG_CMD_ADC=y
+CONFIG_CMD_GPIO=y
+CONFIG_CMD_GPT=y
+CONFIG_CMD_I2C=y
+CONFIG_CMD_MMC=y
+CONFIG_CMD_PCI=y
+CONFIG_CMD_POWEROFF=y
+CONFIG_CMD_READ=y
+CONFIG_CMD_SPI=y
+CONFIG_CMD_USB=y
+CONFIG_CMD_ROCKUSB=y
+CONFIG_CMD_USB_MASS_STORAGE=y
+CONFIG_CMD_EFIDEBUG=y
+CONFIG_CMD_EXCEPTION=y
+CONFIG_CMD_TIME=y
+CONFIG_CMD_PMIC=y
+CONFIG_CMD_REGULATOR=y
+CONFIG_CMD_FS_UUID=y
+CONFIG_PARTITION_TYPE_GUID=y
+CONFIG_SPL_OF_CONTROL=y
+CONFIG_OF_LIVE=y
+CONFIG_DEFAULT_DEVICE_TREE="rk3399-kobol-helios64"
+CONFIG_OF_SPL_REMOVE_PROPS="pinctrl-0 pinctrl-names clock-names interrupt-parent assigned-clocks assigned-clock-rates assigned-clock-parents"
+CONFIG_ENV_IS_IN_MMC=y
+CONFIG_SYS_RELOC_GD_ENV_ADDR=y
+CONFIG_ENV_VARS_UBOOT_RUNTIME_CONFIG=y
+CONFIG_IP_DEFRAG=y
+# CONFIG_DM_DEVICE_REMOVE is not set
+CONFIG_SCSI_AHCI=y
+CONFIG_AHCI_PCI=y
+CONFIG_SPL_FIRMWARE=y
+CONFIG_GPIO_HOG=y
+CONFIG_ROCKCHIP_GPIO=y
+CONFIG_DM_PCA953X=y
+CONFIG_I2C_SET_DEFAULT_BUS_NUM=y
+CONFIG_I2C_DEFAULT_BUS_NUMBER=0x8
+CONFIG_SYS_I2C_ROCKCHIP=y
+CONFIG_LED=y
+CONFIG_LED_GPIO=y
+CONFIG_MISC=y
+CONFIG_ROCKCHIP_EFUSE=y
+CONFIG_ROCKCHIP_OTP=y
+CONFIG_MMC_DW=y
+CONFIG_MMC_DW_ROCKCHIP=y
+CONFIG_MMC_SDHCI=y
+CONFIG_MMC_SDHCI_ROCKCHIP=y
+CONFIG_SPI_FLASH_WINBOND=y
+CONFIG_PHY_REALTEK=y
+CONFIG_DM_ETH=y
+CONFIG_DM_MDIO=y
+CONFIG_PHY_GIGE=y
+CONFIG_ETH_DESIGNWARE=y
+CONFIG_RGMII=y
+CONFIG_MII=y
+CONFIG_GMAC_ROCKCHIP=y
+CONFIG_PCI=y
+CONFIG_PHY_ROCKCHIP_INNO_USB2=y
+CONFIG_PHY_ROCKCHIP_TYPEC=y
+CONFIG_DM_PMIC_FAN53555=y
+CONFIG_PMIC_RK8XX=y
+CONFIG_SPL_DM_REGULATOR=y
+CONFIG_REGULATOR_PWM=y
+CONFIG_SPL_DM_REGULATOR_FIXED=y
+CONFIG_DM_REGULATOR_GPIO=y
+CONFIG_SPL_DM_REGULATOR_GPIO=y
+CONFIG_REGULATOR_RK8XX=y
+CONFIG_PWM_ROCKCHIP=y
+CONFIG_RAM_RK3399_LPDDR4=y
+CONFIG_DM_RESET=y
+CONFIG_SCSI=y
+CONFIG_DM_SCSI=y
+CONFIG_BAUDRATE=1500000
+CONFIG_DEBUG_UART_SHIFT=2
+CONFIG_ROCKCHIP_SPI=y
+CONFIG_SYSRESET=y
+CONFIG_SYSRESET_SYSCON=y
+CONFIG_DM_THERMAL=y
+CONFIG_USB=y
+# CONFIG_SPL_DM_USB is not set
+CONFIG_USB_XHCI_HCD=y
+CONFIG_USB_XHCI_DWC3=y
+CONFIG_USB_EHCI_HCD=y
+CONFIG_USB_EHCI_GENERIC=y
+CONFIG_USB_DWC3=y
+CONFIG_USB_DWC3_GENERIC=y
+CONFIG_USB_GADGET=y
+CONFIG_USB_FUNCTION_ROCKUSB=y
+CONFIG_USB_HOST_ETHER=y
+CONFIG_USB_ETHER_RTL8152=y
+CONFIG_SPL_TINY_MEMSET=y
+CONFIG_ERRNO_STR=y
+CONFIG_HEXDUMP=y
diff --git a/include/configs/helios64.h b/include/configs/helios64.h
new file mode 100644
index 000000000000..6fca9a6be0ab
--- /dev/null
+++ b/include/configs/helios64.h
@@ -0,0 +1,47 @@ 
+/* SPDX-License-Identifier: GPL-2.0+ */
+/*
+ * (C) Copyright 2020 Aditya Prayoga <aditya@kobol.io>
+ */
+
+#ifndef __HELIOS64_H
+#define __HELIOS64_H
+
+#include <configs/rk3399_common.h>
+
+#define SDRAM_BANK_SIZE			(2UL << 30)
+
+#if defined(CONFIG_ENV_IS_IN_MMC)
+	#define CONFIG_SYS_MMC_ENV_DEV 0
+#elif defined(CONFIG_ENV_IS_IN_SPI_FLASH)
+	#define CONFIG_ENV_SPI_BUS		CONFIG_SF_DEFAULT_BUS
+	#define CONFIG_ENV_SPI_CS		CONFIG_SF_DEFAULT_CS
+	#define CONFIG_ENV_SPI_MODE		CONFIG_SF_DEFAULT_MODE
+	#define CONFIG_ENV_SPI_MAX_HZ	CONFIG_SF_DEFAULT_SPEED
+#endif
+
+
+#ifndef CONFIG_SPL_BUILD
+#if CONFIG_IS_ENABLED(SCSI)
+
+	#define CONFIG_SYS_SCSI_MAX_SCSI_ID     5
+	#define CONFIG_SYS_SCSI_MAX_LUN         1
+	#define CONFIG_SYS_SCSI_MAX_DEVICE      (CONFIG_SYS_SCSI_MAX_SCSI_ID * \
+						CONFIG_SYS_SCSI_MAX_LUN)
+
+	#define BOOT_TARGET_SCSI(func) \
+	    func(SCSI, scsi, 0)
+#else
+	#define BOOT_TARGET_SCSI(func)
+#endif
+
+#undef BOOT_TARGET_DEVICES
+#define BOOT_TARGET_DEVICES(func) \
+	BOOT_TARGET_MMC(func) \
+	BOOT_TARGET_USB(func) \
+	BOOT_TARGET_SCSI(func) \
+	BOOT_TARGET_PXE(func) \
+	BOOT_TARGET_DHCP(func)
+
+#endif
+
+#endif