Changes in relation to FriendlyARM's U-Boot nanopi2-v2016.01:
- SPL not supported yet --> no spl-dir in arch/arm/cpu/armv7/s5p4418/.
  Appropriate line in Makefile removed.
- cpu.c: '#include <cpu_func.h>' added.
- arch/arm/cpu/armv7/s5p4418/u-boot.lds removed, is not required
  anylonger.
- "obj-$(CONFIG_ARCH_NEXELL) += s5p-common/" added to
  arch/arm/cpu/armv7/Makefile since s5p-common/pwm.c is used instead
  of drivers/pwm/pwm-nexell.c.
- s5p4418.dtsi: '#include "../../../include/generated/autoconf.h"'
  removed, is not necessary, error at out-of-tree building.
  '#ifdef CONFIG_CPU_NXP4330'-blocks (2x) removed. Some minor changes
  regarding mmc. 'u-boot,dm-pre-reloc' added to dp0 because of added
  DM_VIDEO support.
- board/s5p4418/ renamed to board/friendlyarm/
- All s5p4418-boards except nanopi2 removed because there is no
  possibility to test the other boards.
- Kconfig: Changes to have a structure like mach-bcm283x (RaspberryPi),
  e.g. "config ..." entries moved from/to other Kconfig.
- "CONFIG_" removed from several s5p4418/nanopi2 specific defines
  because the appropriate values do not need to be configurable.
- nanopi2/board.c: All getenv(), getenv_ulong(), setenv() and saveenv()
  renamed to env_get(), env_get_ulong(), env_set() and env_save(),
  respectively. MACH_TYPE_S5P4418 is not defined anymore, therefore
  appropriate code removed (not necessary for DT-kernels).
- nanopi2/onewire.c: All crc8() renamed to crc8_ow() because crc8() is
  already defined in lib/crc8.c (with different parameters).
- dts: "nexell,s5pxx18-i2c" used instead of "i2c-gpio", i2c0 and
  i2c1 added. s5p4418-pinctrl.dtsi not included because there is
  no pinctrl-driver available. gmac-, ehci- and dwc2otg-entries
  removed because the appropriate functionality is not supported yet.

Signed-off-by: Stefan Bosch <stefa...@posteo.net>
---

Changes in v2:
- i2c: "nexell,s5pxx18-i2c"-driver is used now instead of "i2c-gpio".
  i2c0 and i2c1 added. I.e. dts files changed appropriately.
- dts: gmac-, ehci- and dwc2otg-entries removed because the appropriate
  functionality is not supported yet.
- s5p4418-pinctrl.dtsi removed because there is no pinctrl-driver
  available.
- "obj-$(CONFIG_ARCH_NEXELL) += s5p-common/" added to
  arch/arm/cpu/armv7/Makefile since s5p-common/pwm.c is used now instead
  of drivers/pwm/pwm-nexell.c.
- cosmetic: additional GPL license text removed, SPDX-License-Identifier
  is enough. Furthermore file path removed (two files).

 arch/arm/cpu/armv7/Makefile           |   2 +
 arch/arm/cpu/armv7/s5p4418/Makefile   |   6 +
 arch/arm/cpu/armv7/s5p4418/cpu.c      | 120 ++++++
 arch/arm/dts/Makefile                 |   3 +
 arch/arm/dts/s5p4418-nanopi2.dts      | 108 ++++++
 arch/arm/dts/s5p4418.dtsi             | 148 ++++++++
 board/friendlyarm/Kconfig             |  39 ++
 board/friendlyarm/nanopi2/Kconfig     |  12 +
 board/friendlyarm/nanopi2/MAINTAINERS |   7 +
 board/friendlyarm/nanopi2/Makefile    |   6 +
 board/friendlyarm/nanopi2/board.c     | 567 +++++++++++++++++++++++++++
 board/friendlyarm/nanopi2/hwrev.c     | 108 ++++++
 board/friendlyarm/nanopi2/hwrev.h     |  15 +
 board/friendlyarm/nanopi2/lcds.c      | 697 ++++++++++++++++++++++++++++++++++
 board/friendlyarm/nanopi2/nxp-fb.h    |  94 +++++
 board/friendlyarm/nanopi2/onewire.c   | 309 +++++++++++++++
 board/friendlyarm/nanopi2/onewire.h   |  15 +
 17 files changed, 2256 insertions(+)
 create mode 100644 arch/arm/cpu/armv7/s5p4418/Makefile
 create mode 100644 arch/arm/cpu/armv7/s5p4418/cpu.c
 create mode 100644 arch/arm/dts/s5p4418-nanopi2.dts
 create mode 100644 arch/arm/dts/s5p4418.dtsi
 create mode 100644 board/friendlyarm/Kconfig
 create mode 100644 board/friendlyarm/nanopi2/Kconfig
 create mode 100644 board/friendlyarm/nanopi2/MAINTAINERS
 create mode 100644 board/friendlyarm/nanopi2/Makefile
 create mode 100644 board/friendlyarm/nanopi2/board.c
 create mode 100644 board/friendlyarm/nanopi2/hwrev.c
 create mode 100644 board/friendlyarm/nanopi2/hwrev.h
 create mode 100644 board/friendlyarm/nanopi2/lcds.c
 create mode 100644 board/friendlyarm/nanopi2/nxp-fb.h
 create mode 100644 board/friendlyarm/nanopi2/onewire.c
 create mode 100644 board/friendlyarm/nanopi2/onewire.h

diff --git a/arch/arm/cpu/armv7/Makefile b/arch/arm/cpu/armv7/Makefile
index 8c955d0..0e83e39 100644
--- a/arch/arm/cpu/armv7/Makefile
+++ b/arch/arm/cpu/armv7/Makefile
@@ -42,3 +42,5 @@ obj-$(CONFIG_RMOBILE) += rmobile/
 obj-$(if $(filter stv0991,$(SOC)),y) += stv0991/
 obj-$(CONFIG_ARCH_SUNXI) += sunxi/
 obj-$(CONFIG_VF610) += vf610/
+obj-$(CONFIG_ARCH_S5P4418) += s5p4418/
+obj-$(CONFIG_ARCH_NEXELL) += s5p-common/
diff --git a/arch/arm/cpu/armv7/s5p4418/Makefile 
b/arch/arm/cpu/armv7/s5p4418/Makefile
new file mode 100644
index 0000000..321b257
--- /dev/null
+++ b/arch/arm/cpu/armv7/s5p4418/Makefile
@@ -0,0 +1,6 @@
+# SPDX-License-Identifier: GPL-2.0+
+#
+# (C) Copyright 2016 Nexell
+# Hyunseok, Jung <hsj...@nexell.co.kr>
+
+obj-y += cpu.o
diff --git a/arch/arm/cpu/armv7/s5p4418/cpu.c b/arch/arm/cpu/armv7/s5p4418/cpu.c
new file mode 100644
index 0000000..79c284f
--- /dev/null
+++ b/arch/arm/cpu/armv7/s5p4418/cpu.c
@@ -0,0 +1,120 @@
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * (C) Copyright 2016 Nexell
+ * Hyunseok, Jung <hsj...@nexell.co.kr>
+ */
+
+#include <common.h>
+#include <command.h>
+#include <asm/system.h>
+#include <asm/cache.h>
+#include <asm/sections.h>
+#include <asm/io.h>
+#include <asm/arch/nexell.h>
+#include <asm/arch/clk.h>
+#include <asm/arch/reset.h>
+#include <asm/arch/tieoff.h>
+#include <cpu_func.h>
+
+DECLARE_GLOBAL_DATA_PTR;
+
+#ifndef        CONFIG_ARCH_CPU_INIT
+#error must be define the macro "CONFIG_ARCH_CPU_INIT"
+#endif
+
+void s_init(void)
+{
+}
+
+static void cpu_soc_init(void)
+{
+       /*
+        * NOTE> ALIVE Power Gate must enable for Alive register access.
+        *           must be clear wfi jump address
+        */
+       writel(1, ALIVEPWRGATEREG);
+       writel(0xFFFFFFFF, SCR_ARM_SECOND_BOOT);
+
+       /* write 0xf0 on alive scratchpad reg for boot success check */
+       writel(readl(SCR_SIGNAGURE_READ) | 0xF0, (SCR_SIGNAGURE_SET));
+
+       /* set l2 cache tieoff */
+       nx_tieoff_set(NX_TIEOFF_CORTEXA9MP_TOP_QUADL2C_L2RET1N_0, 1);
+       nx_tieoff_set(NX_TIEOFF_CORTEXA9MP_TOP_QUADL2C_L2RET1N_1, 1);
+}
+
+#ifdef CONFIG_PL011_SERIAL
+static void serial_device_init(void)
+{
+       char dev[10];
+       int id;
+
+       sprintf(dev, "nx-uart.%d", CONFIG_CONS_INDEX);
+       id = RESET_ID_UART0 + CONFIG_CONS_INDEX;
+
+       struct clk *clk = clk_get((const char *)dev);
+
+       /* reset control: Low active ___|---   */
+       nx_rstcon_setrst(id, RSTCON_ASSERT);
+       udelay(10);
+       nx_rstcon_setrst(id, RSTCON_NEGATE);
+       udelay(10);
+
+       /* set clock   */
+       clk_disable(clk);
+       clk_set_rate(clk, CONFIG_PL011_CLOCK);
+       clk_enable(clk);
+}
+#endif
+
+int arch_cpu_init(void)
+{
+       flush_dcache_all();
+       cpu_soc_init();
+       clk_init();
+
+#ifdef CONFIG_PL011_SERIAL
+       serial_device_init();
+#endif
+       return 0;
+}
+
+#if defined(CONFIG_DISPLAY_CPUINFO)
+int print_cpuinfo(void)
+{
+       return 0;
+}
+#endif
+
+void reset_cpu(ulong ignored)
+{
+       void *clkpwr_reg = (void *)PHY_BASEADDR_CLKPWR;
+       const u32 sw_rst_enb_bitpos = 3;
+       const u32 sw_rst_enb_mask = 1 << sw_rst_enb_bitpos;
+       const u32 sw_rst_bitpos = 12;
+       const u32 sw_rst_mask = 1 << sw_rst_bitpos;
+       int pwrcont = 0x224;
+       int pwrmode = 0x228;
+       u32 read_value;
+
+       read_value = readl((void *)(clkpwr_reg + pwrcont));
+
+       read_value &= ~sw_rst_enb_mask;
+       read_value |= 1 << sw_rst_enb_bitpos;
+
+       writel(read_value, (void *)(clkpwr_reg + pwrcont));
+       writel(sw_rst_mask, (void *)(clkpwr_reg + pwrmode));
+}
+
+void enable_caches(void)
+{
+       /* Enable D-cache. I-cache is already enabled in start.S */
+       dcache_enable();
+}
+
+#if defined(CONFIG_ARCH_MISC_INIT)
+int arch_misc_init(void)
+{
+       return 0;
+}
+#endif /* CONFIG_ARCH_MISC_INIT */
diff --git a/arch/arm/dts/Makefile b/arch/arm/dts/Makefile
index 04a8ccc..065b2d2 100644
--- a/arch/arm/dts/Makefile
+++ b/arch/arm/dts/Makefile
@@ -137,6 +137,9 @@ dtb-$(CONFIG_ROCKCHIP_RV1108) += \
        rv1108-elgin-r1.dtb \
        rv1108-evb.dtb
 
+dtb-$(CONFIG_ARCH_S5P4418) += \
+       s5p4418-nanopi2.dtb
+
 dtb-$(CONFIG_ARCH_MESON) += \
        meson-gxbb-nanopi-k2.dtb \
        meson-gxbb-odroidc2.dtb \
diff --git a/arch/arm/dts/s5p4418-nanopi2.dts b/arch/arm/dts/s5p4418-nanopi2.dts
new file mode 100644
index 0000000..f86282a
--- /dev/null
+++ b/arch/arm/dts/s5p4418-nanopi2.dts
@@ -0,0 +1,108 @@
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * (C) Copyright 2017 FriendlyElec Computer Tech. Co., Ltd.
+ * (http://www.friendlyarm.com)
+ *
+ * (C) Copyright 2016 Nexell
+ * Youngbok, Park <p...@nexell.co.kr>
+ */
+
+/dts-v1/;
+#include "s5p4418.dtsi"
+
+/ {
+       model = "FriendlyElec boards based on Nexell s5p4418";
+       cpu-model = "S5p4418";
+
+       compatible = "friendlyelec,nanopi2",
+                    "nexell,s5p4418";
+
+       aliases {
+               mmc0 = "/mmc@c0069000";
+               mmc1 = "/mmc@c0062000";
+               i2c0 = "/i2c@c00a4000";
+               i2c1 = "/i2c@c00a5000";
+               i2c2 = "/i2c@c00a6000";
+       };
+
+       mmc0:mmc@c0062000 {
+               frequency = <50000000>;
+               nexell,drive_dly = <0x0>;
+               nexell,drive_shift = <0x03>;
+               nexell,sample_dly = <0x00>;
+               nexell,sample_shift = <0x02>;
+               status = "okay";
+       };
+
+       mmc2:mmc@c0069000 {
+               frequency = <50000000>;
+               nexell,drive_dly = <0x0>;
+               nexell,drive_shift = <0x03>;
+               nexell,sample_dly = <0x00>;
+               nexell,sample_shift = <0x02>;
+               nexell,bus-width = <4>;
+               index = <2>;
+               status = "okay";
+       };
+
+       /* NanoPi2: Header "CON2", NanoPC-T2: EEPROM (MAC-Addr.) and Audio */
+       i2c0:i2c@c00a4000 {
+               status ="okay";
+       };
+
+       /* NanoPi2: Header "CON2" and HDMI, NanoPC-T2: HDMI */
+       i2c1:i2c@c00a5000 {
+               status ="okay";
+       };
+
+       /* NanoPi2: LCD interface, NanoPC-T2: LCD, LVDS and MIPI interfaces */
+       i2c2:i2c@c00a6000 {
+               status ="okay";
+       };
+
+       dp0:dp@c0102800 {
+               status = "okay";
+               module = <0>;
+               lcd-type = "lvds";
+
+               dp-device {
+                       format = <0>;   /* 0:VESA, 1:JEIDA */
+               };
+
+               dp-sync {
+                       h_active_len = <1024>;
+                       h_front_porch = <84>;
+                       h_back_porch = <84>;
+                       h_sync_width = <88>;
+                       h_sync_invert = <0>;
+                       v_active_len = <600>;
+                       v_front_porch = <10>;
+                       v_back_porch = <10>;
+                       v_sync_width = <20>;
+                       v_sync_invert = <0>;
+               };
+
+               dp-ctrl {
+                       clk_src_lv0 = <3>;
+                       clk_div_lv0 = <16>;
+                       clk_src_lv1 = <7>;
+                       clk_div_lv1 = <1>;
+                       out_format = <2>;
+               };
+
+               dp-planes {
+                       layer_top {
+                               screen_width = <1024>;
+                               screen_height = <600>;
+                               back_color = <0x0>;
+                       };
+
+                       layer_1 {       /* RGB 1 */
+                               width = <1024>;
+                               height = <600>;
+                               format = <0x06530000>;
+                               pixel_byte = <4>;
+                       };
+               };
+       };
+};
diff --git a/arch/arm/dts/s5p4418.dtsi b/arch/arm/dts/s5p4418.dtsi
new file mode 100644
index 0000000..d823e61
--- /dev/null
+++ b/arch/arm/dts/s5p4418.dtsi
@@ -0,0 +1,148 @@
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * (C) Copyright 2016 Nexell
+ * Youngbok, Park <p...@nexell.co.kr>
+ */
+
+#include "skeleton.dtsi"
+
+/ {
+       aliases {
+               mmc0 = &mmc0;
+               mmc1 = &mmc1;
+               mmc2 = &mmc2;
+               gmac = "/ethernet@c0060000";
+       };
+
+       mmc2:mmc@c0069000 {
+               #address-cells = <1>;
+               #size-cells = <0>;
+               compatible = "nexell,nexell-dwmmc";
+               reg = <0xc0069000 0x1000>;
+               nexell,bus-width = <4>;
+               index = <2>;
+               max-frequency = <50000000>;
+               status = "disabled";
+       };
+
+       mmc1:mmc@c0068000 {
+               #address-cells = <1>;
+               #size-cells = <0>;
+               compatible = "nexell,nexell-dwmmc";
+               reg = <0xc0068000 0x1000>;
+               nexell,bus-width = <4>;
+               index = <1>;
+               max-frequency = <50000000>;
+               status = "disabled";
+       };
+
+       mmc0:mmc@c0062000 {
+               #address-cells = <1>;
+               #size-cells = <0>;
+               compatible = "nexell,nexell-dwmmc";
+               reg = <0xc0062000 0x1000>;
+               nexell,bus-width = <4>;
+               index = <0>;
+               max-frequency = <50000000>;
+               status = "disabled";
+       };
+
+       i2c0:i2c@c00a4000 {
+               #address-cells = <1>;
+               #size-cells = <0>;
+               compatible = "nexell,s5pxx18-i2c";
+               reg = <0xc00a4000 0x100>;
+               //clock-frequency = <400000>;
+               sda-delay = <10>;
+               status ="disabled";
+       };
+
+       i2c1:i2c@c00a5000 {
+               #address-cells = <1>;
+               #size-cells = <0>;
+               compatible = "nexell,s5pxx18-i2c";
+               reg = <0xc00a5000 0x100>;
+               clock-frequency = <100000>;
+               status ="disabled";
+       };
+
+       i2c2:i2c@c00a6000 {
+               #address-cells = <1>;
+               #size-cells = <0>;
+               compatible = "nexell,s5pxx18-i2c";
+               reg = <0xc00a6000 0x100>;
+               clock-frequency = <100000>;
+               status ="disabled";
+       };
+
+       dp0:dp@c0102800 {
+               compatible = "nexell,nexell-display";
+               reg = <0xc0102800 0x100>;
+               index = <0>;
+               u-boot,dm-pre-reloc;
+               status = "disabled";
+       };
+
+       dp1:dp@c0102c00 {
+               #address-cells = <1>;
+               #size-cells = <0>;
+               compatible = "nexell,nexell-display";
+               reg = <0xc0102c00 0x100>;
+               index = <1>;
+               status = "disabled";
+       };
+
+       gpio_a:gpio@c001a000 {
+               compatible = "nexell,nexell-gpio";
+               reg = <0xc001a000 0x00000010>;
+               altr,gpio-bank-width = <32>;
+               gpio-bank-name = "gpio_a";
+               gpio-controller;
+               #gpio-cells = <2>;
+       };
+
+       gpio_b:gpio@c001b000 {
+               compatible = "nexell,nexell-gpio";
+               reg = <0xc001b000 0x00000010>;
+               altr,gpio-bank-width = <32>;
+               gpio-bank-name = "gpio_b";
+               gpio-controller;
+               #gpio-cells = <2>;
+       };
+
+       gpio_c:gpio@c001c000 {
+               compatible = "nexell,nexell-gpio";
+               reg = <0xc001c000 0x00000010>;
+               nexell,gpio-bank-width = <32>;
+               gpio-bank-name = "gpio_c";
+               gpio-controller;
+               #gpio-cells = <2>;
+       };
+
+       gpio_d:gpio@c001d000 {
+               compatible = "nexell,nexell-gpio";
+               reg = <0xc001d000 0x00000010>;
+               nexell,gpio-bank-width = <32>;
+               gpio-bank-name = "gpio_d";
+               gpio-controller;
+               #gpio-cells = <2>;
+       };
+
+       gpio_e:gpio@c001e000 {
+               compatible = "nexell,nexell-gpio";
+               reg = <0xc001e000 0x00000010>;
+               nexell,gpio-bank-width = <32>;
+               gpio-bank-name = "gpio_e";
+               gpio-controller;
+               #gpio-cells = <2>;
+       };
+
+       gpio_alv:gpio@c0010800 {
+               compatible = "nexell,nexell-gpio";
+               reg = <0xc0010800 0x00000010>;
+               nexell,gpio-bank-width = <32>;
+               gpio-bank-name = "gpio_alv";
+               gpio-controller;
+               #gpio-cells = <2>;
+       };
+};
diff --git a/board/friendlyarm/Kconfig b/board/friendlyarm/Kconfig
new file mode 100644
index 0000000..8f79640
--- /dev/null
+++ b/board/friendlyarm/Kconfig
@@ -0,0 +1,39 @@
+
+#config SYS_CONFIG_NAME
+#      string "Board header file"
+#      help
+#        This option should contain the base name of board header file.
+#        The header file include/configs/<CONFIG_SYS_CONFIG_NAME>.h
+#        should be included from include/config.h.
+
+config S5P4418_ONEWIRE
+       bool "S5P4418_ONEWIRE"
+       #default y
+
+config PWM_NX
+       bool "PWM_NX"
+       #default y
+
+config SYS_RESERVE_MEM_SIZE
+       hex "SYS_RESERVE_MEM_SIZE"
+
+config ROOT_DEV
+       int "ROOT_DEV"
+       help
+         Environment variable rootdev is set to this value if env. var. 
firstboot
+         does not exist. Otherwise rootdev is set to the MMC boot device. 
rootdev
+         determines (together with env. var. bootpart) where the OS (linux) is
+         booted from.
+
+config BOOT_PART
+       int "BOOT_PART"
+       help
+         Environment variable bootpart is set to this value. bootpart 
determines
+         (together with env. var. rootdev) where the OS (linux) is booted from.
+
+config ROOT_PART
+       int "ROOT_PART"
+       help
+         Environment variable rootpart is set to this value.
+
+source "board/friendlyarm/nanopi2/Kconfig"
diff --git a/board/friendlyarm/nanopi2/Kconfig 
b/board/friendlyarm/nanopi2/Kconfig
new file mode 100644
index 0000000..0f68422
--- /dev/null
+++ b/board/friendlyarm/nanopi2/Kconfig
@@ -0,0 +1,12 @@
+if TARGET_NANOPI2
+
+config SYS_BOARD
+       default "nanopi2"
+
+config SYS_VENDOR
+       default "friendlyarm"
+
+config SYS_CONFIG_NAME
+       default "s5p4418_nanopi2"
+
+endif
diff --git a/board/friendlyarm/nanopi2/MAINTAINERS 
b/board/friendlyarm/nanopi2/MAINTAINERS
new file mode 100644
index 0000000..c8e2ce7
--- /dev/null
+++ b/board/friendlyarm/nanopi2/MAINTAINERS
@@ -0,0 +1,7 @@
+NANOPI2 BOARD
+NANOPC-T2 BOARD
+M:  Stefan Bosch <stefa...@posteo.net>
+S:  Maintained
+F:  board/s5p4418/nanopi2/
+F:  include/configs/s5p4418_nanopi2.h
+F:  configs/s5p4418_nanopi2_defconfig
diff --git a/board/friendlyarm/nanopi2/Makefile 
b/board/friendlyarm/nanopi2/Makefile
new file mode 100644
index 0000000..cd459f2
--- /dev/null
+++ b/board/friendlyarm/nanopi2/Makefile
@@ -0,0 +1,6 @@
+# SPDX-License-Identifier: GPL-2.0+
+#
+# (C) Copyright 2016 Nexell
+# Hyunseok, Jung <hsj...@nexell.co.kr>
+
+obj-y  := board.o hwrev.o onewire.o lcds.o
diff --git a/board/friendlyarm/nanopi2/board.c 
b/board/friendlyarm/nanopi2/board.c
new file mode 100644
index 0000000..63094b5
--- /dev/null
+++ b/board/friendlyarm/nanopi2/board.c
@@ -0,0 +1,567 @@
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * Copyright (C) Guangzhou FriendlyARM Computer Tech. Co., Ltd.
+ * (http://www.friendlyarm.com)
+ */
+
+#include <config.h>
+#include <common.h>
+#ifdef CONFIG_PWM_NX
+#include <pwm.h>
+#endif
+#include <asm/io.h>
+
+#include <asm/arch/nexell.h>
+#include <asm/arch/nx_gpio.h>
+#include <asm/arch/display.h>
+#include <asm/arch/display_dev.h>
+
+#include <u-boot/md5.h>
+
+#include "hwrev.h"
+#include "onewire.h"
+#include "nxp-fb.h"
+
+#include <env_internal.h>      /* for env_save() */
+#include <asm/mach-types.h>
+
+DECLARE_GLOBAL_DATA_PTR;
+
+enum gpio_group {
+       gpio_a, gpio_b, gpio_c, gpio_d, gpio_e,
+};
+
+#ifdef CONFIG_PWM_NX
+struct pwm_device {
+       int grp;
+       int bit;
+       int io_fn;
+};
+
+static inline void bd_pwm_config_gpio(int ch)
+{
+       struct pwm_device pwm_dev[] = {
+               [0] = { .grp = gpio_d, .bit = 1,  .io_fn = 0 },
+               [1] = { .grp = gpio_c, .bit = 13, .io_fn = 1 },
+               [2] = { .grp = gpio_c, .bit = 14, .io_fn = 1 },
+               [3] = { .grp = gpio_d, .bit = 0,  .io_fn = 0 },
+       };
+
+       int gp = pwm_dev[ch].grp;
+       int io = pwm_dev[ch].bit;
+
+       /* pwm backlight OFF: HIGH, ON: LOW */
+       nx_gpio_set_pad_function(gp, io, pwm_dev[ch].io_fn);
+       nx_gpio_set_output_value(gp, io, 1);
+       nx_gpio_set_output_enable(gp, io, 1);
+}
+#endif
+
+static void bd_backlight_off(void)
+{
+#ifdef CONFIG_S5P4418_ONEWIRE
+       onewire_set_backlight(0);
+
+#elif defined(BACKLIGHT_CH)
+       bd_pwm_config_gpio(BACKLIGHT_CH);
+#endif
+}
+
+static void bd_backlight_on(void)
+{
+#ifdef CONFIG_S5P4418_ONEWIRE
+       onewire_set_backlight(127);
+
+#elif defined(BACKLIGHT_CH)
+       /* pwm backlight ON: HIGH, ON: LOW */
+       pwm_init(BACKLIGHT_CH,
+                BACKLIGHT_DIV, BACKLIGHT_INV);
+       pwm_config(BACKLIGHT_CH,
+                  TO_DUTY_NS(BACKLIGHT_DUTY, BACKLIGHT_HZ),
+                  TO_PERIOD_NS(BACKLIGHT_HZ));
+#endif
+}
+
+static void bd_lcd_config_gpio(void)
+{
+       int i;
+
+       for (i = 0; i < 28; i++) {
+               nx_gpio_set_pad_function(gpio_a, i, 1);
+               nx_gpio_set_drive_strength(gpio_a, i, 0);
+               nx_gpio_set_pull_mode(gpio_a, i, 2);
+       }
+
+       nx_gpio_set_drive_strength(gpio_a, 0, 1);
+}
+
+/* DEFAULT mmc dev for eMMC boot (dwmmc.2) */
+static int mmc_boot_dev = 0;
+
+int board_mmc_bootdev(void)
+{
+       return mmc_boot_dev;
+}
+
+/* call from common/env_mmc.c */
+int mmc_get_env_dev(void)
+{
+       return mmc_boot_dev;
+}
+
+#ifdef CONFIG_DISPLAY_BOARDINFO
+int checkboard(void)
+{
+       printf("Board: %s\n", get_board_name());
+
+       return 0;
+}
+#endif
+
+int nx_display_fixup_dp(struct nx_display_dev *dp)
+{
+       struct nxp_lcd *lcd = bd_get_lcd();
+       enum lcd_format fmt = bd_get_lcd_format();
+       struct nxp_lcd_timing *timing = &lcd->timing;
+       struct dp_sync_info *sync = &dp->sync;
+       struct dp_plane_info *plane = &dp->planes[0];
+       int i;
+       u32 clk = 800000000;
+       u32 div;
+
+       sync->h_active_len = lcd->width;
+       sync->h_sync_width = timing->h_sw;
+       sync->h_back_porch = timing->h_bp;
+       sync->h_front_porch = timing->h_fp;
+       sync->h_sync_invert = !lcd->polarity.inv_hsync;
+
+       sync->v_active_len = lcd->height;
+       sync->v_sync_width = timing->v_sw;
+       sync->v_back_porch = timing->v_bp;
+       sync->v_front_porch = timing->v_fp;
+       sync->v_sync_invert = !lcd->polarity.inv_vsync;
+
+       /* calculates pixel clock */
+       div  = timing->h_sw + timing->h_bp + timing->h_fp + lcd->width;
+       div *= timing->v_sw + timing->v_bp + timing->v_fp + lcd->height;
+       div *= lcd->freq ? : 60;
+       clk /= div;
+
+       dp->ctrl.clk_div_lv0 = clk;
+       dp->ctrl.clk_inv_lv0 = lcd->polarity.rise_vclk;
+
+       dp->top.screen_width = lcd->width;
+       dp->top.screen_height = lcd->height;
+
+       for (i = 0; i < dp->top.plane_num; i++, plane++) {
+               if (plane->enable) {
+                       plane->width = lcd->width;
+                       plane->height = lcd->height;
+               }
+       }
+
+       /* initialize display device type */
+       if (fmt == LCD_RGB) {
+               dp->dev_type = DP_DEVICE_RGBLCD;
+
+       } else if (fmt == LCD_HDMI) {
+               struct dp_hdmi_dev *dev = (struct dp_hdmi_dev *)dp->device;
+
+               dp->dev_type = DP_DEVICE_HDMI;
+               if (lcd->width == 1920 && lcd->height == 1080)
+                       dev->preset = 1;
+               else
+                       dev->preset = 0;
+
+       } else {
+               struct dp_lvds_dev *dev = (struct dp_lvds_dev *)dp->device;
+
+               dp->dev_type = DP_DEVICE_LVDS;
+               dev->lvds_format = (fmt & 0x3);
+       }
+
+       return 0;
+}
+
+/* --------------------------------------------------------------------------
+ * initialize board status.
+ */
+
+#define        MMC_BOOT_CH0            (0)
+#define        MMC_BOOT_CH1            (1 <<  3)
+#define        MMC_BOOT_CH2            (1 << 19)
+
+static void bd_bootdev_init(void)
+{
+       unsigned int rst = readl(PHY_BASEADDR_CLKPWR + SYSRSTCONFIG);
+
+       rst &= (1 << 19) | (1 << 3);
+       if (rst == MMC_BOOT_CH0) {
+               /* mmc dev 1 for SD boot */
+               mmc_boot_dev = 1;
+       }
+}
+
+static void bd_onewire_init(void)
+{
+       unsigned char lcd;
+       unsigned short fw_ver;
+
+       onewire_init();
+       onewire_get_info(&lcd, &fw_ver);
+}
+
+static void bd_lcd_init(void)
+{
+       struct nxp_lcd *cfg;
+       int id;
+       int ret;
+
+       id = onewire_get_lcd_id();
+       /* -1: onwire probe failed
+        *  0: bad
+        * >0: identified
+        */
+
+       ret = bd_setup_lcd_by_id(id);
+       if (id <= 0 || ret != id) {
+               printf("Panel: N/A (%d)\n", id);
+               bd_setup_lcd_by_name("HDMI720P60");
+
+       } else {
+               printf("Panel: %s\n", bd_get_lcd_name());
+
+               cfg = bd_get_lcd();
+               if (cfg->gpio_init)
+                       cfg->gpio_init();
+       }
+}
+
+static int mac_read_from_generic_eeprom(u8 *addr)
+{
+       return -1;
+}
+
+static void make_ether_addr(u8 *addr)
+{
+       u32 hash[20];
+
+#define ETHER_MAC_TAG  "ethmac"
+       memset(hash, 0, sizeof(hash));
+       memcpy(hash + 12, ETHER_MAC_TAG, sizeof(ETHER_MAC_TAG));
+
+       hash[4] = readl(PHY_BASEADDR_ECID + 0x00);
+       hash[5] = readl(PHY_BASEADDR_ECID + 0x04);
+       hash[6] = readl(PHY_BASEADDR_ECID + 0x08);
+       hash[7] = readl(PHY_BASEADDR_ECID + 0x0c);
+
+       md5((unsigned char *)&hash[4], 64, (unsigned char *)hash);
+
+       hash[0] ^= hash[2];
+       hash[1] ^= hash[3];
+
+       memcpy(addr, (char *)hash, 6);
+       addr[0] &= 0xfe;        /* clear multicast bit */
+       addr[0] |= 0x02;
+}
+
+static void set_ether_addr(void)
+{
+       unsigned char mac[6];
+       char ethaddr[20];
+       int ret;
+
+       if (env_get("ethaddr"))
+               return;
+
+       ret = mac_read_from_generic_eeprom(mac);
+       if (ret < 0)
+               make_ether_addr(mac);
+
+       sprintf(ethaddr, "%02x:%02x:%02x:%02x:%02x:%02x",
+               mac[0], mac[1], mac[2], mac[3], mac[4], mac[5]);
+       if (!ret)
+               printf("MAC:  [%s]\n", ethaddr);
+
+       env_set("ethaddr", ethaddr);
+}
+
+#ifdef CONFIG_REVISION_TAG
+static void set_board_rev(void)
+{
+       char info[64] = {0, };
+
+       snprintf(info, ARRAY_SIZE(info), "%02x", get_board_rev());
+       env_set("board_rev", info);
+}
+#endif
+
+static void set_dtb_name(void)
+{
+       char info[64] = {0, };
+
+       snprintf(info, ARRAY_SIZE(info),
+                "s5p4418-nanopi2-rev%02x.dtb", get_board_rev());
+       env_set("dtb_name", info);
+}
+
+static void bd_update_env(void)
+{
+       char *lcdtype = env_get("lcdtype");
+       char *lcddpi = env_get("lcddpi");
+       char *bootargs = env_get("bootargs");
+       const char *name;
+       char *p = NULL;
+       int rootdev = board_mmc_bootdev();
+       int need_save = 0;
+
+#define CMDLINE_LCD            " lcd="
+       char cmdline[CONFIG_SYS_CBSIZE];
+       int n = 1;
+
+       if (rootdev != CONFIG_ROOT_DEV && !env_get("firstboot")) {
+               env_set_ulong("rootdev", rootdev);
+               env_set("firstboot", "0");
+               need_save = 1;
+       }
+
+       if (lcdtype) {
+               /* Setup again as user specified LCD in env */
+               bd_setup_lcd_by_name(lcdtype);
+       }
+
+       name = bd_get_lcd_name();
+
+       if (bootargs)
+               n = strlen(bootargs);   /* isn't 0 for NULL */
+       else
+               cmdline[0] = '\0';
+
+       if ((n + strlen(name) + sizeof(CMDLINE_LCD)) > sizeof(cmdline)) {
+               printf("Error: `bootargs' is too large (%d)\n", n);
+               goto __exit;
+       }
+
+       if (bootargs) {
+               p = strstr(bootargs, CMDLINE_LCD);
+               if (p) {
+                       n = (p - bootargs);
+                       p += strlen(CMDLINE_LCD);
+               }
+               strncpy(cmdline, bootargs, n);
+       }
+
+       /* add `lcd=NAME,NUMdpi' */
+       strncpy(cmdline + n, CMDLINE_LCD, strlen(CMDLINE_LCD));
+       n += strlen(CMDLINE_LCD);
+
+       strcpy(cmdline + n, name);
+       n += strlen(name);
+
+       if (lcddpi) {
+               n += sprintf(cmdline + n, ",%sdpi", lcddpi);
+       } else {
+               int dpi = bd_get_lcd_density();
+
+               if (dpi > 0 && dpi < 600)
+                       n += sprintf(cmdline + n, ",%ddpi", dpi);
+       }
+
+       /* copy remaining of bootargs */
+       if (p) {
+               p = strstr(p, " ");
+               if (p) {
+                       strcpy(cmdline + n, p);
+                       n += strlen(p);
+               }
+       }
+
+       /* append `bootdev=2' */
+#define CMDLINE_BDEV   " bootdev="
+       if (rootdev > 0 && !strstr(cmdline, CMDLINE_BDEV))
+               n += sprintf(cmdline + n, "%s2", CMDLINE_BDEV);
+
+       /* finally, let's update uboot env & save it */
+       if (bootargs && strncmp(cmdline, bootargs, sizeof(cmdline))) {
+               env_set("bootargs", cmdline);
+               need_save = 1;
+       }
+
+__exit:
+       if (need_save)
+               env_save();
+}
+
+/* --------------------------------------------------------------------------
+ * call from u-boot
+ */
+
+int board_early_init_f(void)
+{
+       return 0;
+}
+
+int board_init(void)
+{
+       bd_hwrev_init();
+       bd_base_rev_init();
+
+       bd_bootdev_init();
+       bd_onewire_init();
+
+       bd_backlight_off();
+
+       bd_lcd_config_gpio();
+       bd_lcd_init();
+
+#ifdef CONFIG_SILENT_CONSOLE
+       gd->flags |= GD_FLG_SILENT;
+#endif
+
+       return 0;
+}
+
+#ifdef CONFIG_BOARD_LATE_INIT
+int board_late_init(void)
+{
+       bd_update_env();
+
+#ifdef CONFIG_REVISION_TAG
+       set_board_rev();
+#endif
+       set_dtb_name();
+
+       set_ether_addr();
+
+#ifdef CONFIG_SILENT_CONSOLE
+       gd->flags &= ~GD_FLG_SILENT;
+#endif
+
+       bd_backlight_on();
+       printf("\n");
+
+       return 0;
+}
+#endif
+
+#ifdef CONFIG_SPLASH_SOURCE
+#include <splash.h>
+static struct splash_location splash_locations[] = {
+       {
+       .name = "mmc_fs",
+       .storage = SPLASH_STORAGE_MMC,
+       .flags = SPLASH_STORAGE_FS,
+       .devpart = __stringify(CONFIG_ROOT_DEV) ":"
+                  __stringify(CONFIG_BOOT_PART),
+       },
+};
+
+int splash_screen_prepare(void)
+{
+       int err;
+       char *env_cmd = env_get("load_splash");
+
+       debug("%s()\n", __func__);
+
+       if (env_cmd) {
+               err = run_command(env_cmd, 0);
+
+       } else {
+               char devpart[64] = { 0, };
+               int bootpart = env_get_ulong("bootpart", 0, CONFIG_BOOT_PART);
+               int rootdev;
+
+               if (env_get("firstboot"))
+                       rootdev = env_get_ulong("rootdev", 0, CONFIG_ROOT_DEV);
+               else
+                       rootdev = board_mmc_bootdev();
+
+               snprintf(devpart, ARRAY_SIZE(devpart), "%d:%d", rootdev,
+                        bootpart);
+               splash_locations[0].devpart = devpart;
+
+               err = splash_source_load(splash_locations,
+                                        ARRAY_SIZE(splash_locations));
+       }
+
+       if (!err) {
+               char addr[64];
+
+               sprintf(addr, "0x%lx", gd->fb_base);
+               env_set("fb_addr", addr);
+       }
+
+       return err;
+}
+#endif
+
+/* u-boot dram initialize */
+int dram_init(void)
+{
+       gd->ram_size = CONFIG_SYS_SDRAM_SIZE;
+       return 0;
+}
+
+/* u-boot dram board specific */
+int dram_init_banksize(void)
+{
+#define SCR_USER_SIG6_READ             (SCR_ALIVE_BASE + 0x0F0)
+       unsigned int reg_val = readl(SCR_USER_SIG6_READ);
+
+       /* set global data memory */
+       gd->bd->bi_boot_params = CONFIG_SYS_SDRAM_BASE + 0x00000100;
+
+       gd->bd->bi_dram[0].start = CONFIG_SYS_SDRAM_BASE;
+       gd->bd->bi_dram[0].size  = CONFIG_SYS_SDRAM_SIZE;
+
+       /* Number of Row: 14 bits */
+       if ((reg_val >> 28) == 14)
+               gd->bd->bi_dram[0].size -= 0x20000000;
+
+       /* Number of Memory Chips */
+       if ((reg_val & 0x3) > 1) {
+               gd->bd->bi_dram[1].start = 0x80000000;
+               gd->bd->bi_dram[1].size  = 0x40000000;
+       }
+       return 0;
+}
+
+#if defined(CONFIG_OF_BOARD_SETUP)
+int ft_board_setup(void *blob, bd_t *bd)
+{
+       int nodeoff;
+       unsigned int rootdev;
+       unsigned int fb_addr;
+
+       if (board_mmc_bootdev() > 0) {
+               rootdev = fdt_getprop_u32_default(blob, "/board", "sdidx", 2);
+               if (rootdev) {
+                       /* find or create "/chosen" node. */
+                       nodeoff = fdt_find_or_add_subnode(blob, 0, "chosen");
+                       if (nodeoff >= 0)
+                               fdt_setprop_u32(blob, nodeoff, "linux,rootdev",
+                                               rootdev);
+               }
+       }
+
+       fb_addr = env_get_ulong("fb_addr", 0, 0);
+       if (fb_addr) {
+               nodeoff = fdt_path_offset(blob, "/reserved-memory");
+               if (nodeoff < 0)
+                       return nodeoff;
+
+               nodeoff = fdt_add_subnode(blob, nodeoff, "display_reserved");
+               if (nodeoff >= 0) {
+                       fdt32_t cells[2];
+
+                       cells[0] = cpu_to_fdt32(fb_addr);
+                       cells[1] = cpu_to_fdt32(0x800000);
+
+                       fdt_setprop(blob, nodeoff, "reg", cells,
+                                   sizeof(cells[0]) * 2);
+               }
+       }
+
+       return 0;
+}
+#endif
diff --git a/board/friendlyarm/nanopi2/hwrev.c 
b/board/friendlyarm/nanopi2/hwrev.c
new file mode 100644
index 0000000..ced9b26
--- /dev/null
+++ b/board/friendlyarm/nanopi2/hwrev.c
@@ -0,0 +1,108 @@
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * Copyright (C) Guangzhou FriendlyARM Computer Tech. Co., Ltd.
+ * (http://www.friendlyarm.com)
+ */
+
+#include <config.h>
+#include <common.h>
+#include <i2c.h>
+#include <asm/io.h>
+
+#include <asm/arch/nexell.h>
+#include <asm/arch/nx_gpio.h>
+
+/* Board revision list: <PCB3 | PCB2 | PCB1>
+ *  0b000 - NanoPi 2
+ *  0b001 - NanoPC-T2
+ *  0b010 - NanoPi S2
+ *  0b011 - Smart4418
+ *  0b100 - NanoPi Fire 2A
+ *  0b111 - NanoPi M2A
+ *
+ * Extented revision:
+ *  0b001 - Smart4418-SDK
+ */
+#define __IO_GRP               2       /* GPIO_C */
+#define __IO_PCB1                      26
+#define __IO_PCB2                      27
+#define __IO_PCB3                      25
+
+static int pcb_rev = -1;
+static int base_rev    = 0;
+
+static void bd_hwrev_config_gpio(void)
+{
+       int gpios[3][2] = {
+               { __IO_PCB1, 1 },
+               { __IO_PCB2, 1 },
+               { __IO_PCB3, 1 },
+       };
+       int i;
+
+       /* gpio input mode, pull-down */
+       for (i = 0; i < 3; i++) {
+               nx_gpio_set_pad_function(__IO_GRP, gpios[i][0], gpios[i][1]);
+               nx_gpio_set_output_enable(__IO_GRP, gpios[i][0], 0);
+               nx_gpio_set_pull_mode(__IO_GRP, gpios[i][0], 0);
+       }
+}
+
+void bd_hwrev_init(void)
+{
+       if (pcb_rev >= 0)
+               return;
+
+       bd_hwrev_config_gpio();
+
+       pcb_rev  = nx_gpio_get_input_value(__IO_GRP, __IO_PCB1);
+       pcb_rev |= nx_gpio_get_input_value(__IO_GRP, __IO_PCB2) << 1;
+       pcb_rev |= nx_gpio_get_input_value(__IO_GRP, __IO_PCB3) << 2;
+}
+
+/* Get extended revision for SmartXX18 */
+void bd_base_rev_init(void)
+{
+       struct udevice *dev;
+       u8 val = 0;
+
+       if (pcb_rev != 0x3)
+               return;
+
+#define PCA9536_I2C_BUS     2
+#define PCA9636_I2C_ADDR    0x41
+       if (i2c_get_chip_for_busnum
+                               (PCA9536_I2C_BUS, PCA9636_I2C_ADDR, 1, &dev))
+               return;
+
+       if (!dm_i2c_read(dev, 0, &val, 1))
+               base_rev = (val & 0xf);
+}
+
+/* To override __weak symbols */
+u32 get_board_rev(void)
+{
+       return (base_rev << 8) | pcb_rev;
+}
+
+const char *get_board_name(void)
+{
+       bd_hwrev_init();
+
+       switch (pcb_rev) {
+       case 0:
+               return "NanoPi 2";
+       case 1:
+               return "NanoPC-T2";
+       case 2:
+               return "NanoPi S2";
+       case 3:
+               return "Smart4418";
+       case 4:
+               return "NanoPi Fire 2A";
+       case 7:
+               return "NanoPi M2A";
+       default:
+               return "s5p4418-X";
+       }
+}
diff --git a/board/friendlyarm/nanopi2/hwrev.h 
b/board/friendlyarm/nanopi2/hwrev.h
new file mode 100644
index 0000000..1b1a828
--- /dev/null
+++ b/board/friendlyarm/nanopi2/hwrev.h
@@ -0,0 +1,15 @@
+/* SPDX-License-Identifier: GPL-2.0+
+ *
+ * Copyright (C) Guangzhou FriendlyARM Computer Tech. Co., Ltd.
+ * (http://www.friendlyarm.com)
+ */
+
+#ifndef __BD_HW_REV_H__
+#define __BD_HW_REV_H__
+
+extern void bd_hwrev_init(void);
+extern void bd_base_rev_init(void);
+extern u32 get_board_rev(void);
+extern const char *get_board_name(void);
+
+#endif /* __BD_HW_REV_H__ */
diff --git a/board/friendlyarm/nanopi2/lcds.c b/board/friendlyarm/nanopi2/lcds.c
new file mode 100644
index 0000000..b3aee5c
--- /dev/null
+++ b/board/friendlyarm/nanopi2/lcds.c
@@ -0,0 +1,697 @@
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * Copyright (c) 2017 FriendlyARM (www.arm9.net)
+ */
+
+#include <config.h>
+#include <common.h>
+#include <errno.h>
+#include <fdtdec.h>
+#include <fdt_support.h>
+#include <asm/io.h>
+
+#include <asm/arch/nexell.h>
+#include <asm/arch/display.h>
+#include <asm/arch/nx_gpio.h>
+
+#include "nxp-fb.h"
+
+/*
+ * param @module_index for nx_gpio APIs and will be removed
+ * after support pinctrl
+ */
+#ifndef PAD_GPIO_A
+#define PAD_GPIO_A     0
+#endif
+
+static inline void common_gpio_init(void)
+{
+       /* PVCLK */
+       nx_gpio_set_fast_slew(PAD_GPIO_A, 0, 1);
+}
+
+static void s70_gpio_init(void)
+{
+       int i;
+
+       /* PVCLK */
+       nx_gpio_set_drive_strength(PAD_GPIO_A, 0, 1);
+
+       /* RGB24 */
+       for (i = 1; i < 25; i++)
+               nx_gpio_set_drive_strength(PAD_GPIO_A, i, 2);
+
+       /* HS/VS/DE */
+       for (; i < 28; i++)
+               nx_gpio_set_drive_strength(PAD_GPIO_A, i, 1);
+}
+
+static void s702_gpio_init(void)
+{
+       int i;
+
+       common_gpio_init();
+
+       nx_gpio_set_drive_strength(PAD_GPIO_A, 0, 2);
+
+       for (i = 1; i < 25; i++)
+               nx_gpio_set_drive_strength(PAD_GPIO_A, i, 0);
+
+       for (; i < 28; i++)
+               nx_gpio_set_drive_strength(PAD_GPIO_A, i, 1);
+}
+
+static void s430_gpio_init(void)
+{
+       int  i;
+
+       for (i = 0; i < 28; i++)
+               nx_gpio_set_drive_strength(PAD_GPIO_A, i, 1);
+}
+
+static void hd101_gpio_init(void)
+{
+       int i;
+
+       common_gpio_init();
+
+       nx_gpio_set_drive_strength(PAD_GPIO_A, 0, 2);
+
+       for (i = 1; i < 25; i++)
+               nx_gpio_set_drive_strength(PAD_GPIO_A, i, 1);
+
+       nx_gpio_set_drive_strength(PAD_GPIO_A, 27, 1);
+}
+
+static void hd700_gpio_init(void)
+{
+       hd101_gpio_init();
+}
+
+/* NXP display configs for supported LCD */
+
+static struct nxp_lcd wxga_hd700 = {
+       .width = 800,
+       .height = 1280,
+       .p_width = 94,
+       .p_height = 151,
+       .bpp = 24,
+       .freq = 60,
+
+       .timing = {
+               .h_fp = 20,
+               .h_bp = 20,
+               .h_sw = 24,
+               .v_fp =  4,
+               .v_fpe = 1,
+               .v_bp =  4,
+               .v_bpe = 1,
+               .v_sw =  8,
+       },
+       .polarity = {
+               .rise_vclk = 0,
+               .inv_hsync = 0,
+               .inv_vsync = 0,
+               .inv_vden = 0,
+       },
+       .gpio_init = hd700_gpio_init,
+};
+
+static struct nxp_lcd wvga_s70 = {
+       .width = 800,
+       .height = 480,
+       .p_width = 155,
+       .p_height = 93,
+       .bpp = 24,
+       .freq = 61,
+
+       .timing = {
+               .h_fp = 48,
+               .h_bp = 36,
+               .h_sw = 10,
+               .v_fp = 22,
+               .v_fpe = 1,
+               .v_bp = 15,
+               .v_bpe = 1,
+               .v_sw = 8,
+       },
+       .polarity = {
+               .rise_vclk = 0,
+               .inv_hsync = 1,
+               .inv_vsync = 1,
+               .inv_vden = 0,
+       },
+       .gpio_init = s70_gpio_init,
+};
+
+static struct nxp_lcd wvga_s702 = {
+       .width = 800,
+       .height = 480,
+       .p_width = 155,
+       .p_height = 93,
+       .bpp = 24,
+       .freq = 61,
+
+       .timing = {
+               .h_fp = 44,
+               .h_bp = 26,
+               .h_sw = 20,
+               .v_fp = 22,
+               .v_fpe = 1,
+               .v_bp = 15,
+               .v_bpe = 1,
+               .v_sw = 8,
+       },
+       .polarity = {
+               .rise_vclk = 1,
+               .inv_hsync = 1,
+               .inv_vsync = 1,
+               .inv_vden = 0,
+       },
+       .gpio_init = s702_gpio_init,
+};
+
+static struct nxp_lcd wvga_s70d = {
+       .width = 800,
+       .height = 480,
+       .p_width = 155,
+       .p_height = 93,
+       .bpp = 24,
+       .freq = 61,
+
+       .timing = {
+               .h_fp = 80,
+               .h_bp = 78,
+               .h_sw = 10,
+               .v_fp = 22,
+               .v_fpe = 1,
+               .v_bp = 24,
+               .v_bpe = 1,
+               .v_sw = 8,
+       },
+       .polarity = {
+               .rise_vclk = 0,
+               .inv_hsync = 1,
+               .inv_vsync = 1,
+               .inv_vden = 0,
+       },
+       .gpio_init = s702_gpio_init,
+};
+
+static struct nxp_lcd wvga_w50 = {
+       .width = 800,
+       .height = 480,
+       .p_width = 108,
+       .p_height = 64,
+       .bpp = 24,
+       .freq = 61,
+
+       .timing = {
+               .h_fp = 40,
+               .h_bp = 40,
+               .h_sw = 48,
+               .v_fp = 20,
+               .v_fpe = 1,
+               .v_bp = 20,
+               .v_bpe = 1,
+               .v_sw = 12,
+       },
+       .polarity = {
+               .rise_vclk = 0,
+               .inv_hsync = 1,
+               .inv_vsync = 1,
+               .inv_vden = 0,
+       },
+       .gpio_init = s70_gpio_init,
+};
+
+static struct nxp_lcd wvga_s430 = {
+       .width = 480,
+       .height = 800,
+       .p_width = 108,
+       .p_height = 64,
+       .bpp = 24,
+       .freq = 60,
+
+       .timing = {
+               .h_fp = 64,
+               .h_bp = 0,
+               .h_sw = 16,
+               .v_fp = 32,
+               .v_fpe = 1,
+               .v_bp = 0,
+               .v_bpe = 1,
+               .v_sw = 16,
+       },
+       .polarity = {
+               .rise_vclk = 1,
+               .inv_hsync = 1,
+               .inv_vsync = 1,
+               .inv_vden = 0,
+       },
+       .gpio_init = s430_gpio_init,
+};
+
+static struct nxp_lcd wsvga_w101 = {
+       .width = 1024,
+       .height = 600,
+       .p_width = 204,
+       .p_height = 120,
+       .bpp = 24,
+       .freq = 60,
+
+       .timing = {
+               .h_fp = 40,
+               .h_bp = 40,
+               .h_sw = 200,
+               .v_fp =  8,
+               .v_fpe = 1,
+               .v_bp =  8,
+               .v_bpe = 1,
+               .v_sw = 16,
+       },
+       .polarity = {
+               .rise_vclk = 1,
+               .inv_hsync = 1,
+               .inv_vsync = 1,
+               .inv_vden = 0,
+       },
+};
+
+static struct nxp_lcd wsvga_x710 = {
+       .width = 1024,
+       .height = 600,
+       .p_width = 154,
+       .p_height = 90,
+       .bpp = 24,
+       .freq = 61,
+
+       .timing = {
+               .h_fp = 84,
+               .h_bp = 84,
+               .h_sw = 88,
+               .v_fp = 10,
+               .v_fpe = 1,
+               .v_bp = 10,
+               .v_bpe = 1,
+               .v_sw = 20,
+       },
+       .polarity = {
+               .rise_vclk = 0,
+               .inv_hsync = 1,
+               .inv_vsync = 1,
+               .inv_vden = 0,
+       },
+       .gpio_init = hd101_gpio_init,
+};
+
+static struct nxp_lcd xga_a97 = {
+       .width = 1024,
+       .height = 768,
+       .p_width = 200,
+       .p_height = 150,
+       .bpp = 24,
+       .freq = 61,
+
+       .timing = {
+               .h_fp = 12,
+               .h_bp = 12,
+               .h_sw = 4,
+               .v_fp = 8,
+               .v_fpe = 1,
+               .v_bp = 8,
+               .v_bpe = 1,
+               .v_sw =  4,
+       },
+       .polarity = {
+               .rise_vclk = 0,
+               .inv_hsync = 1,
+               .inv_vsync = 1,
+               .inv_vden = 0,
+       },
+};
+
+static struct nxp_lcd xga_lq150 = {
+       .width = 1024,
+       .height = 768,
+       .p_width = 304,
+       .p_height = 228,
+       .bpp = 24,
+       .freq = 60,
+
+       .timing = {
+               .h_fp = 12,
+               .h_bp = 12,
+               .h_sw = 40,
+               .v_fp = 8,
+               .v_fpe = 1,
+               .v_bp = 8,
+               .v_bpe = 1,
+               .v_sw = 40,
+       },
+       .polarity = {
+               .rise_vclk = 0,
+               .inv_hsync = 1,
+               .inv_vsync = 1,
+               .inv_vden = 0,
+       },
+};
+
+static struct nxp_lcd vga_l80 = {
+       .width = 640,
+       .height = 480,
+       .p_width = 160,
+       .p_height = 120,
+       .bpp = 32,
+       .freq = 60,
+
+       .timing = {
+               .h_fp = 35,
+               .h_bp = 53,
+               .h_sw = 73,
+               .v_fp = 3,
+               .v_fpe = 1,
+               .v_bp = 29,
+               .v_bpe = 1,
+               .v_sw = 6,
+       },
+       .polarity = {
+               .rise_vclk = 0,
+               .inv_hsync = 1,
+               .inv_vsync = 1,
+               .inv_vden = 0,
+       },
+};
+
+static struct nxp_lcd wxga_bp101 = {
+       .width = 1280,
+       .height = 800,
+       .p_width = 218,
+       .p_height = 136,
+       .bpp = 24,
+       .freq = 60,
+
+       .timing = {
+               .h_fp = 20,
+               .h_bp = 20,
+               .h_sw = 24,
+               .v_fp =  4,
+               .v_fpe = 1,
+               .v_bp =  4,
+               .v_bpe = 1,
+               .v_sw =  8,
+       },
+       .polarity = {
+               .rise_vclk = 1,
+               .inv_hsync = 1,
+               .inv_vsync = 1,
+               .inv_vden = 0,
+       },
+};
+
+static struct nxp_lcd wxga_hd101 = {
+       .width = 1280,
+       .height = 800,
+       .p_width = 218,
+       .p_height = 136,
+       .bpp = 24,
+       .freq = 60,
+
+       .timing = {
+               .h_fp = 16,
+               .h_bp = 16,
+               .h_sw = 30,
+               .v_fp =  8,
+               .v_fpe = 1,
+               .v_bp =  8,
+               .v_bpe = 1,
+               .v_sw = 12,
+       },
+       .polarity = {
+               .rise_vclk = 1,
+               .inv_hsync = 0,
+               .inv_vsync = 0,
+               .inv_vden = 0,
+       },
+       .gpio_init = hd101_gpio_init,
+};
+
+static struct nxp_lcd hvga_h43 = {
+       .width = 480,
+       .height = 272,
+       .p_width = 96,
+       .p_height = 54,
+       .bpp = 32,
+       .freq = 65,
+
+       .timing = {
+               .h_fp =  5,
+               .h_bp = 40,
+               .h_sw =  2,
+               .v_fp =  8,
+               .v_fpe = 1,
+               .v_bp =  8,
+               .v_bpe = 1,
+               .v_sw =  2,
+       },
+       .polarity = {
+               .rise_vclk = 0,
+               .inv_hsync = 1,
+               .inv_vsync = 1,
+               .inv_vden = 0,
+       },
+};
+
+static struct nxp_lcd hvga_p43 = {
+       .width = 480,
+       .height = 272,
+       .p_width = 96,
+       .p_height = 54,
+       .bpp = 32,
+       .freq = 65,
+
+       .timing = {
+               .h_fp =  5,
+               .h_bp = 40,
+               .h_sw =  2,
+               .v_fp =  8,
+               .v_fpe = 1,
+               .v_bp =  9,
+               .v_bpe = 1,
+               .v_sw =  2,
+       },
+       .polarity = {
+               .rise_vclk = 1,
+               .inv_hsync = 1,
+               .inv_vsync = 1,
+               .inv_vden = 0,
+       },
+};
+
+static struct nxp_lcd qvga_w35 = {
+       .width = 320,
+       .height = 240,
+       .p_width = 70,
+       .p_height = 52,
+       .bpp = 16,
+       .freq = 65,
+
+       .timing = {
+               .h_fp =  4,
+               .h_bp = 70,
+               .h_sw =  4,
+               .v_fp =  4,
+               .v_fpe = 1,
+               .v_bp = 12,
+               .v_bpe = 1,
+               .v_sw =  4,
+       },
+       .polarity = {
+               .rise_vclk = 1,
+               .inv_hsync = 0,
+               .inv_vsync = 0,
+               .inv_vden = 0,
+       },
+};
+
+/* HDMI */
+static struct nxp_lcd hdmi_def = {
+       .width = 1920,
+       .height = 1080,
+       .p_width = 480,
+       .p_height = 320,
+       .bpp = 24,
+       .freq = 60,
+
+       .timing = {
+               .h_fp = 12,
+               .h_bp = 12,
+               .h_sw = 4,
+               .v_fp = 8,
+               .v_fpe = 1,
+               .v_bp = 8,
+               .v_bpe = 1,
+               .v_sw =  4,
+       },
+       .polarity = {
+               .rise_vclk = 0,
+               .inv_hsync = 1,
+               .inv_vsync = 1,
+               .inv_vden = 0,
+       },
+};
+
+static struct hdmi_config {
+       char *name;
+       int width;
+       int height;
+} bd_hdmi_config[] = {
+       { "HDMI1080P60",        1920, 1080 },
+       { "HDMI1080I60",        1920, 1080 },
+       { "HDMI1080P30",        1920, 1080 },
+       { "HDMI1080P50",        1920, 1080 },
+       { "HDMI1080I50",        1920, 1080 },
+
+       { "HDMI1080P60D",        960,  536 },
+       { "HDMI1080I60D",        960,  536 },
+       { "HDMI1080P30D",        960,  536 },
+       { "HDMI1080P50D",        960,  536 },
+       { "HDMI1080I50D",        960,  536 },
+
+       { "HDMI720P60",         1280,  720 },
+       { "HDMI720P60D",         640,  360 },
+       { "HDMI720P50",         1280,  720 },
+       { "HDMI720P50D",         640,  360 },
+
+       { "HDMI576P16X9",        720,  576 },
+       { "HDMI576P16X9D",       720,  576 },
+       { "HDMI576P4X3",         720,  576 },
+       { "HDMI576P4X3D",        720,  576 },
+
+       { "HDMI480P16X9",        720,  480 },
+       { "HDMI480P16X9D",       720,  480 },
+       { "HDMI480P4X3",         720,  480 },
+       { "HDMI480P4X3D",        720,  480 },
+};
+
+/* Try to guess LCD panel by kernel command line, or
+ * using *HD101* as default
+ */
+static struct {
+       int id;
+       char *name;
+       struct nxp_lcd *lcd;
+       int dpi;
+       int ctp;
+       enum lcd_format fmt;
+} bd_lcd_config[] = {
+       {  25, "HD101",  &wxga_hd101,   0, 1, LCD_RGB  },
+       {  32, "HD101B", &wxga_hd101,   0, 1, LCD_RGB  },
+       {  18, "HD700",  &wxga_hd700, 213, 1, LCD_RGB  },
+       {  30, "HD702",  &wxga_hd700, 213, 1, LCD_RGB  },
+       {  33, "H70",    &wxga_hd700, 213, 0, LCD_VESA },
+       {   3, "S70",    &wvga_s70,   128, 1, LCD_RGB  },
+       {  36, "S701",   &wvga_s70,   128, 1, LCD_RGB  },
+       {  24, "S702",   &wvga_s702,  128, 3, LCD_RGB  },
+       {  26, "S70D",   &wvga_s70d,  128, 0, LCD_RGB  },
+       {  14, "H43",    &hvga_h43,     0, 0, LCD_RGB  },
+       {  19, "P43",    &hvga_p43,     0, 0, LCD_RGB  },
+       {   8, "W35",    &qvga_w35,     0, 0, LCD_RGB  },
+       {  28, "X710",   &wsvga_x710,   0, 1, LCD_RGB  },
+       {  31, "S430",   &wvga_s430,  180, 1, LCD_RGB  },
+       {   4, "W50",    &wvga_w50,     0, 0, LCD_RGB  },
+
+       /* TODO: Testing */
+       {  15, "W101",   &wsvga_w101,   0, 1, LCD_RGB  },
+       {   5, "L80",    &vga_l80,      0, 1, LCD_RGB  },
+       {  -1, "A97",    &xga_a97,      0, 0, LCD_RGB  },
+       {  -1, "LQ150",  &xga_lq150,    0, 1, LCD_RGB  },
+       {  -1, "BP101",  &wxga_bp101,   0, 1, LCD_RGB  },
+       /* Pls keep it at last */
+       { 128, "HDMI",   &hdmi_def,     0, 0, LCD_HDMI },
+};
+
+static int lcd_idx = 0;
+
+int bd_setup_lcd_by_id(int id)
+{
+       int i;
+
+       for (i = 0; i < ARRAY_SIZE(bd_lcd_config); i++) {
+               if (bd_lcd_config[i].id == id) {
+                       lcd_idx = i;
+                       break;
+               }
+       }
+
+       if (i >= ARRAY_SIZE(bd_lcd_config)) {
+               /* NOT found */
+               return -19;
+       }
+
+       return bd_lcd_config[i].id;
+}
+
+int bd_setup_lcd_by_name(char *str)
+{
+       char *delim;
+       int i;
+
+       delim = strchr(str, ',');
+       if (delim)
+               *delim++ = '\0';
+
+       if (!strncasecmp("HDMI", str, 4)) {
+               struct hdmi_config *cfg = &bd_hdmi_config[0];
+               struct nxp_lcd *lcd;
+
+               lcd_idx = ARRAY_SIZE(bd_lcd_config) - 1;
+               lcd = bd_lcd_config[lcd_idx].lcd;
+
+               for (i = 0; i < ARRAY_SIZE(bd_hdmi_config); i++, cfg++) {
+                       if (!strcasecmp(cfg->name, str)) {
+                               lcd->width = cfg->width;
+                               lcd->height = cfg->height;
+                               bd_lcd_config[lcd_idx].name = cfg->name;
+                               goto __ret;
+                       }
+               }
+       }
+
+       for (i = 0; i < ARRAY_SIZE(bd_lcd_config); i++) {
+               if (!strcasecmp(bd_lcd_config[i].name, str)) {
+                       lcd_idx = i;
+                       break;
+               }
+       }
+
+__ret:
+       return 0;
+}
+
+struct nxp_lcd *bd_get_lcd(void)
+{
+       return bd_lcd_config[lcd_idx].lcd;
+}
+
+const char *bd_get_lcd_name(void)
+{
+       return bd_lcd_config[lcd_idx].name;
+}
+
+enum lcd_format bd_get_lcd_format(void)
+{
+       return bd_lcd_config[lcd_idx].fmt;
+}
+
+int bd_get_lcd_density(void)
+{
+       return bd_lcd_config[lcd_idx].dpi;
+}
+
+#if CONFIG_IS_ENABLED(OF_CONTROL)
+int bd_fixup_lcd_fdt(void *blob, struct nxp_lcd *lcd)
+{
+       return 0;
+}
+#endif
diff --git a/board/friendlyarm/nanopi2/nxp-fb.h 
b/board/friendlyarm/nanopi2/nxp-fb.h
new file mode 100644
index 0000000..d31a03d
--- /dev/null
+++ b/board/friendlyarm/nanopi2/nxp-fb.h
@@ -0,0 +1,94 @@
+/* SPDX-License-Identifier: GPL-2.0+
+ *
+ * Copyright (c) 2017 FriendlyARM (www.arm9.net)
+ *
+ * Copyright (c) 2010 Samsung Electronics Co., Ltd.
+ *              http://www.samsung.com/
+ *
+ * Header file for NXP Display Driver
+ */
+
+#ifndef __MACH_NXP_FB_H__
+#define __MACH_NXP_FB_H__
+
+/*
+ * struct nxp_lcd_polarity
+ * @rise_vclk: if 1, video data is fetched at rising edge
+ * @inv_hsync: if HSYNC polarity is inversed
+ * @inv_vsync: if VSYNC polarity is inversed
+ * @inv_vden:  if VDEN polarity is inversed
+ */
+struct nxp_lcd_polarity {
+       int     rise_vclk;
+       int     inv_hsync;
+       int     inv_vsync;
+       int     inv_vden;
+};
+
+/*
+ * struct nxp_lcd_timing
+ * @h_fp:      horizontal front porch
+ * @h_bp:      horizontal back porch
+ * @h_sw:      horizontal sync width
+ * @v_fp:      vertical front porch
+ * @v_fpe:     vertical front porch for even field
+ * @v_bp:      vertical back porch
+ * @v_bpe:     vertical back porch for even field
+ */
+struct nxp_lcd_timing {
+       int     h_fp;
+       int     h_bp;
+       int     h_sw;
+       int     v_fp;
+       int     v_fpe;
+       int     v_bp;
+       int     v_bpe;
+       int     v_sw;
+};
+
+/*
+ * struct nxp_lcd
+ * @width:             horizontal resolution
+ * @height:            vertical resolution
+ * @p_width:   width of lcd in mm
+ * @p_height:  height of lcd in mm
+ * @bpp:               bits per pixel
+ * @freq:              vframe frequency
+ * @timing:            timing values
+ * @polarity:  polarity settings
+ * @gpio_init: pointer to GPIO init function
+ *
+ */
+struct nxp_lcd {
+       int     width;
+       int     height;
+       int     p_width;
+       int     p_height;
+       int     bpp;
+       int     freq;
+       struct  nxp_lcd_timing timing;
+       struct  nxp_lcd_polarity polarity;
+       void    (*gpio_init)(void);
+};
+
+/**
+ * Public interfaces
+ */
+enum lcd_format {
+       LCD_VESA        = 0,
+       LCD_JEIDA       = 1,
+       LCD_LOC         = 2,
+
+       LCD_RGB         = 4,
+       LCD_HDMI        = 5,
+};
+
+extern int bd_setup_lcd_by_id(int id);
+extern int bd_setup_lcd_by_name(char *name);
+extern struct nxp_lcd *bd_get_lcd(void);
+extern const char *bd_get_lcd_name(void);
+extern int bd_get_lcd_density(void);
+extern enum lcd_format bd_get_lcd_format(void);
+extern int bd_fixup_lcd_fdt(void *blob, struct nxp_lcd *cfg);
+
+#endif /* __MACH_NXP_FB_H__ */
diff --git a/board/friendlyarm/nanopi2/onewire.c 
b/board/friendlyarm/nanopi2/onewire.c
new file mode 100644
index 0000000..2e8f380
--- /dev/null
+++ b/board/friendlyarm/nanopi2/onewire.c
@@ -0,0 +1,309 @@
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * Copyright (C) Guangzhou FriendlyARM Computer Tech. Co., Ltd.
+ * (http://www.friendlyarm.com)
+ */
+
+#include <config.h>
+#include <common.h>
+#include <errno.h>
+#include <asm/io.h>
+#include <asm/arch/clk.h>
+#include <i2c.h>
+#ifdef CONFIG_PWM_NX
+#include <pwm.h>
+#endif
+
+#include <irq_func.h>
+
+#include <asm/arch/nexell.h>
+#include <asm/arch/nx_gpio.h>
+
+#ifndef NSEC_PER_SEC
+#define NSEC_PER_SEC   1000000000L
+#endif
+
+#define SAMPLE_BPS             9600
+#define SAMPLE_IN_US   101             /* (1000000 / BPS) */
+
+#define REQ_INFO               0x60U
+#define REQ_BL                 0x80U
+
+#define BUS_I2C                        0x18
+#define ONEWIRE_I2C_BUS                2
+#define ONEWIRE_I2C_ADDR       0x2f
+
+static int bus_type = -1;
+static int lcd_id = -1;
+static unsigned short lcd_fwrev = 0;
+static int current_brightness = -1;
+#ifdef CONFIG_DM_I2C
+static struct udevice *i2c_dev;
+#endif
+
+/* debug */
+#if (0)
+#define DBGOUT(msg...) do { printf("onewire: " msg); } while (0)
+#else
+#define DBGOUT(msg...) do {} while (0)
+#endif
+
+/* based on web page from http://lfh1986.blogspot.com */
+static unsigned char crc8_ow(unsigned int v, unsigned int len)
+{
+       unsigned char crc = 0xACU;
+
+       while (len--) {
+               if ((crc & 0x80U) != 0) {
+                       crc <<= 1;
+                       crc ^= 0x7U;
+               } else {
+                       crc <<= 1;
+               }
+               if ((v & (1U << 31)) != 0)
+                       crc ^= 0x7U;
+               v <<= 1;
+       }
+       return crc;
+}
+
+/* GPIO helpers */
+#define __IO_GRP               2       /* GPIOC15 */
+#define __IO_IDX               15
+
+static inline void set_pin_as_input(void)
+{
+       nx_gpio_set_output_enable(__IO_GRP, __IO_IDX, 0);
+}
+
+static inline void set_pin_as_output(void)
+{
+       nx_gpio_set_output_enable(__IO_GRP, __IO_IDX, 1);
+}
+
+static inline void set_pin_value(int v)
+{
+       nx_gpio_set_output_value(__IO_GRP, __IO_IDX, !!v);
+}
+
+static inline int get_pin_value(void)
+{
+       return nx_gpio_get_input_value(__IO_GRP, __IO_IDX);
+}
+
+/* Timer helpers */
+#define PWM_CH                         3
+#define PWM_TCON                       (PHY_BASEADDR_PWM + 0x08)
+#define PWM_TCON_START         (1 << 16)
+#define PWM_TINT_CSTAT         (PHY_BASEADDR_PWM + 0x44)
+
+static int onewire_init_timer(void)
+{
+       int period_ns = NSEC_PER_SEC / SAMPLE_BPS;
+
+       /* range: 1080~1970 */
+       period_ns -= 1525;
+
+       return pwm_config(PWM_CH, period_ns >> 1, period_ns);
+}
+
+static void wait_one_tick(void)
+{
+       unsigned int tcon;
+
+       tcon = readl(PWM_TCON);
+       tcon |= PWM_TCON_START;
+       writel(tcon, PWM_TCON);
+
+       while (1) {
+               if (readl(PWM_TINT_CSTAT) & (1 << (5 + PWM_CH)))
+                       break;
+       }
+
+       writel((1 << (5 + PWM_CH)), PWM_TINT_CSTAT);
+
+       tcon &= ~PWM_TCON_START;
+       writel(tcon, PWM_TCON);
+}
+
+/* Session handler */
+static int onewire_session(unsigned char req, unsigned char res[])
+{
+       unsigned int Req;
+       unsigned int *Res;
+       int ints = disable_interrupts();
+       int i;
+       int ret;
+
+       Req = (req << 24) | (crc8_ow(req << 24, 8) << 16);
+       Res = (unsigned int *)res;
+
+       set_pin_value(1);
+       set_pin_as_output();
+       for (i = 0; i < 60; i++)
+               wait_one_tick();
+
+       set_pin_value(0);
+       for (i = 0; i < 2; i++)
+               wait_one_tick();
+
+       for (i = 0; i < 16; i++) {
+               int v = !!(Req & (1U << 31));
+
+               Req <<= 1;
+               set_pin_value(v);
+               wait_one_tick();
+       }
+
+       wait_one_tick();
+       set_pin_as_input();
+       wait_one_tick();
+       for (i = 0; i < 32; i++) {
+               (*Res) <<= 1;
+               (*Res) |= get_pin_value();
+               wait_one_tick();
+       }
+       set_pin_value(1);
+       set_pin_as_output();
+
+       if (ints)
+               enable_interrupts();
+
+       ret = crc8_ow(*Res, 24) == res[0];
+       DBGOUT("req = %02X, res = %02X%02X%02X%02X, ret = %d\n",
+              req, res[3], res[2], res[1], res[0], ret);
+
+       return ret;
+}
+
+static int onewire_i2c_do_request(unsigned char req, unsigned char *buf)
+{
+       unsigned char tx[4];
+       int ret;
+
+       tx[0] = req;
+       tx[1] = crc8_ow(req << 24, 8);
+
+#ifdef CONFIG_DM_I2C
+       if (dm_i2c_write(i2c_dev, 0, tx, 2))
+               return -EIO;
+
+       if (!buf)
+               return 0;
+
+       if (dm_i2c_read(i2c_dev, 0, buf, 4))
+               return -EIO;
+#else
+       if (i2c_write(ONEWIRE_I2C_ADDR, 0, 0, tx, 2))
+               return -EIO;
+
+       if (!buf) /* NO READ */
+               return 0;
+
+       if (i2c_read(ONEWIRE_I2C_ADDR, 0, 0, buf, 4))
+               return -EIO;
+#endif
+
+       ret = crc8_ow((buf[0] << 24) | (buf[1] << 16) | (buf[2] << 8), 24);
+       DBGOUT("req = %02X, res = %02X%02X%02X%02X, ret = %02x\n",
+              req, buf[0], buf[1], buf[2], buf[3], ret);
+
+       return (ret == buf[3]) ? 0 : -EIO;
+}
+
+static void onewire_i2c_init(void)
+{
+       unsigned char buf[4];
+       int ret;
+
+#ifdef CONFIG_DM_I2C
+       ret = i2c_get_chip_for_busnum(ONEWIRE_I2C_BUS,
+                                     ONEWIRE_I2C_ADDR, 0, &i2c_dev);
+#else
+       i2c_init(CONFIG_SYS_I2C_SPEED, CONFIG_SYS_I2C_SLAVE);
+       i2c_set_bus_num(ONEWIRE_I2C_BUS);
+
+       ret = i2c_probe(ONEWIRE_I2C_ADDR);
+#endif
+       if (ret)
+               return;
+
+       ret = onewire_i2c_do_request(REQ_INFO, buf);
+       if (!ret) {
+               lcd_id = buf[0];
+               lcd_fwrev = buf[1] * 0x100 + buf[2];
+               bus_type = BUS_I2C;
+       }
+}
+
+void onewire_init(void)
+{
+       /* GPIO, Pull-off */
+       nx_gpio_set_pad_function(__IO_GRP, __IO_IDX, 1);
+       nx_gpio_set_pull_mode(__IO_GRP, __IO_IDX, 2);
+
+       onewire_init_timer();
+       onewire_i2c_init();
+}
+
+int onewire_get_info(unsigned char *lcd, unsigned short *fw_ver)
+{
+       unsigned char res[4];
+       int i;
+
+       if (bus_type == BUS_I2C && lcd_id > 0) {
+               *lcd = lcd_id;
+               *fw_ver = lcd_fwrev;
+               return 0;
+       }
+
+       for (i = 0; i < 3; i++) {
+               if (onewire_session(REQ_INFO, res)) {
+                       *lcd = res[3];
+                       *fw_ver = res[2] * 0x100 + res[1];
+                       lcd_id = *lcd;
+                       DBGOUT("lcd = %d, fw_ver = %x\n", *lcd, *fw_ver);
+                       return 0;
+               }
+       }
+
+       /* LCD unknown or not connected */
+       *lcd = 0;
+       *fw_ver = -1;
+
+       return -1;
+}
+
+int onewire_get_lcd_id(void)
+{
+       return lcd_id;
+}
+
+int onewire_set_backlight(int brightness)
+{
+       unsigned char res[4];
+       int i;
+
+       if (brightness == current_brightness)
+               return 0;
+
+       if (brightness > 127)
+               brightness = 127;
+       else if (brightness < 0)
+               brightness = 0;
+
+       if (bus_type == BUS_I2C) {
+               onewire_i2c_do_request((REQ_BL | brightness), NULL);
+               current_brightness = brightness;
+               return 0;
+       }
+
+       for (i = 0; i < 3; i++) {
+               if (onewire_session((REQ_BL | brightness), res)) {
+                       current_brightness = brightness;
+                       return 0;
+               }
+       }
+
+       return -1;
+}
diff --git a/board/friendlyarm/nanopi2/onewire.h 
b/board/friendlyarm/nanopi2/onewire.h
new file mode 100644
index 0000000..9f6d7cf
--- /dev/null
+++ b/board/friendlyarm/nanopi2/onewire.h
@@ -0,0 +1,15 @@
+/* SPDX-License-Identifier: GPL-2.0+
+ *
+ * Copyright (C) Guangzhou FriendlyARM Computer Tech. Co., Ltd.
+ * (http://www.friendlyarm.com)
+ */
+
+#ifndef __ONE_WIRE_H__
+#define __ONE_WIRE_H__
+
+extern void onewire_init(void);
+extern int  onewire_get_info(unsigned char *lcd, unsigned short *fw_ver);
+extern int  onewire_get_lcd_id(void);
+extern int  onewire_set_backlight(int brightness);
+
+#endif /* __ONE_WIRE_H__ */
-- 
1.9.1

Reply via email to