diff --git a/layers/meta-balena b/layers/meta-balena
index f2295d2b9..9d7e6d1d6 160000
--- a/layers/meta-balena
+++ b/layers/meta-balena
@@ -1 +1 @@
-Subproject commit f2295d2b9fc9b8993b7264a5144a7051184ee61c
+Subproject commit 9d7e6d1d64ab2b1c5a9aef0d721534688d00191c
diff --git a/layers/meta-balena-nanopc-t4/conf/layer.conf b/layers/meta-balena-nanopc-t4/conf/layer.conf
index 959450cd5..c54181f76 100644
--- a/layers/meta-balena-nanopc-t4/conf/layer.conf
+++ b/layers/meta-balena-nanopc-t4/conf/layer.conf
@@ -7,4 +7,6 @@ BBFILE_COLLECTIONS += "balena-nanopc-t4"
 BBFILE_PATTERN_balena-nanopc-t4 := "^${LAYERDIR}/"
 BBFILE_PRIORITY_balena-nanopc-t4 = "1337"
 
+BBMASK += "/meta-nanopc-t4/recipes-bsp/u-boot/u-boot-rockchip.bb"
+
 LAYERSERIES_COMPAT_balena-nanopc-t4 = "thud"
diff --git a/layers/meta-balena-nanopc-t4/conf/machine/lec-px30.conf b/layers/meta-balena-nanopc-t4/conf/machine/lec-px30.conf
new file mode 100644
index 000000000..8fa59b769
--- /dev/null
+++ b/layers/meta-balena-nanopc-t4/conf/machine/lec-px30.conf
@@ -0,0 +1,24 @@
+#@TYPE: Machine
+#@NAME: ADLINK LEC-PX30
+#@SOC: Rockchip PX30
+#@DESCRIPTION: Machine configuration for ADLINK LEC-PX30
+
+require conf/machine/include/arm/arch-armv8.inc
+require conf/machine/include/soc-family.inc
+# require conf/machine/include/px30.inc
+
+PREFERRED_PROVIDER_virtual/bootloader = "u-boot-rockchip"
+PREFERRED_PROVIDER_virtual/kernel = "linux-rockchip"
+PREFERRED_VERSION_linux-rockchip = "4.4.185%"
+
+UBOOT_MACHINE = "evb-px30_defconfig"
+
+KERNEL_IMAGETYPE = "Image"
+
+SERIAL_CONSOLES = "1500000;ttyFIQ0"
+
+#KBUILD_DEFCONFIG = "lec-px30_config"
+
+KERNEL_DEVICETREE = "rockchip/px30-evb-ddr3-v10-linux.dtb"
+
+MACHINE_ESSENTIAL_EXTRA_RDEPENDS += "kernel-devicetree rkbin-wifi"
diff --git a/layers/meta-balena-nanopc-t4/conf/machine/smarc-px30.conf b/layers/meta-balena-nanopc-t4/conf/machine/smarc-px30.conf
new file mode 100644
index 000000000..eefdbeb81
--- /dev/null
+++ b/layers/meta-balena-nanopc-t4/conf/machine/smarc-px30.conf
@@ -0,0 +1,6 @@
+#@TYPE: Machine
+##@NAME: smarc-px30
+##@DESCRIPTION: Machine configuration for the I-Pi SMARC PX30
+
+MACHINEOVERRIDES = "lec-px30:${MACHINE}"
+include conf/machine/lec-px30.conf
diff --git a/layers/meta-balena-nanopc-t4/conf/samples/local.conf.sample b/layers/meta-balena-nanopc-t4/conf/samples/local.conf.sample
index fca7f601e..779b08283 100644
--- a/layers/meta-balena-nanopc-t4/conf/samples/local.conf.sample
+++ b/layers/meta-balena-nanopc-t4/conf/samples/local.conf.sample
@@ -1,6 +1,6 @@
 # Supported machines
 #MACHINE ?= "nanopc-t4"
-
+#MACHINE ?= "lec-px30"
 BALENA_STORAGE = "overlay2"
 
 # More info meta-resin/README.md
diff --git a/layers/meta-balena-nanopc-t4/recipes-bsp/rkbin/files/PX30TRUST.ini b/layers/meta-balena-nanopc-t4/recipes-bsp/rkbin/files/PX30TRUST.ini
new file mode 100644
index 000000000..f6cfc2ec1
--- /dev/null
+++ b/layers/meta-balena-nanopc-t4/recipes-bsp/rkbin/files/PX30TRUST.ini
@@ -0,0 +1,15 @@
+[VERSION]
+MAJOR=1
+MINOR=0
+[BL30_OPTION]
+SEC=0
+[BL31_OPTION]
+SEC=1
+PATH=rk33/px30_bl31_v1.14.elf
+ADDR=0x00040000
+[BL32_OPTION]
+SEC=0
+[BL33_OPTION]
+SEC=0
+[OUTPUT]
+PATH=trust.img
diff --git a/layers/meta-balena-nanopc-t4/recipes-bsp/rkbin/rkbin_git.bbappend b/layers/meta-balena-nanopc-t4/recipes-bsp/rkbin/rkbin_git.bbappend
new file mode 100644
index 000000000..ac6d69d57
--- /dev/null
+++ b/layers/meta-balena-nanopc-t4/recipes-bsp/rkbin/rkbin_git.bbappend
@@ -0,0 +1,15 @@
+FILESEXTRAPATHS_append := ":${THISDIR}/files"
+
+SRC_URI_append_lec-px30 = " \
+    file://PX30TRUST.ini \
+"
+
+do_compile_lec-px30() {
+    cp ${WORKDIR}/PX30TRUST.ini .
+    tools/trust_merger PX30TRUST.ini
+}
+
+do_deploy_append_lec-px30 () {
+    install -m 755 ${S}/rk33/px30_ddr_333MHz_v1.10.bin ${DEPLOYDIR}/rkbin
+    install -m 755 ${S}/rk33/px30_miniloader_v1.15.bin ${DEPLOYDIR}/rkbin
+}
diff --git a/layers/meta-balena-nanopc-t4/recipes-bsp/u-boot/files/0000-rockchip-add-support-for-px30.patch b/layers/meta-balena-nanopc-t4/recipes-bsp/u-boot/files/0000-rockchip-add-support-for-px30.patch
new file mode 100644
index 000000000..4624da2e0
--- /dev/null
+++ b/layers/meta-balena-nanopc-t4/recipes-bsp/u-boot/files/0000-rockchip-add-support-for-px30.patch
@@ -0,0 +1,10395 @@
+From patchwork Thu Oct 24 23:27:52 2019
+Content-Type: text/plain; charset="utf-8"
+MIME-Version: 1.0
+Content-Transfer-Encoding: 7bit
+X-Patchwork-Submitter: =?utf-8?q?Heiko_St=C3=BCbner?= <heiko@sntech.de>
+X-Patchwork-Id: 1183652
+X-Patchwork-Delegate: ykai007@gmail.com
+Return-Path: <u-boot-bounces@lists.denx.de>
+X-Original-To: incoming@patchwork.ozlabs.org
+Delivered-To: patchwork-incoming@bilbo.ozlabs.org
+Authentication-Results: ozlabs.org;
+ spf=none (no SPF record) smtp.mailfrom=lists.denx.de
+ (client-ip=81.169.180.215; helo=lists.denx.de;
+ envelope-from=u-boot-bounces@lists.denx.de;
+ receiver=<UNKNOWN>)
+Authentication-Results: ozlabs.org;
+ dmarc=none (p=none dis=none) header.from=sntech.de
+Received: from lists.denx.de (dione.denx.de [81.169.180.215])
+ by ozlabs.org (Postfix) with ESMTP id 46zk2Q1bSKz9sPL
+ for <incoming@patchwork.ozlabs.org>;
+ Fri, 25 Oct 2019 10:28:28 +1100 (AEDT)
+Received: by lists.denx.de (Postfix, from userid 105)
+ id 14E82C21E47; Thu, 24 Oct 2019 23:28:20 +0000 (UTC)
+X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on lists.denx.de
+X-Spam-Level: 
+X-Spam-Status: No, score=0.0 required=5.0 tests=none autolearn=unavailable
+ autolearn_force=no version=3.4.0
+Received: from lists.denx.de (localhost [IPv6:::1])
+ by lists.denx.de (Postfix) with ESMTP id B39C3C21DA1;
+ Thu, 24 Oct 2019 23:28:18 +0000 (UTC)
+Received: by lists.denx.de (Postfix, from userid 105)
+ id C2FBCC21DB5; Thu, 24 Oct 2019 23:28:17 +0000 (UTC)
+Received: from gloria.sntech.de (gloria.sntech.de [185.11.138.130])
+ by lists.denx.de (Postfix) with ESMTPS id 659DAC21D9A
+ for <u-boot@lists.denx.de>; Thu, 24 Oct 2019 23:28:17 +0000 (UTC)
+Received: from ip5f5a6266.dynamic.kabel-deutschland.de ([95.90.98.102]
+ helo=phil.fritz.box) by gloria.sntech.de with esmtpsa
+ (TLS1.2:ECDHE_RSA_AES_128_GCM_SHA256:128)
+ (Exim 4.89) (envelope-from <heiko@sntech.de>)
+ id 1iNmWd-0002cR-9G; Fri, 25 Oct 2019 01:28:15 +0200
+From: Heiko Stuebner <heiko@sntech.de>
+To: u-boot@lists.denx.de
+Date: Fri, 25 Oct 2019 01:27:52 +0200
+Message-Id: <20191024232803.10338-2-heiko@sntech.de>
+X-Mailer: git-send-email 2.23.0
+In-Reply-To: <20191024232803.10338-1-heiko@sntech.de>
+References: <20191024232803.10338-1-heiko@sntech.de>
+MIME-Version: 1.0
+Cc: Heiko Stuebner <heiko.stuebner@theobroma-systems.com>,
+ joe.hershberger@ni.com, christoph.muellner@theobroma-systems.com
+Subject: [U-Boot] [PATCH 01/12] spl: separate SPL_FRAMEWORK config for spl
+ and tpl
+X-BeenThere: u-boot@lists.denx.de
+X-Mailman-Version: 2.1.18
+Precedence: list
+List-Id: U-Boot discussion <u-boot.lists.denx.de>
+List-Unsubscribe: <https://lists.denx.de/options/u-boot>,
+ <mailto:u-boot-request@lists.denx.de?subject=unsubscribe>
+List-Archive: <http://lists.denx.de/pipermail/u-boot/>
+List-Post: <mailto:u-boot@lists.denx.de>
+List-Help: <mailto:u-boot-request@lists.denx.de?subject=help>
+List-Subscribe: <https://lists.denx.de/listinfo/u-boot>,
+ <mailto:u-boot-request@lists.denx.de?subject=subscribe>
+Errors-To: u-boot-bounces@lists.denx.de
+Sender: "U-Boot" <u-boot-bounces@lists.denx.de>
+
+From: Heiko Stuebner <heiko.stuebner@theobroma-systems.com>
+
+Right now enabling SPL_FRAMEWORK will also enable it for the TPL in all
+cases, making the TPL bigger. There may be cases where the TPL is really
+size constrained due to its underlying ram size.
+
+Therefore introduce a new TPL_FRAMEWORK option and make the relevant
+conditionals check for both. The default is set to "y if SPL_FRAMEWORK"
+to mimic the previous behaviour where the TPL would always get the
+SPL framework if it was enabled in SPL.
+
+Signed-off-by: Heiko Stuebner <heiko.stuebner@theobroma-systems.com>
+---
+ arch/arm/lib/Makefile     | 2 +-
+ arch/arm/lib/crt0.S       | 2 +-
+ arch/arm/lib/crt0_64.S    | 2 ++
+ arch/powerpc/lib/Makefile | 2 +-
+ common/spl/Kconfig        | 8 ++++++++
+ common/spl/Makefile       | 2 +-
+ scripts/Makefile.spl      | 4 ++++
+ 7 files changed, 18 insertions(+), 4 deletions(-)
+
+diff --git a/arch/arm/lib/Makefile b/arch/arm/lib/Makefile
+index 48ee6c3c60..9de9a9acee 100644
+--- a/arch/arm/lib/Makefile
++++ b/arch/arm/lib/Makefile
+@@ -35,7 +35,7 @@ obj-$(CONFIG_CMD_BOOTM) += bootm.o
+ obj-$(CONFIG_CMD_BOOTZ) += bootm.o zimage.o
+ obj-$(CONFIG_SYS_L2_PL310) += cache-pl310.o
+ else
+-obj-$(CONFIG_SPL_FRAMEWORK) += spl.o
++obj-$(CONFIG_$(SPL_TPL_)FRAMEWORK) += spl.o
+ obj-$(CONFIG_SPL_FRAMEWORK) += zimage.o
+ obj-$(CONFIG_OF_LIBFDT) += bootm-fdt.o
+ endif
+diff --git a/arch/arm/lib/crt0.S b/arch/arm/lib/crt0.S
+index c74641dcd9..fb6c37cf51 100644
+--- a/arch/arm/lib/crt0.S
++++ b/arch/arm/lib/crt0.S
+@@ -149,7 +149,7 @@ here:
+ 
+ 	bl	c_runtime_cpu_setup	/* we still call old routine here */
+ #endif
+-#if !defined(CONFIG_SPL_BUILD) || defined(CONFIG_SPL_FRAMEWORK)
++#if !defined(CONFIG_SPL_BUILD) || CONFIG_IS_ENABLED(FRAMEWORK)
+ 
+ #if !defined(CONFIG_SPL_EARLY_BSS)
+ 	SPL_CLEAR_BSS
+diff --git a/arch/arm/lib/crt0_64.S b/arch/arm/lib/crt0_64.S
+index e76b25a03e..04afa518ac 100644
+--- a/arch/arm/lib/crt0_64.S
++++ b/arch/arm/lib/crt0_64.S
+@@ -120,6 +120,7 @@ relocation_return:
+  */
+ 	bl	c_runtime_cpu_setup		/* still call old routine */
+ #endif /* !CONFIG_SPL_BUILD */
++#if !defined(CONFIG_SPL_BUILD) || CONFIG_IS_ENABLED(FRAMEWORK)
+ #if defined(CONFIG_SPL_BUILD)
+ 	bl	spl_relocate_stack_gd           /* may return NULL */
+ 	/* set up gd here, outside any C code, if new stack is returned */
+@@ -152,5 +153,6 @@ clear_loop:
+ 	b	board_init_r			/* PC relative jump */
+ 
+ 	/* NOTREACHED - board_init_r() does not return */
++#endif
+ 
+ ENDPROC(_main)
+diff --git a/arch/powerpc/lib/Makefile b/arch/powerpc/lib/Makefile
+index 8ac49bdd06..01c9dd51be 100644
+--- a/arch/powerpc/lib/Makefile
++++ b/arch/powerpc/lib/Makefile
+@@ -41,5 +41,5 @@ obj-y	+= time.o
+ endif # not minimal
+ 
+ ifdef CONFIG_SPL_BUILD
+-obj-$(CONFIG_SPL_FRAMEWORK) += spl.o
++obj-$(CONFIG_$(SPL_TPL)_FRAMEWORK) += spl.o
+ endif
+diff --git a/common/spl/Kconfig b/common/spl/Kconfig
+index f467eca2be..4d5c4ddc46 100644
+--- a/common/spl/Kconfig
++++ b/common/spl/Kconfig
+@@ -1183,6 +1183,14 @@ config TPL
+ 
+ if TPL
+ 
++config TPL_FRAMEWORK
++	bool "Support TPL based upon the common SPL framework"
++	default y if SPL_FRAMEWORK
++	help
++	  Enable the SPL framework under common/spl/ for TPL builds.
++	  This framework supports MMC, NAND and YMODEM and other methods
++	  loading of U-Boot's SPL stage. If unsure, say Y.
++
+ config TPL_HANDOFF
+ 	bool "Pass hand-off information from TPL to SPL and U-Boot proper"
+ 	depends on HANDOFF
+diff --git a/common/spl/Makefile b/common/spl/Makefile
+index 5ce6f4ae48..eaa57f5ce5 100644
+--- a/common/spl/Makefile
++++ b/common/spl/Makefile
+@@ -7,7 +7,7 @@
+ #
+ 
+ ifdef CONFIG_SPL_BUILD
+-obj-$(CONFIG_SPL_FRAMEWORK) += spl.o
++obj-$(CONFIG_$(SPL_TPL_)FRAMEWORK) += spl.o
+ obj-$(CONFIG_$(SPL_TPL_)BOOTROM_SUPPORT) += spl_bootrom.o
+ obj-$(CONFIG_$(SPL_TPL_)LOAD_FIT) += spl_fit.o
+ obj-$(CONFIG_$(SPL_TPL_)NOR_SUPPORT) += spl_nor.o
+diff --git a/scripts/Makefile.spl b/scripts/Makefile.spl
+index 7af6b120b6..090c831710 100644
+--- a/scripts/Makefile.spl
++++ b/scripts/Makefile.spl
+@@ -71,7 +71,11 @@ HAVE_VENDOR_COMMON_LIB = $(if $(wildcard $(srctree)/board/$(VENDOR)/common/Makef
+ libs-y += $(if $(BOARDDIR),board/$(BOARDDIR)/)
+ libs-$(HAVE_VENDOR_COMMON_LIB) += board/$(VENDOR)/common/
+ 
++ifeq ($(CONFIG_TPL_BUILD),y)
++libs-$(CONFIG_TPL_FRAMEWORK) += common/spl/
++else
+ libs-$(CONFIG_SPL_FRAMEWORK) += common/spl/
++endif
+ libs-y += common/init/
+ 
+ # Special handling for a few options which support SPL/TPL
+
+From patchwork Thu Oct 24 23:27:53 2019
+Content-Type: text/plain; charset="utf-8"
+MIME-Version: 1.0
+Content-Transfer-Encoding: 7bit
+X-Patchwork-Submitter: =?utf-8?q?Heiko_St=C3=BCbner?= <heiko@sntech.de>
+X-Patchwork-Id: 1183654
+X-Patchwork-Delegate: ykai007@gmail.com
+Return-Path: <u-boot-bounces@lists.denx.de>
+X-Original-To: incoming@patchwork.ozlabs.org
+Delivered-To: patchwork-incoming@bilbo.ozlabs.org
+Authentication-Results: ozlabs.org;
+ spf=none (no SPF record) smtp.mailfrom=lists.denx.de
+ (client-ip=81.169.180.215; helo=lists.denx.de;
+ envelope-from=u-boot-bounces@lists.denx.de;
+ receiver=<UNKNOWN>)
+Authentication-Results: ozlabs.org;
+ dmarc=none (p=none dis=none) header.from=sntech.de
+Received: from lists.denx.de (dione.denx.de [81.169.180.215])
+ by ozlabs.org (Postfix) with ESMTP id 46zk3w75Tkz9sPL
+ for <incoming@patchwork.ozlabs.org>;
+ Fri, 25 Oct 2019 10:29:48 +1100 (AEDT)
+Received: by lists.denx.de (Postfix, from userid 105)
+ id 9D54FC21DE8; Thu, 24 Oct 2019 23:29:18 +0000 (UTC)
+X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on lists.denx.de
+X-Spam-Level: 
+X-Spam-Status: No, score=0.0 required=5.0 tests=none autolearn=unavailable
+ autolearn_force=no version=3.4.0
+Received: from lists.denx.de (localhost [IPv6:::1])
+ by lists.denx.de (Postfix) with ESMTP id 0186FC21E34;
+ Thu, 24 Oct 2019 23:28:21 +0000 (UTC)
+Received: by lists.denx.de (Postfix, from userid 105)
+ id 290B6C21C6A; Thu, 24 Oct 2019 23:28:17 +0000 (UTC)
+Received: from gloria.sntech.de (gloria.sntech.de [185.11.138.130])
+ by lists.denx.de (Postfix) with ESMTPS id 629A5C21D8A
+ for <u-boot@lists.denx.de>; Thu, 24 Oct 2019 23:28:17 +0000 (UTC)
+Received: from ip5f5a6266.dynamic.kabel-deutschland.de ([95.90.98.102]
+ helo=phil.fritz.box) by gloria.sntech.de with esmtpsa
+ (TLS1.2:ECDHE_RSA_AES_128_GCM_SHA256:128)
+ (Exim 4.89) (envelope-from <heiko@sntech.de>)
+ id 1iNmWd-0002cR-MF; Fri, 25 Oct 2019 01:28:15 +0200
+From: Heiko Stuebner <heiko@sntech.de>
+To: u-boot@lists.denx.de
+Date: Fri, 25 Oct 2019 01:27:53 +0200
+Message-Id: <20191024232803.10338-3-heiko@sntech.de>
+X-Mailer: git-send-email 2.23.0
+In-Reply-To: <20191024232803.10338-1-heiko@sntech.de>
+References: <20191024232803.10338-1-heiko@sntech.de>
+MIME-Version: 1.0
+Cc: Heiko Stuebner <heiko.stuebner@theobroma-systems.com>,
+ joe.hershberger@ni.com, christoph.muellner@theobroma-systems.com
+Subject: [U-Boot] [PATCH 02/12] rockchip: add core px30 headers
+X-BeenThere: u-boot@lists.denx.de
+X-Mailman-Version: 2.1.18
+Precedence: list
+List-Id: U-Boot discussion <u-boot.lists.denx.de>
+List-Unsubscribe: <https://lists.denx.de/options/u-boot>,
+ <mailto:u-boot-request@lists.denx.de?subject=unsubscribe>
+List-Archive: <http://lists.denx.de/pipermail/u-boot/>
+List-Post: <mailto:u-boot@lists.denx.de>
+List-Help: <mailto:u-boot-request@lists.denx.de?subject=help>
+List-Subscribe: <https://lists.denx.de/listinfo/u-boot>,
+ <mailto:u-boot-request@lists.denx.de?subject=subscribe>
+Errors-To: u-boot-bounces@lists.denx.de
+Sender: "U-Boot" <u-boot-bounces@lists.denx.de>
+
+Add headers needed by the upcoming px30 support, including two
+new dt-binding headers taken from the Linux kernel.
+
+Signed-off-by: Heiko Stuebner <heiko.stuebner@theobroma-systems.com>
+---
+ arch/arm/include/asm/arch-rockchip/grf_px30.h | 144 ++++++++++++++++++
+ include/configs/px30_common.h                 |  62 ++++++++
+ include/dt-bindings/power/px30-power.h        |  27 ++++
+ include/dt-bindings/soc/rockchip,boot-mode.h  |  16 ++
+ 4 files changed, 249 insertions(+)
+ create mode 100644 arch/arm/include/asm/arch-rockchip/grf_px30.h
+ create mode 100644 include/configs/px30_common.h
+ create mode 100644 include/dt-bindings/power/px30-power.h
+ create mode 100644 include/dt-bindings/soc/rockchip,boot-mode.h
+
+diff --git a/arch/arm/include/asm/arch-rockchip/grf_px30.h b/arch/arm/include/asm/arch-rockchip/grf_px30.h
+new file mode 100644
+index 0000000000..c167bb42fa
+--- /dev/null
++++ b/arch/arm/include/asm/arch-rockchip/grf_px30.h
+@@ -0,0 +1,144 @@
++/* SPDX-License-Identifier: GPL-2.0+ */
++/*
++ * (C) Copyright 2017 Rockchip Electronics Co., Ltd.
++ */
++#ifndef _ASM_ARCH_GRF_px30_H
++#define _ASM_ARCH_GRF_px30_H
++
++#include <common.h>
++
++struct px30_grf {
++	unsigned int gpio1al_iomux;
++	unsigned int gpio1ah_iomux;
++	unsigned int gpio1bl_iomux;
++	unsigned int gpio1bh_iomux;
++	unsigned int gpio1cl_iomux;
++	unsigned int gpio1ch_iomux;
++	unsigned int gpio1dl_iomux;
++	unsigned int gpio1dh_iomux;
++
++	unsigned int gpio2al_iomux;
++	unsigned int gpio2ah_iomux;
++	unsigned int gpio2bl_iomux;
++	unsigned int gpio2bh_iomux;
++	unsigned int gpio2cl_iomux;
++	unsigned int gpio2ch_iomux;
++	unsigned int gpio2dl_iomux;
++	unsigned int gpio2dh_iomux;
++
++	unsigned int gpio3al_iomux;
++	unsigned int gpio3ah_iomux;
++	unsigned int gpio3bl_iomux;
++	unsigned int gpio3bh_iomux;
++	unsigned int gpio3cl_iomux;
++	unsigned int gpio3ch_iomux;
++	unsigned int gpio3dl_iomux;
++	unsigned int gpio3dh_iomux;
++
++	unsigned int gpio1a_p;
++	unsigned int gpio1b_p;
++	unsigned int gpio1c_p;
++	unsigned int gpio1d_p;
++	unsigned int gpio2a_p;
++	unsigned int gpio2b_p;
++	unsigned int gpio2c_p;
++	unsigned int gpio2d_p;
++	unsigned int gpio3a_p;
++	unsigned int gpio3b_p;
++	unsigned int gpio3c_p;
++	unsigned int gpio3d_p;
++	unsigned int gpio1a_sr;
++	unsigned int gpio1b_sr;
++	unsigned int gpio1c_sr;
++	unsigned int gpio1d_sr;
++	unsigned int gpio2a_sr;
++	unsigned int gpio2b_sr;
++	unsigned int gpio2c_sr;
++	unsigned int gpio2d_sr;
++	unsigned int gpio3a_sr;
++	unsigned int gpio3b_sr;
++	unsigned int gpio3c_sr;
++	unsigned int gpio3d_sr;
++	unsigned int gpio1a_smt;
++	unsigned int gpio1b_smt;
++	unsigned int gpio1c_smt;
++	unsigned int gpio1d_smt;
++	unsigned int gpio2a_smt;
++	unsigned int gpio2b_smt;
++	unsigned int gpio2c_smt;
++	unsigned int gpio2d_smt;
++	unsigned int gpio3a_smt;
++	unsigned int gpio3b_smt;
++	unsigned int gpio3c_smt;
++	unsigned int gpio3d_smt;
++	unsigned int gpio1a_e;
++	unsigned int gpio1b_e;
++	unsigned int gpio1c_e;
++	unsigned int gpio1d_e;
++	unsigned int gpio2a_e;
++	unsigned int gpio2b_e;
++	unsigned int gpio2c_e;
++	unsigned int gpio2d_e;
++	unsigned int gpio3a_e;
++	unsigned int gpio3b_e;
++	unsigned int gpio3c_e;
++	unsigned int gpio3d_e;
++
++	unsigned int reserved0[(0x180 - 0x11C) / 4 - 1];
++	unsigned int io_vsel;
++	unsigned int iofunc_con0;
++	unsigned int reserved1[(0x400 - 0x184) / 4 - 1];
++	unsigned int soc_con[6];
++	unsigned int reserved2[(0x480 - 0x414) / 4 - 1];
++	unsigned int soc_status0;
++	unsigned int reserved3[(0x500 - 0x480) / 4 - 1];
++	unsigned int cpu_con[3];
++	unsigned int reserved4[5];
++	unsigned int cpu_status[2];
++	unsigned int reserved5[2];
++	unsigned int soc_noc_con[2];
++	unsigned int reserved6[6];
++	unsigned int ddr_bankhash[4];
++	unsigned int reserved7[(0x700 - 0x55c) / 4 - 1];
++	unsigned int host0_con[2];
++	unsigned int reserved8[(0x880 - 0x704) / 4 - 1];
++	unsigned int otg_con3;
++	unsigned int reserved9[3];
++	unsigned int host0_status4;
++	unsigned int reserved10[(0x904 - 0x890) / 4 - 1];
++	unsigned int mac_con1;
++};
++
++check_member(px30_grf, mac_con1, 0x904);
++
++struct px30_pmugrf {
++	unsigned int gpio0a_e;
++	unsigned int gpio0b_e;
++	unsigned int gpio0c_e;
++	unsigned int gpio0d_e;
++	unsigned int gpio0a_p;
++	unsigned int gpio0b_p;
++	unsigned int gpio0c_p;
++	unsigned int gpio0d_p;
++	unsigned int gpio0al_iomux;
++	unsigned int gpio0bl_iomux;
++	unsigned int gpio0cl_iomux;
++	unsigned int gpio0dl_iomux;
++	unsigned int gpio0l_sr;
++	unsigned int gpio0h_sr;
++	unsigned int gpio0l_smt;
++	unsigned int gpio0h_smt;
++	unsigned int reserved1[(0x100 - 0x3c) / 4 - 1];
++	unsigned int soc_con[4];
++	unsigned int reserved2[(0x180 - 0x10c) / 4 - 1];
++	unsigned int pvtm_con[2];
++	unsigned int reserved3[2];
++	unsigned int pvtm_status[2];
++	unsigned int reserved4[(0x200 - 0x194) / 4 - 1];
++	unsigned int os_reg[12];
++	unsigned int reset_function_status;
++};
++
++check_member(px30_pmugrf, reset_function_status, 0x230);
++
++#endif
+diff --git a/include/configs/px30_common.h b/include/configs/px30_common.h
+new file mode 100644
+index 0000000000..d6c70601dd
+--- /dev/null
++++ b/include/configs/px30_common.h
+@@ -0,0 +1,62 @@
++/* SPDX-License-Identifier: GPL-2.0+ */
++/*
++ * (C) Copyright 2017 Rockchip Electronics Co., Ltd
++ */
++
++#ifndef __CONFIG_PX30_COMMON_H
++#define __CONFIG_PX30_COMMON_H
++
++#include "rockchip-common.h"
++
++#define CONFIG_SYS_CBSIZE		1024
++#define CONFIG_SKIP_LOWLEVEL_INIT
++
++#define CONFIG_SYS_NS16550_MEM32
++
++#define CONFIG_ROCKCHIP_STIMER_BASE	0xff220020
++#define COUNTER_FREQUENCY		24000000
++
++/* FIXME: ff020000 is pmu_mem (10k), while ff0e0000 is regular int_mem */
++#define CONFIG_IRAM_BASE		0xff020000
++
++#define CONFIG_SYS_INIT_SP_ADDR		0x00400000
++#define CONFIG_SYS_LOAD_ADDR		0x00800800
++#define CONFIG_SPL_STACK		0x00400000
++#define CONFIG_SPL_MAX_SIZE		0x20000
++#define CONFIG_SPL_BSS_START_ADDR	0x4000000
++#define CONFIG_SPL_BSS_MAX_SIZE		0x4000
++#define CONFIG_SYS_BOOTM_LEN		(64 << 20)	/* 64M */
++
++#define GICD_BASE			0xff131000
++#define GICC_BASE			0xff132000
++
++#define CONFIG_SYS_BOOTM_LEN	(64 << 20)	/* 64M */
++
++/* MMC/SD IP block */
++//#define CONFIG_BOUNCE_BUFFER
++
++#define CONFIG_SYS_SDRAM_BASE		0
++#define SDRAM_MAX_SIZE			0xff000000
++#define SDRAM_BANK_SIZE			(2UL << 30)
++
++#ifndef CONFIG_SPL_BUILD
++
++#define ENV_MEM_LAYOUT_SETTINGS \
++	"scriptaddr=0x00500000\0" \
++	"pxefile_addr_r=0x00600000\0" \
++	"fdt_addr_r=0x08300000\0" \
++	"kernel_addr_r=0x00280000\0" \
++	"kernel_addr_c=0x03e80000\0" \
++	"ramdisk_addr_r=0x0a200000\0"
++
++#include <config_distro_bootcmd.h>
++#define CONFIG_EXTRA_ENV_SETTINGS \
++	ENV_MEM_LAYOUT_SETTINGS \
++	"fdtfile=" CONFIG_DEFAULT_FDT_FILE "\0" \
++	"partitions=" PARTS_DEFAULT \
++	ROCKCHIP_DEVICE_SETTINGS \
++	BOOTENV
++
++#endif
++
++#endif
+diff --git a/include/dt-bindings/power/px30-power.h b/include/dt-bindings/power/px30-power.h
+new file mode 100644
+index 0000000000..30917a99ad
+--- /dev/null
++++ b/include/dt-bindings/power/px30-power.h
+@@ -0,0 +1,27 @@
++/* SPDX-License-Identifier: GPL-2.0 */
++#ifndef __DT_BINDINGS_POWER_PX30_POWER_H__
++#define __DT_BINDINGS_POWER_PX30_POWER_H__
++
++/* VD_CORE */
++#define PX30_PD_A35_0		0
++#define PX30_PD_A35_1		1
++#define PX30_PD_A35_2		2
++#define PX30_PD_A35_3		3
++#define PX30_PD_SCU		4
++
++/* VD_LOGIC */
++#define PX30_PD_USB		5
++#define PX30_PD_DDR		6
++#define PX30_PD_SDCARD		7
++#define PX30_PD_CRYPTO		8
++#define PX30_PD_GMAC		9
++#define PX30_PD_MMC_NAND	10
++#define PX30_PD_VPU		11
++#define PX30_PD_VO		12
++#define PX30_PD_VI		13
++#define PX30_PD_GPU		14
++
++/* VD_PMU */
++#define PX30_PD_PMU		15
++
++#endif
+diff --git a/include/dt-bindings/soc/rockchip,boot-mode.h b/include/dt-bindings/soc/rockchip,boot-mode.h
+new file mode 100644
+index 0000000000..4b0914c098
+--- /dev/null
++++ b/include/dt-bindings/soc/rockchip,boot-mode.h
+@@ -0,0 +1,16 @@
++/* SPDX-License-Identifier: GPL-2.0 */
++#ifndef __ROCKCHIP_BOOT_MODE_H
++#define __ROCKCHIP_BOOT_MODE_H
++
++/*high 24 bits is tag, low 8 bits is type*/
++#define REBOOT_FLAG		0x5242C300
++/* normal boot */
++#define BOOT_NORMAL		(REBOOT_FLAG + 0)
++/* enter bootloader rockusb mode */
++#define BOOT_BL_DOWNLOAD	(REBOOT_FLAG + 1)
++/* enter recovery */
++#define BOOT_RECOVERY		(REBOOT_FLAG + 3)
++ /* enter fastboot mode */
++#define BOOT_FASTBOOT		(REBOOT_FLAG + 9)
++
++#endif
+
+From patchwork Thu Oct 24 23:27:54 2019
+Content-Type: text/plain; charset="utf-8"
+MIME-Version: 1.0
+Content-Transfer-Encoding: 7bit
+X-Patchwork-Submitter: =?utf-8?q?Heiko_St=C3=BCbner?= <heiko@sntech.de>
+X-Patchwork-Id: 1183653
+X-Patchwork-Delegate: ykai007@gmail.com
+Return-Path: <u-boot-bounces@lists.denx.de>
+X-Original-To: incoming@patchwork.ozlabs.org
+Delivered-To: patchwork-incoming@bilbo.ozlabs.org
+Authentication-Results: ozlabs.org;
+ spf=none (no SPF record) smtp.mailfrom=lists.denx.de
+ (client-ip=81.169.180.215; helo=lists.denx.de;
+ envelope-from=u-boot-bounces@lists.denx.de;
+ receiver=<UNKNOWN>)
+Authentication-Results: ozlabs.org;
+ dmarc=none (p=none dis=none) header.from=sntech.de
+Received: from lists.denx.de (dione.denx.de [81.169.180.215])
+ by ozlabs.org (Postfix) with ESMTP id 46zk3J4RTSz9sQm
+ for <incoming@patchwork.ozlabs.org>;
+ Fri, 25 Oct 2019 10:29:16 +1100 (AEDT)
+Received: by lists.denx.de (Postfix, from userid 105)
+ id 4016FC21D8A; Thu, 24 Oct 2019 23:28:39 +0000 (UTC)
+X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on lists.denx.de
+X-Spam-Level: 
+X-Spam-Status: No, score=0.0 required=5.0 tests=none autolearn=unavailable
+ autolearn_force=no version=3.4.0
+Received: from lists.denx.de (localhost [IPv6:::1])
+ by lists.denx.de (Postfix) with ESMTP id 507BDC21DD9;
+ Thu, 24 Oct 2019 23:28:19 +0000 (UTC)
+Received: by lists.denx.de (Postfix, from userid 105)
+ id CBEBDC21C6A; Thu, 24 Oct 2019 23:28:17 +0000 (UTC)
+Received: from gloria.sntech.de (gloria.sntech.de [185.11.138.130])
+ by lists.denx.de (Postfix) with ESMTPS id 61B44C21C6A
+ for <u-boot@lists.denx.de>; Thu, 24 Oct 2019 23:28:17 +0000 (UTC)
+Received: from ip5f5a6266.dynamic.kabel-deutschland.de ([95.90.98.102]
+ helo=phil.fritz.box) by gloria.sntech.de with esmtpsa
+ (TLS1.2:ECDHE_RSA_AES_128_GCM_SHA256:128)
+ (Exim 4.89) (envelope-from <heiko@sntech.de>)
+ id 1iNmWe-0002cR-38; Fri, 25 Oct 2019 01:28:16 +0200
+From: Heiko Stuebner <heiko@sntech.de>
+To: u-boot@lists.denx.de
+Date: Fri, 25 Oct 2019 01:27:54 +0200
+Message-Id: <20191024232803.10338-4-heiko@sntech.de>
+X-Mailer: git-send-email 2.23.0
+In-Reply-To: <20191024232803.10338-1-heiko@sntech.de>
+References: <20191024232803.10338-1-heiko@sntech.de>
+MIME-Version: 1.0
+Cc: Heiko Stuebner <heiko.stuebner@theobroma-systems.com>,
+ joe.hershberger@ni.com, David Wu <david.wu@rock-chips.com>,
+ christoph.muellner@theobroma-systems.com
+Subject: [U-Boot] [PATCH 03/12] pinctrl: rockchip: add px30 pinctrl driver
+X-BeenThere: u-boot@lists.denx.de
+X-Mailman-Version: 2.1.18
+Precedence: list
+List-Id: U-Boot discussion <u-boot.lists.denx.de>
+List-Unsubscribe: <https://lists.denx.de/options/u-boot>,
+ <mailto:u-boot-request@lists.denx.de?subject=unsubscribe>
+List-Archive: <http://lists.denx.de/pipermail/u-boot/>
+List-Post: <mailto:u-boot@lists.denx.de>
+List-Help: <mailto:u-boot-request@lists.denx.de?subject=help>
+List-Subscribe: <https://lists.denx.de/listinfo/u-boot>,
+ <mailto:u-boot-request@lists.denx.de?subject=subscribe>
+Errors-To: u-boot-bounces@lists.denx.de
+Sender: "U-Boot" <u-boot-bounces@lists.denx.de>
+
+From: David Wu <david.wu@rock-chips.com>
+
+Add the necessary glue code to allow pinctrl setting on px30 socs.
+
+Signed-off-by: David Wu <david.wu@rock-chips.com>
+Signed-off-by: Heiko Stuebner <heiko.stuebner@theobroma-systems.com>
+Reviewed-by: Kever Yang<kever.yang@rock-chips.com>
+---
+ drivers/pinctrl/rockchip/Makefile       |   1 +
+ drivers/pinctrl/rockchip/pinctrl-px30.c | 368 ++++++++++++++++++++++++
+ 2 files changed, 369 insertions(+)
+ create mode 100644 drivers/pinctrl/rockchip/pinctrl-px30.c
+
+diff --git a/drivers/pinctrl/rockchip/Makefile b/drivers/pinctrl/rockchip/Makefile
+index a616d8587f..83913f668f 100644
+--- a/drivers/pinctrl/rockchip/Makefile
++++ b/drivers/pinctrl/rockchip/Makefile
+@@ -3,6 +3,7 @@
+ # Copyright (c) 2017 Rockchip Electronics Co., Ltd
+ 
+ obj-y += pinctrl-rockchip-core.o
++obj-$(CONFIG_ROCKCHIP_PX30) += pinctrl-px30.o
+ obj-$(CONFIG_ROCKCHIP_RK3036) += pinctrl-rk3036.o
+ obj-$(CONFIG_ROCKCHIP_RK3128) += pinctrl-rk3128.o
+ obj-$(CONFIG_ROCKCHIP_RK3188) += pinctrl-rk3188.o
+diff --git a/drivers/pinctrl/rockchip/pinctrl-px30.c b/drivers/pinctrl/rockchip/pinctrl-px30.c
+new file mode 100644
+index 0000000000..bb56ae9fb3
+--- /dev/null
++++ b/drivers/pinctrl/rockchip/pinctrl-px30.c
+@@ -0,0 +1,368 @@
++// SPDX-License-Identifier: GPL-2.0+
++/*
++ * (C) Copyright 2019 Rockchip Electronics Co., Ltd
++ */
++
++#include <common.h>
++#include <dm.h>
++#include <dm/pinctrl.h>
++#include <regmap.h>
++#include <syscon.h>
++
++#include "pinctrl-rockchip.h"
++
++static struct rockchip_mux_route_data px30_mux_route_data[] = {
++	{
++		/* cif-d2m0 */
++		.bank_num = 2,
++		.pin = 0,
++		.func = 1,
++		.route_offset = 0x184,
++		.route_val = BIT(16 + 7),
++	}, {
++		/* cif-d2m1 */
++		.bank_num = 3,
++		.pin = 3,
++		.func = 3,
++		.route_offset = 0x184,
++		.route_val = BIT(16 + 7) | BIT(7),
++	}, {
++		/* pdm-m0 */
++		.bank_num = 3,
++		.pin = 22,
++		.func = 2,
++		.route_offset = 0x184,
++		.route_val = BIT(16 + 8),
++	}, {
++		/* pdm-m1 */
++		.bank_num = 2,
++		.pin = 22,
++		.func = 1,
++		.route_offset = 0x184,
++		.route_val = BIT(16 + 8) | BIT(8),
++	}, {
++		/* uart2-rxm0 */
++		.bank_num = 1,
++		.pin = 27,
++		.func = 2,
++		.route_offset = 0x184,
++		.route_val = BIT(16 + 10),
++	}, {
++		/* uart2-rxm1 */
++		.bank_num = 2,
++		.pin = 14,
++		.func = 2,
++		.route_offset = 0x184,
++		.route_val = BIT(16 + 10) | BIT(10),
++	}, {
++		/* uart3-rxm0 */
++		.bank_num = 0,
++		.pin = 17,
++		.func = 2,
++		.route_offset = 0x184,
++		.route_val = BIT(16 + 9),
++	}, {
++		/* uart3-rxm1 */
++		.bank_num = 1,
++		.pin = 15,
++		.func = 2,
++		.route_offset = 0x184,
++		.route_val = BIT(16 + 9) | BIT(9),
++	},
++};
++
++static int px30_set_mux(struct rockchip_pin_bank *bank, int pin, int mux)
++{
++	struct rockchip_pinctrl_priv *priv = bank->priv;
++	int iomux_num = (pin / 8);
++	struct regmap *regmap;
++	int reg, ret, mask, mux_type;
++	u8 bit;
++	u32 data, route_reg, route_val;
++
++	regmap = (bank->iomux[iomux_num].type & IOMUX_SOURCE_PMU)
++				? priv->regmap_pmu : priv->regmap_base;
++
++	/* get basic quadrupel of mux registers and the correct reg inside */
++	mux_type = bank->iomux[iomux_num].type;
++	reg = bank->iomux[iomux_num].offset;
++	reg += rockchip_get_mux_data(mux_type, pin, &bit, &mask);
++
++	if (bank->route_mask & BIT(pin)) {
++		if (rockchip_get_mux_route(bank, pin, mux, &route_reg,
++					   &route_val)) {
++			ret = regmap_write(regmap, route_reg, route_val);
++			if (ret)
++				return ret;
++		}
++	}
++
++	data = (mask << (bit + 16));
++	data |= (mux & mask) << bit;
++	ret = regmap_write(regmap, reg, data);
++
++	return ret;
++}
++
++#define PX30_PULL_PMU_OFFSET		0x10
++#define PX30_PULL_GRF_OFFSET		0x60
++#define PX30_PULL_BITS_PER_PIN		2
++#define PX30_PULL_PINS_PER_REG		8
++#define PX30_PULL_BANK_STRIDE		16
++
++static void px30_calc_pull_reg_and_bit(struct rockchip_pin_bank *bank,
++				       int pin_num, struct regmap **regmap,
++				       int *reg, u8 *bit)
++{
++	struct rockchip_pinctrl_priv *priv = bank->priv;
++
++	/* The first 32 pins of the first bank are located in PMU */
++	if (bank->bank_num == 0) {
++		*regmap = priv->regmap_pmu;
++		*reg = PX30_PULL_PMU_OFFSET;
++	} else {
++		*regmap = priv->regmap_base;
++		*reg = PX30_PULL_GRF_OFFSET;
++
++		/* correct the offset, as we're starting with the 2nd bank */
++		*reg -= 0x10;
++		*reg += bank->bank_num * PX30_PULL_BANK_STRIDE;
++	}
++
++	*reg += ((pin_num / PX30_PULL_PINS_PER_REG) * 4);
++	*bit = (pin_num % PX30_PULL_PINS_PER_REG);
++	*bit *= PX30_PULL_BITS_PER_PIN;
++}
++
++static int px30_set_pull(struct rockchip_pin_bank *bank,
++			 int pin_num, int pull)
++{
++	struct regmap *regmap;
++	int reg, ret;
++	u8 bit, type;
++	u32 data;
++
++	if (pull == PIN_CONFIG_BIAS_PULL_PIN_DEFAULT)
++		return -ENOTSUPP;
++
++	px30_calc_pull_reg_and_bit(bank, pin_num, &regmap, &reg, &bit);
++	type = bank->pull_type[pin_num / 8];
++	ret = rockchip_translate_pull_value(type, pull);
++	if (ret < 0) {
++		debug("unsupported pull setting %d\n", pull);
++		return ret;
++	}
++
++	/* enable the write to the equivalent lower bits */
++	data = ((1 << ROCKCHIP_PULL_BITS_PER_PIN) - 1) << (bit + 16);
++	data |= (ret << bit);
++	ret = regmap_write(regmap, reg, data);
++
++	return ret;
++}
++
++#define PX30_DRV_PMU_OFFSET		0x20
++#define PX30_DRV_GRF_OFFSET		0xf0
++#define PX30_DRV_BITS_PER_PIN		2
++#define PX30_DRV_PINS_PER_REG		8
++#define PX30_DRV_BANK_STRIDE		16
++
++static void px30_calc_drv_reg_and_bit(struct rockchip_pin_bank *bank,
++				      int pin_num, struct regmap **regmap,
++				      int *reg, u8 *bit)
++{
++	struct rockchip_pinctrl_priv *priv = bank->priv;
++
++	/* The first 32 pins of the first bank are located in PMU */
++	if (bank->bank_num == 0) {
++		*regmap = priv->regmap_pmu;
++		*reg = PX30_DRV_PMU_OFFSET;
++	} else {
++		*regmap = priv->regmap_base;
++		*reg = PX30_DRV_GRF_OFFSET;
++
++		/* correct the offset, as we're starting with the 2nd bank */
++		*reg -= 0x10;
++		*reg += bank->bank_num * PX30_DRV_BANK_STRIDE;
++	}
++
++	*reg += ((pin_num / PX30_DRV_PINS_PER_REG) * 4);
++	*bit = (pin_num % PX30_DRV_PINS_PER_REG);
++	*bit *= PX30_DRV_BITS_PER_PIN;
++}
++
++static int px30_set_drive(struct rockchip_pin_bank *bank,
++			  int pin_num, int strength)
++{
++	struct regmap *regmap;
++	int reg, ret;
++	u32 data, rmask_bits, temp;
++	u8 bit;
++	int drv_type = bank->drv[pin_num / 8].drv_type;
++
++	px30_calc_drv_reg_and_bit(bank, pin_num, &regmap, &reg, &bit);
++	ret = rockchip_translate_drive_value(drv_type, strength);
++	if (ret < 0) {
++		debug("unsupported driver strength %d\n", strength);
++		return ret;
++	}
++
++	switch (drv_type) {
++	case DRV_TYPE_IO_1V8_3V0_AUTO:
++	case DRV_TYPE_IO_3V3_ONLY:
++		rmask_bits = ROCKCHIP_DRV_3BITS_PER_PIN;
++		switch (bit) {
++		case 0 ... 12:
++			/* regular case, nothing to do */
++			break;
++		case 15:
++			/*
++			 * drive-strength offset is special, as it is spread
++			 * over 2 registers, the bit data[15] contains bit 0
++			 * of the value while temp[1:0] contains bits 2 and 1
++			 */
++			data = (ret & 0x1) << 15;
++			temp = (ret >> 0x1) & 0x3;
++
++			data |= BIT(31);
++			ret = regmap_write(regmap, reg, data);
++			if (ret)
++				return ret;
++
++			temp |= (0x3 << 16);
++			reg += 0x4;
++			ret = regmap_write(regmap, reg, temp);
++
++			return ret;
++		case 18 ... 21:
++			/* setting fully enclosed in the second register */
++			reg += 4;
++			bit -= 16;
++			break;
++		default:
++			debug("unsupported bit: %d for pinctrl drive type: %d\n",
++			      bit, drv_type);
++			return -EINVAL;
++		}
++		break;
++	case DRV_TYPE_IO_DEFAULT:
++	case DRV_TYPE_IO_1V8_OR_3V0:
++	case DRV_TYPE_IO_1V8_ONLY:
++		rmask_bits = ROCKCHIP_DRV_BITS_PER_PIN;
++		break;
++	default:
++		debug("unsupported pinctrl drive type: %d\n",
++		      drv_type);
++		return -EINVAL;
++	}
++
++	/* enable the write to the equivalent lower bits */
++	data = ((1 << rmask_bits) - 1) << (bit + 16);
++	data |= (ret << bit);
++	ret = regmap_write(regmap, reg, data);
++
++	return ret;
++}
++
++#define PX30_SCHMITT_PMU_OFFSET			0x38
++#define PX30_SCHMITT_GRF_OFFSET			0xc0
++#define PX30_SCHMITT_PINS_PER_PMU_REG		16
++#define PX30_SCHMITT_BANK_STRIDE		16
++#define PX30_SCHMITT_PINS_PER_GRF_REG		8
++
++static int px30_calc_schmitt_reg_and_bit(struct rockchip_pin_bank *bank,
++					 int pin_num,
++					 struct regmap **regmap,
++					 int *reg, u8 *bit)
++{
++	struct rockchip_pinctrl_priv *priv = bank->priv;
++	int pins_per_reg;
++
++	if (bank->bank_num == 0) {
++		*regmap = priv->regmap_pmu;
++		*reg = PX30_SCHMITT_PMU_OFFSET;
++		pins_per_reg = PX30_SCHMITT_PINS_PER_PMU_REG;
++	} else {
++		*regmap = priv->regmap_base;
++		*reg = PX30_SCHMITT_GRF_OFFSET;
++		pins_per_reg = PX30_SCHMITT_PINS_PER_GRF_REG;
++		*reg += (bank->bank_num - 1) * PX30_SCHMITT_BANK_STRIDE;
++	}
++	*reg += ((pin_num / pins_per_reg) * 4);
++	*bit = pin_num % pins_per_reg;
++
++	return 0;
++}
++
++static int px30_set_schmitt(struct rockchip_pin_bank *bank,
++			    int pin_num, int enable)
++{
++	struct regmap *regmap;
++	int reg;
++	u8 bit;
++	u32 data;
++
++	px30_calc_schmitt_reg_and_bit(bank, pin_num, &regmap, &reg, &bit);
++	/* enable the write to the equivalent lower bits */
++	data = BIT(bit + 16) | (enable << bit);
++
++	return regmap_write(regmap, reg, data);
++}
++
++static struct rockchip_pin_bank px30_pin_banks[] = {
++	PIN_BANK_IOMUX_FLAGS(0, 32, "gpio0", IOMUX_SOURCE_PMU,
++					     IOMUX_SOURCE_PMU,
++					     IOMUX_SOURCE_PMU,
++					     IOMUX_SOURCE_PMU
++			    ),
++	PIN_BANK_IOMUX_FLAGS(1, 32, "gpio1", IOMUX_WIDTH_4BIT,
++					     IOMUX_WIDTH_4BIT,
++					     IOMUX_WIDTH_4BIT,
++					     IOMUX_WIDTH_4BIT
++			    ),
++	PIN_BANK_IOMUX_FLAGS(2, 32, "gpio2", IOMUX_WIDTH_4BIT,
++					     IOMUX_WIDTH_4BIT,
++					     IOMUX_WIDTH_4BIT,
++					     IOMUX_WIDTH_4BIT
++			    ),
++	PIN_BANK_IOMUX_FLAGS(3, 32, "gpio3", IOMUX_WIDTH_4BIT,
++					     IOMUX_WIDTH_4BIT,
++					     IOMUX_WIDTH_4BIT,
++					     IOMUX_WIDTH_4BIT
++			    ),
++};
++
++static struct rockchip_pin_ctrl px30_pin_ctrl = {
++	.pin_banks		= px30_pin_banks,
++	.nr_banks		= ARRAY_SIZE(px30_pin_banks),
++	.grf_mux_offset		= 0x0,
++	.pmu_mux_offset		= 0x0,
++	.grf_drv_offset		= 0xf0,
++	.pmu_drv_offset		= 0x20,
++	.iomux_routes		= px30_mux_route_data,
++	.niomux_routes		= ARRAY_SIZE(px30_mux_route_data),
++	.set_mux		= px30_set_mux,
++	.set_pull		= px30_set_pull,
++	.set_drive		= px30_set_drive,
++	.set_schmitt		= px30_set_schmitt,
++};
++
++static const struct udevice_id px30_pinctrl_ids[] = {
++	{
++		.compatible = "rockchip,px30-pinctrl",
++		.data = (ulong)&px30_pin_ctrl
++	},
++	{ }
++};
++
++U_BOOT_DRIVER(pinctrl_px30) = {
++	.name		= "rockchip_px30_pinctrl",
++	.id		= UCLASS_PINCTRL,
++	.of_match	= px30_pinctrl_ids,
++	.priv_auto_alloc_size = sizeof(struct rockchip_pinctrl_priv),
++	.ops		= &rockchip_pinctrl_ops,
++#if !CONFIG_IS_ENABLED(OF_PLATDATA)
++	.bind		= dm_scan_fdt_dev,
++#endif
++	.probe		= rockchip_pinctrl_probe,
++};
+
+From patchwork Thu Oct 24 23:27:55 2019
+Content-Type: text/plain; charset="utf-8"
+MIME-Version: 1.0
+Content-Transfer-Encoding: 7bit
+X-Patchwork-Submitter: =?utf-8?q?Heiko_St=C3=BCbner?= <heiko@sntech.de>
+X-Patchwork-Id: 1183659
+X-Patchwork-Delegate: ykai007@gmail.com
+Return-Path: <u-boot-bounces@lists.denx.de>
+X-Original-To: incoming@patchwork.ozlabs.org
+Delivered-To: patchwork-incoming@bilbo.ozlabs.org
+Authentication-Results: ozlabs.org;
+ spf=none (no SPF record) smtp.mailfrom=lists.denx.de
+ (client-ip=81.169.180.215; helo=lists.denx.de;
+ envelope-from=u-boot-bounces@lists.denx.de;
+ receiver=<UNKNOWN>)
+Authentication-Results: ozlabs.org;
+ dmarc=none (p=none dis=none) header.from=sntech.de
+Received: from lists.denx.de (dione.denx.de [81.169.180.215])
+ by ozlabs.org (Postfix) with ESMTP id 46zk730ZxBz9sPL
+ for <incoming@patchwork.ozlabs.org>;
+ Fri, 25 Oct 2019 10:32:31 +1100 (AEDT)
+Received: by lists.denx.de (Postfix, from userid 105)
+ id C00E2C21E12; Thu, 24 Oct 2019 23:30:13 +0000 (UTC)
+X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on lists.denx.de
+X-Spam-Level: 
+X-Spam-Status: No, score=0.0 required=5.0 tests=none autolearn=unavailable
+ autolearn_force=no version=3.4.0
+Received: from lists.denx.de (localhost [IPv6:::1])
+ by lists.denx.de (Postfix) with ESMTP id F0E2EC21E62;
+ Thu, 24 Oct 2019 23:28:22 +0000 (UTC)
+Received: by lists.denx.de (Postfix, from userid 105)
+ id 9226BC21D74; Thu, 24 Oct 2019 23:28:18 +0000 (UTC)
+Received: from gloria.sntech.de (gloria.sntech.de [185.11.138.130])
+ by lists.denx.de (Postfix) with ESMTPS id 66177C21DA1
+ for <u-boot@lists.denx.de>; Thu, 24 Oct 2019 23:28:17 +0000 (UTC)
+Received: from ip5f5a6266.dynamic.kabel-deutschland.de ([95.90.98.102]
+ helo=phil.fritz.box) by gloria.sntech.de with esmtpsa
+ (TLS1.2:ECDHE_RSA_AES_128_GCM_SHA256:128)
+ (Exim 4.89) (envelope-from <heiko@sntech.de>)
+ id 1iNmWe-0002cR-FK; Fri, 25 Oct 2019 01:28:16 +0200
+From: Heiko Stuebner <heiko@sntech.de>
+To: u-boot@lists.denx.de
+Date: Fri, 25 Oct 2019 01:27:55 +0200
+Message-Id: <20191024232803.10338-5-heiko@sntech.de>
+X-Mailer: git-send-email 2.23.0
+In-Reply-To: <20191024232803.10338-1-heiko@sntech.de>
+References: <20191024232803.10338-1-heiko@sntech.de>
+MIME-Version: 1.0
+Cc: Heiko Stuebner <heiko.stuebner@theobroma-systems.com>,
+ joe.hershberger@ni.com, christoph.muellner@theobroma-systems.com
+Subject: [U-Boot] [PATCH 04/12] rockchip: clk: add px30 clock driver
+X-BeenThere: u-boot@lists.denx.de
+X-Mailman-Version: 2.1.18
+Precedence: list
+List-Id: U-Boot discussion <u-boot.lists.denx.de>
+List-Unsubscribe: <https://lists.denx.de/options/u-boot>,
+ <mailto:u-boot-request@lists.denx.de?subject=unsubscribe>
+List-Archive: <http://lists.denx.de/pipermail/u-boot/>
+List-Post: <mailto:u-boot@lists.denx.de>
+List-Help: <mailto:u-boot-request@lists.denx.de?subject=help>
+List-Subscribe: <https://lists.denx.de/listinfo/u-boot>,
+ <mailto:u-boot-request@lists.denx.de?subject=subscribe>
+Errors-To: u-boot-bounces@lists.denx.de
+Sender: "U-Boot" <u-boot-bounces@lists.denx.de>
+
+From: Kever Yang <kever.yang@rock-chips.com>
+
+The px30 contains 2 separate clock controllers, pmucru and cru.
+Add drivers for them.
+
+Signed-off-by: Kever Yang <kever.yang@rock-chips.com>
+Signed-off-by: Heiko Stuebner <heiko.stuebner@theobroma-systems.com>
+---
+ arch/arm/include/asm/arch-rockchip/cru_px30.h |  432 +++++
+ drivers/clk/rockchip/Makefile                 |    1 +
+ drivers/clk/rockchip/clk_px30.c               | 1630 +++++++++++++++++
+ include/dt-bindings/clock/px30-cru.h          |  389 ++++
+ 4 files changed, 2452 insertions(+)
+ create mode 100644 arch/arm/include/asm/arch-rockchip/cru_px30.h
+ create mode 100644 drivers/clk/rockchip/clk_px30.c
+ create mode 100644 include/dt-bindings/clock/px30-cru.h
+
+diff --git a/arch/arm/include/asm/arch-rockchip/cru_px30.h b/arch/arm/include/asm/arch-rockchip/cru_px30.h
+new file mode 100644
+index 0000000000..7d9fd181ac
+--- /dev/null
++++ b/arch/arm/include/asm/arch-rockchip/cru_px30.h
+@@ -0,0 +1,432 @@
++/* SPDX-License-Identifier: GPL-2.0+ */
++/*
++ * (C) Copyright 2017 Rockchip Electronics Co., Ltd.
++ */
++#ifndef _ASM_ARCH_CRU_PX30_H
++#define _ASM_ARCH_CRU_PX30_H
++
++#include <common.h>
++
++#define MHz		1000000
++#define KHz		1000
++#define OSC_HZ		(24 * MHz)
++
++#define APLL_HZ		(600 * MHz)
++#define GPLL_HZ		(1200 * MHz)
++#define NPLL_HZ		(1188 * MHz)
++#define ACLK_BUS_HZ	(200 * MHz)
++#define HCLK_BUS_HZ	(150 * MHz)
++#define PCLK_BUS_HZ	(100 * MHz)
++#define ACLK_PERI_HZ	(200 * MHz)
++#define HCLK_PERI_HZ	(150 * MHz)
++#define PCLK_PMU_HZ	(100 * MHz)
++
++/* PX30 pll id */
++enum px30_pll_id {
++	APLL,
++	DPLL,
++	CPLL,
++	NPLL,
++	GPLL,
++	PLL_COUNT,
++};
++
++struct px30_clk_priv {
++	struct px30_cru *cru;
++	ulong gpll_hz;
++};
++
++struct px30_pmuclk_priv {
++	struct px30_pmucru *pmucru;
++	ulong gpll_hz;
++};
++
++struct px30_pll {
++	unsigned int con0;
++	unsigned int con1;
++	unsigned int con2;
++	unsigned int con3;
++	unsigned int con4;
++	unsigned int reserved0[3];
++};
++
++struct px30_cru {
++	struct px30_pll pll[4];
++	unsigned int reserved1[8];
++	unsigned int mode;
++	unsigned int misc;
++	unsigned int reserved2[2];
++	unsigned int glb_cnt_th;
++	unsigned int glb_rst_st;
++	unsigned int glb_srst_fst;
++	unsigned int glb_srst_snd;
++	unsigned int glb_rst_con;
++	unsigned int reserved3[7];
++	unsigned int hwffc_con0;
++	unsigned int reserved4;
++	unsigned int hwffc_th;
++	unsigned int hwffc_intst;
++	unsigned int apll_con0_s;
++	unsigned int apll_con1_s;
++	unsigned int clksel_con0_s;
++	unsigned int reserved5;
++	unsigned int clksel_con[60];
++	unsigned int reserved6[4];
++	unsigned int clkgate_con[18];
++	unsigned int reserved7[(0x280 - 0x244) / 4 - 1];
++	unsigned int ssgtbl[32];
++	unsigned int softrst_con[12];
++	unsigned int reserved8[(0x380 - 0x32c) / 4 - 1];
++	unsigned int sdmmc_con[2];
++	unsigned int sdio_con[2];
++	unsigned int emmc_con[2];
++	unsigned int reserved9[(0x400 - 0x394) / 4 - 1];
++	unsigned int autocs_con[8];
++};
++
++check_member(px30_cru, autocs_con[7], 0x41c);
++
++struct px30_pmucru {
++	struct px30_pll pll;
++	unsigned int pmu_mode;
++	unsigned int reserved1[7];
++	unsigned int pmu_clksel_con[6];
++	unsigned int reserved2[10];
++	unsigned int pmu_clkgate_con[2];
++	unsigned int reserved3[14];
++	unsigned int pmu_autocs_con[2];
++};
++
++check_member(px30_pmucru, pmu_autocs_con[1], 0xc4);
++
++struct pll_rate_table {
++	unsigned long rate;
++	unsigned int fbdiv;
++	unsigned int postdiv1;
++	unsigned int refdiv;
++	unsigned int postdiv2;
++	unsigned int dsmpd;
++	unsigned int frac;
++};
++
++struct cpu_rate_table {
++	unsigned long rate;
++	unsigned int aclk_div;
++	unsigned int pclk_div;
++};
++
++enum {
++	/* PLLCON0*/
++	PLL_BP_SHIFT		= 15,
++	PLL_POSTDIV1_SHIFT	= 12,
++	PLL_POSTDIV1_MASK	= 7 << PLL_POSTDIV1_SHIFT,
++	PLL_FBDIV_SHIFT		= 0,
++	PLL_FBDIV_MASK		= 0xfff,
++
++	/* PLLCON1 */
++	PLL_PDSEL_SHIFT		= 15,
++	PLL_PD1_SHIFT		= 14,
++	PLL_PD_SHIFT		= 13,
++	PLL_PD_MASK		= 1 << PLL_PD_SHIFT,
++	PLL_DSMPD_SHIFT		= 12,
++	PLL_DSMPD_MASK		= 1 << PLL_DSMPD_SHIFT,
++	PLL_LOCK_STATUS_SHIFT	= 10,
++	PLL_LOCK_STATUS_MASK	= 1 << PLL_LOCK_STATUS_SHIFT,
++	PLL_POSTDIV2_SHIFT	= 6,
++	PLL_POSTDIV2_MASK	= 7 << PLL_POSTDIV2_SHIFT,
++	PLL_REFDIV_SHIFT	= 0,
++	PLL_REFDIV_MASK		= 0x3f,
++
++	/* PLLCON2 */
++	PLL_FOUT4PHASEPD_SHIFT	= 27,
++	PLL_FOUTVCOPD_SHIFT	= 26,
++	PLL_FOUTPOSTDIVPD_SHIFT	= 25,
++	PLL_DACPD_SHIFT		= 24,
++	PLL_FRAC_DIV	= 0xffffff,
++
++	/* CRU_MODE */
++	PLLMUX_FROM_XIN24M	= 0,
++	PLLMUX_FROM_PLL,
++	PLLMUX_FROM_RTC32K,
++	USBPHY480M_MODE_SHIFT	= 8,
++	USBPHY480M_MODE_MASK	= 3 << USBPHY480M_MODE_SHIFT,
++	NPLL_MODE_SHIFT		= 6,
++	NPLL_MODE_MASK		= 3 << NPLL_MODE_SHIFT,
++	DPLL_MODE_SHIFT		= 4,
++	DPLL_MODE_MASK		= 3 << DPLL_MODE_SHIFT,
++	CPLL_MODE_SHIFT		= 2,
++	CPLL_MODE_MASK		= 3 << CPLL_MODE_SHIFT,
++	APLL_MODE_SHIFT		= 0,
++	APLL_MODE_MASK		= 3 << APLL_MODE_SHIFT,
++
++	/* CRU_CLK_SEL0_CON */
++	CORE_ACLK_DIV_SHIFT	= 12,
++	CORE_ACLK_DIV_MASK	= 0x07 << CORE_ACLK_DIV_SHIFT,
++	CORE_DBG_DIV_SHIFT	= 8,
++	CORE_DBG_DIV_MASK	= 0x03 << CORE_DBG_DIV_SHIFT,
++	CORE_CLK_PLL_SEL_SHIFT	= 7,
++	CORE_CLK_PLL_SEL_MASK	= 1 << CORE_CLK_PLL_SEL_SHIFT,
++	CORE_CLK_PLL_SEL_APLL	= 0,
++	CORE_CLK_PLL_SEL_GPLL,
++	CORE_DIV_CON_SHIFT	= 0,
++	CORE_DIV_CON_MASK	= 0x0f << CORE_DIV_CON_SHIFT,
++
++	/* CRU_CLK_SEL3_CON */
++	ACLK_VO_PLL_SHIFT	= 6,
++	ACLK_VO_PLL_MASK	= 0x3 << ACLK_VO_PLL_SHIFT,
++	ACLK_VO_SEL_GPLL	= 0,
++	ACLK_VO_SEL_CPLL,
++	ACLK_VO_SEL_NPLL,
++	ACLK_VO_DIV_SHIFT	= 0,
++	ACLK_VO_DIV_MASK	= 0x1f << ACLK_VO_DIV_SHIFT,
++
++	/* CRU_CLK_SEL5_CON */
++	DCLK_VOPB_SEL_SHIFT	= 14,
++	DCLK_VOPB_SEL_MASK	= 0x3 << DCLK_VOPB_SEL_SHIFT,
++	DCLK_VOPB_SEL_DIVOUT	= 0,
++	DCLK_VOPB_SEL_FRACOUT,
++	DCLK_VOPB_SEL_24M,
++	DCLK_VOPB_PLL_SEL_SHIFT	= 11,
++	DCLK_VOPB_PLL_SEL_MASK	= 0x1 << DCLK_VOPB_PLL_SEL_SHIFT,
++	DCLK_VOPB_PLL_SEL_CPLL	= 0,
++	DCLK_VOPB_PLL_SEL_NPLL,
++	DCLK_VOPB_DIV_SHIFT	= 0,
++	DCLK_VOPB_DIV_MASK	= 0xff,
++
++	/* CRU_CLK_SEL8_CON */
++	DCLK_VOPL_SEL_SHIFT	= 14,
++	DCLK_VOPL_SEL_MASK	= 0x3 << DCLK_VOPL_SEL_SHIFT,
++	DCLK_VOPL_SEL_DIVOUT	= 0,
++	DCLK_VOPL_SEL_FRACOUT,
++	DCLK_VOPL_SEL_24M,
++	DCLK_VOPL_PLL_SEL_SHIFT	= 11,
++	DCLK_VOPL_PLL_SEL_MASK	= 0x1 << DCLK_VOPL_PLL_SEL_SHIFT,
++	DCLK_VOPL_PLL_SEL_NPLL	= 0,
++	DCLK_VOPL_PLL_SEL_CPLL,
++	DCLK_VOPL_DIV_SHIFT	= 0,
++	DCLK_VOPL_DIV_MASK	= 0xff,
++
++	/* CRU_CLK_SEL14_CON */
++	PERI_PLL_SEL_SHIFT	= 15,
++	PERI_PLL_SEL_MASK	= 3 << PERI_PLL_SEL_SHIFT,
++	PERI_PLL_GPLL		= 0,
++	PERI_PLL_CPLL,
++	PERI_HCLK_DIV_SHIFT	= 8,
++	PERI_HCLK_DIV_MASK	= 0x1f << PERI_HCLK_DIV_SHIFT,
++	PERI_ACLK_DIV_SHIFT	= 0,
++	PERI_ACLK_DIV_MASK	= 0x1f << PERI_ACLK_DIV_SHIFT,
++
++	/* CRU_CLKSEL15_CON */
++	NANDC_CLK_SEL_SHIFT	= 15,
++	NANDC_CLK_SEL_MASK	= 0x1 << NANDC_CLK_SEL_SHIFT,
++	NANDC_CLK_SEL_NANDC	= 0,
++	NANDC_CLK_SEL_NANDC_DIV50,
++	NANDC_DIV50_SHIFT	= 8,
++	NANDC_DIV50_MASK	= 0x1f << NANDC_DIV50_SHIFT,
++	NANDC_PLL_SHIFT		= 6,
++	NANDC_PLL_MASK		= 0x3 << NANDC_PLL_SHIFT,
++	NANDC_SEL_GPLL		= 0,
++	NANDC_SEL_CPLL,
++	NANDC_SEL_NPLL,
++	NANDC_DIV_SHIFT		= 0,
++	NANDC_DIV_MASK		= 0x1f << NANDC_DIV_SHIFT,
++
++	/* CRU_CLKSEL20_CON */
++	EMMC_PLL_SHIFT		= 14,
++	EMMC_PLL_MASK		= 3 << EMMC_PLL_SHIFT,
++	EMMC_SEL_GPLL		= 0,
++	EMMC_SEL_CPLL,
++	EMMC_SEL_NPLL,
++	EMMC_SEL_24M,
++	EMMC_DIV_SHIFT		= 0,
++	EMMC_DIV_MASK		= 0xff << EMMC_DIV_SHIFT,
++
++	/* CRU_CLKSEL21_CON */
++	EMMC_CLK_SEL_SHIFT	= 15,
++	EMMC_CLK_SEL_MASK	= 1 << EMMC_CLK_SEL_SHIFT,
++	EMMC_CLK_SEL_EMMC	= 0,
++	EMMC_CLK_SEL_EMMC_DIV50,
++	EMMC_DIV50_SHIFT	= 0,
++	EMMC_DIV50_MASK		= 0xff << EMMC_DIV_SHIFT,
++
++	/* CRU_CLKSEL22_CON */
++	GMAC_PLL_SEL_SHIFT	= 14,
++	GMAC_PLL_SEL_MASK	= 3 << GMAC_PLL_SEL_SHIFT,
++	GMAC_PLL_SEL_GPLL	= 0,
++	GMAC_PLL_SEL_CPLL,
++	GMAC_PLL_SEL_NPLL,
++	CLK_GMAC_DIV_SHIFT	= 8,
++	CLK_GMAC_DIV_MASK	= 0x1f << CLK_GMAC_DIV_SHIFT,
++	SFC_PLL_SEL_SHIFT	= 7,
++	SFC_PLL_SEL_MASK	= 1 << SFC_PLL_SEL_SHIFT,
++	SFC_DIV_CON_SHIFT	= 0,
++	SFC_DIV_CON_MASK	= 0x7f,
++
++	/* CRU_CLK_SEL23_CON */
++	BUS_PLL_SEL_SHIFT	= 15,
++	BUS_PLL_SEL_MASK	= 1 << BUS_PLL_SEL_SHIFT,
++	BUS_PLL_SEL_GPLL	= 0,
++	BUS_PLL_SEL_CPLL,
++	BUS_ACLK_DIV_SHIFT	= 8,
++	BUS_ACLK_DIV_MASK	= 0x1f << BUS_ACLK_DIV_SHIFT,
++	RMII_CLK_SEL_SHIFT	= 7,
++	RMII_CLK_SEL_MASK	= 1 << RMII_CLK_SEL_SHIFT,
++	RMII_CLK_SEL_10M	= 0,
++	RMII_CLK_SEL_100M,
++	RMII_EXTCLK_SEL_SHIFT	= 6,
++	RMII_EXTCLK_SEL_MASK	= 1 << RMII_EXTCLK_SEL_SHIFT,
++	RMII_EXTCLK_SEL_INT	= 0,
++	RMII_EXTCLK_SEL_EXT,
++	PCLK_GMAC_DIV_SHIFT	= 0,
++	PCLK_GMAC_DIV_MASK	= 0x0f << PCLK_GMAC_DIV_SHIFT,
++
++	/* CRU_CLK_SEL24_CON */
++	BUS_PCLK_DIV_SHIFT	= 8,
++	BUS_PCLK_DIV_MASK	= 3 << BUS_PCLK_DIV_SHIFT,
++	BUS_HCLK_DIV_SHIFT	= 0,
++	BUS_HCLK_DIV_MASK	= 0x1f << BUS_HCLK_DIV_SHIFT,
++
++	/* CRU_CLK_SEL25_CON */
++	CRYPTO_APK_SEL_SHIFT	= 14,
++	CRYPTO_APK_PLL_SEL_MASK	= 3 << CRYPTO_APK_SEL_SHIFT,
++	CRYPTO_PLL_SEL_GPLL	= 0,
++	CRYPTO_PLL_SEL_CPLL,
++	CRYPTO_PLL_SEL_NPLL	= 0,
++	CRYPTO_APK_DIV_SHIFT	= 8,
++	CRYPTO_APK_DIV_MASK	= 0x1f << CRYPTO_APK_DIV_SHIFT,
++	CRYPTO_PLL_SEL_SHIFT	= 6,
++	CRYPTO_PLL_SEL_MASK	= 3 << CRYPTO_PLL_SEL_SHIFT,
++	CRYPTO_DIV_SHIFT	= 0,
++	CRYPTO_DIV_MASK		= 0x1f << CRYPTO_DIV_SHIFT,
++
++	/* CRU_CLK_SEL30_CON */
++	CLK_I2S1_DIV_CON_MASK	= 0x7f,
++	CLK_I2S1_PLL_SEL_MASK	= 0X1 << 8,
++	CLK_I2S1_PLL_SEL_GPLL	= 0X0 << 8,
++	CLK_I2S1_PLL_SEL_NPLL	= 0X1 << 8,
++	CLK_I2S1_SEL_MASK	= 0x3 << 10,
++	CLK_I2S1_SEL_I2S1	= 0x0 << 10,
++	CLK_I2S1_SEL_FRAC	= 0x1 << 10,
++	CLK_I2S1_SEL_MCLK_IN	= 0x2 << 10,
++	CLK_I2S1_SEL_OSC	= 0x3 << 10,
++	CLK_I2S1_OUT_SEL_MASK	= 0x1 << 15,
++	CLK_I2S1_OUT_SEL_I2S1	= 0x0 << 15,
++	CLK_I2S1_OUT_SEL_OSC	= 0x1 << 15,
++
++	/* CRU_CLK_SEL31_CON */
++	CLK_I2S1_FRAC_NUMERATOR_SHIFT	= 16,
++	CLK_I2S1_FRAC_NUMERATOR_MASK	= 0xffff << 16,
++	CLK_I2S1_FRAC_DENOMINATOR_SHIFT	= 0,
++	CLK_I2S1_FRAC_DENOMINATOR_MASK	= 0xffff,
++
++	/* CRU_CLK_SEL34_CON */
++	UART1_PLL_SEL_SHIFT	= 14,
++	UART1_PLL_SEL_MASK	= 3 << UART1_PLL_SEL_SHIFT,
++	UART1_PLL_SEL_GPLL	= 0,
++	UART1_PLL_SEL_24M,
++	UART1_PLL_SEL_480M,
++	UART1_PLL_SEL_NPLL,
++	UART1_DIV_CON_SHIFT	= 0,
++	UART1_DIV_CON_MASK	= 0x1f << UART1_DIV_CON_SHIFT,
++
++	/* CRU_CLK_SEL35_CON */
++	UART1_CLK_SEL_SHIFT	= 14,
++	UART1_CLK_SEL_MASK	= 3 << UART1_PLL_SEL_SHIFT,
++	UART1_CLK_SEL_UART1	= 0,
++	UART1_CLK_SEL_UART1_NP5,
++	UART1_CLK_SEL_UART1_FRAC,
++	UART1_DIVNP5_SHIFT	= 0,
++	UART1_DIVNP5_MASK	= 0x1f << UART1_DIVNP5_SHIFT,
++
++	/* CRU_CLK_SEL37_CON */
++	UART2_PLL_SEL_SHIFT	= 14,
++	UART2_PLL_SEL_MASK	= 3 << UART2_PLL_SEL_SHIFT,
++	UART2_PLL_SEL_GPLL	= 0,
++	UART2_PLL_SEL_24M,
++	UART2_PLL_SEL_480M,
++	UART2_PLL_SEL_NPLL,
++	UART2_DIV_CON_SHIFT	= 0,
++	UART2_DIV_CON_MASK	= 0x1f << UART2_DIV_CON_SHIFT,
++
++	/* CRU_CLK_SEL38_CON */
++	UART2_CLK_SEL_SHIFT	= 14,
++	UART2_CLK_SEL_MASK	= 3 << UART2_PLL_SEL_SHIFT,
++	UART2_CLK_SEL_UART2	= 0,
++	UART2_CLK_SEL_UART2_NP5,
++	UART2_CLK_SEL_UART2_FRAC,
++	UART2_DIVNP5_SHIFT	= 0,
++	UART2_DIVNP5_MASK	= 0x1f << UART2_DIVNP5_SHIFT,
++
++	/* CRU_CLK_SEL46_CON */
++	UART5_PLL_SEL_SHIFT	= 14,
++	UART5_PLL_SEL_MASK	= 3 << UART5_PLL_SEL_SHIFT,
++	UART5_PLL_SEL_GPLL	= 0,
++	UART5_PLL_SEL_24M,
++	UART5_PLL_SEL_480M,
++	UART5_PLL_SEL_NPLL,
++	UART5_DIV_CON_SHIFT	= 0,
++	UART5_DIV_CON_MASK	= 0x1f << UART5_DIV_CON_SHIFT,
++
++	/* CRU_CLK_SEL47_CON */
++	UART5_CLK_SEL_SHIFT	= 14,
++	UART5_CLK_SEL_MASK	= 3 << UART5_PLL_SEL_SHIFT,
++	UART5_CLK_SEL_UART5	= 0,
++	UART5_CLK_SEL_UART5_NP5,
++	UART5_CLK_SEL_UART5_FRAC,
++	UART5_DIVNP5_SHIFT	= 0,
++	UART5_DIVNP5_MASK	= 0x1f << UART5_DIVNP5_SHIFT,
++
++	/* CRU_CLK_SEL49_CON */
++	CLK_I2C_PLL_SEL_GPLL		= 0,
++	CLK_I2C_PLL_SEL_24M,
++	CLK_I2C_DIV_CON_MASK		= 0x7f,
++	CLK_I2C_PLL_SEL_MASK		= 1,
++	CLK_I2C1_PLL_SEL_SHIFT		= 15,
++	CLK_I2C1_DIV_CON_SHIFT		= 8,
++	CLK_I2C0_PLL_SEL_SHIFT		= 7,
++	CLK_I2C0_DIV_CON_SHIFT		= 0,
++
++	/* CRU_CLK_SEL50_CON */
++	CLK_I2C3_PLL_SEL_SHIFT		= 15,
++	CLK_I2C3_DIV_CON_SHIFT		= 8,
++	CLK_I2C2_PLL_SEL_SHIFT		= 7,
++	CLK_I2C2_DIV_CON_SHIFT		= 0,
++
++	/* CRU_CLK_SEL52_CON */
++	CLK_PWM_PLL_SEL_GPLL		= 0,
++	CLK_PWM_PLL_SEL_24M,
++	CLK_PWM_DIV_CON_MASK		= 0x7f,
++	CLK_PWM_PLL_SEL_MASK		= 1,
++	CLK_PWM1_PLL_SEL_SHIFT		= 15,
++	CLK_PWM1_DIV_CON_SHIFT		= 8,
++	CLK_PWM0_PLL_SEL_SHIFT		= 7,
++	CLK_PWM0_DIV_CON_SHIFT		= 0,
++
++	/* CRU_CLK_SEL53_CON */
++	CLK_SPI_PLL_SEL_GPLL		= 0,
++	CLK_SPI_PLL_SEL_24M,
++	CLK_SPI_DIV_CON_MASK		= 0x7f,
++	CLK_SPI_PLL_SEL_MASK		= 1,
++	CLK_SPI1_PLL_SEL_SHIFT		= 15,
++	CLK_SPI1_DIV_CON_SHIFT		= 8,
++	CLK_SPI0_PLL_SEL_SHIFT		= 7,
++	CLK_SPI0_DIV_CON_SHIFT		= 0,
++
++	/* CRU_CLK_SEL55_CON */
++	CLK_SARADC_DIV_CON_SHIFT	= 0,
++	CLK_SARADC_DIV_CON_MASK		= 0x7ff,
++
++	/* CRU_CLK_GATE10_CON */
++	CLK_I2S1_OUT_MCLK_PAD_MASK	= 0x1 << 9,
++	CLK_I2S1_OUT_MCLK_PAD_ENABLE	= 0x1 << 9,
++	CLK_I2S1_OUT_MCLK_PAD_DISABLE	= 0x0 << 9,
++
++	/* CRU_PMU_MODE */
++	GPLL_MODE_SHIFT			= 0,
++	GPLL_MODE_MASK			= 3 << GPLL_MODE_SHIFT,
++
++	/* CRU_PMU_CLK_SEL0_CON */
++	CLK_PMU_PCLK_DIV_SHIFT		= 0,
++	CLK_PMU_PCLK_DIV_MASK		= 0x1f << CLK_PMU_PCLK_DIV_SHIFT,
++};
++#endif
+diff --git a/drivers/clk/rockchip/Makefile b/drivers/clk/rockchip/Makefile
+index 41cfb7ad3f..f9134fd51f 100644
+--- a/drivers/clk/rockchip/Makefile
++++ b/drivers/clk/rockchip/Makefile
+@@ -3,6 +3,7 @@
+ # Copyright (c) 2017 Rockchip Electronics Co., Ltd
+ #
+ 
++obj-$(CONFIG_ROCKCHIP_PX30) += clk_px30.o
+ obj-$(CONFIG_ROCKCHIP_RK3036) += clk_rk3036.o
+ obj-$(CONFIG_ROCKCHIP_RK3128) += clk_rk3128.o
+ obj-$(CONFIG_ROCKCHIP_RK3188) += clk_rk3188.o
+diff --git a/drivers/clk/rockchip/clk_px30.c b/drivers/clk/rockchip/clk_px30.c
+new file mode 100644
+index 0000000000..36764c128b
+--- /dev/null
++++ b/drivers/clk/rockchip/clk_px30.c
+@@ -0,0 +1,1630 @@
++// SPDX-License-Identifier: GPL-2.0
++/*
++ * (C) Copyright 2017 Rockchip Electronics Co., Ltd
++ */
++
++#include <common.h>
++#include <bitfield.h>
++#include <clk-uclass.h>
++#include <dm.h>
++#include <errno.h>
++#include <syscon.h>
++#include <asm/arch-rockchip/clock.h>
++#include <asm/arch-rockchip/cru_px30.h>
++#include <asm/arch-rockchip/hardware.h>
++#include <asm/io.h>
++#include <dm/lists.h>
++#include <dt-bindings/clock/px30-cru.h>
++
++DECLARE_GLOBAL_DATA_PTR;
++
++enum {
++	VCO_MAX_HZ	= 3200U * 1000000,
++	VCO_MIN_HZ	= 800 * 1000000,
++	OUTPUT_MAX_HZ	= 3200U * 1000000,
++	OUTPUT_MIN_HZ	= 24 * 1000000,
++};
++
++#define PX30_VOP_PLL_LIMIT			600000000
++
++#define PX30_PLL_RATE(_rate, _refdiv, _fbdiv, _postdiv1,	\
++			_postdiv2, _dsmpd, _frac)		\
++{								\
++	.rate	= _rate##U,					\
++	.fbdiv = _fbdiv,					\
++	.postdiv1 = _postdiv1,					\
++	.refdiv = _refdiv,					\
++	.postdiv2 = _postdiv2,					\
++	.dsmpd = _dsmpd,					\
++	.frac = _frac,						\
++}
++
++#define PX30_CPUCLK_RATE(_rate, _aclk_div, _pclk_div)		\
++{								\
++	.rate	= _rate##U,					\
++	.aclk_div = _aclk_div,					\
++	.pclk_div = _pclk_div,					\
++}
++
++#define DIV_TO_RATE(input_rate, div)    ((input_rate) / ((div) + 1))
++
++#define PX30_CLK_DUMP(_id, _name, _iscru)	\
++{						\
++	.id = _id,				\
++	.name = _name,				\
++	.is_cru = _iscru,			\
++}
++
++static struct pll_rate_table px30_pll_rates[] = {
++	/* _mhz, _refdiv, _fbdiv, _postdiv1, _postdiv2, _dsmpd, _frac */
++	PX30_PLL_RATE(1200000000, 1, 50, 1, 1, 1, 0),
++	PX30_PLL_RATE(1188000000, 2, 99, 1, 1, 1, 0),
++	PX30_PLL_RATE(1100000000, 12, 550, 1, 1, 1, 0),
++	PX30_PLL_RATE(1008000000, 1, 84, 2, 1, 1, 0),
++	PX30_PLL_RATE(1000000000, 6, 500, 2, 1, 1, 0),
++	PX30_PLL_RATE(816000000, 1, 68, 2, 1, 1, 0),
++	PX30_PLL_RATE(600000000, 1, 75, 3, 1, 1, 0),
++};
++
++static struct cpu_rate_table px30_cpu_rates[] = {
++	PX30_CPUCLK_RATE(1200000000, 1, 5),
++	PX30_CPUCLK_RATE(1008000000, 1, 5),
++	PX30_CPUCLK_RATE(816000000, 1, 3),
++	PX30_CPUCLK_RATE(600000000, 1, 3),
++	PX30_CPUCLK_RATE(408000000, 1, 1),
++};
++
++static u8 pll_mode_shift[PLL_COUNT] = {
++	APLL_MODE_SHIFT, DPLL_MODE_SHIFT, CPLL_MODE_SHIFT,
++	NPLL_MODE_SHIFT, GPLL_MODE_SHIFT
++};
++
++static u32 pll_mode_mask[PLL_COUNT] = {
++	APLL_MODE_MASK, DPLL_MODE_MASK, CPLL_MODE_MASK,
++	NPLL_MODE_MASK, GPLL_MODE_MASK
++};
++
++static struct pll_rate_table auto_table;
++
++static ulong px30_clk_get_pll_rate(struct px30_clk_priv *priv,
++				   enum px30_pll_id pll_id);
++
++static struct pll_rate_table *pll_clk_set_by_auto(u32 drate)
++{
++	struct pll_rate_table *rate = &auto_table;
++	u32 ref_khz = OSC_HZ / KHz, refdiv, fbdiv = 0;
++	u32 postdiv1, postdiv2 = 1;
++	u32 fref_khz;
++	u32 diff_khz, best_diff_khz;
++	const u32 max_refdiv = 63, max_fbdiv = 3200, min_fbdiv = 16;
++	const u32 max_postdiv1 = 7, max_postdiv2 = 7;
++	u32 vco_khz;
++	u32 rate_khz = drate / KHz;
++
++	if (!drate) {
++		printf("%s: the frequency can't be 0 Hz\n", __func__);
++		return NULL;
++	}
++
++	postdiv1 = DIV_ROUND_UP(VCO_MIN_HZ / 1000, rate_khz);
++	if (postdiv1 > max_postdiv1) {
++		postdiv2 = DIV_ROUND_UP(postdiv1, max_postdiv1);
++		postdiv1 = DIV_ROUND_UP(postdiv1, postdiv2);
++	}
++
++	vco_khz = rate_khz * postdiv1 * postdiv2;
++
++	if (vco_khz < (VCO_MIN_HZ / KHz) || vco_khz > (VCO_MAX_HZ / KHz) ||
++	    postdiv2 > max_postdiv2) {
++		printf("%s: Cannot find out a supported VCO for Freq (%uHz)\n",
++		       __func__, rate_khz);
++		return NULL;
++	}
++
++	rate->postdiv1 = postdiv1;
++	rate->postdiv2 = postdiv2;
++
++	best_diff_khz = vco_khz;
++	for (refdiv = 1; refdiv < max_refdiv && best_diff_khz; refdiv++) {
++		fref_khz = ref_khz / refdiv;
++
++		fbdiv = vco_khz / fref_khz;
++		if (fbdiv >= max_fbdiv || fbdiv <= min_fbdiv)
++			continue;
++
++		diff_khz = vco_khz - fbdiv * fref_khz;
++		if (fbdiv + 1 < max_fbdiv && diff_khz > fref_khz / 2) {
++			fbdiv++;
++			diff_khz = fref_khz - diff_khz;
++		}
++
++		if (diff_khz >= best_diff_khz)
++			continue;
++
++		best_diff_khz = diff_khz;
++		rate->refdiv = refdiv;
++		rate->fbdiv = fbdiv;
++	}
++
++	if (best_diff_khz > 4 * (MHz / KHz)) {
++		printf("%s: Failed to match output frequency %u bestis %u Hz\n",
++		       __func__, rate_khz,
++		       best_diff_khz * KHz);
++		return NULL;
++	}
++
++	return rate;
++}
++
++static const struct pll_rate_table *get_pll_settings(unsigned long rate)
++{
++	unsigned int rate_count = ARRAY_SIZE(px30_pll_rates);
++	int i;
++
++	for (i = 0; i < rate_count; i++) {
++		if (rate == px30_pll_rates[i].rate)
++			return &px30_pll_rates[i];
++	}
++
++	return pll_clk_set_by_auto(rate);
++}
++
++static const struct cpu_rate_table *get_cpu_settings(unsigned long rate)
++{
++	unsigned int rate_count = ARRAY_SIZE(px30_cpu_rates);
++	int i;
++
++	for (i = 0; i < rate_count; i++) {
++		if (rate == px30_cpu_rates[i].rate)
++			return &px30_cpu_rates[i];
++	}
++
++	return NULL;
++}
++
++/*
++ * How to calculate the PLL(from TRM V0.3 Part 1 Page 63):
++ * Formulas also embedded within the Fractional PLL Verilog model:
++ * If DSMPD = 1 (DSM is disabled, "integer mode")
++ * FOUTVCO = FREF / REFDIV * FBDIV
++ * FOUTPOSTDIV = FOUTVCO / POSTDIV1 / POSTDIV2
++ * Where:
++ * FOUTVCO = Fractional PLL non-divided output frequency
++ * FOUTPOSTDIV = Fractional PLL divided output frequency
++ *               (output of second post divider)
++ * FREF = Fractional PLL input reference frequency, (the OSC_HZ 24MHz input)
++ * REFDIV = Fractional PLL input reference clock divider
++ * FBDIV = Integer value programmed into feedback divide
++ *
++ */
++static int rkclk_set_pll(struct px30_pll *pll, unsigned int *mode,
++			 enum px30_pll_id pll_id,
++			 unsigned long drate)
++{
++	const struct pll_rate_table *rate;
++	uint vco_hz, output_hz;
++
++	rate = get_pll_settings(drate);
++	if (!rate) {
++		printf("%s unsupport rate\n", __func__);
++		return -EINVAL;
++	}
++
++	/* All PLLs have same VCO and output frequency range restrictions. */
++	vco_hz = OSC_HZ / 1000 * rate->fbdiv / rate->refdiv * 1000;
++	output_hz = vco_hz / rate->postdiv1 / rate->postdiv2;
++
++	debug("PLL at %p: fb=%d, ref=%d, pst1=%d, pst2=%d, vco=%u Hz, output=%u Hz\n",
++	      pll, rate->fbdiv, rate->refdiv, rate->postdiv1,
++	      rate->postdiv2, vco_hz, output_hz);
++	assert(vco_hz >= VCO_MIN_HZ && vco_hz <= VCO_MAX_HZ &&
++	       output_hz >= OUTPUT_MIN_HZ && output_hz <= OUTPUT_MAX_HZ);
++
++	/*
++	 * When power on or changing PLL setting,
++	 * we must force PLL into slow mode to ensure output stable clock.
++	 */
++	rk_clrsetreg(mode, pll_mode_mask[pll_id],
++		     PLLMUX_FROM_XIN24M << pll_mode_shift[pll_id]);
++
++	/* use integer mode */
++	rk_setreg(&pll->con1, 1 << PLL_DSMPD_SHIFT);
++	/* Power down */
++	rk_setreg(&pll->con1, 1 << PLL_PD_SHIFT);
++
++	rk_clrsetreg(&pll->con0,
++		     PLL_POSTDIV1_MASK | PLL_FBDIV_MASK,
++		     (rate->postdiv1 << PLL_POSTDIV1_SHIFT) | rate->fbdiv);
++	rk_clrsetreg(&pll->con1, PLL_POSTDIV2_MASK | PLL_REFDIV_MASK,
++		     (rate->postdiv2 << PLL_POSTDIV2_SHIFT |
++		     rate->refdiv << PLL_REFDIV_SHIFT));
++
++	/* Power Up */
++	rk_clrreg(&pll->con1, 1 << PLL_PD_SHIFT);
++
++	/* waiting for pll lock */
++	while (!(readl(&pll->con1) & (1 << PLL_LOCK_STATUS_SHIFT)))
++		udelay(1);
++
++	rk_clrsetreg(mode, pll_mode_mask[pll_id],
++		     PLLMUX_FROM_PLL << pll_mode_shift[pll_id]);
++
++	return 0;
++}
++
++static uint32_t rkclk_pll_get_rate(struct px30_pll *pll, unsigned int *mode,
++				   enum px30_pll_id pll_id)
++{
++	u32 refdiv, fbdiv, postdiv1, postdiv2;
++	u32 con, shift, mask;
++
++	con = readl(mode);
++	shift = pll_mode_shift[pll_id];
++	mask = pll_mode_mask[pll_id];
++
++	switch ((con & mask) >> shift) {
++	case PLLMUX_FROM_XIN24M:
++		return OSC_HZ;
++	case PLLMUX_FROM_PLL:
++		/* normal mode */
++		con = readl(&pll->con0);
++		postdiv1 = (con & PLL_POSTDIV1_MASK) >> PLL_POSTDIV1_SHIFT;
++		fbdiv = (con & PLL_FBDIV_MASK) >> PLL_FBDIV_SHIFT;
++		con = readl(&pll->con1);
++		postdiv2 = (con & PLL_POSTDIV2_MASK) >> PLL_POSTDIV2_SHIFT;
++		refdiv = (con & PLL_REFDIV_MASK) >> PLL_REFDIV_SHIFT;
++		return (24 * fbdiv / (refdiv * postdiv1 * postdiv2)) * 1000000;
++	case PLLMUX_FROM_RTC32K:
++	default:
++		return 32768;
++	}
++}
++
++static ulong px30_i2c_get_clk(struct px30_clk_priv *priv, ulong clk_id)
++{
++	struct px30_cru *cru = priv->cru;
++	u32 div, con;
++
++	switch (clk_id) {
++	case SCLK_I2C0:
++		con = readl(&cru->clksel_con[49]);
++		div = con >> CLK_I2C0_DIV_CON_SHIFT & CLK_I2C_DIV_CON_MASK;
++		break;
++	case SCLK_I2C1:
++		con = readl(&cru->clksel_con[49]);
++		div = con >> CLK_I2C1_DIV_CON_SHIFT & CLK_I2C_DIV_CON_MASK;
++		break;
++	case SCLK_I2C2:
++		con = readl(&cru->clksel_con[50]);
++		div = con >> CLK_I2C2_DIV_CON_SHIFT & CLK_I2C_DIV_CON_MASK;
++		break;
++	case SCLK_I2C3:
++		con = readl(&cru->clksel_con[50]);
++		div = con >> CLK_I2C3_DIV_CON_SHIFT & CLK_I2C_DIV_CON_MASK;
++		break;
++	default:
++		printf("do not support this i2c bus\n");
++		return -EINVAL;
++	}
++
++	return DIV_TO_RATE(priv->gpll_hz, div);
++}
++
++static ulong px30_i2c_set_clk(struct px30_clk_priv *priv, ulong clk_id, uint hz)
++{
++	struct px30_cru *cru = priv->cru;
++	int src_clk_div;
++
++	src_clk_div = DIV_ROUND_UP(priv->gpll_hz, hz);
++	assert(src_clk_div - 1 <= 127);
++
++	switch (clk_id) {
++	case SCLK_I2C0:
++		rk_clrsetreg(&cru->clksel_con[49],
++			     CLK_I2C_DIV_CON_MASK << CLK_I2C0_DIV_CON_SHIFT |
++			     CLK_I2C_PLL_SEL_MASK << CLK_I2C0_PLL_SEL_SHIFT,
++			     (src_clk_div - 1) << CLK_I2C0_DIV_CON_SHIFT |
++			     CLK_I2C_PLL_SEL_GPLL << CLK_I2C0_PLL_SEL_SHIFT);
++		break;
++	case SCLK_I2C1:
++		rk_clrsetreg(&cru->clksel_con[49],
++			     CLK_I2C_DIV_CON_MASK << CLK_I2C1_DIV_CON_SHIFT |
++			     CLK_I2C_PLL_SEL_MASK << CLK_I2C1_PLL_SEL_SHIFT,
++			     (src_clk_div - 1) << CLK_I2C1_DIV_CON_SHIFT |
++			     CLK_I2C_PLL_SEL_GPLL << CLK_I2C1_PLL_SEL_SHIFT);
++		break;
++	case SCLK_I2C2:
++		rk_clrsetreg(&cru->clksel_con[50],
++			     CLK_I2C_DIV_CON_MASK << CLK_I2C2_DIV_CON_SHIFT |
++			     CLK_I2C_PLL_SEL_MASK << CLK_I2C2_PLL_SEL_SHIFT,
++			     (src_clk_div - 1) << CLK_I2C2_DIV_CON_SHIFT |
++			     CLK_I2C_PLL_SEL_GPLL << CLK_I2C2_PLL_SEL_SHIFT);
++		break;
++	case SCLK_I2C3:
++		rk_clrsetreg(&cru->clksel_con[50],
++			     CLK_I2C_DIV_CON_MASK << CLK_I2C3_DIV_CON_SHIFT |
++			     CLK_I2C_PLL_SEL_MASK << CLK_I2C3_PLL_SEL_SHIFT,
++			     (src_clk_div - 1) << CLK_I2C3_DIV_CON_SHIFT |
++			     CLK_I2C_PLL_SEL_GPLL << CLK_I2C3_PLL_SEL_SHIFT);
++		break;
++	default:
++		printf("do not support this i2c bus\n");
++		return -EINVAL;
++	}
++
++	return px30_i2c_get_clk(priv, clk_id);
++}
++
++/*
++ * calculate best rational approximation for a given fraction
++ * taking into account restricted register size, e.g. to find
++ * appropriate values for a pll with 5 bit denominator and
++ * 8 bit numerator register fields, trying to set up with a
++ * frequency ratio of 3.1415, one would say:
++ *
++ * rational_best_approximation(31415, 10000,
++ *		(1 << 8) - 1, (1 << 5) - 1, &n, &d);
++ *
++ * you may look at given_numerator as a fixed point number,
++ * with the fractional part size described in given_denominator.
++ *
++ * for theoretical background, see:
++ * http://en.wikipedia.org/wiki/Continued_fraction
++ */
++static void rational_best_approximation(unsigned long given_numerator,
++					unsigned long given_denominator,
++					unsigned long max_numerator,
++					unsigned long max_denominator,
++					unsigned long *best_numerator,
++					unsigned long *best_denominator)
++{
++	unsigned long n, d, n0, d0, n1, d1;
++
++	n = given_numerator;
++	d = given_denominator;
++	n0 = 0;
++	d1 = 0;
++	n1 = 1;
++	d0 = 1;
++	for (;;) {
++		unsigned long t, a;
++
++		if (n1 > max_numerator || d1 > max_denominator) {
++			n1 = n0;
++			d1 = d0;
++			break;
++		}
++		if (d == 0)
++			break;
++		t = d;
++		a = n / d;
++		d = n % d;
++		n = t;
++		t = n0 + a * n1;
++		n0 = n1;
++		n1 = t;
++		t = d0 + a * d1;
++		d0 = d1;
++		d1 = t;
++	}
++	*best_numerator = n1;
++	*best_denominator = d1;
++}
++
++static ulong px30_i2s_get_clk(struct px30_clk_priv *priv, ulong clk_id)
++{
++	u32 con, fracdiv, gate;
++	u32 clk_src = priv->gpll_hz / 2;
++	unsigned long m, n;
++	struct px30_cru *cru = priv->cru;
++
++	switch (clk_id) {
++	case SCLK_I2S1:
++		con = readl(&cru->clksel_con[30]);
++		fracdiv = readl(&cru->clksel_con[31]);
++		gate = readl(&cru->clkgate_con[10]);
++		m = fracdiv & CLK_I2S1_FRAC_NUMERATOR_MASK;
++		m >>= CLK_I2S1_FRAC_NUMERATOR_SHIFT;
++		n = fracdiv & CLK_I2S1_FRAC_DENOMINATOR_MASK;
++		n >>= CLK_I2S1_FRAC_DENOMINATOR_SHIFT;
++		debug("con30: 0x%x, gate: 0x%x, frac: 0x%x\n",
++		      con, gate, fracdiv);
++		break;
++	default:
++		printf("do not support this i2s bus\n");
++		return -EINVAL;
++	}
++
++	return clk_src * n / m;
++}
++
++static ulong px30_i2s_set_clk(struct px30_clk_priv *priv, ulong clk_id, uint hz)
++{
++	u32 clk_src;
++	unsigned long m, n, val;
++	struct px30_cru *cru = priv->cru;
++
++	clk_src = priv->gpll_hz / 2;
++	rational_best_approximation(hz, clk_src,
++				    GENMASK(16 - 1, 0),
++				    GENMASK(16 - 1, 0),
++				    &m, &n);
++	switch (clk_id) {
++	case SCLK_I2S1:
++		rk_clrsetreg(&cru->clksel_con[30],
++			     CLK_I2S1_PLL_SEL_MASK, CLK_I2S1_PLL_SEL_GPLL);
++		rk_clrsetreg(&cru->clksel_con[30],
++			     CLK_I2S1_DIV_CON_MASK, 0x1);
++		rk_clrsetreg(&cru->clksel_con[30],
++			     CLK_I2S1_SEL_MASK, CLK_I2S1_SEL_FRAC);
++		val = m << CLK_I2S1_FRAC_NUMERATOR_SHIFT | n;
++		writel(val, &cru->clksel_con[31]);
++		rk_clrsetreg(&cru->clkgate_con[10],
++			     CLK_I2S1_OUT_MCLK_PAD_MASK,
++			     CLK_I2S1_OUT_MCLK_PAD_ENABLE);
++		break;
++	default:
++		printf("do not support this i2s bus\n");
++		return -EINVAL;
++	}
++
++	return px30_i2s_get_clk(priv, clk_id);
++}
++
++static ulong px30_nandc_get_clk(struct px30_clk_priv *priv)
++{
++	struct px30_cru *cru = priv->cru;
++	u32 div, con;
++
++	con = readl(&cru->clksel_con[15]);
++	div = (con & NANDC_DIV_MASK) >> NANDC_DIV_SHIFT;
++
++	return DIV_TO_RATE(priv->gpll_hz, div);
++}
++
++static ulong px30_nandc_set_clk(struct px30_clk_priv *priv,
++				ulong set_rate)
++{
++	struct px30_cru *cru = priv->cru;
++	int src_clk_div;
++
++	/* Select nandc source from GPLL by default */
++	/* nandc clock defaulg div 2 internal, need provide double in cru */
++	src_clk_div = DIV_ROUND_UP(priv->gpll_hz, set_rate);
++	assert(src_clk_div - 1 <= 31);
++
++	rk_clrsetreg(&cru->clksel_con[15],
++		     NANDC_CLK_SEL_MASK | NANDC_PLL_MASK |
++		     NANDC_DIV_MASK,
++		     NANDC_CLK_SEL_NANDC << NANDC_CLK_SEL_SHIFT |
++		     NANDC_SEL_GPLL << NANDC_PLL_SHIFT |
++		     (src_clk_div - 1) << NANDC_DIV_SHIFT);
++
++	return px30_nandc_get_clk(priv);
++}
++
++static ulong px30_mmc_get_clk(struct px30_clk_priv *priv, uint clk_id)
++{
++	struct px30_cru *cru = priv->cru;
++	u32 div, con, con_id;
++
++	switch (clk_id) {
++	case HCLK_SDMMC:
++	case SCLK_SDMMC:
++		con_id = 16;
++		break;
++	case HCLK_EMMC:
++	case SCLK_EMMC:
++	case SCLK_EMMC_SAMPLE:
++		con_id = 20;
++		break;
++	default:
++		return -EINVAL;
++	}
++
++	con = readl(&cru->clksel_con[con_id]);
++	div = (con & EMMC_DIV_MASK) >> EMMC_DIV_SHIFT;
++
++	if ((con & EMMC_PLL_MASK) >> EMMC_PLL_SHIFT
++	    == EMMC_SEL_24M)
++		return DIV_TO_RATE(OSC_HZ, div) / 2;
++	else
++		return DIV_TO_RATE(priv->gpll_hz, div) / 2;
++}
++
++static ulong px30_mmc_set_clk(struct px30_clk_priv *priv,
++			      ulong clk_id, ulong set_rate)
++{
++	struct px30_cru *cru = priv->cru;
++	int src_clk_div;
++	u32 con_id;
++
++	switch (clk_id) {
++	case HCLK_SDMMC:
++	case SCLK_SDMMC:
++		con_id = 16;
++		break;
++	case HCLK_EMMC:
++	case SCLK_EMMC:
++		con_id = 20;
++		break;
++	default:
++		return -EINVAL;
++	}
++
++	/* Select clk_sdmmc/emmc source from GPLL by default */
++	/* mmc clock defaulg div 2 internal, need provide double in cru */
++	src_clk_div = DIV_ROUND_UP(priv->gpll_hz / 2, set_rate);
++
++	if (src_clk_div > 127) {
++		/* use 24MHz source for 400KHz clock */
++		src_clk_div = DIV_ROUND_UP(OSC_HZ / 2, set_rate);
++		rk_clrsetreg(&cru->clksel_con[con_id],
++			     EMMC_PLL_MASK | EMMC_DIV_MASK,
++			     EMMC_SEL_24M << EMMC_PLL_SHIFT |
++			     (src_clk_div - 1) << EMMC_DIV_SHIFT);
++	} else {
++		rk_clrsetreg(&cru->clksel_con[con_id],
++			     EMMC_PLL_MASK | EMMC_DIV_MASK,
++			     EMMC_SEL_GPLL << EMMC_PLL_SHIFT |
++			     (src_clk_div - 1) << EMMC_DIV_SHIFT);
++	}
++	rk_clrsetreg(&cru->clksel_con[con_id + 1], EMMC_CLK_SEL_MASK,
++		     EMMC_CLK_SEL_EMMC);
++
++	return px30_mmc_get_clk(priv, clk_id);
++}
++
++static ulong px30_pwm_get_clk(struct px30_clk_priv *priv, ulong clk_id)
++{
++	struct px30_cru *cru = priv->cru;
++	u32 div, con;
++
++	switch (clk_id) {
++	case SCLK_PWM0:
++		con = readl(&cru->clksel_con[52]);
++		div = con >> CLK_PWM0_DIV_CON_SHIFT & CLK_PWM_DIV_CON_MASK;
++		break;
++	case SCLK_PWM1:
++		con = readl(&cru->clksel_con[52]);
++		div = con >> CLK_PWM1_DIV_CON_SHIFT & CLK_PWM_DIV_CON_MASK;
++		break;
++	default:
++		printf("do not support this pwm bus\n");
++		return -EINVAL;
++	}
++
++	return DIV_TO_RATE(priv->gpll_hz, div);
++}
++
++static ulong px30_pwm_set_clk(struct px30_clk_priv *priv, ulong clk_id, uint hz)
++{
++	struct px30_cru *cru = priv->cru;
++	int src_clk_div;
++
++	src_clk_div = DIV_ROUND_UP(priv->gpll_hz, hz);
++	assert(src_clk_div - 1 <= 127);
++
++	switch (clk_id) {
++	case SCLK_PWM0:
++		rk_clrsetreg(&cru->clksel_con[52],
++			     CLK_PWM_DIV_CON_MASK << CLK_PWM0_DIV_CON_SHIFT |
++			     CLK_PWM_PLL_SEL_MASK << CLK_PWM0_PLL_SEL_SHIFT,
++			     (src_clk_div - 1) << CLK_PWM0_DIV_CON_SHIFT |
++			     CLK_PWM_PLL_SEL_GPLL << CLK_PWM0_PLL_SEL_SHIFT);
++		break;
++	case SCLK_PWM1:
++		rk_clrsetreg(&cru->clksel_con[52],
++			     CLK_PWM_DIV_CON_MASK << CLK_PWM1_DIV_CON_SHIFT |
++			     CLK_PWM_PLL_SEL_MASK << CLK_PWM1_PLL_SEL_SHIFT,
++			     (src_clk_div - 1) << CLK_PWM1_DIV_CON_SHIFT |
++			     CLK_PWM_PLL_SEL_GPLL << CLK_PWM1_PLL_SEL_SHIFT);
++		break;
++	default:
++		printf("do not support this pwm bus\n");
++		return -EINVAL;
++	}
++
++	return px30_pwm_get_clk(priv, clk_id);
++}
++
++static ulong px30_saradc_get_clk(struct px30_clk_priv *priv)
++{
++	struct px30_cru *cru = priv->cru;
++	u32 div, con;
++
++	con = readl(&cru->clksel_con[55]);
++	div = con >> CLK_SARADC_DIV_CON_SHIFT & CLK_SARADC_DIV_CON_MASK;
++
++	return DIV_TO_RATE(OSC_HZ, div);
++}
++
++static ulong px30_saradc_set_clk(struct px30_clk_priv *priv, uint hz)
++{
++	struct px30_cru *cru = priv->cru;
++	int src_clk_div;
++
++	src_clk_div = DIV_ROUND_UP(OSC_HZ, hz);
++	assert(src_clk_div - 1 <= 2047);
++
++	rk_clrsetreg(&cru->clksel_con[55],
++		     CLK_SARADC_DIV_CON_MASK,
++		     (src_clk_div - 1) << CLK_SARADC_DIV_CON_SHIFT);
++
++	return px30_saradc_get_clk(priv);
++}
++
++static ulong px30_tsadc_get_clk(struct px30_clk_priv *priv)
++{
++	struct px30_cru *cru = priv->cru;
++	u32 div, con;
++
++	con = readl(&cru->clksel_con[54]);
++	div = con >> CLK_SARADC_DIV_CON_SHIFT & CLK_SARADC_DIV_CON_MASK;
++
++	return DIV_TO_RATE(OSC_HZ, div);
++}
++
++static ulong px30_tsadc_set_clk(struct px30_clk_priv *priv, uint hz)
++{
++	struct px30_cru *cru = priv->cru;
++	int src_clk_div;
++
++	src_clk_div = DIV_ROUND_UP(OSC_HZ, hz);
++	assert(src_clk_div - 1 <= 2047);
++
++	rk_clrsetreg(&cru->clksel_con[54],
++		     CLK_SARADC_DIV_CON_MASK,
++		     (src_clk_div - 1) << CLK_SARADC_DIV_CON_SHIFT);
++
++	return px30_tsadc_get_clk(priv);
++}
++
++static ulong px30_spi_get_clk(struct px30_clk_priv *priv, ulong clk_id)
++{
++	struct px30_cru *cru = priv->cru;
++	u32 div, con;
++
++	switch (clk_id) {
++	case SCLK_SPI0:
++		con = readl(&cru->clksel_con[53]);
++		div = con >> CLK_SPI0_DIV_CON_SHIFT & CLK_SPI_DIV_CON_MASK;
++		break;
++	case SCLK_SPI1:
++		con = readl(&cru->clksel_con[53]);
++		div = con >> CLK_SPI1_DIV_CON_SHIFT & CLK_SPI_DIV_CON_MASK;
++		break;
++	default:
++		printf("do not support this pwm bus\n");
++		return -EINVAL;
++	}
++
++	return DIV_TO_RATE(priv->gpll_hz, div);
++}
++
++static ulong px30_spi_set_clk(struct px30_clk_priv *priv, ulong clk_id, uint hz)
++{
++	struct px30_cru *cru = priv->cru;
++	int src_clk_div;
++
++	src_clk_div = DIV_ROUND_UP(priv->gpll_hz, hz);
++	assert(src_clk_div - 1 <= 127);
++
++	switch (clk_id) {
++	case SCLK_SPI0:
++		rk_clrsetreg(&cru->clksel_con[53],
++			     CLK_SPI_DIV_CON_MASK << CLK_SPI0_DIV_CON_SHIFT |
++			     CLK_SPI_PLL_SEL_MASK << CLK_SPI0_PLL_SEL_SHIFT,
++			     (src_clk_div - 1) << CLK_SPI0_DIV_CON_SHIFT |
++			     CLK_SPI_PLL_SEL_GPLL << CLK_SPI0_PLL_SEL_SHIFT);
++		break;
++	case SCLK_SPI1:
++		rk_clrsetreg(&cru->clksel_con[53],
++			     CLK_SPI_DIV_CON_MASK << CLK_SPI1_DIV_CON_SHIFT |
++			     CLK_SPI_PLL_SEL_MASK << CLK_SPI1_PLL_SEL_SHIFT,
++			     (src_clk_div - 1) << CLK_SPI1_DIV_CON_SHIFT |
++			     CLK_SPI_PLL_SEL_GPLL << CLK_SPI1_PLL_SEL_SHIFT);
++		break;
++	default:
++		printf("do not support this pwm bus\n");
++		return -EINVAL;
++	}
++
++	return px30_spi_get_clk(priv, clk_id);
++}
++
++static ulong px30_vop_get_clk(struct px30_clk_priv *priv, ulong clk_id)
++{
++	struct px30_cru *cru = priv->cru;
++	u32 div, con, parent;
++
++	switch (clk_id) {
++	case ACLK_VOPB:
++	case ACLK_VOPL:
++		con = readl(&cru->clksel_con[3]);
++		div = con & ACLK_VO_DIV_MASK;
++		parent = priv->gpll_hz;
++		break;
++	case DCLK_VOPB:
++		con = readl(&cru->clksel_con[5]);
++		div = con & DCLK_VOPB_DIV_MASK;
++		parent = rkclk_pll_get_rate(&cru->pll[CPLL], &cru->mode, CPLL);
++		break;
++	case DCLK_VOPL:
++		con = readl(&cru->clksel_con[8]);
++		div = con & DCLK_VOPL_DIV_MASK;
++		parent = rkclk_pll_get_rate(&cru->pll[NPLL], &cru->mode, NPLL);
++		break;
++	default:
++		return -ENOENT;
++	}
++
++	return DIV_TO_RATE(parent, div);
++}
++
++static ulong px30_vop_set_clk(struct px30_clk_priv *priv, ulong clk_id, uint hz)
++{
++	struct px30_cru *cru = priv->cru;
++	ulong npll_hz;
++	int src_clk_div;
++
++	switch (clk_id) {
++	case ACLK_VOPB:
++	case ACLK_VOPL:
++		src_clk_div = DIV_ROUND_UP(priv->gpll_hz, hz);
++		assert(src_clk_div - 1 <= 31);
++		rk_clrsetreg(&cru->clksel_con[3],
++			     ACLK_VO_PLL_MASK | ACLK_VO_DIV_MASK,
++			     ACLK_VO_SEL_GPLL << ACLK_VO_PLL_SHIFT |
++			     (src_clk_div - 1) << ACLK_VO_DIV_SHIFT);
++		break;
++	case DCLK_VOPB:
++		if (hz < PX30_VOP_PLL_LIMIT) {
++			src_clk_div = DIV_ROUND_UP(PX30_VOP_PLL_LIMIT, hz);
++			if (src_clk_div % 2)
++				src_clk_div = src_clk_div - 1;
++		} else {
++			src_clk_div = 1;
++		}
++		assert(src_clk_div - 1 <= 255);
++		rkclk_set_pll(&cru->pll[CPLL], &cru->mode,
++			      CPLL, hz * src_clk_div);
++		rk_clrsetreg(&cru->clksel_con[5],
++			     DCLK_VOPB_SEL_MASK | DCLK_VOPB_PLL_SEL_MASK |
++			     DCLK_VOPB_DIV_MASK,
++			     DCLK_VOPB_SEL_DIVOUT << DCLK_VOPB_SEL_SHIFT |
++			     DCLK_VOPB_PLL_SEL_CPLL << DCLK_VOPB_PLL_SEL_SHIFT |
++			     (src_clk_div - 1) << DCLK_VOPB_DIV_SHIFT);
++		break;
++	case DCLK_VOPL:
++		npll_hz = px30_clk_get_pll_rate(priv, NPLL);
++		if (npll_hz >= PX30_VOP_PLL_LIMIT && npll_hz >= hz &&
++		    npll_hz % hz == 0) {
++			src_clk_div = npll_hz / hz;
++			assert(src_clk_div - 1 <= 255);
++		} else {
++			if (hz < PX30_VOP_PLL_LIMIT) {
++				src_clk_div = DIV_ROUND_UP(PX30_VOP_PLL_LIMIT,
++							   hz);
++				if (src_clk_div % 2)
++					src_clk_div = src_clk_div - 1;
++			} else {
++				src_clk_div = 1;
++			}
++			assert(src_clk_div - 1 <= 255);
++			rkclk_set_pll(&cru->pll[NPLL], &cru->mode, NPLL,
++				      hz * src_clk_div);
++		}
++		rk_clrsetreg(&cru->clksel_con[8],
++			     DCLK_VOPL_SEL_MASK | DCLK_VOPL_PLL_SEL_MASK |
++			     DCLK_VOPL_DIV_MASK,
++			     DCLK_VOPL_SEL_DIVOUT << DCLK_VOPL_SEL_SHIFT |
++			     DCLK_VOPL_PLL_SEL_NPLL << DCLK_VOPL_PLL_SEL_SHIFT |
++			     (src_clk_div - 1) << DCLK_VOPL_DIV_SHIFT);
++		break;
++	default:
++		printf("do not support this vop freq\n");
++		return -EINVAL;
++	}
++
++	return px30_vop_get_clk(priv, clk_id);
++}
++
++static ulong px30_bus_get_clk(struct px30_clk_priv *priv, ulong clk_id)
++{
++	struct px30_cru *cru = priv->cru;
++	u32 div, con, parent;
++
++	switch (clk_id) {
++	case ACLK_BUS_PRE:
++		con = readl(&cru->clksel_con[23]);
++		div = (con & BUS_ACLK_DIV_MASK) >> BUS_ACLK_DIV_SHIFT;
++		parent = priv->gpll_hz;
++		break;
++	case HCLK_BUS_PRE:
++		con = readl(&cru->clksel_con[24]);
++		div = (con & BUS_HCLK_DIV_MASK) >> BUS_HCLK_DIV_SHIFT;
++		parent = priv->gpll_hz;
++		break;
++	case PCLK_BUS_PRE:
++	case PCLK_WDT_NS:
++		parent = px30_bus_get_clk(priv, ACLK_BUS_PRE);
++		con = readl(&cru->clksel_con[24]);
++		div = (con & BUS_PCLK_DIV_MASK) >> BUS_PCLK_DIV_SHIFT;
++		break;
++	default:
++		return -ENOENT;
++	}
++
++	return DIV_TO_RATE(parent, div);
++}
++
++static ulong px30_bus_set_clk(struct px30_clk_priv *priv, ulong clk_id,
++			      ulong hz)
++{
++	struct px30_cru *cru = priv->cru;
++	int src_clk_div;
++
++	/*
++	 * select gpll as pd_bus bus clock source and
++	 * set up dependent divisors for PCLK/HCLK and ACLK clocks.
++	 */
++	switch (clk_id) {
++	case ACLK_BUS_PRE:
++		src_clk_div = DIV_ROUND_UP(priv->gpll_hz, hz);
++		assert(src_clk_div - 1 <= 31);
++		rk_clrsetreg(&cru->clksel_con[23],
++			     BUS_PLL_SEL_MASK | BUS_ACLK_DIV_MASK,
++			     BUS_PLL_SEL_GPLL << BUS_PLL_SEL_SHIFT |
++			     (src_clk_div - 1) << BUS_ACLK_DIV_SHIFT);
++		break;
++	case HCLK_BUS_PRE:
++		src_clk_div = DIV_ROUND_UP(priv->gpll_hz, hz);
++		assert(src_clk_div - 1 <= 31);
++		rk_clrsetreg(&cru->clksel_con[24],
++			     BUS_PLL_SEL_MASK | BUS_HCLK_DIV_MASK,
++			     BUS_PLL_SEL_GPLL << BUS_PLL_SEL_SHIFT |
++			     (src_clk_div - 1) << BUS_HCLK_DIV_SHIFT);
++		break;
++	case PCLK_BUS_PRE:
++		src_clk_div =
++			DIV_ROUND_UP(px30_bus_get_clk(priv, ACLK_BUS_PRE), hz);
++		assert(src_clk_div - 1 <= 3);
++		rk_clrsetreg(&cru->clksel_con[24],
++			     BUS_PCLK_DIV_MASK,
++			     (src_clk_div - 1) << BUS_PCLK_DIV_SHIFT);
++		break;
++	default:
++		printf("do not support this bus freq\n");
++		return -EINVAL;
++	}
++
++	return px30_bus_get_clk(priv, clk_id);
++}
++
++static ulong px30_peri_get_clk(struct px30_clk_priv *priv, ulong clk_id)
++{
++	struct px30_cru *cru = priv->cru;
++	u32 div, con, parent;
++
++	switch (clk_id) {
++	case ACLK_PERI_PRE:
++		con = readl(&cru->clksel_con[14]);
++		div = (con & PERI_ACLK_DIV_MASK) >> PERI_ACLK_DIV_SHIFT;
++		parent = priv->gpll_hz;
++		break;
++	case HCLK_PERI_PRE:
++		con = readl(&cru->clksel_con[14]);
++		div = (con & PERI_HCLK_DIV_MASK) >> PERI_HCLK_DIV_SHIFT;
++		parent = priv->gpll_hz;
++		break;
++	default:
++		return -ENOENT;
++	}
++
++	return DIV_TO_RATE(parent, div);
++}
++
++static ulong px30_peri_set_clk(struct px30_clk_priv *priv, ulong clk_id,
++			       ulong hz)
++{
++	struct px30_cru *cru = priv->cru;
++	int src_clk_div;
++
++	src_clk_div = DIV_ROUND_UP(priv->gpll_hz, hz);
++	assert(src_clk_div - 1 <= 31);
++
++	/*
++	 * select gpll as pd_peri bus clock source and
++	 * set up dependent divisors for HCLK and ACLK clocks.
++	 */
++	switch (clk_id) {
++	case ACLK_PERI_PRE:
++		rk_clrsetreg(&cru->clksel_con[14],
++			     PERI_PLL_SEL_MASK | PERI_ACLK_DIV_MASK,
++			     PERI_PLL_GPLL << PERI_PLL_SEL_SHIFT |
++			     (src_clk_div - 1) << PERI_ACLK_DIV_SHIFT);
++		break;
++	case HCLK_PERI_PRE:
++		rk_clrsetreg(&cru->clksel_con[14],
++			     PERI_PLL_SEL_MASK | PERI_HCLK_DIV_MASK,
++			     PERI_PLL_GPLL << PERI_PLL_SEL_SHIFT |
++			     (src_clk_div - 1) << PERI_HCLK_DIV_SHIFT);
++		break;
++	default:
++		printf("do not support this peri freq\n");
++		return -EINVAL;
++	}
++
++	return px30_peri_get_clk(priv, clk_id);
++}
++
++#ifndef CONFIG_SPL_BUILD
++static ulong px30_crypto_get_clk(struct px30_clk_priv *priv, ulong clk_id)
++{
++	struct px30_cru *cru = priv->cru;
++	u32 div, con, parent;
++
++	switch (clk_id) {
++	case SCLK_CRYPTO:
++		con = readl(&cru->clksel_con[25]);
++		div = (con & CRYPTO_DIV_MASK) >> CRYPTO_DIV_SHIFT;
++		parent = priv->gpll_hz;
++		break;
++	case SCLK_CRYPTO_APK:
++		con = readl(&cru->clksel_con[25]);
++		div = (con & CRYPTO_APK_DIV_MASK) >> CRYPTO_APK_DIV_SHIFT;
++		parent = priv->gpll_hz;
++		break;
++	default:
++		return -ENOENT;
++	}
++
++	return DIV_TO_RATE(parent, div);
++}
++
++static ulong px30_crypto_set_clk(struct px30_clk_priv *priv, ulong clk_id,
++				 ulong hz)
++{
++	struct px30_cru *cru = priv->cru;
++	int src_clk_div;
++
++	src_clk_div = DIV_ROUND_UP(priv->gpll_hz, hz);
++	assert(src_clk_div - 1 <= 31);
++
++	/*
++	 * select gpll as crypto clock source and
++	 * set up dependent divisors for crypto clocks.
++	 */
++	switch (clk_id) {
++	case SCLK_CRYPTO:
++		rk_clrsetreg(&cru->clksel_con[25],
++			     CRYPTO_PLL_SEL_MASK | CRYPTO_DIV_MASK,
++			     CRYPTO_PLL_SEL_GPLL << CRYPTO_PLL_SEL_SHIFT |
++			     (src_clk_div - 1) << CRYPTO_DIV_SHIFT);
++		break;
++	case SCLK_CRYPTO_APK:
++		rk_clrsetreg(&cru->clksel_con[25],
++			     CRYPTO_APK_PLL_SEL_MASK | CRYPTO_APK_DIV_MASK,
++			     CRYPTO_PLL_SEL_GPLL << CRYPTO_APK_SEL_SHIFT |
++			     (src_clk_div - 1) << CRYPTO_APK_DIV_SHIFT);
++		break;
++	default:
++		printf("do not support this peri freq\n");
++		return -EINVAL;
++	}
++
++	return px30_crypto_get_clk(priv, clk_id);
++}
++
++static ulong px30_i2s1_mclk_get_clk(struct px30_clk_priv *priv, ulong clk_id)
++{
++	struct px30_cru *cru = priv->cru;
++	u32 con;
++
++	con = readl(&cru->clksel_con[30]);
++
++	if (!(con & CLK_I2S1_OUT_SEL_MASK))
++		return -ENOENT;
++
++	return 12000000;
++}
++
++static ulong px30_i2s1_mclk_set_clk(struct px30_clk_priv *priv, ulong clk_id,
++				    ulong hz)
++{
++	struct px30_cru *cru = priv->cru;
++
++	if (hz != 12000000) {
++		printf("do not support this i2s1_mclk freq\n");
++		return -EINVAL;
++	}
++
++	rk_clrsetreg(&cru->clksel_con[30], CLK_I2S1_OUT_SEL_MASK,
++		     CLK_I2S1_OUT_SEL_OSC);
++	rk_clrsetreg(&cru->clkgate_con[10], CLK_I2S1_OUT_MCLK_PAD_MASK,
++		     CLK_I2S1_OUT_MCLK_PAD_ENABLE);
++
++	return px30_i2s1_mclk_get_clk(priv, clk_id);
++}
++
++static ulong px30_mac_set_clk(struct px30_clk_priv *priv, uint hz)
++{
++	struct px30_cru *cru = priv->cru;
++	u32 con = readl(&cru->clksel_con[22]);
++	ulong pll_rate;
++	u8 div;
++
++	if ((con >> GMAC_PLL_SEL_SHIFT) & GMAC_PLL_SEL_CPLL)
++		pll_rate = px30_clk_get_pll_rate(priv, CPLL);
++	else if ((con >> GMAC_PLL_SEL_SHIFT) & GMAC_PLL_SEL_NPLL)
++		pll_rate = px30_clk_get_pll_rate(priv, NPLL);
++	else
++		pll_rate = priv->gpll_hz;
++
++	/*default set 50MHZ for gmac*/
++	if (!hz)
++		hz = 50000000;
++
++	div = DIV_ROUND_UP(pll_rate, hz) - 1;
++	assert(div < 32);
++	rk_clrsetreg(&cru->clksel_con[22], CLK_GMAC_DIV_MASK,
++		     div << CLK_GMAC_DIV_SHIFT);
++
++	return DIV_TO_RATE(pll_rate, div);
++}
++
++static int px30_mac_set_speed_clk(struct px30_clk_priv *priv, uint hz)
++{
++	struct px30_cru *cru = priv->cru;
++
++	if (hz != 2500000 && hz != 25000000) {
++		debug("Unsupported mac speed:%d\n", hz);
++		return -EINVAL;
++	}
++
++	rk_clrsetreg(&cru->clksel_con[23], RMII_CLK_SEL_MASK,
++		     ((hz == 2500000) ? 0 : 1) << RMII_CLK_SEL_SHIFT);
++
++	return 0;
++}
++
++#endif
++
++static ulong px30_clk_get_pll_rate(struct px30_clk_priv *priv,
++				   enum px30_pll_id pll_id)
++{
++	struct px30_cru *cru = priv->cru;
++
++	return rkclk_pll_get_rate(&cru->pll[pll_id], &cru->mode, pll_id);
++}
++
++static ulong px30_clk_set_pll_rate(struct px30_clk_priv *priv,
++				   enum px30_pll_id pll_id, ulong hz)
++{
++	struct px30_cru *cru = priv->cru;
++
++	if (rkclk_set_pll(&cru->pll[pll_id], &cru->mode, pll_id, hz))
++		return -EINVAL;
++	return rkclk_pll_get_rate(&cru->pll[pll_id], &cru->mode, pll_id);
++}
++
++static ulong px30_armclk_set_clk(struct px30_clk_priv *priv, ulong hz)
++{
++	struct px30_cru *cru = priv->cru;
++	const struct cpu_rate_table *rate;
++	ulong old_rate;
++
++	rate = get_cpu_settings(hz);
++	if (!rate) {
++		printf("%s unsupport rate\n", __func__);
++		return -EINVAL;
++	}
++
++	/*
++	 * select apll as cpu/core clock pll source and
++	 * set up dependent divisors for PERI and ACLK clocks.
++	 * core hz : apll = 1:1
++	 */
++	old_rate = px30_clk_get_pll_rate(priv, APLL);
++	if (old_rate > hz) {
++		if (rkclk_set_pll(&cru->pll[APLL], &cru->mode, APLL, hz))
++			return -EINVAL;
++		rk_clrsetreg(&cru->clksel_con[0],
++			     CORE_CLK_PLL_SEL_MASK | CORE_DIV_CON_MASK |
++			     CORE_ACLK_DIV_MASK | CORE_DBG_DIV_MASK,
++			     rate->aclk_div << CORE_ACLK_DIV_SHIFT |
++			     rate->pclk_div << CORE_DBG_DIV_SHIFT |
++			     CORE_CLK_PLL_SEL_APLL << CORE_CLK_PLL_SEL_SHIFT |
++			     0 << CORE_DIV_CON_SHIFT);
++	} else if (old_rate < hz) {
++		rk_clrsetreg(&cru->clksel_con[0],
++			     CORE_CLK_PLL_SEL_MASK | CORE_DIV_CON_MASK |
++			     CORE_ACLK_DIV_MASK | CORE_DBG_DIV_MASK,
++			     rate->aclk_div << CORE_ACLK_DIV_SHIFT |
++			     rate->pclk_div << CORE_DBG_DIV_SHIFT |
++			     CORE_CLK_PLL_SEL_APLL << CORE_CLK_PLL_SEL_SHIFT |
++			     0 << CORE_DIV_CON_SHIFT);
++		if (rkclk_set_pll(&cru->pll[APLL], &cru->mode, APLL, hz))
++			return -EINVAL;
++	}
++
++	return px30_clk_get_pll_rate(priv, APLL);
++}
++
++static ulong px30_clk_get_rate(struct clk *clk)
++{
++	struct px30_clk_priv *priv = dev_get_priv(clk->dev);
++	ulong rate = 0;
++
++	if (!priv->gpll_hz && clk->id > ARMCLK) {
++		printf("%s gpll=%lu\n", __func__, priv->gpll_hz);
++		return -ENOENT;
++	}
++
++	debug("%s %ld\n", __func__, clk->id);
++	switch (clk->id) {
++	case PLL_APLL:
++		rate = px30_clk_get_pll_rate(priv, APLL);
++		break;
++	case PLL_DPLL:
++		rate = px30_clk_get_pll_rate(priv, DPLL);
++		break;
++	case PLL_CPLL:
++		rate = px30_clk_get_pll_rate(priv, CPLL);
++		break;
++	case PLL_NPLL:
++		rate = px30_clk_get_pll_rate(priv, NPLL);
++		break;
++	case ARMCLK:
++		rate = px30_clk_get_pll_rate(priv, APLL);
++		break;
++	case HCLK_SDMMC:
++	case HCLK_EMMC:
++	case SCLK_SDMMC:
++	case SCLK_EMMC:
++	case SCLK_EMMC_SAMPLE:
++		rate = px30_mmc_get_clk(priv, clk->id);
++		break;
++	case SCLK_I2C0:
++	case SCLK_I2C1:
++	case SCLK_I2C2:
++	case SCLK_I2C3:
++		rate = px30_i2c_get_clk(priv, clk->id);
++		break;
++	case SCLK_I2S1:
++		rate = px30_i2s_get_clk(priv, clk->id);
++		break;
++	case SCLK_NANDC:
++		rate = px30_nandc_get_clk(priv);
++		break;
++	case SCLK_PWM0:
++	case SCLK_PWM1:
++		rate = px30_pwm_get_clk(priv, clk->id);
++		break;
++	case SCLK_SARADC:
++		rate = px30_saradc_get_clk(priv);
++		break;
++	case SCLK_TSADC:
++		rate = px30_tsadc_get_clk(priv);
++		break;
++	case SCLK_SPI0:
++	case SCLK_SPI1:
++		rate = px30_spi_get_clk(priv, clk->id);
++		break;
++	case ACLK_VOPB:
++	case ACLK_VOPL:
++	case DCLK_VOPB:
++	case DCLK_VOPL:
++		rate = px30_vop_get_clk(priv, clk->id);
++		break;
++	case ACLK_BUS_PRE:
++	case HCLK_BUS_PRE:
++	case PCLK_BUS_PRE:
++	case PCLK_WDT_NS:
++		rate = px30_bus_get_clk(priv, clk->id);
++		break;
++	case ACLK_PERI_PRE:
++	case HCLK_PERI_PRE:
++		rate = px30_peri_get_clk(priv, clk->id);
++		break;
++#ifndef CONFIG_SPL_BUILD
++	case SCLK_CRYPTO:
++	case SCLK_CRYPTO_APK:
++		rate = px30_crypto_get_clk(priv, clk->id);
++		break;
++#endif
++	default:
++		return -ENOENT;
++	}
++
++	return rate;
++}
++
++static ulong px30_clk_set_rate(struct clk *clk, ulong rate)
++{
++	struct px30_clk_priv *priv = dev_get_priv(clk->dev);
++	ulong ret = 0;
++
++	if (!priv->gpll_hz && clk->id > ARMCLK) {
++		printf("%s gpll=%lu\n", __func__, priv->gpll_hz);
++		return -ENOENT;
++	}
++
++	debug("%s %ld %ld\n", __func__, clk->id, rate);
++	switch (clk->id) {
++	case PLL_NPLL:
++		ret = px30_clk_set_pll_rate(priv, NPLL, rate);
++		break;
++	case ARMCLK:
++		ret = px30_armclk_set_clk(priv, rate);
++		break;
++	case HCLK_SDMMC:
++	case HCLK_EMMC:
++	case SCLK_SDMMC:
++	case SCLK_EMMC:
++		ret = px30_mmc_set_clk(priv, clk->id, rate);
++		break;
++	case SCLK_I2C0:
++	case SCLK_I2C1:
++	case SCLK_I2C2:
++	case SCLK_I2C3:
++		ret = px30_i2c_set_clk(priv, clk->id, rate);
++		break;
++	case SCLK_I2S1:
++		ret = px30_i2s_set_clk(priv, clk->id, rate);
++		break;
++	case SCLK_NANDC:
++		ret = px30_nandc_set_clk(priv, rate);
++		break;
++	case SCLK_PWM0:
++	case SCLK_PWM1:
++		ret = px30_pwm_set_clk(priv, clk->id, rate);
++		break;
++	case SCLK_SARADC:
++		ret = px30_saradc_set_clk(priv, rate);
++		break;
++	case SCLK_TSADC:
++		ret = px30_tsadc_set_clk(priv, rate);
++		break;
++	case SCLK_SPI0:
++	case SCLK_SPI1:
++		ret = px30_spi_set_clk(priv, clk->id, rate);
++		break;
++	case ACLK_VOPB:
++	case ACLK_VOPL:
++	case DCLK_VOPB:
++	case DCLK_VOPL:
++		ret = px30_vop_set_clk(priv, clk->id, rate);
++		break;
++	case ACLK_BUS_PRE:
++	case HCLK_BUS_PRE:
++	case PCLK_BUS_PRE:
++		ret = px30_bus_set_clk(priv, clk->id, rate);
++		break;
++	case ACLK_PERI_PRE:
++	case HCLK_PERI_PRE:
++		ret = px30_peri_set_clk(priv, clk->id, rate);
++		break;
++#ifndef CONFIG_SPL_BUILD
++	case SCLK_CRYPTO:
++	case SCLK_CRYPTO_APK:
++		ret = px30_crypto_set_clk(priv, clk->id, rate);
++		break;
++	case SCLK_I2S1_OUT:
++		ret = px30_i2s1_mclk_set_clk(priv, clk->id, rate);
++		break;
++	case SCLK_GMAC:
++	case SCLK_GMAC_SRC:
++		ret = px30_mac_set_clk(priv, rate);
++		break;
++	case SCLK_GMAC_RMII:
++		ret = px30_mac_set_speed_clk(priv, rate);
++		break;
++#endif
++	default:
++		return -ENOENT;
++	}
++
++	return ret;
++}
++
++#if CONFIG_IS_ENABLED(OF_CONTROL) && !CONFIG_IS_ENABLED(OF_PLATDATA)
++static int px30_gmac_set_parent(struct clk *clk, struct clk *parent)
++{
++	struct px30_clk_priv *priv = dev_get_priv(clk->dev);
++	struct px30_cru *cru = priv->cru;
++
++	if (parent->id == SCLK_GMAC_SRC) {
++		debug("%s: switching GAMC to SCLK_GMAC_SRC\n", __func__);
++		rk_clrsetreg(&cru->clksel_con[23], RMII_EXTCLK_SEL_MASK,
++			     RMII_EXTCLK_SEL_INT << RMII_EXTCLK_SEL_SHIFT);
++	} else {
++		debug("%s: switching GMAC to external clock\n", __func__);
++		rk_clrsetreg(&cru->clksel_con[23], RMII_EXTCLK_SEL_MASK,
++			     RMII_EXTCLK_SEL_EXT << RMII_EXTCLK_SEL_SHIFT);
++	}
++	return 0;
++}
++
++static int px30_clk_set_parent(struct clk *clk, struct clk *parent)
++{
++	switch (clk->id) {
++	case SCLK_GMAC:
++		return px30_gmac_set_parent(clk, parent);
++	default:
++		return -ENOENT;
++	}
++}
++#endif
++
++static int px30_clk_enable(struct clk *clk)
++{
++	switch (clk->id) {
++	case HCLK_HOST:
++	case SCLK_GMAC:
++	case SCLK_GMAC_RX_TX:
++	case SCLK_MAC_REF:
++	case SCLK_MAC_REFOUT:
++	case ACLK_GMAC:
++	case PCLK_GMAC:
++	case SCLK_GMAC_RMII:
++		/* Required to successfully probe the Designware GMAC driver */
++		return 0;
++	}
++
++	debug("%s: unsupported clk %ld\n", __func__, clk->id);
++	return -ENOENT;
++}
++
++static struct clk_ops px30_clk_ops = {
++	.get_rate = px30_clk_get_rate,
++	.set_rate = px30_clk_set_rate,
++#if CONFIG_IS_ENABLED(OF_CONTROL) && !CONFIG_IS_ENABLED(OF_PLATDATA)
++	.set_parent = px30_clk_set_parent,
++#endif
++	.enable = px30_clk_enable,
++};
++
++static void px30_clk_init(struct px30_clk_priv *priv)
++{
++	ulong npll_hz;
++	int ret;
++
++	npll_hz = px30_clk_get_pll_rate(priv, NPLL);
++	if (npll_hz != NPLL_HZ) {
++		ret = px30_clk_set_pll_rate(priv, NPLL, NPLL_HZ);
++		if (ret < 0)
++			printf("%s failed to set npll rate\n", __func__);
++	}
++
++	px30_bus_set_clk(priv, ACLK_BUS_PRE, ACLK_BUS_HZ);
++	px30_bus_set_clk(priv, HCLK_BUS_PRE, HCLK_BUS_HZ);
++	px30_bus_set_clk(priv, PCLK_BUS_PRE, PCLK_BUS_HZ);
++	px30_peri_set_clk(priv, ACLK_PERI_PRE, ACLK_PERI_HZ);
++	px30_peri_set_clk(priv, HCLK_PERI_PRE, HCLK_PERI_HZ);
++}
++
++static int px30_clk_probe(struct udevice *dev)
++{
++	struct px30_clk_priv *priv = dev_get_priv(dev);
++	struct clk clk_gpll;
++	int ret;
++
++	if (px30_clk_get_pll_rate(priv, APLL) != APLL_HZ)
++		px30_armclk_set_clk(priv, APLL_HZ);
++
++	/* get the GPLL rate from the pmucru */
++	ret = clk_get_by_name(dev, "gpll", &clk_gpll);
++	if (ret) {
++		printf("%s: failed to get gpll clk from pmucru\n", __func__);
++		return ret;
++	}
++
++	priv->gpll_hz = clk_get_rate(&clk_gpll);
++
++	px30_clk_init(priv);
++
++	return 0;
++}
++
++static int px30_clk_ofdata_to_platdata(struct udevice *dev)
++{
++	struct px30_clk_priv *priv = dev_get_priv(dev);
++
++	priv->cru = dev_read_addr_ptr(dev);
++
++	return 0;
++}
++
++static int px30_clk_bind(struct udevice *dev)
++{
++	int ret;
++	struct udevice *sys_child;
++	struct sysreset_reg *priv;
++
++	/* The reset driver does not have a device node, so bind it here */
++	ret = device_bind_driver(dev, "rockchip_sysreset", "sysreset",
++				 &sys_child);
++	if (ret) {
++		debug("Warning: No sysreset driver: ret=%d\n", ret);
++	} else {
++		priv = malloc(sizeof(struct sysreset_reg));
++		priv->glb_srst_fst_value = offsetof(struct px30_cru,
++						    glb_srst_fst);
++		priv->glb_srst_snd_value = offsetof(struct px30_cru,
++						    glb_srst_snd);
++		sys_child->priv = priv;
++	}
++
++#if CONFIG_IS_ENABLED(RESET_ROCKCHIP)
++	ret = offsetof(struct px30_cru, softrst_con[0]);
++	ret = rockchip_reset_bind(dev, ret, 12);
++	if (ret)
++		debug("Warning: software reset driver bind faile\n");
++#endif
++
++	return 0;
++}
++
++static const struct udevice_id px30_clk_ids[] = {
++	{ .compatible = "rockchip,px30-cru" },
++	{ }
++};
++
++U_BOOT_DRIVER(rockchip_px30_cru) = {
++	.name		= "rockchip_px30_cru",
++	.id		= UCLASS_CLK,
++	.of_match	= px30_clk_ids,
++	.priv_auto_alloc_size = sizeof(struct px30_clk_priv),
++	.ofdata_to_platdata = px30_clk_ofdata_to_platdata,
++	.ops		= &px30_clk_ops,
++	.bind		= px30_clk_bind,
++	.probe		= px30_clk_probe,
++};
++
++static ulong px30_pclk_pmu_get_pmuclk(struct px30_pmuclk_priv *priv)
++{
++	struct px30_pmucru *pmucru = priv->pmucru;
++	u32 div, con;
++
++	con = readl(&pmucru->pmu_clksel_con[0]);
++	div = (con & CLK_PMU_PCLK_DIV_MASK) >> CLK_PMU_PCLK_DIV_SHIFT;
++
++	return DIV_TO_RATE(priv->gpll_hz, div);
++}
++
++static ulong px30_pclk_pmu_set_pmuclk(struct px30_pmuclk_priv *priv, ulong hz)
++{
++	struct px30_pmucru *pmucru = priv->pmucru;
++	int src_clk_div;
++
++	src_clk_div = DIV_ROUND_UP(priv->gpll_hz, hz);
++	assert(src_clk_div - 1 <= 31);
++
++	rk_clrsetreg(&pmucru->pmu_clksel_con[0],
++		     CLK_PMU_PCLK_DIV_MASK,
++		     (src_clk_div - 1) << CLK_PMU_PCLK_DIV_SHIFT);
++
++	return px30_pclk_pmu_get_pmuclk(priv);
++}
++
++static ulong px30_pmuclk_get_gpll_rate(struct px30_pmuclk_priv *priv)
++{
++	struct px30_pmucru *pmucru = priv->pmucru;
++
++	return rkclk_pll_get_rate(&pmucru->pll, &pmucru->pmu_mode, GPLL);
++}
++
++static ulong px30_pmuclk_set_gpll_rate(struct px30_pmuclk_priv *priv, ulong hz)
++{
++	struct px30_pmucru *pmucru = priv->pmucru;
++	ulong pclk_pmu_rate;
++	u32 div;
++
++	if (priv->gpll_hz == hz)
++		return priv->gpll_hz;
++
++	div = DIV_ROUND_UP(hz, priv->gpll_hz);
++
++	/* save clock rate */
++	pclk_pmu_rate = px30_pclk_pmu_get_pmuclk(priv);
++
++	/* avoid rate too large, reduce rate first */
++	px30_pclk_pmu_set_pmuclk(priv, pclk_pmu_rate / div);
++
++	/* change gpll rate */
++	rkclk_set_pll(&pmucru->pll, &pmucru->pmu_mode, GPLL, hz);
++	priv->gpll_hz = px30_pmuclk_get_gpll_rate(priv);
++
++	/* restore clock rate */
++	px30_pclk_pmu_set_pmuclk(priv, pclk_pmu_rate);
++
++	return priv->gpll_hz;
++}
++
++static ulong px30_pmuclk_get_rate(struct clk *clk)
++{
++	struct px30_pmuclk_priv *priv = dev_get_priv(clk->dev);
++	ulong rate = 0;
++
++	debug("%s %ld\n", __func__, clk->id);
++	switch (clk->id) {
++	case PLL_GPLL:
++		rate = px30_pmuclk_get_gpll_rate(priv);
++		break;
++	case PCLK_PMU_PRE:
++		rate = px30_pclk_pmu_get_pmuclk(priv);
++		break;
++	default:
++		return -ENOENT;
++	}
++
++	return rate;
++}
++
++static ulong px30_pmuclk_set_rate(struct clk *clk, ulong rate)
++{
++	struct px30_pmuclk_priv *priv = dev_get_priv(clk->dev);
++	ulong ret = 0;
++
++	debug("%s %ld %ld\n", __func__, clk->id, rate);
++	switch (clk->id) {
++	case PLL_GPLL:
++		ret = px30_pmuclk_set_gpll_rate(priv, rate);
++		break;
++	case PCLK_PMU_PRE:
++		ret = px30_pclk_pmu_set_pmuclk(priv, rate);
++		break;
++	default:
++		return -ENOENT;
++	}
++
++	return ret;
++}
++
++static struct clk_ops px30_pmuclk_ops = {
++	.get_rate = px30_pmuclk_get_rate,
++	.set_rate = px30_pmuclk_set_rate,
++};
++
++static void px30_pmuclk_init(struct px30_pmuclk_priv *priv)
++{
++	priv->gpll_hz = px30_pmuclk_get_gpll_rate(priv);
++	px30_pmuclk_set_gpll_rate(priv, GPLL_HZ);
++
++	px30_pclk_pmu_set_pmuclk(priv, PCLK_PMU_HZ);
++}
++
++static int px30_pmuclk_probe(struct udevice *dev)
++{
++	struct px30_pmuclk_priv *priv = dev_get_priv(dev);
++
++	px30_pmuclk_init(priv);
++
++	return 0;
++}
++
++static int px30_pmuclk_ofdata_to_platdata(struct udevice *dev)
++{
++	struct px30_pmuclk_priv *priv = dev_get_priv(dev);
++
++	priv->pmucru = dev_read_addr_ptr(dev);
++
++	return 0;
++}
++
++static const struct udevice_id px30_pmuclk_ids[] = {
++	{ .compatible = "rockchip,px30-pmucru" },
++	{ }
++};
++
++U_BOOT_DRIVER(rockchip_px30_pmucru) = {
++	.name		= "rockchip_px30_pmucru",
++	.id		= UCLASS_CLK,
++	.of_match	= px30_pmuclk_ids,
++	.priv_auto_alloc_size = sizeof(struct px30_pmuclk_priv),
++	.ofdata_to_platdata = px30_pmuclk_ofdata_to_platdata,
++	.ops		= &px30_pmuclk_ops,
++	.probe		= px30_pmuclk_probe,
++};
+diff --git a/include/dt-bindings/clock/px30-cru.h b/include/dt-bindings/clock/px30-cru.h
+new file mode 100644
+index 0000000000..e5e59690b5
+--- /dev/null
++++ b/include/dt-bindings/clock/px30-cru.h
+@@ -0,0 +1,389 @@
++/* SPDX-License-Identifier: GPL-2.0 */
++/*
++ * Copyright (c) 2017 Rockchip Electronics Co. Ltd.
++ * Author: Elaine <zhangqing@rock-chips.com>
++ */
++
++#ifndef _DT_BINDINGS_CLK_ROCKCHIP_PX30_H
++#define _DT_BINDINGS_CLK_ROCKCHIP_PX30_H
++
++/* core clocks */
++#define PLL_APLL		1
++#define PLL_DPLL		2
++#define PLL_CPLL		3
++#define PLL_NPLL		4
++#define APLL_BOOST_H		5
++#define APLL_BOOST_L		6
++#define ARMCLK			7
++
++/* sclk gates (special clocks) */
++#define USB480M			14
++#define SCLK_PDM		15
++#define SCLK_I2S0_TX		16
++#define SCLK_I2S0_TX_OUT	17
++#define SCLK_I2S0_RX		18
++#define SCLK_I2S0_RX_OUT	19
++#define SCLK_I2S1		20
++#define SCLK_I2S1_OUT		21
++#define SCLK_I2S2		22
++#define SCLK_I2S2_OUT		23
++#define SCLK_UART1		24
++#define SCLK_UART2		25
++#define SCLK_UART3		26
++#define SCLK_UART4		27
++#define SCLK_UART5		28
++#define SCLK_I2C0		29
++#define SCLK_I2C1		30
++#define SCLK_I2C2		31
++#define SCLK_I2C3		32
++#define SCLK_I2C4		33
++#define SCLK_PWM0		34
++#define SCLK_PWM1		35
++#define SCLK_SPI0		36
++#define SCLK_SPI1		37
++#define SCLK_TIMER0		38
++#define SCLK_TIMER1		39
++#define SCLK_TIMER2		40
++#define SCLK_TIMER3		41
++#define SCLK_TIMER4		42
++#define SCLK_TIMER5		43
++#define SCLK_TSADC		44
++#define SCLK_SARADC		45
++#define SCLK_OTP		46
++#define SCLK_OTP_USR		47
++#define SCLK_CRYPTO		48
++#define SCLK_CRYPTO_APK		49
++#define SCLK_DDRC		50
++#define SCLK_ISP		51
++#define SCLK_CIF_OUT		52
++#define SCLK_RGA_CORE		53
++#define SCLK_VOPB_PWM		54
++#define SCLK_NANDC		55
++#define SCLK_SDIO		56
++#define SCLK_EMMC		57
++#define SCLK_SFC		58
++#define SCLK_SDMMC		59
++#define SCLK_OTG_ADP		60
++#define SCLK_GMAC_SRC		61
++#define SCLK_GMAC		62
++#define SCLK_GMAC_RX_TX		63
++#define SCLK_MAC_REF		64
++#define SCLK_MAC_REFOUT		65
++#define SCLK_MAC_OUT		66
++#define SCLK_SDMMC_DRV		67
++#define SCLK_SDMMC_SAMPLE	68
++#define SCLK_SDIO_DRV		69
++#define SCLK_SDIO_SAMPLE	70
++#define SCLK_EMMC_DRV		71
++#define SCLK_EMMC_SAMPLE	72
++#define SCLK_GPU		73
++#define SCLK_PVTM		74
++#define SCLK_CORE_VPU		75
++#define SCLK_GMAC_RMII		76
++#define SCLK_UART2_SRC		77
++#define SCLK_NANDC_DIV		78
++#define SCLK_NANDC_DIV50	79
++#define SCLK_SDIO_DIV		80
++#define SCLK_SDIO_DIV50		81
++#define SCLK_EMMC_DIV		82
++#define SCLK_EMMC_DIV50		83
++
++/* dclk gates */
++#define DCLK_VOPB		150
++#define DCLK_VOPL		151
++
++/* aclk gates */
++#define ACLK_GPU		170
++#define ACLK_BUS_PRE		171
++#define ACLK_CRYPTO		172
++#define ACLK_VI_PRE		173
++#define ACLK_VO_PRE		174
++#define ACLK_VPU		175
++#define ACLK_PERI_PRE		176
++#define ACLK_GMAC		178
++#define ACLK_CIF		179
++#define ACLK_ISP		180
++#define ACLK_VOPB		181
++#define ACLK_VOPL		182
++#define ACLK_RGA		183
++#define ACLK_GIC		184
++#define ACLK_DCF		186
++#define ACLK_DMAC		187
++
++/* hclk gates */
++#define HCLK_BUS_PRE		240
++#define HCLK_CRYPTO		241
++#define HCLK_VI_PRE		242
++#define HCLK_VO_PRE		243
++#define HCLK_VPU		244
++#define HCLK_PERI_PRE		245
++#define HCLK_MMC_NAND		246
++#define HCLK_SDMMC		247
++#define HCLK_USB		248
++#define HCLK_CIF		249
++#define HCLK_ISP		250
++#define HCLK_VOPB		251
++#define HCLK_VOPL		252
++#define HCLK_RGA		253
++#define HCLK_NANDC		254
++#define HCLK_SDIO		255
++#define HCLK_EMMC		256
++#define HCLK_SFC		257
++#define HCLK_OTG		258
++#define HCLK_HOST		259
++#define HCLK_HOST_ARB		260
++#define HCLK_PDM		261
++#define HCLK_I2S0		262
++#define HCLK_I2S1		263
++#define HCLK_I2S2		264
++
++/* pclk gates */
++#define PCLK_BUS_PRE		320
++#define PCLK_DDR		321
++#define PCLK_VO_PRE		322
++#define PCLK_GMAC		323
++#define PCLK_MIPI_DSI		324
++#define PCLK_MIPIDSIPHY		325
++#define PCLK_MIPICSIPHY		326
++#define PCLK_USB_GRF		327
++#define PCLK_DCF		328
++#define PCLK_UART1		329
++#define PCLK_UART2		330
++#define PCLK_UART3		331
++#define PCLK_UART4		332
++#define PCLK_UART5		333
++#define PCLK_I2C0		334
++#define PCLK_I2C1		335
++#define PCLK_I2C2		336
++#define PCLK_I2C3		337
++#define PCLK_I2C4		338
++#define PCLK_PWM0		339
++#define PCLK_PWM1		340
++#define PCLK_SPI0		341
++#define PCLK_SPI1		342
++#define PCLK_SARADC		343
++#define PCLK_TSADC		344
++#define PCLK_TIMER		345
++#define PCLK_OTP_NS		346
++#define PCLK_WDT_NS		347
++#define PCLK_GPIO1		348
++#define PCLK_GPIO2		349
++#define PCLK_GPIO3		350
++#define PCLK_ISP		351
++#define PCLK_CIF		352
++#define PCLK_OTP_PHY		353
++
++#define CLK_NR_CLKS		(PCLK_OTP_PHY + 1)
++
++/* pmu-clocks indices */
++
++#define PLL_GPLL		1
++
++#define SCLK_RTC32K_PMU		4
++#define SCLK_WIFI_PMU		5
++#define SCLK_UART0_PMU		6
++#define SCLK_PVTM_PMU		7
++#define PCLK_PMU_PRE		8
++#define SCLK_REF24M_PMU		9
++#define SCLK_USBPHY_REF		10
++#define SCLK_MIPIDSIPHY_REF	11
++
++#define XIN24M_DIV		12
++
++#define PCLK_GPIO0_PMU		20
++#define PCLK_UART0_PMU		21
++
++#define CLKPMU_NR_CLKS		(PCLK_UART0_PMU + 1)
++
++/* soft-reset indices */
++#define SRST_CORE0_PO		0
++#define SRST_CORE1_PO		1
++#define SRST_CORE2_PO		2
++#define SRST_CORE3_PO		3
++#define SRST_CORE0		4
++#define SRST_CORE1		5
++#define SRST_CORE2		6
++#define SRST_CORE3		7
++#define SRST_CORE0_DBG		8
++#define SRST_CORE1_DBG		9
++#define SRST_CORE2_DBG		10
++#define SRST_CORE3_DBG		11
++#define SRST_TOPDBG		12
++#define SRST_CORE_NOC		13
++#define SRST_STRC_A		14
++#define SRST_L2C		15
++
++#define SRST_DAP		16
++#define SRST_CORE_PVTM		17
++#define SRST_GPU		18
++#define SRST_GPU_NIU		19
++#define SRST_UPCTL2		20
++#define SRST_UPCTL2_A		21
++#define SRST_UPCTL2_P		22
++#define SRST_MSCH		23
++#define SRST_MSCH_P		24
++#define SRST_DDRMON_P		25
++#define SRST_DDRSTDBY_P		26
++#define SRST_DDRSTDBY		27
++#define SRST_DDRGRF_p		28
++#define SRST_AXI_SPLIT_A	29
++#define SRST_AXI_CMD_A		30
++#define SRST_AXI_CMD_P		31
++
++#define SRST_DDRPHY		32
++#define SRST_DDRPHYDIV		33
++#define SRST_DDRPHY_P		34
++#define SRST_VPU_A		36
++#define SRST_VPU_NIU_A		37
++#define SRST_VPU_H		38
++#define SRST_VPU_NIU_H		39
++#define SRST_VI_NIU_A		40
++#define SRST_VI_NIU_H		41
++#define SRST_ISP_H		42
++#define SRST_ISP		43
++#define SRST_CIF_A		44
++#define SRST_CIF_H		45
++#define SRST_CIF_PCLKIN		46
++#define SRST_MIPICSIPHY_P	47
++
++#define SRST_VO_NIU_A		48
++#define SRST_VO_NIU_H		49
++#define SRST_VO_NIU_P		50
++#define SRST_VOPB_A		51
++#define SRST_VOPB_H		52
++#define SRST_VOPB		53
++#define SRST_PWM_VOPB		54
++#define SRST_VOPL_A		55
++#define SRST_VOPL_H		56
++#define SRST_VOPL		57
++#define SRST_RGA_A		58
++#define SRST_RGA_H		59
++#define SRST_RGA		60
++#define SRST_MIPIDSI_HOST_P	61
++#define SRST_MIPIDSIPHY_P	62
++#define SRST_VPU_CORE		63
++
++#define SRST_PERI_NIU_A		64
++#define SRST_USB_NIU_H		65
++#define SRST_USB2OTG_H		66
++#define SRST_USB2OTG		67
++#define SRST_USB2OTG_ADP	68
++#define SRST_USB2HOST_H		69
++#define SRST_USB2HOST_ARB_H	70
++#define SRST_USB2HOST_AUX_H	71
++#define SRST_USB2HOST_EHCI	72
++#define SRST_USB2HOST		73
++#define SRST_USBPHYPOR		74
++#define SRST_USBPHY_OTG_PORT	75
++#define SRST_USBPHY_HOST_PORT	76
++#define SRST_USBPHY_GRF		77
++#define SRST_CPU_BOOST_P	78
++#define SRST_CPU_BOOST		79
++
++#define SRST_MMC_NAND_NIU_H	80
++#define SRST_SDIO_H		81
++#define SRST_EMMC_H		82
++#define SRST_SFC_H		83
++#define SRST_SFC		84
++#define SRST_SDCARD_NIU_H	85
++#define SRST_SDMMC_H		86
++#define SRST_NANDC_H		89
++#define SRST_NANDC		90
++#define SRST_GMAC_NIU_A		92
++#define SRST_GMAC_NIU_P		93
++#define SRST_GMAC_A		94
++
++#define SRST_PMU_NIU_P		96
++#define SRST_PMU_SGRF_P		97
++#define SRST_PMU_GRF_P		98
++#define SRST_PMU		99
++#define SRST_PMU_MEM_P		100
++#define SRST_PMU_GPIO0_P	101
++#define SRST_PMU_UART0_P	102
++#define SRST_PMU_CRU_P		103
++#define SRST_PMU_PVTM		104
++#define SRST_PMU_UART		105
++#define SRST_PMU_NIU_H		106
++#define SRST_PMU_DDR_FAIL_SAVE	107
++#define SRST_PMU_CORE_PERF_A	108
++#define SRST_PMU_CORE_GRF_P	109
++#define SRST_PMU_GPU_PERF_A	110
++#define SRST_PMU_GPU_GRF_P	111
++
++#define SRST_CRYPTO_NIU_A	112
++#define SRST_CRYPTO_NIU_H	113
++#define SRST_CRYPTO_A		114
++#define SRST_CRYPTO_H		115
++#define SRST_CRYPTO		116
++#define SRST_CRYPTO_APK		117
++#define SRST_BUS_NIU_H		120
++#define SRST_USB_NIU_P		121
++#define SRST_BUS_TOP_NIU_P	122
++#define SRST_INTMEM_A		123
++#define SRST_GIC_A		124
++#define SRST_ROM_H		126
++#define SRST_DCF_A		127
++
++#define SRST_DCF_P		128
++#define SRST_PDM_H		129
++#define SRST_PDM		130
++#define SRST_I2S0_H		131
++#define SRST_I2S0_TX		132
++#define SRST_I2S1_H		133
++#define SRST_I2S1		134
++#define SRST_I2S2_H		135
++#define SRST_I2S2		136
++#define SRST_UART1_P		137
++#define SRST_UART1		138
++#define SRST_UART2_P		139
++#define SRST_UART2		140
++#define SRST_UART3_P		141
++#define SRST_UART3		142
++#define SRST_UART4_P		143
++
++#define SRST_UART4		144
++#define SRST_UART5_P		145
++#define SRST_UART5		146
++#define SRST_I2C0_P		147
++#define SRST_I2C0		148
++#define SRST_I2C1_P		149
++#define SRST_I2C1		150
++#define SRST_I2C2_P		151
++#define SRST_I2C2		152
++#define SRST_I2C3_P		153
++#define SRST_I2C3		154
++#define SRST_PWM0_P		157
++#define SRST_PWM0		158
++#define SRST_PWM1_P		159
++
++#define SRST_PWM1		160
++#define SRST_SPI0_P		161
++#define SRST_SPI0		162
++#define SRST_SPI1_P		163
++#define SRST_SPI1		164
++#define SRST_SARADC_P		165
++#define SRST_SARADC		166
++#define SRST_TSADC_P		167
++#define SRST_TSADC		168
++#define SRST_TIMER_P		169
++#define SRST_TIMER0		170
++#define SRST_TIMER1		171
++#define SRST_TIMER2		172
++#define SRST_TIMER3		173
++#define SRST_TIMER4		174
++#define SRST_TIMER5		175
++
++#define SRST_OTP_NS_P		176
++#define SRST_OTP_NS_SBPI	177
++#define SRST_OTP_NS_USR		178
++#define SRST_OTP_PHY_P		179
++#define SRST_OTP_PHY		180
++#define SRST_WDT_NS_P		181
++#define SRST_GPIO1_P		182
++#define SRST_GPIO2_P		183
++#define SRST_GPIO3_P		184
++#define SRST_SGRF_P		185
++#define SRST_GRF_P		186
++#define SRST_I2S0_RX		191
++
++#endif
+
+From patchwork Thu Oct 24 23:27:56 2019
+Content-Type: text/plain; charset="utf-8"
+MIME-Version: 1.0
+Content-Transfer-Encoding: 7bit
+X-Patchwork-Submitter: =?utf-8?q?Heiko_St=C3=BCbner?= <heiko@sntech.de>
+X-Patchwork-Id: 1183656
+X-Patchwork-Delegate: ykai007@gmail.com
+Return-Path: <u-boot-bounces@lists.denx.de>
+X-Original-To: incoming@patchwork.ozlabs.org
+Delivered-To: patchwork-incoming@bilbo.ozlabs.org
+Authentication-Results: ozlabs.org;
+ spf=none (no SPF record) smtp.mailfrom=lists.denx.de
+ (client-ip=81.169.180.215; helo=lists.denx.de;
+ envelope-from=u-boot-bounces@lists.denx.de;
+ receiver=<UNKNOWN>)
+Authentication-Results: ozlabs.org;
+ dmarc=none (p=none dis=none) header.from=sntech.de
+Received: from lists.denx.de (dione.denx.de [81.169.180.215])
+ by ozlabs.org (Postfix) with ESMTP id 46zk4y0XzPz9sPL
+ for <incoming@patchwork.ozlabs.org>;
+ Fri, 25 Oct 2019 10:30:42 +1100 (AEDT)
+Received: by lists.denx.de (Postfix, from userid 105)
+ id BAF13C21E1B; Thu, 24 Oct 2019 23:28:58 +0000 (UTC)
+X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on lists.denx.de
+X-Spam-Level: 
+X-Spam-Status: No, score=0.0 required=5.0 tests=none autolearn=unavailable
+ autolearn_force=no version=3.4.0
+Received: from lists.denx.de (localhost [IPv6:::1])
+ by lists.denx.de (Postfix) with ESMTP id D7FFAC21E0F;
+ Thu, 24 Oct 2019 23:28:19 +0000 (UTC)
+Received: by lists.denx.de (Postfix, from userid 105)
+ id EEFA9C21D74; Thu, 24 Oct 2019 23:28:17 +0000 (UTC)
+Received: from gloria.sntech.de (gloria.sntech.de [185.11.138.130])
+ by lists.denx.de (Postfix) with ESMTPS id 668F7C21DA6
+ for <u-boot@lists.denx.de>; Thu, 24 Oct 2019 23:28:17 +0000 (UTC)
+Received: from ip5f5a6266.dynamic.kabel-deutschland.de ([95.90.98.102]
+ helo=phil.fritz.box) by gloria.sntech.de with esmtpsa
+ (TLS1.2:ECDHE_RSA_AES_128_GCM_SHA256:128)
+ (Exim 4.89) (envelope-from <heiko@sntech.de>)
+ id 1iNmWe-0002cR-VL; Fri, 25 Oct 2019 01:28:17 +0200
+From: Heiko Stuebner <heiko@sntech.de>
+To: u-boot@lists.denx.de
+Date: Fri, 25 Oct 2019 01:27:56 +0200
+Message-Id: <20191024232803.10338-6-heiko@sntech.de>
+X-Mailer: git-send-email 2.23.0
+In-Reply-To: <20191024232803.10338-1-heiko@sntech.de>
+References: <20191024232803.10338-1-heiko@sntech.de>
+MIME-Version: 1.0
+Cc: Heiko Stuebner <heiko.stuebner@theobroma-systems.com>,
+ joe.hershberger@ni.com, christoph.muellner@theobroma-systems.com
+Subject: [U-Boot] [PATCH 05/12] net: gmac_rockchip: add support for px30
+X-BeenThere: u-boot@lists.denx.de
+X-Mailman-Version: 2.1.18
+Precedence: list
+List-Id: U-Boot discussion <u-boot.lists.denx.de>
+List-Unsubscribe: <https://lists.denx.de/options/u-boot>,
+ <mailto:u-boot-request@lists.denx.de?subject=unsubscribe>
+List-Archive: <http://lists.denx.de/pipermail/u-boot/>
+List-Post: <mailto:u-boot@lists.denx.de>
+List-Help: <mailto:u-boot-request@lists.denx.de?subject=help>
+List-Subscribe: <https://lists.denx.de/listinfo/u-boot>,
+ <mailto:u-boot-request@lists.denx.de?subject=subscribe>
+Errors-To: u-boot-bounces@lists.denx.de
+Sender: "U-Boot" <u-boot-bounces@lists.denx.de>
+
+Add the glue code to allow the px30 variant of the Rockchip gmac
+to provide network functionality.
+
+Signed-off-by: Heiko Stuebner <heiko.stuebner@theobroma-systems.com>
+Reviewed-by: Kever Yang<kever.yang@rock-chips.com>
+---
+ drivers/net/gmac_rockchip.c | 69 +++++++++++++++++++++++++++++++++++++
+ 1 file changed, 69 insertions(+)
+
+diff --git a/drivers/net/gmac_rockchip.c b/drivers/net/gmac_rockchip.c
+index 26a6121175..3f3e38a2c6 100644
+--- a/drivers/net/gmac_rockchip.c
++++ b/drivers/net/gmac_rockchip.c
+@@ -14,6 +14,7 @@
+ #include <asm/arch-rockchip/periph.h>
+ #include <asm/arch-rockchip/clock.h>
+ #include <asm/arch-rockchip/hardware.h>
++#include <asm/arch-rockchip/grf_px30.h>
+ #include <asm/arch-rockchip/grf_rk322x.h>
+ #include <asm/arch-rockchip/grf_rk3288.h>
+ #include <asm/arch-rockchip/grf_rk3328.h>
+@@ -72,6 +73,47 @@ static int gmac_rockchip_ofdata_to_platdata(struct udevice *dev)
+ 	return designware_eth_ofdata_to_platdata(dev);
+ }
+ 
++static int px30_gmac_fix_mac_speed(struct dw_eth_dev *priv)
++{
++	struct px30_grf *grf;
++	struct clk clk_speed;
++	int speed, ret;
++	enum {
++		PX30_GMAC_SPEED_SHIFT = 0x2,
++		PX30_GMAC_SPEED_MASK  = BIT(2),
++		PX30_GMAC_SPEED_10M   = 0,
++		PX30_GMAC_SPEED_100M  = BIT(2),
++	};
++
++	ret = clk_get_by_name(priv->phydev->dev, "clk_mac_speed",
++			      &clk_speed);
++	if (ret)
++		return ret;
++
++	switch (priv->phydev->speed) {
++	case 10:
++		speed = PX30_GMAC_SPEED_10M;
++		ret = clk_set_rate(&clk_speed, 2500000);
++		if (ret)
++			return ret;
++		break;
++	case 100:
++		speed = PX30_GMAC_SPEED_100M;
++		ret = clk_set_rate(&clk_speed, 25000000);
++		if (ret)
++			return ret;
++		break;
++	default:
++		debug("Unknown phy speed: %d\n", priv->phydev->speed);
++		return -EINVAL;
++	}
++
++	grf = syscon_get_first_range(ROCKCHIP_SYSCON_GRF);
++	rk_clrsetreg(&grf->mac_con1, PX30_GMAC_SPEED_MASK, speed);
++
++	return 0;
++}
++
+ static int rk3228_gmac_fix_mac_speed(struct dw_eth_dev *priv)
+ {
+ 	struct rk322x_grf *grf;
+@@ -257,6 +299,22 @@ static int rv1108_set_rmii_speed(struct dw_eth_dev *priv)
+ 	return 0;
+ }
+ 
++static void px30_gmac_set_to_rmii(struct gmac_rockchip_platdata *pdata)
++{
++	struct px30_grf *grf;
++	enum {
++		PX30_GMAC_PHY_INTF_SEL_SHIFT = 4,
++		PX30_GMAC_PHY_INTF_SEL_MASK  = GENMASK(4, 6),
++		PX30_GMAC_PHY_INTF_SEL_RMII  = BIT(6),
++	};
++
++	grf = syscon_get_first_range(ROCKCHIP_SYSCON_GRF);
++
++	rk_clrsetreg(&grf->mac_con1,
++		     PX30_GMAC_PHY_INTF_SEL_MASK,
++		     PX30_GMAC_PHY_INTF_SEL_RMII);
++}
++
+ static void rk3228_gmac_set_to_rgmii(struct gmac_rockchip_platdata *pdata)
+ {
+ 	struct rk322x_grf *grf;
+@@ -445,6 +503,10 @@ static int gmac_rockchip_probe(struct udevice *dev)
+ 	ulong rate;
+ 	int ret;
+ 
++	ret = clk_set_defaults(dev);
++	if (ret)
++		debug("%s clk_set_defaults failed %d\n", __func__, ret);
++
+ 	ret = clk_get_by_index(dev, 0, &clk);
+ 	if (ret)
+ 		return ret;
+@@ -569,6 +631,11 @@ const struct eth_ops gmac_rockchip_eth_ops = {
+ 	.write_hwaddr		= designware_eth_write_hwaddr,
+ };
+ 
++const struct rk_gmac_ops px30_gmac_ops = {
++	.fix_mac_speed = px30_gmac_fix_mac_speed,
++	.set_to_rmii = px30_gmac_set_to_rmii,
++};
++
+ const struct rk_gmac_ops rk3228_gmac_ops = {
+ 	.fix_mac_speed = rk3228_gmac_fix_mac_speed,
+ 	.set_to_rgmii = rk3228_gmac_set_to_rgmii,
+@@ -600,6 +667,8 @@ const struct rk_gmac_ops rv1108_gmac_ops = {
+ };
+ 
+ static const struct udevice_id rockchip_gmac_ids[] = {
++	{ .compatible = "rockchip,px30-gmac",
++	  .data = (ulong)&px30_gmac_ops },
+ 	{ .compatible = "rockchip,rk3228-gmac",
+ 	  .data = (ulong)&rk3228_gmac_ops },
+ 	{ .compatible = "rockchip,rk3288-gmac",
+
+From patchwork Thu Oct 24 23:27:57 2019
+Content-Type: text/plain; charset="utf-8"
+MIME-Version: 1.0
+Content-Transfer-Encoding: 7bit
+X-Patchwork-Submitter: =?utf-8?q?Heiko_St=C3=BCbner?= <heiko@sntech.de>
+X-Patchwork-Id: 1183655
+X-Patchwork-Delegate: ykai007@gmail.com
+Return-Path: <u-boot-bounces@lists.denx.de>
+X-Original-To: incoming@patchwork.ozlabs.org
+Delivered-To: patchwork-incoming@bilbo.ozlabs.org
+Authentication-Results: ozlabs.org;
+ spf=none (no SPF record) smtp.mailfrom=lists.denx.de
+ (client-ip=81.169.180.215; helo=lists.denx.de;
+ envelope-from=u-boot-bounces@lists.denx.de;
+ receiver=<UNKNOWN>)
+Authentication-Results: ozlabs.org;
+ dmarc=none (p=none dis=none) header.from=sntech.de
+Received: from lists.denx.de (dione.denx.de [81.169.180.215])
+ by ozlabs.org (Postfix) with ESMTP id 46zk4t73sdz9sPL
+ for <incoming@patchwork.ozlabs.org>;
+ Fri, 25 Oct 2019 10:30:38 +1100 (AEDT)
+Received: by lists.denx.de (Postfix, from userid 105)
+ id B8310C21DC1; Thu, 24 Oct 2019 23:29:09 +0000 (UTC)
+X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on lists.denx.de
+X-Spam-Level: 
+X-Spam-Status: No, score=0.0 required=5.0 tests=none autolearn=unavailable
+ autolearn_force=no version=3.4.0
+Received: from lists.denx.de (localhost [IPv6:::1])
+ by lists.denx.de (Postfix) with ESMTP id 7CDCBC21E1B;
+ Thu, 24 Oct 2019 23:28:20 +0000 (UTC)
+Received: by lists.denx.de (Postfix, from userid 105)
+ id 10669C21D8A; Thu, 24 Oct 2019 23:28:17 +0000 (UTC)
+Received: from gloria.sntech.de (gloria.sntech.de [185.11.138.130])
+ by lists.denx.de (Postfix) with ESMTPS id A1DB1C21DB3
+ for <u-boot@lists.denx.de>; Thu, 24 Oct 2019 23:28:17 +0000 (UTC)
+Received: from ip5f5a6266.dynamic.kabel-deutschland.de ([95.90.98.102]
+ helo=phil.fritz.box) by gloria.sntech.de with esmtpsa
+ (TLS1.2:ECDHE_RSA_AES_128_GCM_SHA256:128)
+ (Exim 4.89) (envelope-from <heiko@sntech.de>)
+ id 1iNmWf-0002cR-B0; Fri, 25 Oct 2019 01:28:17 +0200
+From: Heiko Stuebner <heiko@sntech.de>
+To: u-boot@lists.denx.de
+Date: Fri, 25 Oct 2019 01:27:57 +0200
+Message-Id: <20191024232803.10338-7-heiko@sntech.de>
+X-Mailer: git-send-email 2.23.0
+In-Reply-To: <20191024232803.10338-1-heiko@sntech.de>
+References: <20191024232803.10338-1-heiko@sntech.de>
+MIME-Version: 1.0
+Cc: Heiko Stuebner <heiko.stuebner@theobroma-systems.com>,
+ joe.hershberger@ni.com, christoph.muellner@theobroma-systems.com
+Subject: [U-Boot] [PATCH 06/12] rockchip: mkimage: add support for px30
+X-BeenThere: u-boot@lists.denx.de
+X-Mailman-Version: 2.1.18
+Precedence: list
+List-Id: U-Boot discussion <u-boot.lists.denx.de>
+List-Unsubscribe: <https://lists.denx.de/options/u-boot>,
+ <mailto:u-boot-request@lists.denx.de?subject=unsubscribe>
+List-Archive: <http://lists.denx.de/pipermail/u-boot/>
+List-Post: <mailto:u-boot@lists.denx.de>
+List-Help: <mailto:u-boot-request@lists.denx.de?subject=help>
+List-Subscribe: <https://lists.denx.de/listinfo/u-boot>,
+ <mailto:u-boot-request@lists.denx.de?subject=subscribe>
+Errors-To: u-boot-bounces@lists.denx.de
+Sender: "U-Boot" <u-boot-bounces@lists.denx.de>
+
+From: Kever Yang <kever.yang@rock-chips.com>
+
+Add the table entry for px30 socs.
+The px30 has 10K of sram available.
+
+Signed-off-by: Kever Yang <kever.yang@rock-chips.com>
+Signed-off-by: Heiko Stuebner <heiko.stuebner@theobroma-systems.com>
+Reviewed-by: Kever Yang<kever.yang@rock-chips.com>
+---
+ tools/rkcommon.c | 1 +
+ 1 file changed, 1 insertion(+)
+
+diff --git a/tools/rkcommon.c b/tools/rkcommon.c
+index 831c2ad820..83df82e4b0 100644
+--- a/tools/rkcommon.c
++++ b/tools/rkcommon.c
+@@ -67,6 +67,7 @@ struct spl_info {
+ };
+ 
+ static struct spl_info spl_infos[] = {
++	{ "px30", "RK33", 0x2800, false },
+ 	{ "rk3036", "RK30", 0x1000, false },
+ 	{ "rk3128", "RK31", 0x1800, false },
+ 	{ "rk3188", "RK31", 0x8000 - 0x800, true },
+
+From patchwork Thu Oct 24 23:27:58 2019
+Content-Type: text/plain; charset="utf-8"
+MIME-Version: 1.0
+Content-Transfer-Encoding: 7bit
+X-Patchwork-Submitter: =?utf-8?q?Heiko_St=C3=BCbner?= <heiko@sntech.de>
+X-Patchwork-Id: 1183658
+X-Patchwork-Delegate: ykai007@gmail.com
+Return-Path: <u-boot-bounces@lists.denx.de>
+X-Original-To: incoming@patchwork.ozlabs.org
+Delivered-To: patchwork-incoming@bilbo.ozlabs.org
+Authentication-Results: ozlabs.org;
+ spf=none (no SPF record) smtp.mailfrom=lists.denx.de
+ (client-ip=81.169.180.215; helo=lists.denx.de;
+ envelope-from=u-boot-bounces@lists.denx.de;
+ receiver=<UNKNOWN>)
+Authentication-Results: ozlabs.org;
+ dmarc=none (p=none dis=none) header.from=sntech.de
+Received: from lists.denx.de (dione.denx.de [81.169.180.215])
+ by ozlabs.org (Postfix) with ESMTP id 46zk5k66Vpz9sPL
+ for <incoming@patchwork.ozlabs.org>;
+ Fri, 25 Oct 2019 10:31:22 +1100 (AEDT)
+Received: by lists.denx.de (Postfix, from userid 105)
+ id 8E320C21E13; Thu, 24 Oct 2019 23:29:48 +0000 (UTC)
+X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on lists.denx.de
+X-Spam-Level: 
+X-Spam-Status: No, score=0.0 required=5.0 tests=none autolearn=unavailable
+ autolearn_force=no version=3.4.0
+Received: from lists.denx.de (localhost [IPv6:::1])
+ by lists.denx.de (Postfix) with ESMTP id 45147C21E5B;
+ Thu, 24 Oct 2019 23:28:22 +0000 (UTC)
+Received: by lists.denx.de (Postfix, from userid 105)
+ id 526D9C21DA6; Thu, 24 Oct 2019 23:28:18 +0000 (UTC)
+Received: from gloria.sntech.de (gloria.sntech.de [185.11.138.130])
+ by lists.denx.de (Postfix) with ESMTPS id 191A0C21D9A
+ for <u-boot@lists.denx.de>; Thu, 24 Oct 2019 23:28:18 +0000 (UTC)
+Received: from ip5f5a6266.dynamic.kabel-deutschland.de ([95.90.98.102]
+ helo=phil.fritz.box) by gloria.sntech.de with esmtpsa
+ (TLS1.2:ECDHE_RSA_AES_128_GCM_SHA256:128)
+ (Exim 4.89) (envelope-from <heiko@sntech.de>)
+ id 1iNmWf-0002cR-P0; Fri, 25 Oct 2019 01:28:17 +0200
+From: Heiko Stuebner <heiko@sntech.de>
+To: u-boot@lists.denx.de
+Date: Fri, 25 Oct 2019 01:27:58 +0200
+Message-Id: <20191024232803.10338-8-heiko@sntech.de>
+X-Mailer: git-send-email 2.23.0
+In-Reply-To: <20191024232803.10338-1-heiko@sntech.de>
+References: <20191024232803.10338-1-heiko@sntech.de>
+MIME-Version: 1.0
+Cc: Heiko Stuebner <heiko.stuebner@theobroma-systems.com>,
+ joe.hershberger@ni.com, Finley Xiao <finley.xiao@rock-chips.com>,
+ christoph.muellner@theobroma-systems.com
+Subject: [U-Boot] [PATCH 07/12] misc: add driver for the Rockchip otp
+ controller
+X-BeenThere: u-boot@lists.denx.de
+X-Mailman-Version: 2.1.18
+Precedence: list
+List-Id: U-Boot discussion <u-boot.lists.denx.de>
+List-Unsubscribe: <https://lists.denx.de/options/u-boot>,
+ <mailto:u-boot-request@lists.denx.de?subject=unsubscribe>
+List-Archive: <http://lists.denx.de/pipermail/u-boot/>
+List-Post: <mailto:u-boot@lists.denx.de>
+List-Help: <mailto:u-boot-request@lists.denx.de?subject=help>
+List-Subscribe: <https://lists.denx.de/listinfo/u-boot>,
+ <mailto:u-boot-request@lists.denx.de?subject=subscribe>
+Errors-To: u-boot-bounces@lists.denx.de
+Sender: "U-Boot" <u-boot-bounces@lists.denx.de>
+
+From: Finley Xiao <finley.xiao@rock-chips.com>
+
+Newer Rockchip socs like the px30 use a different ip block to handle
+one-time-programmable memory, so add a misc driver for it as well.
+
+Signed-off-by: Finley Xiao <finley.xiao@rock-chips.com>
+Signed-off-by: Heiko Stuebner <heiko.stuebner@theobroma-systems.com>
+Reviewed-by: Kever Yang<kever.yang@rock-chips.com>
+---
+ drivers/misc/Kconfig        |   9 ++
+ drivers/misc/Makefile       |   1 +
+ drivers/misc/rockchip-otp.c | 176 ++++++++++++++++++++++++++++++++++++
+ 3 files changed, 186 insertions(+)
+ create mode 100644 drivers/misc/rockchip-otp.c
+
+diff --git a/drivers/misc/Kconfig b/drivers/misc/Kconfig
+index 8037b6ee2d..d68b24e6ec 100644
+--- a/drivers/misc/Kconfig
++++ b/drivers/misc/Kconfig
+@@ -59,6 +59,15 @@ config ROCKCHIP_EFUSE
+ 	  extended (by porting the read function from the Linux kernel sources)
+ 	  to support other recent Rockchip devices.
+ 
++config ROCKCHIP_OTP
++	bool "Rockchip OTP Support"
++	depends on MISC
++	help
++	  Enable (read-only) access for the one-time-programmable memory block
++	  found in Rockchip SoCs: accesses can either be made using byte
++	  addressing and a length or through child-nodes that are generated
++	  based on the e-fuse map retrieved from the DTS.
++
+ config VEXPRESS_CONFIG
+ 	bool "Enable support for Arm Versatile Express config bus"
+ 	depends on MISC
+diff --git a/drivers/misc/Makefile b/drivers/misc/Makefile
+index 509c588582..b172567297 100644
+--- a/drivers/misc/Makefile
++++ b/drivers/misc/Makefile
+@@ -52,6 +52,7 @@ obj-$(CONFIG_PCA9551_LED) += pca9551_led.o
+ obj-$(CONFIG_$(SPL_)PWRSEQ) += pwrseq-uclass.o
+ obj-$(CONFIG_QFW) += qfw.o
+ obj-$(CONFIG_ROCKCHIP_EFUSE) += rockchip-efuse.o
++obj-$(CONFIG_ROCKCHIP_OTP) += rockchip-otp.o
+ obj-$(CONFIG_SANDBOX) += swap_case.o
+ obj-$(CONFIG_SANDBOX) += syscon_sandbox.o misc_sandbox.o
+ obj-$(CONFIG_SMSC_LPC47M) += smsc_lpc47m.o
+diff --git a/drivers/misc/rockchip-otp.c b/drivers/misc/rockchip-otp.c
+new file mode 100644
+index 0000000000..bdd443b3db
+--- /dev/null
++++ b/drivers/misc/rockchip-otp.c
+@@ -0,0 +1,176 @@
++// SPDX-License-Identifier: GPL-2.0
++/*
++ * Copyright (c) 2019 Fuzhou Rockchip Electronics Co., Ltd
++ */
++
++#include <common.h>
++#include <asm/io.h>
++#include <command.h>
++#include <dm.h>
++#include <linux/bitops.h>
++#include <linux/delay.h>
++#include <misc.h>
++
++/* OTP Register Offsets */
++#define OTPC_SBPI_CTRL			0x0020
++#define OTPC_SBPI_CMD_VALID_PRE		0x0024
++#define OTPC_SBPI_CS_VALID_PRE		0x0028
++#define OTPC_SBPI_STATUS		0x002C
++#define OTPC_USER_CTRL			0x0100
++#define OTPC_USER_ADDR			0x0104
++#define OTPC_USER_ENABLE		0x0108
++#define OTPC_USER_QP			0x0120
++#define OTPC_USER_Q			0x0124
++#define OTPC_INT_STATUS			0x0304
++#define OTPC_SBPI_CMD0_OFFSET		0x1000
++#define OTPC_SBPI_CMD1_OFFSET		0x1004
++
++/* OTP Register bits and masks */
++#define OTPC_USER_ADDR_MASK		GENMASK(31, 16)
++#define OTPC_USE_USER			BIT(0)
++#define OTPC_USE_USER_MASK		GENMASK(16, 16)
++#define OTPC_USER_FSM_ENABLE		BIT(0)
++#define OTPC_USER_FSM_ENABLE_MASK	GENMASK(16, 16)
++#define OTPC_SBPI_DONE			BIT(1)
++#define OTPC_USER_DONE			BIT(2)
++
++#define SBPI_DAP_ADDR			0x02
++#define SBPI_DAP_ADDR_SHIFT		8
++#define SBPI_DAP_ADDR_MASK		GENMASK(31, 24)
++#define SBPI_CMD_VALID_MASK		GENMASK(31, 16)
++#define SBPI_DAP_CMD_WRF		0xC0
++#define SBPI_DAP_REG_ECC		0x3A
++#define SBPI_ECC_ENABLE			0x00
++#define SBPI_ECC_DISABLE		0x09
++#define SBPI_ENABLE			BIT(0)
++#define SBPI_ENABLE_MASK		GENMASK(16, 16)
++
++#define OTPC_TIMEOUT			10000
++
++struct rockchip_otp_platdata {
++	void __iomem *base;
++	unsigned long secure_conf_base;
++	unsigned long otp_mask_base;
++};
++
++static int rockchip_otp_wait_status(struct rockchip_otp_platdata *otp,
++				    u32 flag)
++{
++	int delay = OTPC_TIMEOUT;
++
++	while (!(readl(otp->base + OTPC_INT_STATUS) & flag)) {
++		udelay(1);
++		delay--;
++		if (delay <= 0) {
++			printf("%s: wait init status timeout\n", __func__);
++			return -ETIMEDOUT;
++		}
++	}
++
++	/* clean int status */
++	writel(flag, otp->base + OTPC_INT_STATUS);
++
++	return 0;
++}
++
++static int rockchip_otp_ecc_enable(struct rockchip_otp_platdata *otp,
++				   bool enable)
++{
++	int ret = 0;
++
++	writel(SBPI_DAP_ADDR_MASK | (SBPI_DAP_ADDR << SBPI_DAP_ADDR_SHIFT),
++	       otp->base + OTPC_SBPI_CTRL);
++
++	writel(SBPI_CMD_VALID_MASK | 0x1, otp->base + OTPC_SBPI_CMD_VALID_PRE);
++	writel(SBPI_DAP_CMD_WRF | SBPI_DAP_REG_ECC,
++	       otp->base + OTPC_SBPI_CMD0_OFFSET);
++
++	if (enable)
++		writel(SBPI_ECC_ENABLE, otp->base + OTPC_SBPI_CMD1_OFFSET);
++	else
++		writel(SBPI_ECC_DISABLE, otp->base + OTPC_SBPI_CMD1_OFFSET);
++
++	writel(SBPI_ENABLE_MASK | SBPI_ENABLE, otp->base + OTPC_SBPI_CTRL);
++
++	ret = rockchip_otp_wait_status(otp, OTPC_SBPI_DONE);
++	if (ret < 0)
++		printf("%s timeout during ecc_enable\n", __func__);
++
++	return ret;
++}
++
++static int rockchip_px30_otp_read(struct udevice *dev, int offset,
++				  void *buf, int size)
++{
++	struct rockchip_otp_platdata *otp = dev_get_platdata(dev);
++	u8 *buffer = buf;
++	int ret = 0;
++
++	ret = rockchip_otp_ecc_enable(otp, false);
++	if (ret < 0) {
++		printf("%s rockchip_otp_ecc_enable err\n", __func__);
++		return ret;
++	}
++
++	writel(OTPC_USE_USER | OTPC_USE_USER_MASK, otp->base + OTPC_USER_CTRL);
++	udelay(5);
++	while (size--) {
++		writel(offset++ | OTPC_USER_ADDR_MASK,
++		       otp->base + OTPC_USER_ADDR);
++		writel(OTPC_USER_FSM_ENABLE | OTPC_USER_FSM_ENABLE_MASK,
++		       otp->base + OTPC_USER_ENABLE);
++
++		ret = rockchip_otp_wait_status(otp, OTPC_USER_DONE);
++		if (ret < 0) {
++			printf("%s timeout during read setup\n", __func__);
++			goto read_end;
++		}
++
++		*buffer++ = readb(otp->base + OTPC_USER_Q);
++	}
++
++read_end:
++	writel(0x0 | OTPC_USE_USER_MASK, otp->base + OTPC_USER_CTRL);
++
++	return ret;
++}
++
++static int rockchip_otp_read(struct udevice *dev, int offset,
++			     void *buf, int size)
++{
++	return rockchip_px30_otp_read(dev, offset, buf, size);
++}
++
++static const struct misc_ops rockchip_otp_ops = {
++	.read = rockchip_otp_read,
++};
++
++static int rockchip_otp_ofdata_to_platdata(struct udevice *dev)
++{
++	struct rockchip_otp_platdata *otp = dev_get_platdata(dev);
++
++	otp->base = dev_read_addr_ptr(dev);
++
++	return 0;
++}
++
++static const struct udevice_id rockchip_otp_ids[] = {
++	{
++		.compatible = "rockchip,px30-otp",
++		.data = (ulong)&rockchip_px30_otp_read,
++	},
++	{
++		.compatible = "rockchip,rk3308-otp",
++		.data = (ulong)&rockchip_px30_otp_read,
++	},
++	{}
++};
++
++U_BOOT_DRIVER(rockchip_otp) = {
++	.name = "rockchip_otp",
++	.id = UCLASS_MISC,
++	.of_match = rockchip_otp_ids,
++	.ops = &rockchip_otp_ops,
++	.ofdata_to_platdata = rockchip_otp_ofdata_to_platdata,
++	.platdata_auto_alloc_size = sizeof(struct rockchip_otp_platdata),
++};
+
+From patchwork Thu Oct 24 23:27:59 2019
+Content-Type: text/plain; charset="utf-8"
+MIME-Version: 1.0
+Content-Transfer-Encoding: 7bit
+X-Patchwork-Submitter: =?utf-8?q?Heiko_St=C3=BCbner?= <heiko@sntech.de>
+X-Patchwork-Id: 1183660
+X-Patchwork-Delegate: ykai007@gmail.com
+Return-Path: <u-boot-bounces@lists.denx.de>
+X-Original-To: incoming@patchwork.ozlabs.org
+Delivered-To: patchwork-incoming@bilbo.ozlabs.org
+Authentication-Results: ozlabs.org;
+ spf=none (no SPF record) smtp.mailfrom=lists.denx.de
+ (client-ip=81.169.180.215; helo=lists.denx.de;
+ envelope-from=u-boot-bounces@lists.denx.de;
+ receiver=<UNKNOWN>)
+Authentication-Results: ozlabs.org;
+ dmarc=none (p=none dis=none) header.from=sntech.de
+Received: from lists.denx.de (dione.denx.de [81.169.180.215])
+ by ozlabs.org (Postfix) with ESMTP id 46zk7M11qTz9sPL
+ for <incoming@patchwork.ozlabs.org>;
+ Fri, 25 Oct 2019 10:32:47 +1100 (AEDT)
+Received: by lists.denx.de (Postfix, from userid 105)
+ id CDB04C21DB3; Thu, 24 Oct 2019 23:31:26 +0000 (UTC)
+X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on lists.denx.de
+X-Spam-Level: 
+X-Spam-Status: No, score=0.0 required=5.0 tests=none autolearn=unavailable
+ autolearn_force=no version=3.4.0
+Received: from lists.denx.de (localhost [IPv6:::1])
+ by lists.denx.de (Postfix) with ESMTP id 74184C21E73;
+ Thu, 24 Oct 2019 23:28:23 +0000 (UTC)
+Received: by lists.denx.de (Postfix, from userid 105)
+ id A4C7DC21D9A; Thu, 24 Oct 2019 23:28:18 +0000 (UTC)
+Received: from gloria.sntech.de (gloria.sntech.de [185.11.138.130])
+ by lists.denx.de (Postfix) with ESMTPS id 74C64C21C6A
+ for <u-boot@lists.denx.de>; Thu, 24 Oct 2019 23:28:18 +0000 (UTC)
+Received: from ip5f5a6266.dynamic.kabel-deutschland.de ([95.90.98.102]
+ helo=phil.fritz.box) by gloria.sntech.de with esmtpsa
+ (TLS1.2:ECDHE_RSA_AES_128_GCM_SHA256:128)
+ (Exim 4.89) (envelope-from <heiko@sntech.de>)
+ id 1iNmWg-0002cR-5C; Fri, 25 Oct 2019 01:28:18 +0200
+From: Heiko Stuebner <heiko@sntech.de>
+To: u-boot@lists.denx.de
+Date: Fri, 25 Oct 2019 01:27:59 +0200
+Message-Id: <20191024232803.10338-9-heiko@sntech.de>
+X-Mailer: git-send-email 2.23.0
+In-Reply-To: <20191024232803.10338-1-heiko@sntech.de>
+References: <20191024232803.10338-1-heiko@sntech.de>
+MIME-Version: 1.0
+Cc: Heiko Stuebner <heiko.stuebner@theobroma-systems.com>,
+ joe.hershberger@ni.com, christoph.muellner@theobroma-systems.com
+Subject: [U-Boot] [PATCH 08/12] rockchip: misc: read cpuid either from efuse
+ or otp
+X-BeenThere: u-boot@lists.denx.de
+X-Mailman-Version: 2.1.18
+Precedence: list
+List-Id: U-Boot discussion <u-boot.lists.denx.de>
+List-Unsubscribe: <https://lists.denx.de/options/u-boot>,
+ <mailto:u-boot-request@lists.denx.de?subject=unsubscribe>
+List-Archive: <http://lists.denx.de/pipermail/u-boot/>
+List-Post: <mailto:u-boot@lists.denx.de>
+List-Help: <mailto:u-boot-request@lists.denx.de?subject=help>
+List-Subscribe: <https://lists.denx.de/listinfo/u-boot>,
+ <mailto:u-boot-request@lists.denx.de?subject=subscribe>
+Errors-To: u-boot-bounces@lists.denx.de
+Sender: "U-Boot" <u-boot-bounces@lists.denx.de>
+
+From: Heiko Stuebner <heiko.stuebner@theobroma-systems.com>
+
+Newer Rockchip socs use a different ip block to handle one-time-
+programmable memory, so depending on what got enabled get the cpuid
+from either source.
+
+Signed-off-by: Heiko Stuebner <heiko.stuebner@theobroma-systems.com>
+Reviewed-by: Kever Yang<kever.yang@rock-chips.com>
+---
+ arch/arm/mach-rockchip/misc.c | 7 ++++++-
+ 1 file changed, 6 insertions(+), 1 deletion(-)
+
+diff --git a/arch/arm/mach-rockchip/misc.c b/arch/arm/mach-rockchip/misc.c
+index c0e4fdbc00..bed4317f7e 100644
+--- a/arch/arm/mach-rockchip/misc.c
++++ b/arch/arm/mach-rockchip/misc.c
+@@ -57,13 +57,18 @@ int rockchip_cpuid_from_efuse(const u32 cpuid_offset,
+ 			      const u32 cpuid_length,
+ 			      u8 *cpuid)
+ {
+-#if CONFIG_IS_ENABLED(ROCKCHIP_EFUSE)
++#if CONFIG_IS_ENABLED(ROCKCHIP_EFUSE) || CONFIG_IS_ENABLED(ROCKCHIP_OTP)
+ 	struct udevice *dev;
+ 	int ret;
+ 
+ 	/* retrieve the device */
++#if CONFIG_IS_ENABLED(ROCKCHIP_EFUSE)
+ 	ret = uclass_get_device_by_driver(UCLASS_MISC,
+ 					  DM_GET_DRIVER(rockchip_efuse), &dev);
++#elif CONFIG_IS_ENABLED(ROCKCHIP_OTP)
++	ret = uclass_get_device_by_driver(UCLASS_MISC,
++					  DM_GET_DRIVER(rockchip_otp), &dev);
++#endif
+ 	if (ret) {
+ 		debug("%s: could not find efuse device\n", __func__);
+ 		return -1;
+
+From patchwork Thu Oct 24 23:28:00 2019
+Content-Type: text/plain; charset="utf-8"
+MIME-Version: 1.0
+Content-Transfer-Encoding: 7bit
+X-Patchwork-Submitter: =?utf-8?q?Heiko_St=C3=BCbner?= <heiko@sntech.de>
+X-Patchwork-Id: 1183661
+X-Patchwork-Delegate: ykai007@gmail.com
+Return-Path: <u-boot-bounces@lists.denx.de>
+X-Original-To: incoming@patchwork.ozlabs.org
+Delivered-To: patchwork-incoming@bilbo.ozlabs.org
+Authentication-Results: ozlabs.org;
+ spf=none (no SPF record) smtp.mailfrom=lists.denx.de
+ (client-ip=81.169.180.215; helo=lists.denx.de;
+ envelope-from=u-boot-bounces@lists.denx.de;
+ receiver=<UNKNOWN>)
+Authentication-Results: ozlabs.org;
+ dmarc=none (p=none dis=none) header.from=sntech.de
+Received: from lists.denx.de (dione.denx.de [81.169.180.215])
+ by ozlabs.org (Postfix) with ESMTP id 46zk7g4c2rz9sPL
+ for <incoming@patchwork.ozlabs.org>;
+ Fri, 25 Oct 2019 10:33:03 +1100 (AEDT)
+Received: by lists.denx.de (Postfix, from userid 105)
+ id 4B5BCC21E47; Thu, 24 Oct 2019 23:31:35 +0000 (UTC)
+X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on lists.denx.de
+X-Spam-Level: 
+X-Spam-Status: No, score=0.0 required=5.0 tests=none autolearn=unavailable
+ autolearn_force=no version=3.4.0
+Received: from lists.denx.de (localhost [IPv6:::1])
+ by lists.denx.de (Postfix) with ESMTP id 05287C21E7F;
+ Thu, 24 Oct 2019 23:28:29 +0000 (UTC)
+Received: by lists.denx.de (Postfix, from userid 105)
+ id 12715C21DF3; Thu, 24 Oct 2019 23:28:20 +0000 (UTC)
+Received: from gloria.sntech.de (gloria.sntech.de [185.11.138.130])
+ by lists.denx.de (Postfix) with ESMTPS id CF8A3C21DA6
+ for <u-boot@lists.denx.de>; Thu, 24 Oct 2019 23:28:18 +0000 (UTC)
+Received: from ip5f5a6266.dynamic.kabel-deutschland.de ([95.90.98.102]
+ helo=phil.fritz.box) by gloria.sntech.de with esmtpsa
+ (TLS1.2:ECDHE_RSA_AES_128_GCM_SHA256:128)
+ (Exim 4.89) (envelope-from <heiko@sntech.de>)
+ id 1iNmWg-0002cR-Ha; Fri, 25 Oct 2019 01:28:18 +0200
+From: Heiko Stuebner <heiko@sntech.de>
+To: u-boot@lists.denx.de
+Date: Fri, 25 Oct 2019 01:28:00 +0200
+Message-Id: <20191024232803.10338-10-heiko@sntech.de>
+X-Mailer: git-send-email 2.23.0
+In-Reply-To: <20191024232803.10338-1-heiko@sntech.de>
+References: <20191024232803.10338-1-heiko@sntech.de>
+MIME-Version: 1.0
+Cc: Heiko Stuebner <heiko.stuebner@theobroma-systems.com>,
+ joe.hershberger@ni.com, christoph.muellner@theobroma-systems.com
+Subject: [U-Boot] [PATCH 09/12] rockchip: ram: add dm-based sdram driver
+X-BeenThere: u-boot@lists.denx.de
+X-Mailman-Version: 2.1.18
+Precedence: list
+List-Id: U-Boot discussion <u-boot.lists.denx.de>
+List-Unsubscribe: <https://lists.denx.de/options/u-boot>,
+ <mailto:u-boot-request@lists.denx.de?subject=unsubscribe>
+List-Archive: <http://lists.denx.de/pipermail/u-boot/>
+List-Post: <mailto:u-boot@lists.denx.de>
+List-Help: <mailto:u-boot-request@lists.denx.de?subject=help>
+List-Subscribe: <https://lists.denx.de/listinfo/u-boot>,
+ <mailto:u-boot-request@lists.denx.de?subject=subscribe>
+Errors-To: u-boot-bounces@lists.denx.de
+Sender: "U-Boot" <u-boot-bounces@lists.denx.de>
+
+From: Heiko Stuebner <heiko.stuebner@theobroma-systems.com>
+
+sdram configuration happens outside of dm-infrastructure in special
+tpl-code, so the sdram driver itself has just the function to read
+back the sdram configuration and allow main uboot to handle dram sizes.
+
+Signed-off-by: Heiko Stuebner <heiko.stuebner@theobroma-systems.com>
+---
+ drivers/ram/rockchip/Makefile     |  1 +
+ drivers/ram/rockchip/sdram_px30.c | 57 +++++++++++++++++++++++++++++++
+ 2 files changed, 58 insertions(+)
+ create mode 100644 drivers/ram/rockchip/sdram_px30.c
+
+diff --git a/drivers/ram/rockchip/Makefile b/drivers/ram/rockchip/Makefile
+index feb1f82d00..a51df57411 100644
+--- a/drivers/ram/rockchip/Makefile
++++ b/drivers/ram/rockchip/Makefile
+@@ -5,6 +5,7 @@
+ 
+ obj-$(CONFIG_RAM_ROCKCHIP_DEBUG) += sdram_debug.o
+ obj-$(CONFIG_ROCKCHIP_RK3368) = dmc-rk3368.o
++obj-$(CONFIG_ROCKCHIP_PX30) = sdram_px30.o
+ obj-$(CONFIG_ROCKCHIP_RK3128) = sdram_rk3128.o
+ obj-$(CONFIG_ROCKCHIP_RK3188) = sdram_rk3188.o
+ obj-$(CONFIG_ROCKCHIP_RK322X) = sdram_rk322x.o
+diff --git a/drivers/ram/rockchip/sdram_px30.c b/drivers/ram/rockchip/sdram_px30.c
+new file mode 100644
+index 0000000000..bdb97f2b5c
+--- /dev/null
++++ b/drivers/ram/rockchip/sdram_px30.c
+@@ -0,0 +1,57 @@
++// SPDX-License-Identifier: GPL-2.0+ OR BSD-3-Clause
++/*
++ * (C) Copyright 2017 Rockchip Electronics Co., Ltd.
++ */
++
++#include <common.h>
++#include <dm.h>
++#include <ram.h>
++#include <syscon.h>
++#include <asm/arch-rockchip/clock.h>
++#include <asm/arch-rockchip/grf_px30.h>
++#include <asm/arch-rockchip/sdram_common.h>
++
++struct dram_info {
++	struct ram_info info;
++	struct px30_pmugrf *pmugrf;
++};
++
++static int px30_dmc_probe(struct udevice *dev)
++{
++	struct dram_info *priv = dev_get_priv(dev);
++
++	priv->pmugrf = syscon_get_first_range(ROCKCHIP_SYSCON_PMUGRF);
++	debug("%s: grf=%p\n", __func__, priv->pmugrf);
++	priv->info.base = CONFIG_SYS_SDRAM_BASE;
++	priv->info.size =
++		rockchip_sdram_size((phys_addr_t)&priv->pmugrf->os_reg[2]);
++
++	return 0;
++}
++
++static int px30_dmc_get_info(struct udevice *dev, struct ram_info *info)
++{
++	struct dram_info *priv = dev_get_priv(dev);
++
++	*info = priv->info;
++
++	return 0;
++}
++
++static struct ram_ops px30_dmc_ops = {
++	.get_info = px30_dmc_get_info,
++};
++
++static const struct udevice_id px30_dmc_ids[] = {
++	{ .compatible = "rockchip,px30-dmc" },
++	{ }
++};
++
++U_BOOT_DRIVER(dmc_px30) = {
++	.name = "rockchip_px30_dmc",
++	.id = UCLASS_RAM,
++	.of_match = px30_dmc_ids,
++	.ops = &px30_dmc_ops,
++	.probe = px30_dmc_probe,
++	.priv_auto_alloc_size = sizeof(struct dram_info),
++};
+
+From patchwork Thu Oct 24 23:28:01 2019
+Content-Type: text/plain; charset="utf-8"
+MIME-Version: 1.0
+Content-Transfer-Encoding: 7bit
+X-Patchwork-Submitter: =?utf-8?q?Heiko_St=C3=BCbner?= <heiko@sntech.de>
+X-Patchwork-Id: 1183665
+X-Patchwork-Delegate: ykai007@gmail.com
+Return-Path: <u-boot-bounces@lists.denx.de>
+X-Original-To: incoming@patchwork.ozlabs.org
+Delivered-To: patchwork-incoming@bilbo.ozlabs.org
+Authentication-Results: ozlabs.org;
+ spf=none (no SPF record) smtp.mailfrom=lists.denx.de
+ (client-ip=81.169.180.215; helo=lists.denx.de;
+ envelope-from=u-boot-bounces@lists.denx.de;
+ receiver=<UNKNOWN>)
+Authentication-Results: ozlabs.org;
+ dmarc=none (p=none dis=none) header.from=sntech.de
+Received: from lists.denx.de (dione.denx.de [81.169.180.215])
+ by ozlabs.org (Postfix) with ESMTP id 46zkWL1XGLz9sQm
+ for <incoming@patchwork.ozlabs.org>;
+ Fri, 25 Oct 2019 10:50:06 +1100 (AEDT)
+Received: by lists.denx.de (Postfix, from userid 105)
+ id CF9C2C21DA1; Thu, 24 Oct 2019 23:49:56 +0000 (UTC)
+X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on lists.denx.de
+X-Spam-Level: 
+X-Spam-Status: No, score=0.0 required=5.0 tests=none autolearn=unavailable
+ autolearn_force=no version=3.4.0
+Received: from lists.denx.de (localhost [IPv6:::1])
+ by lists.denx.de (Postfix) with ESMTP id 25EB1C21E12;
+ Thu, 24 Oct 2019 23:48:26 +0000 (UTC)
+Received: by lists.denx.de (Postfix, from userid 105)
+ id 9613FC21E12; Thu, 24 Oct 2019 23:48:24 +0000 (UTC)
+Received: from gloria.sntech.de (gloria.sntech.de [185.11.138.130])
+ by lists.denx.de (Postfix) with ESMTPS id B4FA4C21E13
+ for <u-boot@lists.denx.de>; Thu, 24 Oct 2019 23:47:59 +0000 (UTC)
+Received: from ip5f5a6266.dynamic.kabel-deutschland.de ([95.90.98.102]
+ helo=phil.fritz.box) by gloria.sntech.de with esmtpsa
+ (TLS1.2:ECDHE_RSA_AES_128_GCM_SHA256:128)
+ (Exim 4.89) (envelope-from <heiko@sntech.de>)
+ id 1iNmWg-0002cR-Ty; Fri, 25 Oct 2019 01:28:19 +0200
+From: Heiko Stuebner <heiko@sntech.de>
+To: u-boot@lists.denx.de
+Date: Fri, 25 Oct 2019 01:28:01 +0200
+Message-Id: <20191024232803.10338-11-heiko@sntech.de>
+X-Mailer: git-send-email 2.23.0
+In-Reply-To: <20191024232803.10338-1-heiko@sntech.de>
+References: <20191024232803.10338-1-heiko@sntech.de>
+MIME-Version: 1.0
+Cc: Heiko Stuebner <heiko.stuebner@theobroma-systems.com>,
+ joe.hershberger@ni.com, christoph.muellner@theobroma-systems.com
+Subject: [U-Boot] [PATCH 10/12] rockchip: add px30 devicetrees
+X-BeenThere: u-boot@lists.denx.de
+X-Mailman-Version: 2.1.18
+Precedence: list
+List-Id: U-Boot discussion <u-boot.lists.denx.de>
+List-Unsubscribe: <https://lists.denx.de/options/u-boot>,
+ <mailto:u-boot-request@lists.denx.de?subject=unsubscribe>
+List-Archive: <http://lists.denx.de/pipermail/u-boot/>
+List-Post: <mailto:u-boot@lists.denx.de>
+List-Help: <mailto:u-boot-request@lists.denx.de?subject=help>
+List-Subscribe: <https://lists.denx.de/listinfo/u-boot>,
+ <mailto:u-boot-request@lists.denx.de?subject=subscribe>
+Errors-To: u-boot-bounces@lists.denx.de
+Sender: "U-Boot" <u-boot-bounces@lists.denx.de>
+
+From: Heiko Stuebner <heiko.stuebner@theobroma-systems.com>
+
+Add px30 related devicetrees synced from the Linux kernel.
+
+Signed-off-by: Heiko Stuebner <heiko.stuebner@theobroma-systems.com>
+---
+ arch/arm/dts/Makefile             |    3 +
+ arch/arm/dts/px30-evb-u-boot.dtsi |   81 ++
+ arch/arm/dts/px30-evb.dts         |  527 ++++++++
+ arch/arm/dts/px30.dtsi            | 2068 +++++++++++++++++++++++++++++
+ 4 files changed, 2679 insertions(+)
+ create mode 100644 arch/arm/dts/px30-evb-u-boot.dtsi
+ create mode 100644 arch/arm/dts/px30-evb.dts
+ create mode 100644 arch/arm/dts/px30.dtsi
+
+diff --git a/arch/arm/dts/Makefile b/arch/arm/dts/Makefile
+index dbb062edda..04ddbfb11f 100644
+--- a/arch/arm/dts/Makefile
++++ b/arch/arm/dts/Makefile
+@@ -67,6 +67,9 @@ dtb-$(CONFIG_KIRKWOOD) += \
+ dtb-$(CONFIG_ARCH_OWL) += \
+ 	bubblegum_96.dtb
+ 
++dtb-$(CONFIG_ROCKCHIP_PX30) += \
++	px30-evb.dtb
++
+ dtb-$(CONFIG_ROCKCHIP_RK3036) += \
+ 	rk3036-sdk.dtb
+ 
+diff --git a/arch/arm/dts/px30-evb-u-boot.dtsi b/arch/arm/dts/px30-evb-u-boot.dtsi
+new file mode 100644
+index 0000000000..3de9c7068e
+--- /dev/null
++++ b/arch/arm/dts/px30-evb-u-boot.dtsi
+@@ -0,0 +1,81 @@
++// SPDX-License-Identifier: (GPL-2.0+ OR MIT)
++/*
++ * (C) Copyright 2017 Rockchip Electronics Co., Ltd
++ */
++
++/ {
++	aliases {
++		mmc0 = &emmc;
++		mmc1 = &sdmmc;
++	};
++
++	chosen {
++		u-boot,spl-boot-order = &emmc, &sdmmc;
++	};
++};
++
++&dmc {
++	u-boot,dm-pre-reloc;
++};
++
++&uart2 {
++	clock-frequency = <24000000>;
++	u-boot,dm-pre-reloc;
++};
++
++&uart5 {
++	clock-frequency = <24000000>;
++	u-boot,dm-pre-reloc;
++};
++
++&sdmmc {
++	u-boot,dm-pre-reloc;
++
++	/* temporary till I find out why dma mode doesn't work */
++	fifo-mode;
++};
++
++&emmc {
++	u-boot,dm-pre-reloc;
++};
++
++&grf {
++	u-boot,dm-pre-reloc;
++};
++
++&pmugrf {
++	u-boot,dm-pre-reloc;
++};
++
++&xin24m {
++	u-boot,dm-pre-reloc;
++};
++
++&cru {
++	u-boot,dm-pre-reloc;
++};
++
++&pmucru {
++	u-boot,dm-pre-reloc;
++};
++
++&saradc {
++	u-boot,dm-pre-reloc;
++	status = "okay";
++};
++
++&gpio0 {
++	u-boot,dm-pre-reloc;
++};
++
++&gpio1 {
++	u-boot,dm-pre-reloc;
++};
++
++&gpio2 {
++	u-boot,dm-pre-reloc;
++};
++
++&gpio3 {
++	u-boot,dm-pre-reloc;
++};
+diff --git a/arch/arm/dts/px30-evb.dts b/arch/arm/dts/px30-evb.dts
+new file mode 100644
+index 0000000000..089a7ade4e
+--- /dev/null
++++ b/arch/arm/dts/px30-evb.dts
+@@ -0,0 +1,527 @@
++// SPDX-License-Identifier: (GPL-2.0+ OR MIT)
++/*
++ * Copyright (c) 2018 Fuzhou Rockchip Electronics Co., Ltd
++ */
++
++/dts-v1/;
++#include <dt-bindings/gpio/gpio.h>
++#include <dt-bindings/input/input.h>
++#include <dt-bindings/pinctrl/rockchip.h>
++#include "px30.dtsi"
++#include "px30-evb-u-boot.dtsi"
++
++/ {
++	model = "Rockchip PX30 EVB";
++	compatible = "rockchip,px30-evb", "rockchip,px30";
++
++	chosen {
++		stdout-path = "serial5:115200n8";
++	};
++
++	adc-keys {
++		compatible = "adc-keys";
++		io-channels = <&saradc 2>;
++		io-channel-names = "buttons";
++		keyup-threshold-microvolt = <1800000>;
++		poll-interval = <100>;
++
++		esc-key {
++			label = "esc";
++			linux,code = <KEY_ESC>;
++			press-threshold-microvolt = <1310000>;
++		};
++
++		home-key {
++			label = "home";
++			linux,code = <KEY_HOME>;
++			press-threshold-microvolt = <624000>;
++		};
++
++		menu-key {
++			label = "menu";
++			linux,code = <KEY_MENU>;
++			press-threshold-microvolt = <987000>;
++		};
++
++		vol-down-key {
++			label = "volume down";
++			linux,code = <KEY_VOLUMEDOWN>;
++			press-threshold-microvolt = <300000>;
++		};
++
++		vol-up-key {
++			label = "volume up";
++			linux,code = <KEY_VOLUMEUP>;
++			press-threshold-microvolt = <17000>;
++		};
++	};
++
++	backlight: backlight {
++		compatible = "pwm-backlight";
++		pwms = <&pwm1 0 25000 0>;
++		power-supply = <&vcc3v3_lcd>;
++	};
++
++	emmc_pwrseq: emmc-pwrseq {
++		compatible = "mmc-pwrseq-emmc";
++		pinctrl-0 = <&emmc_reset>;
++		pinctrl-names = "default";
++		reset-gpios = <&gpio1 RK_PB3 GPIO_ACTIVE_HIGH>;
++	};
++
++	sdio_pwrseq: sdio-pwrseq {
++		compatible = "mmc-pwrseq-simple";
++		pinctrl-names = "default";
++		pinctrl-0 = <&wifi_enable_h>;
++
++		/*
++		 * On the module itself this is one of these (depending
++		 * on the actual card populated):
++		 * - SDIO_RESET_L_WL_REG_ON
++		 * - PDN (power down when low)
++		 */
++		reset-gpios = <&gpio0 RK_PA2 GPIO_ACTIVE_LOW>; /* GPIO3_A4 */
++	};
++
++	vcc5v0_sys: vccsys {
++		compatible = "regulator-fixed";
++		regulator-name = "vcc5v0_sys";
++		regulator-always-on;
++		regulator-boot-on;
++		regulator-min-microvolt = <5000000>;
++		regulator-max-microvolt = <5000000>;
++	};
++};
++
++&cpu0 {
++	cpu-supply = <&vdd_arm>;
++};
++
++&cpu1 {
++	cpu-supply = <&vdd_arm>;
++};
++
++&cpu2 {
++	cpu-supply = <&vdd_arm>;
++};
++
++&cpu3 {
++	cpu-supply = <&vdd_arm>;
++};
++
++&display_subsystem {
++	status = "okay";
++};
++
++&dsi {
++	status = "okay";
++
++	ports {
++		mipi_out: port@1 {
++			reg = <1>;
++
++			mipi_out_panel: endpoint {
++				remote-endpoint = <&mipi_in_panel>;
++			};
++		};
++	};
++
++	panel@0 {
++		compatible = "sitronix,st7703";
++		reg = <0>;
++		backlight = <&backlight>;
++		iovcc-supply = <&vcc_1v8>;
++		vci-supply = <&vcc3v3_lcd>;
++
++		ports {
++			#address-cells = <1>;
++			#size-cells = <0>;
++
++			port@0 {
++				reg = <0>;
++
++				mipi_in_panel: endpoint {
++					remote-endpoint = <&mipi_out_panel>;
++				};
++			};
++		};
++	};
++};
++
++&dsi_dphy {
++	status = "okay";
++};
++
++&emmc {
++	bus-width = <8>;
++	cap-mmc-highspeed;
++	mmc-hs200-1_8v;
++	non-removable;
++	mmc-pwrseq = <&emmc_pwrseq>;
++	vmmc-supply = <&vcc_3v0>;
++	vqmmc-supply = <&vccio_flash>;
++	status = "okay";
++};
++
++&gmac {
++	clock_in_out = "output";
++	phy-supply = <&vcc_rmii>;
++	snps,reset-gpio = <&gpio2 13 GPIO_ACTIVE_LOW>;
++	snps,reset-active-low;
++	snps,reset-delays-us = <0 50000 50000>;
++	status = "okay";
++};
++
++&i2c0 {
++	status = "okay";
++
++	rk809: pmic@20 {
++		compatible = "rockchip,rk809";
++		reg = <0x20>;
++		interrupt-parent = <&gpio0>;
++		interrupts = <7 IRQ_TYPE_LEVEL_LOW>;
++		pinctrl-names = "default";
++		pinctrl-0 = <&pmic_int>;
++		rockchip,system-power-controller;
++		wakeup-source;
++		#clock-cells = <0>;
++		clock-output-names = "xin32k";
++
++		vcc1-supply = <&vcc5v0_sys>;
++		vcc2-supply = <&vcc5v0_sys>;
++		vcc3-supply = <&vcc5v0_sys>;
++		vcc4-supply = <&vcc5v0_sys>;
++		vcc5-supply = <&vcc3v3_sys>;
++		vcc6-supply = <&vcc3v3_sys>;
++		vcc7-supply = <&vcc3v3_sys>;
++		vcc8-supply = <&vcc3v3_sys>;
++		vcc9-supply = <&vcc5v0_sys>;
++
++		regulators {
++			vdd_log: DCDC_REG1 {
++				regulator-name = "vdd_log";
++				regulator-min-microvolt = <950000>;
++				regulator-max-microvolt = <1350000>;
++				regulator-ramp-delay = <6001>;
++				regulator-always-on;
++				regulator-boot-on;
++
++				regulator-state-mem {
++					regulator-on-in-suspend;
++					regulator-suspend-microvolt = <950000>;
++				};
++			};
++
++			vdd_arm: DCDC_REG2 {
++				regulator-name = "vdd_arm";
++				regulator-min-microvolt = <950000>;
++				regulator-max-microvolt = <1350000>;
++				regulator-ramp-delay = <6001>;
++				regulator-always-on;
++				regulator-boot-on;
++
++				regulator-state-mem {
++					regulator-off-in-suspend;
++					regulator-suspend-microvolt = <950000>;
++				};
++			};
++
++			vcc_ddr: DCDC_REG3 {
++				regulator-name = "vcc_ddr";
++				regulator-always-on;
++				regulator-boot-on;
++
++				regulator-state-mem {
++					regulator-on-in-suspend;
++				};
++			};
++
++			vcc_3v0: vcc_rmii: DCDC_REG4 {
++				regulator-name = "vcc_3v0";
++				regulator-min-microvolt = <3000000>;
++				regulator-max-microvolt = <3000000>;
++				regulator-always-on;
++				regulator-boot-on;
++
++				regulator-state-mem {
++					regulator-on-in-suspend;
++					regulator-suspend-microvolt = <3000000>;
++				};
++			};
++
++			vcc3v3_sys: DCDC_REG5 {
++				regulator-name = "vcc3v3_sys";
++				regulator-min-microvolt = <3300000>;
++				regulator-max-microvolt = <3300000>;
++				regulator-always-on;
++				regulator-boot-on;
++
++				regulator-state-mem {
++					regulator-on-in-suspend;
++					regulator-suspend-microvolt = <3300000>;
++				};
++			};
++
++			vcc_1v0: LDO_REG1 {
++				regulator-name = "vcc_1v0";
++				regulator-min-microvolt = <1000000>;
++				regulator-max-microvolt = <1000000>;
++				regulator-always-on;
++				regulator-boot-on;
++
++				regulator-state-mem {
++					regulator-on-in-suspend;
++					regulator-suspend-microvolt = <1000000>;
++				};
++			};
++
++			vcc_1v8: vccio_flash: vccio_sdio: LDO_REG2 {
++				regulator-name = "vcc_1v8";
++				regulator-min-microvolt = <1800000>;
++				regulator-max-microvolt = <1800000>;
++				regulator-always-on;
++				regulator-boot-on;
++
++				regulator-state-mem {
++					regulator-on-in-suspend;
++					regulator-suspend-microvolt = <1800000>;
++				};
++			};
++
++			vdd_1v0: LDO_REG3 {
++				regulator-name = "vdd_1v0";
++				regulator-min-microvolt = <1000000>;
++				regulator-max-microvolt = <1000000>;
++				regulator-always-on;
++				regulator-boot-on;
++
++				regulator-state-mem {
++					regulator-on-in-suspend;
++					regulator-suspend-microvolt = <1000000>;
++				};
++			};
++
++			vcc3v0_pmu: LDO_REG4 {
++				regulator-name = "vcc3v0_pmu";
++				regulator-min-microvolt = <3000000>;
++				regulator-max-microvolt = <3000000>;
++				regulator-always-on;
++				regulator-boot-on;
++
++				regulator-state-mem {
++					regulator-on-in-suspend;
++					regulator-suspend-microvolt = <3000000>;
++				};
++			};
++
++			vccio_sd: LDO_REG5 {
++				regulator-name = "vccio_sd";
++				regulator-min-microvolt = <1800000>;
++				regulator-max-microvolt = <3300000>;
++				regulator-always-on;
++				regulator-boot-on;
++
++				regulator-state-mem {
++					regulator-on-in-suspend;
++					regulator-suspend-microvolt = <3300000>;
++				};
++			};
++
++			vcc_sd: LDO_REG6 {
++				regulator-name = "vcc_sd";
++				regulator-min-microvolt = <3300000>;
++				regulator-max-microvolt = <3300000>;
++				regulator-boot-on;
++
++				regulator-state-mem {
++					regulator-on-in-suspend;
++					regulator-suspend-microvolt = <3300000>;
++				};
++			};
++
++			vcc2v8_dvp: LDO_REG7 {
++				regulator-name = "vcc2v8_dvp";
++				regulator-min-microvolt = <2800000>;
++				regulator-max-microvolt = <2800000>;
++				regulator-boot-on;
++
++				regulator-state-mem {
++					regulator-off-in-suspend;
++					regulator-suspend-microvolt = <2800000>;
++				};
++			};
++
++			vcc1v8_dvp: LDO_REG8 {
++				regulator-name = "vcc1v8_dvp";
++				regulator-min-microvolt = <1800000>;
++				regulator-max-microvolt = <1800000>;
++				regulator-boot-on;
++
++				regulator-state-mem {
++					regulator-on-in-suspend;
++					regulator-suspend-microvolt = <1800000>;
++				};
++			};
++
++			vcc1v5_dvp: LDO_REG9 {
++				regulator-name = "vcc1v5_dvp";
++				regulator-min-microvolt = <1500000>;
++				regulator-max-microvolt = <1500000>;
++				regulator-boot-on;
++
++				regulator-state-mem {
++					regulator-off-in-suspend;
++					regulator-suspend-microvolt = <1500000>;
++				};
++			};
++
++			vcc3v3_lcd: SWITCH_REG1 {
++				regulator-name = "vcc3v3_lcd";
++				regulator-boot-on;
++			};
++
++			vcc5v0_host: SWITCH_REG2 {
++				regulator-name = "vcc5v0_host";
++				regulator-always-on;
++				regulator-boot-on;
++			};
++		};
++	};
++};
++
++&i2s1_2ch {
++	status = "okay";
++};
++
++&io_domains {
++	status = "okay";
++
++	vccio1-supply = <&vccio_sdio>;
++	vccio2-supply = <&vccio_sd>;
++	vccio3-supply = <&vcc_3v0>;
++	vccio4-supply = <&vcc3v0_pmu>;
++	vccio5-supply = <&vcc_3v0>;
++	vccio6-supply = <&vccio_flash>;
++};
++
++&pinctrl {
++	headphone {
++		hp_det: hp-det {
++			rockchip,pins =
++				<2 RK_PB0 RK_FUNC_GPIO &pcfg_pull_down>;
++		};
++	};
++
++	emmc {
++		emmc_reset: emmc-reset {
++			rockchip,pins = <1 RK_PB3 RK_FUNC_GPIO &pcfg_pull_none>;
++		};
++	};
++
++	pmic {
++		pmic_int: pmic_int {
++			rockchip,pins =
++				<0 RK_PA7 RK_FUNC_GPIO &pcfg_pull_up>;
++		};
++
++		soc_slppin_gpio: soc_slppin_gpio {
++			rockchip,pins =
++				<0 RK_PA4 RK_FUNC_GPIO &pcfg_output_low>;
++		};
++
++		soc_slppin_slp: soc_slppin_slp {
++			rockchip,pins =
++				<0 RK_PA4 1 &pcfg_pull_none>;
++		};
++
++		soc_slppin_rst: soc_slppin_rst {
++			rockchip,pins =
++				<0 RK_PA4 2 &pcfg_pull_none>;
++		};
++	};
++
++	sdio-pwrseq {
++		wifi_enable_h: wifi-enable-h {
++			rockchip,pins =
++				<0 RK_PA2 RK_FUNC_GPIO &pcfg_pull_none>;
++		};
++	};
++};
++
++&pmu_io_domains {
++	status = "okay";
++
++	pmuio1-supply = <&vcc3v0_pmu>;
++	pmuio2-supply = <&vcc3v0_pmu>;
++};
++
++&pwm1 {
++	status = "okay";
++};
++
++&saradc {
++	vref-supply = <&vcc_1v8>;
++	status = "okay";
++};
++
++&sdmmc {
++	bus-width = <4>;
++	cap-mmc-highspeed;
++	cap-sd-highspeed;
++	card-detect-delay = <800>;
++	sd-uhs-sdr12;
++	sd-uhs-sdr25;
++	sd-uhs-sdr50;
++	sd-uhs-sdr104;
++	vmmc-supply = <&vcc_sd>;
++	vqmmc-supply = <&vccio_sd>;
++	status = "okay";
++};
++
++&sdio {
++	bus-width = <4>;
++	cap-sd-highspeed;
++	keep-power-in-suspend;
++	non-removable;
++	mmc-pwrseq = <&sdio_pwrseq>;
++	sd-uhs-sdr104;
++	status = "okay";
++};
++
++&uart1 {
++	pinctrl-names = "default";
++	pinctrl-0 = <&uart1_xfer &uart1_cts>;
++	status = "okay";
++};
++
++&uart5 {
++	status = "okay";
++};
++
++&usb20_otg {
++	status = "okay";
++};
++
++&usb_host0_ehci {
++	status = "okay";
++};
++
++&usb_host0_ohci {
++	status = "okay";
++};
++
++&vopb {
++	status = "okay";
++};
++
++&vopb_mmu {
++	status = "okay";
++};
++
++&vopl {
++	status = "okay";
++};
++
++&vopl_mmu {
++	status = "okay";
++};
+diff --git a/arch/arm/dts/px30.dtsi b/arch/arm/dts/px30.dtsi
+new file mode 100644
+index 0000000000..0d2325a77f
+--- /dev/null
++++ b/arch/arm/dts/px30.dtsi
+@@ -0,0 +1,2068 @@
++// SPDX-License-Identifier: (GPL-2.0+ OR MIT)
++/*
++ * Copyright (c) 2018 Fuzhou Rockchip Electronics Co., Ltd
++ */
++
++#include <dt-bindings/clock/px30-cru.h>
++#include <dt-bindings/gpio/gpio.h>
++#include <dt-bindings/interrupt-controller/arm-gic.h>
++#include <dt-bindings/interrupt-controller/irq.h>
++#include <dt-bindings/pinctrl/rockchip.h>
++#include <dt-bindings/power/px30-power.h>
++#include <dt-bindings/soc/rockchip,boot-mode.h>
++
++/ {
++	compatible = "rockchip,px30";
++
++	interrupt-parent = <&gic>;
++	#address-cells = <2>;
++	#size-cells = <2>;
++
++	aliases {
++		ethernet0 = &gmac;
++		i2c0 = &i2c0;
++		i2c1 = &i2c1;
++		i2c2 = &i2c2;
++		i2c3 = &i2c3;
++		serial0 = &uart0;
++		serial1 = &uart1;
++		serial2 = &uart2;
++		serial3 = &uart3;
++		serial4 = &uart4;
++		serial5 = &uart5;
++		spi0 = &spi0;
++		spi1 = &spi1;
++	};
++
++	cpus {
++		#address-cells = <2>;
++		#size-cells = <0>;
++
++		cpu0: cpu@0 {
++			device_type = "cpu";
++			compatible = "arm,cortex-a35";
++			reg = <0x0 0x0>;
++			enable-method = "psci";
++			clocks = <&cru ARMCLK>;
++			#cooling-cells = <2>;
++			cpu-idle-states = <&CPU_SLEEP &CLUSTER_SLEEP>;
++			dynamic-power-coefficient = <90>;
++			operating-points-v2 = <&cpu0_opp_table>;
++		};
++
++		cpu1: cpu@1 {
++			device_type = "cpu";
++			compatible = "arm,cortex-a35";
++			reg = <0x0 0x1>;
++			enable-method = "psci";
++			clocks = <&cru ARMCLK>;
++			#cooling-cells = <2>;
++			cpu-idle-states = <&CPU_SLEEP &CLUSTER_SLEEP>;
++			dynamic-power-coefficient = <90>;
++			operating-points-v2 = <&cpu0_opp_table>;
++		};
++
++		cpu2: cpu@2 {
++			device_type = "cpu";
++			compatible = "arm,cortex-a35";
++			reg = <0x0 0x2>;
++			enable-method = "psci";
++			clocks = <&cru ARMCLK>;
++			#cooling-cells = <2>;
++			cpu-idle-states = <&CPU_SLEEP &CLUSTER_SLEEP>;
++			dynamic-power-coefficient = <90>;
++			operating-points-v2 = <&cpu0_opp_table>;
++		};
++
++		cpu3: cpu@3 {
++			device_type = "cpu";
++			compatible = "arm,cortex-a35";
++			reg = <0x0 0x3>;
++			enable-method = "psci";
++			clocks = <&cru ARMCLK>;
++			#cooling-cells = <2>;
++			cpu-idle-states = <&CPU_SLEEP &CLUSTER_SLEEP>;
++			dynamic-power-coefficient = <90>;
++			operating-points-v2 = <&cpu0_opp_table>;
++		};
++
++		idle-states {
++			entry-method = "psci";
++
++			CPU_SLEEP: cpu-sleep {
++				compatible = "arm,idle-state";
++				local-timer-stop;
++				arm,psci-suspend-param = <0x0010000>;
++				entry-latency-us = <120>;
++				exit-latency-us = <250>;
++				min-residency-us = <900>;
++			};
++
++			CLUSTER_SLEEP: cluster-sleep {
++				compatible = "arm,idle-state";
++				local-timer-stop;
++				arm,psci-suspend-param = <0x1010000>;
++				entry-latency-us = <400>;
++				exit-latency-us = <500>;
++				min-residency-us = <2000>;
++			};
++		};
++	};
++
++	cpu0_opp_table: cpu0-opp-table {
++		compatible = "operating-points-v2";
++		opp-shared;
++
++		opp-408000000 {
++			opp-hz = /bits/ 64 <408000000>;
++			opp-microvolt = <950000 950000 1350000>;
++			clock-latency-ns = <40000>;
++			opp-suspend;
++		};
++		opp-600000000 {
++			opp-hz = /bits/ 64 <600000000>;
++			opp-microvolt = <950000 950000 1350000>;
++			clock-latency-ns = <40000>;
++		};
++		opp-816000000 {
++			opp-hz = /bits/ 64 <816000000>;
++			opp-microvolt = <1050000 1050000 1350000>;
++			clock-latency-ns = <40000>;
++		};
++		opp-1008000000 {
++			opp-hz = /bits/ 64 <1008000000>;
++			opp-microvolt = <1175000 1175000 1350000>;
++			clock-latency-ns = <40000>;
++		};
++		opp-1200000000 {
++			opp-hz = /bits/ 64 <1200000000>;
++			opp-microvolt = <1300000 1300000 1350000>;
++			clock-latency-ns = <40000>;
++		};
++		opp-1296000000 {
++			opp-hz = /bits/ 64 <1296000000>;
++			opp-microvolt = <1350000 1350000 1350000>;
++			clock-latency-ns = <40000>;
++		};
++	};
++
++	arm-pmu {
++		compatible = "arm,cortex-a53-pmu";
++		interrupts = <GIC_SPI 100 IRQ_TYPE_LEVEL_HIGH>,
++			     <GIC_SPI 101 IRQ_TYPE_LEVEL_HIGH>,
++			     <GIC_SPI 102 IRQ_TYPE_LEVEL_HIGH>,
++			     <GIC_SPI 103 IRQ_TYPE_LEVEL_HIGH>;
++		interrupt-affinity = <&cpu0>, <&cpu1>, <&cpu2>, <&cpu3>;
++	};
++
++	dmc: dmc {
++		compatible = "rockchip,px30-dmc", "syscon";
++		reg = <0x0 0xff2a0000 0x0 0x1000>;
++	};
++
++	display_subsystem: display-subsystem {
++		compatible = "rockchip,display-subsystem";
++		ports = <&vopb_out>, <&vopl_out>;
++		status = "disabled";
++	};
++
++	gmac_clkin: external-gmac-clock {
++		compatible = "fixed-clock";
++		clock-frequency = <50000000>;
++		clock-output-names = "gmac_clkin";
++		#clock-cells = <0>;
++	};
++
++	psci {
++		compatible = "arm,psci-1.0";
++		method = "smc";
++	};
++
++	timer {
++		compatible = "arm,armv8-timer";
++		interrupts = <GIC_PPI 13 (GIC_CPU_MASK_SIMPLE(4) | IRQ_TYPE_LEVEL_HIGH)>,
++			     <GIC_PPI 14 (GIC_CPU_MASK_SIMPLE(4) | IRQ_TYPE_LEVEL_HIGH)>,
++			     <GIC_PPI 11 (GIC_CPU_MASK_SIMPLE(4) | IRQ_TYPE_LEVEL_HIGH)>,
++			     <GIC_PPI 10 (GIC_CPU_MASK_SIMPLE(4) | IRQ_TYPE_LEVEL_HIGH)>;
++	};
++
++	xin24m: xin24m {
++		compatible = "fixed-clock";
++		#clock-cells = <0>;
++		clock-frequency = <24000000>;
++		clock-output-names = "xin24m";
++	};
++
++	pmu: power-management@ff000000 {
++		compatible = "rockchip,px30-pmu", "syscon", "simple-mfd";
++		reg = <0x0 0xff000000 0x0 0x1000>;
++
++		power: power-controller {
++			compatible = "rockchip,px30-power-controller";
++			#power-domain-cells = <1>;
++			#address-cells = <1>;
++			#size-cells = <0>;
++
++			/* These power domains are grouped by VD_LOGIC */
++			pd_usb@PX30_PD_USB {
++				reg = <PX30_PD_USB>;
++				clocks = <&cru HCLK_HOST>,
++					 <&cru HCLK_OTG>,
++					 <&cru SCLK_OTG_ADP>;
++				pm_qos = <&qos_usb_host>, <&qos_usb_otg>;
++			};
++			pd_sdcard@PX30_PD_SDCARD {
++				reg = <PX30_PD_SDCARD>;
++				clocks = <&cru HCLK_SDMMC>,
++					 <&cru SCLK_SDMMC>;
++				pm_qos = <&qos_sdmmc>;
++			};
++			pd_gmac@PX30_PD_GMAC {
++				reg = <PX30_PD_GMAC>;
++				clocks = <&cru ACLK_GMAC>,
++					 <&cru PCLK_GMAC>,
++					 <&cru SCLK_MAC_REF>,
++					 <&cru SCLK_GMAC_RX_TX>;
++				pm_qos = <&qos_gmac>;
++			};
++			pd_mmc_nand@PX30_PD_MMC_NAND {
++				reg = <PX30_PD_MMC_NAND>;
++				clocks =  <&cru HCLK_NANDC>,
++					  <&cru HCLK_EMMC>,
++					  <&cru HCLK_SDIO>,
++					  <&cru HCLK_SFC>,
++					  <&cru SCLK_EMMC>,
++					  <&cru SCLK_NANDC>,
++					  <&cru SCLK_SDIO>,
++					  <&cru SCLK_SFC>;
++				pm_qos = <&qos_emmc>, <&qos_nand>,
++					 <&qos_sdio>, <&qos_sfc>;
++			};
++			pd_vpu@PX30_PD_VPU {
++				reg = <PX30_PD_VPU>;
++				clocks = <&cru ACLK_VPU>,
++					 <&cru HCLK_VPU>,
++					 <&cru SCLK_CORE_VPU>;
++				pm_qos = <&qos_vpu>, <&qos_vpu_r128>;
++			};
++			pd_vo@PX30_PD_VO {
++				reg = <PX30_PD_VO>;
++				clocks = <&cru ACLK_RGA>,
++					 <&cru ACLK_VOPB>,
++					 <&cru ACLK_VOPL>,
++					 <&cru DCLK_VOPB>,
++					 <&cru DCLK_VOPL>,
++					 <&cru HCLK_RGA>,
++					 <&cru HCLK_VOPB>,
++					 <&cru HCLK_VOPL>,
++					 <&cru PCLK_MIPI_DSI>,
++					 <&cru SCLK_RGA_CORE>,
++					 <&cru SCLK_VOPB_PWM>;
++				pm_qos = <&qos_rga_rd>, <&qos_rga_wr>,
++					 <&qos_vop_m0>, <&qos_vop_m1>;
++			};
++			pd_vi@PX30_PD_VI {
++				reg = <PX30_PD_VI>;
++				clocks = <&cru ACLK_CIF>,
++					 <&cru ACLK_ISP>,
++					 <&cru HCLK_CIF>,
++					 <&cru HCLK_ISP>,
++					 <&cru SCLK_ISP>;
++				pm_qos = <&qos_isp_128>, <&qos_isp_rd>,
++					 <&qos_isp_wr>, <&qos_isp_m1>,
++					 <&qos_vip>;
++			};
++			pd_gpu@PX30_PD_GPU {
++				reg = <PX30_PD_GPU>;
++				clocks = <&cru SCLK_GPU>;
++				pm_qos = <&qos_gpu>;
++			};
++		};
++	};
++
++	pmugrf: syscon@ff010000 {
++		compatible = "rockchip,px30-pmugrf", "syscon", "simple-mfd";
++		reg = <0x0 0xff010000 0x0 0x1000>;
++		#address-cells = <1>;
++		#size-cells = <1>;
++
++		pmu_io_domains: io-domains {
++			compatible = "rockchip,px30-pmu-io-voltage-domain";
++			status = "disabled";
++		};
++
++		reboot-mode {
++			compatible = "syscon-reboot-mode";
++			offset = <0x200>;
++			mode-bootloader = <BOOT_BL_DOWNLOAD>;
++			mode-fastboot = <BOOT_FASTBOOT>;
++			mode-loader = <BOOT_BL_DOWNLOAD>;
++			mode-normal = <BOOT_NORMAL>;
++			mode-recovery = <BOOT_RECOVERY>;
++		};
++	};
++
++	uart0: serial@ff030000 {
++		compatible = "rockchip,px30-uart", "snps,dw-apb-uart";
++		reg = <0x0 0xff030000 0x0 0x100>;
++		interrupts = <GIC_SPI 15 IRQ_TYPE_LEVEL_HIGH>;
++		clocks = <&pmucru SCLK_UART0_PMU>, <&pmucru PCLK_UART0_PMU>;
++		clock-names = "baudclk", "apb_pclk";
++		dmas = <&dmac 0>, <&dmac 1>;
++		dma-names = "tx", "rx";
++		reg-shift = <2>;
++		reg-io-width = <4>;
++		pinctrl-names = "default";
++		pinctrl-0 = <&uart0_xfer &uart0_cts &uart0_rts>;
++		status = "disabled";
++	};
++
++	i2s1_2ch: i2s@ff070000 {
++		compatible = "rockchip,px30-i2s", "rockchip,rk3066-i2s";
++		reg = <0x0 0xff070000 0x0 0x1000>;
++		interrupts = <GIC_SPI 13 IRQ_TYPE_LEVEL_HIGH>;
++		clocks = <&cru SCLK_I2S1>, <&cru HCLK_I2S1>;
++		clock-names = "i2s_clk", "i2s_hclk";
++		dmas = <&dmac 18>, <&dmac 19>;
++		dma-names = "tx", "rx";
++		pinctrl-names = "default";
++		pinctrl-0 = <&i2s1_2ch_sclk &i2s1_2ch_lrck
++			     &i2s1_2ch_sdi &i2s1_2ch_sdo>;
++		#sound-dai-cells = <0>;
++		status = "disabled";
++	};
++
++	i2s2_2ch: i2s@ff080000 {
++		compatible = "rockchip,px30-i2s", "rockchip,rk3066-i2s";
++		reg = <0x0 0xff080000 0x0 0x1000>;
++		interrupts = <GIC_SPI 14 IRQ_TYPE_LEVEL_HIGH>;
++		clocks = <&cru SCLK_I2S2>, <&cru HCLK_I2S2>;
++		clock-names = "i2s_clk", "i2s_hclk";
++		dmas = <&dmac 20>, <&dmac 21>;
++		dma-names = "tx", "rx";
++		pinctrl-names = "default";
++		pinctrl-0 = <&i2s2_2ch_sclk &i2s2_2ch_lrck
++			     &i2s2_2ch_sdi &i2s2_2ch_sdo>;
++		#sound-dai-cells = <0>;
++		status = "disabled";
++	};
++
++	gic: interrupt-controller@ff131000 {
++		compatible = "arm,gic-400";
++		#interrupt-cells = <3>;
++		#address-cells = <0>;
++		interrupt-controller;
++		reg = <0x0 0xff131000 0 0x1000>,
++		      <0x0 0xff132000 0 0x2000>,
++		      <0x0 0xff134000 0 0x2000>,
++		      <0x0 0xff136000 0 0x2000>;
++		interrupts = <GIC_PPI 9
++		      (GIC_CPU_MASK_SIMPLE(4) | IRQ_TYPE_LEVEL_HIGH)>;
++	};
++
++	grf: syscon@ff140000 {
++		compatible = "rockchip,px30-grf", "syscon", "simple-mfd";
++		reg = <0x0 0xff140000 0x0 0x1000>;
++		#address-cells = <1>;
++		#size-cells = <1>;
++
++		io_domains: io-domains {
++			compatible = "rockchip,px30-io-voltage-domain";
++			status = "disabled";
++		};
++	};
++
++	uart1: serial@ff158000 {
++		compatible = "rockchip,px30-uart", "snps,dw-apb-uart";
++		reg = <0x0 0xff158000 0x0 0x100>;
++		interrupts = <GIC_SPI 16 IRQ_TYPE_LEVEL_HIGH>;
++		clocks = <&cru SCLK_UART1>, <&cru PCLK_UART1>;
++		clock-names = "baudclk", "apb_pclk";
++		dmas = <&dmac 2>, <&dmac 3>;
++		dma-names = "tx", "rx";
++		reg-shift = <2>;
++		reg-io-width = <4>;
++		pinctrl-names = "default";
++		pinctrl-0 = <&uart1_xfer &uart1_cts &uart1_rts>;
++		status = "disabled";
++	};
++
++	uart2: serial@ff160000 {
++		compatible = "rockchip,px30-uart", "snps,dw-apb-uart";
++		reg = <0x0 0xff160000 0x0 0x100>;
++		interrupts = <GIC_SPI 17 IRQ_TYPE_LEVEL_HIGH>;
++		clocks = <&cru SCLK_UART2>, <&cru PCLK_UART2>;
++		clock-names = "baudclk", "apb_pclk";
++		dmas = <&dmac 4>, <&dmac 5>;
++		dma-names = "tx", "rx";
++		reg-shift = <2>;
++		reg-io-width = <4>;
++		pinctrl-names = "default";
++		pinctrl-0 = <&uart2m0_xfer>;
++		status = "disabled";
++	};
++
++	uart3: serial@ff168000 {
++		compatible = "rockchip,px30-uart", "snps,dw-apb-uart";
++		reg = <0x0 0xff168000 0x0 0x100>;
++		interrupts = <GIC_SPI 18 IRQ_TYPE_LEVEL_HIGH>;
++		clocks = <&cru SCLK_UART3>, <&cru PCLK_UART3>;
++		clock-names = "baudclk", "apb_pclk";
++		dmas = <&dmac 6>, <&dmac 7>;
++		dma-names = "tx", "rx";
++		reg-shift = <2>;
++		reg-io-width = <4>;
++		pinctrl-names = "default";
++		pinctrl-0 = <&uart3m1_xfer &uart3m1_cts &uart3m1_rts>;
++		status = "disabled";
++	};
++
++	uart4: serial@ff170000 {
++		compatible = "rockchip,px30-uart", "snps,dw-apb-uart";
++		reg = <0x0 0xff170000 0x0 0x100>;
++		interrupts = <GIC_SPI 19 IRQ_TYPE_LEVEL_HIGH>;
++		clocks = <&cru SCLK_UART4>, <&cru PCLK_UART4>;
++		clock-names = "baudclk", "apb_pclk";
++		dmas = <&dmac 8>, <&dmac 9>;
++		dma-names = "tx", "rx";
++		reg-shift = <2>;
++		reg-io-width = <4>;
++		pinctrl-names = "default";
++		pinctrl-0 = <&uart4_xfer &uart4_cts &uart4_rts>;
++		status = "disabled";
++	};
++
++	uart5: serial@ff178000 {
++		compatible = "rockchip,px30-uart", "snps,dw-apb-uart";
++		reg = <0x0 0xff178000 0x0 0x100>;
++		interrupts = <GIC_SPI 20 IRQ_TYPE_LEVEL_HIGH>;
++		clocks = <&cru SCLK_UART5>, <&cru PCLK_UART5>;
++		clock-names = "baudclk", "apb_pclk";
++		dmas = <&dmac 10>, <&dmac 11>;
++		dma-names = "tx", "rx";
++		reg-shift = <2>;
++		reg-io-width = <4>;
++		pinctrl-names = "default";
++		pinctrl-0 = <&uart5_xfer &uart5_cts &uart5_rts>;
++		status = "disabled";
++	};
++
++	i2c0: i2c@ff180000 {
++		compatible = "rockchip,px30-i2c", "rockchip,rk3399-i2c";
++		reg = <0x0 0xff180000 0x0 0x1000>;
++		clocks =  <&cru SCLK_I2C0>, <&cru PCLK_I2C0>;
++		clock-names = "i2c", "pclk";
++		interrupts = <GIC_SPI 7 IRQ_TYPE_LEVEL_HIGH>;
++		pinctrl-names = "default";
++		pinctrl-0 = <&i2c0_xfer>;
++		#address-cells = <1>;
++		#size-cells = <0>;
++		status = "disabled";
++	};
++
++	i2c1: i2c@ff190000 {
++		compatible = "rockchip,px30-i2c", "rockchip,rk3399-i2c";
++		reg = <0x0 0xff190000 0x0 0x1000>;
++		clocks = <&cru SCLK_I2C1>, <&cru PCLK_I2C1>;
++		clock-names = "i2c", "pclk";
++		interrupts = <GIC_SPI 8 IRQ_TYPE_LEVEL_HIGH>;
++		pinctrl-names = "default";
++		pinctrl-0 = <&i2c1_xfer>;
++		#address-cells = <1>;
++		#size-cells = <0>;
++		status = "disabled";
++	};
++
++	i2c2: i2c@ff1a0000 {
++		compatible = "rockchip,px30-i2c", "rockchip,rk3399-i2c";
++		reg = <0x0 0xff1a0000 0x0 0x1000>;
++		clocks = <&cru SCLK_I2C2>, <&cru PCLK_I2C2>;
++		clock-names = "i2c", "pclk";
++		interrupts = <GIC_SPI 9 IRQ_TYPE_LEVEL_HIGH>;
++		pinctrl-names = "default";
++		pinctrl-0 = <&i2c2_xfer>;
++		#address-cells = <1>;
++		#size-cells = <0>;
++		status = "disabled";
++	};
++
++	i2c3: i2c@ff1b0000 {
++		compatible = "rockchip,px30-i2c", "rockchip,rk3399-i2c";
++		reg = <0x0 0xff1b0000 0x0 0x1000>;
++		clocks = <&cru SCLK_I2C3>, <&cru PCLK_I2C3>;
++		clock-names = "i2c", "pclk";
++		interrupts = <GIC_SPI 10 IRQ_TYPE_LEVEL_HIGH>;
++		pinctrl-names = "default";
++		pinctrl-0 = <&i2c3_xfer>;
++		#address-cells = <1>;
++		#size-cells = <0>;
++		status = "disabled";
++	};
++
++	spi0: spi@ff1d0000 {
++		compatible = "rockchip,px30-spi", "rockchip,rk3066-spi";
++		reg = <0x0 0xff1d0000 0x0 0x1000>;
++		interrupts = <GIC_SPI 26 IRQ_TYPE_LEVEL_HIGH>;
++		clocks = <&cru SCLK_SPI0>, <&cru PCLK_SPI0>;
++		clock-names = "spiclk", "apb_pclk";
++		dmas = <&dmac 12>, <&dmac 13>;
++		dma-names = "tx", "rx";
++		pinctrl-names = "default";
++		pinctrl-0 = <&spi0_clk &spi0_csn &spi0_miso &spi0_mosi>;
++		#address-cells = <1>;
++		#size-cells = <0>;
++		status = "disabled";
++	};
++
++	spi1: spi@ff1d8000 {
++		compatible = "rockchip,px30-spi", "rockchip,rk3066-spi";
++		reg = <0x0 0xff1d8000 0x0 0x1000>;
++		interrupts = <GIC_SPI 27 IRQ_TYPE_LEVEL_HIGH>;
++		clocks = <&cru SCLK_SPI1>, <&cru PCLK_SPI1>;
++		clock-names = "spiclk", "apb_pclk";
++		dmas = <&dmac 14>, <&dmac 15>;
++		dma-names = "tx", "rx";
++		pinctrl-names = "default";
++		pinctrl-0 = <&spi1_clk &spi1_csn0 &spi1_csn1 &spi1_miso &spi1_mosi>;
++		#address-cells = <1>;
++		#size-cells = <0>;
++		status = "disabled";
++	};
++
++	wdt: watchdog@ff1e0000 {
++		compatible = "snps,dw-wdt";
++		reg = <0x0 0xff1e0000 0x0 0x100>;
++		clocks = <&cru PCLK_WDT_NS>;
++		interrupts = <GIC_SPI 37 IRQ_TYPE_LEVEL_HIGH>;
++		status = "disabled";
++	};
++
++	pwm0: pwm@ff200000 {
++		compatible = "rockchip,px30-pwm", "rockchip,rk3328-pwm";
++		reg = <0x0 0xff200000 0x0 0x10>;
++		clocks = <&cru SCLK_PWM0>, <&cru PCLK_PWM0>;
++		clock-names = "pwm", "pclk";
++		pinctrl-names = "default";
++		pinctrl-0 = <&pwm0_pin>;
++		#pwm-cells = <3>;
++		status = "disabled";
++	};
++
++	pwm1: pwm@ff200010 {
++		compatible = "rockchip,px30-pwm", "rockchip,rk3328-pwm";
++		reg = <0x0 0xff200010 0x0 0x10>;
++		clocks = <&cru SCLK_PWM0>, <&cru PCLK_PWM0>;
++		clock-names = "pwm", "pclk";
++		pinctrl-names = "default";
++		pinctrl-0 = <&pwm1_pin>;
++		#pwm-cells = <3>;
++		status = "disabled";
++	};
++
++	pwm2: pwm@ff200020 {
++		compatible = "rockchip,px30-pwm", "rockchip,rk3328-pwm";
++		reg = <0x0 0xff200020 0x0 0x10>;
++		clocks = <&cru SCLK_PWM0>, <&cru PCLK_PWM0>;
++		clock-names = "pwm", "pclk";
++		pinctrl-names = "default";
++		pinctrl-0 = <&pwm2_pin>;
++		#pwm-cells = <3>;
++		status = "disabled";
++	};
++
++	pwm3: pwm@ff200030 {
++		compatible = "rockchip,px30-pwm", "rockchip,rk3328-pwm";
++		reg = <0x0 0xff200030 0x0 0x10>;
++		clocks = <&cru SCLK_PWM0>, <&cru PCLK_PWM0>;
++		clock-names = "pwm", "pclk";
++		pinctrl-names = "default";
++		pinctrl-0 = <&pwm3_pin>;
++		#pwm-cells = <3>;
++		status = "disabled";
++	};
++
++	pwm4: pwm@ff208000 {
++		compatible = "rockchip,px30-pwm", "rockchip,rk3328-pwm";
++		reg = <0x0 0xff208000 0x0 0x10>;
++		clocks = <&cru SCLK_PWM1>, <&cru PCLK_PWM1>;
++		clock-names = "pwm", "pclk";
++		pinctrl-names = "default";
++		pinctrl-0 = <&pwm4_pin>;
++		#pwm-cells = <3>;
++		status = "disabled";
++	};
++
++	pwm5: pwm@ff208010 {
++		compatible = "rockchip,px30-pwm", "rockchip,rk3328-pwm";
++		reg = <0x0 0xff208010 0x0 0x10>;
++		clocks = <&cru SCLK_PWM1>, <&cru PCLK_PWM1>;
++		clock-names = "pwm", "pclk";
++		pinctrl-names = "default";
++		pinctrl-0 = <&pwm5_pin>;
++		#pwm-cells = <3>;
++		status = "disabled";
++	};
++
++	pwm6: pwm@ff208020 {
++		compatible = "rockchip,px30-pwm", "rockchip,rk3328-pwm";
++		reg = <0x0 0xff208020 0x0 0x10>;
++		clocks = <&cru SCLK_PWM1>, <&cru PCLK_PWM1>;
++		clock-names = "pwm", "pclk";
++		pinctrl-names = "default";
++		pinctrl-0 = <&pwm6_pin>;
++		#pwm-cells = <3>;
++		status = "disabled";
++	};
++
++	pwm7: pwm@ff208030 {
++		compatible = "rockchip,px30-pwm", "rockchip,rk3328-pwm";
++		reg = <0x0 0xff208030 0x0 0x10>;
++		clocks = <&cru SCLK_PWM1>, <&cru PCLK_PWM1>;
++		clock-names = "pwm", "pclk";
++		pinctrl-names = "default";
++		pinctrl-0 = <&pwm7_pin>;
++		#pwm-cells = <3>;
++		status = "disabled";
++	};
++
++	rktimer: timer@ff210000 {
++		compatible = "rockchip,px30-timer", "rockchip,rk3288-timer";
++		reg = <0x0 0xff210000 0x0 0x1000>;
++		interrupts = <GIC_SPI 30 IRQ_TYPE_LEVEL_HIGH>;
++		clocks = <&cru PCLK_TIMER>, <&cru SCLK_TIMER0>;
++		clock-names = "pclk", "timer";
++	};
++
++	amba {
++		compatible = "simple-bus";
++		#address-cells = <2>;
++		#size-cells = <2>;
++		ranges;
++
++		dmac: dmac@ff240000 {
++			compatible = "arm,pl330", "arm,primecell";
++			reg = <0x0 0xff240000 0x0 0x4000>;
++			interrupts = <GIC_SPI 1 IRQ_TYPE_LEVEL_HIGH>,
++				     <GIC_SPI 2 IRQ_TYPE_LEVEL_HIGH>;
++			clocks = <&cru ACLK_DMAC>;
++			clock-names = "apb_pclk";
++			#dma-cells = <1>;
++		};
++	};
++
++	saradc: saradc@ff288000 {
++		compatible = "rockchip,px30-saradc", "rockchip,rk3399-saradc";
++		reg = <0x0 0xff288000 0x0 0x100>;
++		interrupts = <GIC_SPI 84 IRQ_TYPE_LEVEL_HIGH>;
++		#io-channel-cells = <1>;
++		clocks = <&cru SCLK_SARADC>, <&cru PCLK_SARADC>;
++		clock-names = "saradc", "apb_pclk";
++		resets = <&cru SRST_SARADC_P>;
++		reset-names = "saradc-apb";
++		status = "disabled";
++	};
++
++	otp: nvmem@ff290000 {
++		compatible = "rockchip,px30-otp";
++		reg = <0x0 0xff290000 0x0 0x4000>;
++		clocks = <&cru SCLK_OTP_USR>, <&cru PCLK_OTP_NS>,
++			 <&cru PCLK_OTP_PHY>;
++		clock-names = "otp", "apb_pclk", "phy";
++		resets = <&cru SRST_OTP_PHY>;
++		reset-names = "phy";
++		#address-cells = <1>;
++		#size-cells = <1>;
++
++		/* Data cells */
++		cpu_id: id@7 {
++			reg = <0x07 0x10>;
++		};
++		cpu_leakage: cpu-leakage@17 {
++			reg = <0x17 0x1>;
++		};
++		performance: performance@1e {
++			reg = <0x1e 0x1>;
++			bits = <4 3>;
++		};
++	};
++
++	cru: clock-controller@ff2b0000 {
++		compatible = "rockchip,px30-cru";
++		reg = <0x0 0xff2b0000 0x0 0x1000>;
++		clocks = <&xin24m>, <&pmucru PLL_GPLL>;
++		clock-names = "xin24m", "gpll";
++		rockchip,grf = <&grf>;
++		#clock-cells = <1>;
++		#reset-cells = <1>;
++	};
++
++	pmucru: clock-controller@ff2bc000 {
++		compatible = "rockchip,px30-pmucru";
++		reg = <0x0 0xff2bc000 0x0 0x1000>;
++		clocks = <&xin24m>;
++		clock-names = "xin24m";
++		rockchip,grf = <&grf>;
++		#clock-cells = <1>;
++		#reset-cells = <1>;
++	};
++
++	dsi_dphy: phy@ff2e0000 {
++		compatible = "rockchip,px30-dsi-dphy";
++		reg = <0x0 0xff2e0000 0x0 0x10000>;
++		clocks = <&pmucru SCLK_MIPIDSIPHY_REF>, <&cru PCLK_MIPIDSIPHY>;
++		clock-names = "ref", "pclk";
++		#clock-cells = <0>;
++		resets = <&cru SRST_MIPIDSIPHY_P>;
++		reset-names = "apb";
++		#phy-cells = <0>;
++		power-domains = <&power PX30_PD_VO>;
++		status = "disabled";
++	};
++
++	usb20_otg: usb@ff300000 {
++		compatible = "rockchip,px30-usb", "rockchip,rk3066-usb",
++			     "snps,dwc2";
++		reg = <0x0 0xff300000 0x0 0x40000>;
++		interrupts = <GIC_SPI 62 IRQ_TYPE_LEVEL_HIGH>;
++		clocks = <&cru HCLK_OTG>;
++		clock-names = "otg";
++		dr_mode = "otg";
++		g-np-tx-fifo-size = <16>;
++		g-rx-fifo-size = <280>;
++		g-tx-fifo-size = <256 128 128 64 32 16>;
++		g-use-dma;
++		power-domains = <&power PX30_PD_USB>;
++		status = "disabled";
++	};
++
++	usb_host0_ehci: usb@ff340000 {
++		compatible = "generic-ehci";
++		reg = <0x0 0xff340000 0x0 0x10000>;
++		interrupts = <GIC_SPI 60 IRQ_TYPE_LEVEL_HIGH>;
++		clocks = <&cru HCLK_HOST>;
++		clock-names = "usbhost";
++		power-domains = <&power PX30_PD_USB>;
++		status = "disabled";
++	};
++
++	usb_host0_ohci: usb@ff350000 {
++		compatible = "generic-ohci";
++		reg = <0x0 0xff350000 0x0 0x10000>;
++		interrupts = <GIC_SPI 61 IRQ_TYPE_LEVEL_HIGH>;
++		clocks = <&cru HCLK_HOST>;
++		clock-names = "usbhost";
++		power-domains = <&power PX30_PD_USB>;
++		status = "disabled";
++	};
++
++	gmac: ethernet@ff360000 {
++		compatible = "rockchip,px30-gmac";
++		reg = <0x0 0xff360000 0x0 0x10000>;
++		interrupts = <GIC_SPI 43 IRQ_TYPE_LEVEL_HIGH>;
++		interrupt-names = "macirq";
++		clocks = <&cru SCLK_GMAC>, <&cru SCLK_GMAC_RX_TX>,
++			 <&cru SCLK_GMAC_RX_TX>, <&cru SCLK_MAC_REF>,
++			 <&cru SCLK_MAC_REFOUT>, <&cru ACLK_GMAC>,
++			 <&cru PCLK_GMAC>, <&cru SCLK_GMAC_RMII>;
++		clock-names = "stmmaceth", "mac_clk_rx",
++			      "mac_clk_tx", "clk_mac_ref",
++			      "clk_mac_refout", "aclk_mac",
++			      "pclk_mac", "clk_mac_speed";
++		rockchip,grf = <&grf>;
++		phy-mode = "rmii";
++		pinctrl-names = "default";
++		pinctrl-0 = <&rmii_pins &mac_refclk_12ma>;
++		power-domains = <&power PX30_PD_GMAC>;
++		resets = <&cru SRST_GMAC_A>;
++		reset-names = "stmmaceth";
++		status = "disabled";
++	};
++
++	sdmmc: dwmmc@ff370000 {
++		compatible = "rockchip,px30-dw-mshc", "rockchip,rk3288-dw-mshc";
++		reg = <0x0 0xff370000 0x0 0x4000>;
++		interrupts = <GIC_SPI 54 IRQ_TYPE_LEVEL_HIGH>;
++		clocks = <&cru HCLK_SDMMC>, <&cru SCLK_SDMMC>,
++			 <&cru SCLK_SDMMC_DRV>, <&cru SCLK_SDMMC_SAMPLE>;
++		clock-names = "biu", "ciu", "ciu-drv", "ciu-sample";
++		fifo-depth = <0x100>;
++		max-frequency = <150000000>;
++		pinctrl-names = "default";
++		pinctrl-0 = <&sdmmc_clk &sdmmc_cmd &sdmmc_det &sdmmc_bus4>;
++		power-domains = <&power PX30_PD_SDCARD>;
++		status = "disabled";
++	};
++
++	sdio: dwmmc@ff380000 {
++		compatible = "rockchip,px30-dw-mshc", "rockchip,rk3288-dw-mshc";
++		reg = <0x0 0xff380000 0x0 0x4000>;
++		interrupts = <GIC_SPI 55 IRQ_TYPE_LEVEL_HIGH>;
++		clocks = <&cru HCLK_SDIO>, <&cru SCLK_SDIO>,
++			 <&cru SCLK_SDIO_DRV>, <&cru SCLK_SDIO_SAMPLE>;
++		clock-names = "biu", "ciu", "ciu-drv", "ciu-sample";
++		fifo-depth = <0x100>;
++		max-frequency = <150000000>;
++		pinctrl-names = "default";
++		pinctrl-0 = <&sdio_bus4 &sdio_cmd &sdio_clk>;
++		power-domains = <&power PX30_PD_MMC_NAND>;
++		status = "disabled";
++	};
++
++	emmc: dwmmc@ff390000 {
++		compatible = "rockchip,px30-dw-mshc", "rockchip,rk3288-dw-mshc";
++		reg = <0x0 0xff390000 0x0 0x4000>;
++		interrupts = <GIC_SPI 53 IRQ_TYPE_LEVEL_HIGH>;
++		clocks = <&cru HCLK_EMMC>, <&cru SCLK_EMMC>,
++			 <&cru SCLK_EMMC_DRV>, <&cru SCLK_EMMC_SAMPLE>;
++		clock-names = "biu", "ciu", "ciu-drv", "ciu-sample";
++		fifo-depth = <0x100>;
++		max-frequency = <150000000>;
++		pinctrl-names = "default";
++		pinctrl-0 = <&emmc_clk &emmc_cmd &emmc_bus8>;
++		power-domains = <&power PX30_PD_MMC_NAND>;
++		status = "disabled";
++	};
++
++	dsi: dsi@ff450000 {
++		compatible = "rockchip,px30-mipi-dsi";
++		reg = <0x0 0xff450000 0x0 0x10000>;
++		interrupts = <GIC_SPI 75 IRQ_TYPE_LEVEL_HIGH>;
++		clocks = <&cru PCLK_MIPI_DSI>, <&dsi_dphy>;
++		clock-names = "pclk", "pll";
++		resets = <&cru SRST_MIPIDSI_HOST_P>;
++		reset-names = "apb";
++		phys = <&dsi_dphy>;
++		phy-names = "dphy";
++		power-domains = <&power PX30_PD_VO>;
++		rockchip,grf = <&grf>;
++		#address-cells = <1>;
++		#size-cells = <0>;
++		status = "disabled";
++
++		ports {
++			#address-cells = <1>;
++			#size-cells = <0>;
++
++			port@0 {
++				reg = <0>;
++				#address-cells = <1>;
++				#size-cells = <0>;
++
++				dsi_in_vopb: endpoint@0 {
++					reg = <0>;
++					remote-endpoint = <&vopb_out_dsi>;
++				};
++
++				dsi_in_vopl: endpoint@1 {
++					reg = <1>;
++					remote-endpoint = <&vopl_out_dsi>;
++				};
++			};
++		};
++	};
++
++	vopb: vop@ff460000 {
++		compatible = "rockchip,px30-vop-big";
++		reg = <0x0 0xff460000 0x0 0xefc>;
++		interrupts = <GIC_SPI 77 IRQ_TYPE_LEVEL_HIGH>;
++		clocks = <&cru ACLK_VOPB>, <&cru DCLK_VOPB>,
++			 <&cru HCLK_VOPB>;
++		clock-names = "aclk_vop", "dclk_vop", "hclk_vop";
++		resets = <&cru SRST_VOPB_A>, <&cru SRST_VOPB_H>, <&cru SRST_VOPB>;
++		reset-names = "axi", "ahb", "dclk";
++		iommus = <&vopb_mmu>;
++		power-domains = <&power PX30_PD_VO>;
++		rockchip,grf = <&grf>;
++		status = "disabled";
++
++		vopb_out: port {
++			#address-cells = <1>;
++			#size-cells = <0>;
++
++			vopb_out_dsi: endpoint@0 {
++				reg = <0>;
++				remote-endpoint = <&dsi_in_vopb>;
++			};
++		};
++	};
++
++	vopb_mmu: iommu@ff460f00 {
++		compatible = "rockchip,iommu";
++		reg = <0x0 0xff460f00 0x0 0x100>;
++		interrupts = <GIC_SPI 77 IRQ_TYPE_LEVEL_HIGH>;
++		interrupt-names = "vopb_mmu";
++		clocks = <&cru ACLK_VOPB>, <&cru HCLK_VOPB>;
++		clock-names = "aclk", "iface";
++		power-domains = <&power PX30_PD_VO>;
++		#iommu-cells = <0>;
++		status = "disabled";
++	};
++
++	vopl: vop@ff470000 {
++		compatible = "rockchip,px30-vop-lit";
++		reg = <0x0 0xff470000 0x0 0xefc>;
++		interrupts = <GIC_SPI 78 IRQ_TYPE_LEVEL_HIGH>;
++		clocks = <&cru ACLK_VOPL>, <&cru DCLK_VOPL>,
++			 <&cru HCLK_VOPL>;
++		clock-names = "aclk_vop", "dclk_vop", "hclk_vop";
++		resets = <&cru SRST_VOPL_A>, <&cru SRST_VOPL_H>, <&cru SRST_VOPL>;
++		reset-names = "axi", "ahb", "dclk";
++		iommus = <&vopl_mmu>;
++		power-domains = <&power PX30_PD_VO>;
++		rockchip,grf = <&grf>;
++		status = "disabled";
++
++		vopl_out: port {
++			#address-cells = <1>;
++			#size-cells = <0>;
++
++			vopl_out_dsi: endpoint@0 {
++				reg = <0>;
++				remote-endpoint = <&dsi_in_vopl>;
++			};
++		};
++	};
++
++	vopl_mmu: iommu@ff470f00 {
++		compatible = "rockchip,iommu";
++		reg = <0x0 0xff470f00 0x0 0x100>;
++		interrupts = <GIC_SPI 79 IRQ_TYPE_LEVEL_HIGH>;
++		interrupt-names = "vopl_mmu";
++		clocks = <&cru ACLK_VOPL>, <&cru HCLK_VOPL>;
++		clock-names = "aclk", "iface";
++		power-domains = <&power PX30_PD_VO>;
++		#iommu-cells = <0>;
++		status = "disabled";
++	};
++
++	qos_gmac: qos@ff518000 {
++		compatible = "syscon";
++		reg = <0x0 0xff518000 0x0 0x20>;
++	};
++
++	qos_gpu: qos@ff520000 {
++		compatible = "syscon";
++		reg = <0x0 0xff520000 0x0 0x20>;
++	};
++
++	qos_sdmmc: qos@ff52c000 {
++		compatible = "syscon";
++		reg = <0x0 0xff52c000 0x0 0x20>;
++	};
++
++	qos_emmc: qos@ff538000 {
++		compatible = "syscon";
++		reg = <0x0 0xff538000 0x0 0x20>;
++	};
++
++	qos_nand: qos@ff538080 {
++		compatible = "syscon";
++		reg = <0x0 0xff538080 0x0 0x20>;
++	};
++
++	qos_sdio: qos@ff538100 {
++		compatible = "syscon";
++		reg = <0x0 0xff538100 0x0 0x20>;
++	};
++
++	qos_sfc: qos@ff538180 {
++		compatible = "syscon";
++		reg = <0x0 0xff538180 0x0 0x20>;
++	};
++
++	qos_usb_host: qos@ff540000 {
++		compatible = "syscon";
++		reg = <0x0 0xff540000 0x0 0x20>;
++	};
++
++	qos_usb_otg: qos@ff540080 {
++		compatible = "syscon";
++		reg = <0x0 0xff540080 0x0 0x20>;
++	};
++
++	qos_isp_128: qos@ff548000 {
++		compatible = "syscon";
++		reg = <0x0 0xff548000 0x0 0x20>;
++	};
++
++	qos_isp_rd: qos@ff548080 {
++		compatible = "syscon";
++		reg = <0x0 0xff548080 0x0 0x20>;
++	};
++
++	qos_isp_wr: qos@ff548100 {
++		compatible = "syscon";
++		reg = <0x0 0xff548100 0x0 0x20>;
++	};
++
++	qos_isp_m1: qos@ff548180 {
++		compatible = "syscon";
++		reg = <0x0 0xff548180 0x0 0x20>;
++	};
++
++	qos_vip: qos@ff548200 {
++		compatible = "syscon";
++		reg = <0x0 0xff548200 0x0 0x20>;
++	};
++
++	qos_rga_rd: qos@ff550000 {
++		compatible = "syscon";
++		reg = <0x0 0xff550000 0x0 0x20>;
++	};
++
++	qos_rga_wr: qos@ff550080 {
++		compatible = "syscon";
++		reg = <0x0 0xff550080 0x0 0x20>;
++	};
++
++	qos_vop_m0: qos@ff550100 {
++		compatible = "syscon";
++		reg = <0x0 0xff550100 0x0 0x20>;
++	};
++
++	qos_vop_m1: qos@ff550180 {
++		compatible = "syscon";
++		reg = <0x0 0xff550180 0x0 0x20>;
++	};
++
++	qos_vpu: qos@ff558000 {
++		compatible = "syscon";
++		reg = <0x0 0xff558000 0x0 0x20>;
++	};
++
++	qos_vpu_r128: qos@ff558080 {
++		compatible = "syscon";
++		reg = <0x0 0xff558080 0x0 0x20>;
++	};
++
++	pinctrl: pinctrl {
++		compatible = "rockchip,px30-pinctrl";
++		rockchip,grf = <&grf>;
++		rockchip,pmu = <&pmugrf>;
++		#address-cells = <2>;
++		#size-cells = <2>;
++		ranges;
++
++		gpio0: gpio0@ff040000 {
++			compatible = "rockchip,gpio-bank";
++			reg = <0x0 0xff040000 0x0 0x100>;
++			interrupts = <GIC_SPI 3 IRQ_TYPE_LEVEL_HIGH>;
++			clocks = <&pmucru PCLK_GPIO0_PMU>;
++			gpio-controller;
++			#gpio-cells = <2>;
++
++			interrupt-controller;
++			#interrupt-cells = <2>;
++		};
++
++		gpio1: gpio1@ff250000 {
++			compatible = "rockchip,gpio-bank";
++			reg = <0x0 0xff250000 0x0 0x100>;
++			interrupts = <GIC_SPI 4 IRQ_TYPE_LEVEL_HIGH>;
++			clocks = <&cru PCLK_GPIO1>;
++			gpio-controller;
++			#gpio-cells = <2>;
++
++			interrupt-controller;
++			#interrupt-cells = <2>;
++		};
++
++		gpio2: gpio2@ff260000 {
++			compatible = "rockchip,gpio-bank";
++			reg = <0x0 0xff260000 0x0 0x100>;
++			interrupts = <GIC_SPI 5 IRQ_TYPE_LEVEL_HIGH>;
++			clocks = <&cru PCLK_GPIO2>;
++			gpio-controller;
++			#gpio-cells = <2>;
++
++			interrupt-controller;
++			#interrupt-cells = <2>;
++		};
++
++		gpio3: gpio3@ff270000 {
++			compatible = "rockchip,gpio-bank";
++			reg = <0x0 0xff270000 0x0 0x100>;
++			interrupts = <GIC_SPI 6 IRQ_TYPE_LEVEL_HIGH>;
++			clocks = <&cru PCLK_GPIO3>;
++			gpio-controller;
++			#gpio-cells = <2>;
++
++			interrupt-controller;
++			#interrupt-cells = <2>;
++		};
++
++		pcfg_pull_up: pcfg-pull-up {
++			bias-pull-up;
++		};
++
++		pcfg_pull_down: pcfg-pull-down {
++			bias-pull-down;
++		};
++
++		pcfg_pull_none: pcfg-pull-none {
++			bias-disable;
++		};
++
++		pcfg_pull_none_2ma: pcfg-pull-none-2ma {
++			bias-disable;
++			drive-strength = <2>;
++		};
++
++		pcfg_pull_up_2ma: pcfg-pull-up-2ma {
++			bias-pull-up;
++			drive-strength = <2>;
++		};
++
++		pcfg_pull_up_4ma: pcfg-pull-up-4ma {
++			bias-pull-up;
++			drive-strength = <4>;
++		};
++
++		pcfg_pull_none_4ma: pcfg-pull-none-4ma {
++			bias-disable;
++			drive-strength = <4>;
++		};
++
++		pcfg_pull_down_4ma: pcfg-pull-down-4ma {
++			bias-pull-down;
++			drive-strength = <4>;
++		};
++
++		pcfg_pull_none_8ma: pcfg-pull-none-8ma {
++			bias-disable;
++			drive-strength = <8>;
++		};
++
++		pcfg_pull_up_8ma: pcfg-pull-up-8ma {
++			bias-pull-up;
++			drive-strength = <8>;
++		};
++
++		pcfg_pull_none_12ma: pcfg-pull-none-12ma {
++			bias-disable;
++			drive-strength = <12>;
++		};
++
++		pcfg_pull_up_12ma: pcfg-pull-up-12ma {
++			bias-pull-up;
++			drive-strength = <12>;
++		};
++
++		pcfg_pull_none_smt: pcfg-pull-none-smt {
++			bias-disable;
++			input-schmitt-enable;
++		};
++
++		pcfg_output_high: pcfg-output-high {
++			output-high;
++		};
++
++		pcfg_output_low: pcfg-output-low {
++			output-low;
++		};
++
++		pcfg_input_high: pcfg-input-high {
++			bias-pull-up;
++			input-enable;
++		};
++
++		pcfg_input: pcfg-input {
++			input-enable;
++		};
++
++		i2c0 {
++			i2c0_xfer: i2c0-xfer {
++				rockchip,pins =
++					<0 RK_PB0 1 &pcfg_pull_none_smt>,
++					<0 RK_PB1 1 &pcfg_pull_none_smt>;
++			};
++		};
++
++		i2c1 {
++			i2c1_xfer: i2c1-xfer {
++				rockchip,pins =
++					<0 RK_PC2 1 &pcfg_pull_none_smt>,
++					<0 RK_PC3 1 &pcfg_pull_none_smt>;
++			};
++		};
++
++		i2c2 {
++			i2c2_xfer: i2c2-xfer {
++				rockchip,pins =
++					<2 RK_PB7 2 &pcfg_pull_none_smt>,
++					<2 RK_PC0 2 &pcfg_pull_none_smt>;
++			};
++		};
++
++		i2c3 {
++			i2c3_xfer: i2c3-xfer {
++				rockchip,pins =
++					<1 RK_PB4 4 &pcfg_pull_none_smt>,
++					<1 RK_PB5 4 &pcfg_pull_none_smt>;
++			};
++		};
++
++		tsadc {
++			tsadc_otp_gpio: tsadc-otp-gpio {
++				rockchip,pins =
++					<0 RK_PA6 RK_FUNC_GPIO &pcfg_pull_none>;
++			};
++
++			tsadc_otp_out: tsadc-otp-out {
++				rockchip,pins =
++					<0 RK_PA6 1 &pcfg_pull_none>;
++			};
++		};
++
++		uart0 {
++			uart0_xfer: uart0-xfer {
++				rockchip,pins =
++					<0 RK_PB2 1 &pcfg_pull_up>,
++					<0 RK_PB3 1 &pcfg_pull_up>;
++			};
++
++			uart0_cts: uart0-cts {
++				rockchip,pins =
++					<0 RK_PB4 1 &pcfg_pull_none>;
++			};
++
++			uart0_rts: uart0-rts {
++				rockchip,pins =
++					<0 RK_PB5 1 &pcfg_pull_none>;
++			};
++		};
++
++		uart1 {
++			uart1_xfer: uart1-xfer {
++				rockchip,pins =
++					<1 RK_PC1 1 &pcfg_pull_up>,
++					<1 RK_PC0 1 &pcfg_pull_up>;
++			};
++
++			uart1_cts: uart1-cts {
++				rockchip,pins =
++					<1 RK_PC2 1 &pcfg_pull_none>;
++			};
++
++			uart1_rts: uart1-rts {
++				rockchip,pins =
++					<1 RK_PC3 1 &pcfg_pull_none>;
++			};
++		};
++
++		uart2-m0 {
++			uart2m0_xfer: uart2m0-xfer {
++				rockchip,pins =
++					<1 RK_PD2 2 &pcfg_pull_up>,
++					<1 RK_PD3 2 &pcfg_pull_up>;
++			};
++		};
++
++		uart2-m1 {
++			uart2m1_xfer: uart2m1-xfer {
++				rockchip,pins =
++					<2 RK_PB4 2 &pcfg_pull_up>,
++					<2 RK_PB6 2 &pcfg_pull_up>;
++			};
++		};
++
++		uart3-m0 {
++			uart3m0_xfer: uart3m0-xfer {
++				rockchip,pins =
++					<0 RK_PC0 2 &pcfg_pull_up>,
++					<0 RK_PC1 2 &pcfg_pull_up>;
++			};
++
++			uart3m0_cts: uart3m0-cts {
++				rockchip,pins =
++					<0 RK_PC2 2 &pcfg_pull_none>;
++			};
++
++			uart3m0_rts: uart3m0-rts {
++				rockchip,pins =
++					<0 RK_PC3 2 &pcfg_pull_none>;
++			};
++		};
++
++		uart3-m1 {
++			uart3m1_xfer: uart3m1-xfer {
++				rockchip,pins =
++					<1 RK_PB6 2 &pcfg_pull_up>,
++					<1 RK_PB7 2 &pcfg_pull_up>;
++			};
++
++			uart3m1_cts: uart3m1-cts {
++				rockchip,pins =
++					<1 RK_PB4 2 &pcfg_pull_none>;
++			};
++
++			uart3m1_rts: uart3m1-rts {
++				rockchip,pins =
++					<1 RK_PB5 2 &pcfg_pull_none>;
++			};
++		};
++
++		uart4 {
++			uart4_xfer: uart4-xfer {
++				rockchip,pins =
++					<1 RK_PD4 2 &pcfg_pull_up>,
++					<1 RK_PD5 2 &pcfg_pull_up>;
++			};
++
++			uart4_cts: uart4-cts {
++				rockchip,pins =
++					<1 RK_PD6 2 &pcfg_pull_none>;
++			};
++
++			uart4_rts: uart4-rts {
++				rockchip,pins =
++					<1 RK_PD7 2 &pcfg_pull_none>;
++			};
++		};
++
++		uart5 {
++			uart5_xfer: uart5-xfer {
++				rockchip,pins =
++					<3 RK_PA2 4 &pcfg_pull_up>,
++					<3 RK_PA1 4 &pcfg_pull_up>;
++			};
++
++			uart5_cts: uart5-cts {
++				rockchip,pins =
++					<3 RK_PA3 4 &pcfg_pull_none>;
++			};
++
++			uart5_rts: uart5-rts {
++				rockchip,pins =
++					<3 RK_PA5 4 &pcfg_pull_none>;
++			};
++		};
++
++		spi0 {
++			spi0_clk: spi0-clk {
++				rockchip,pins =
++					<1 RK_PB7 3 &pcfg_pull_up_4ma>;
++			};
++
++			spi0_csn: spi0-csn {
++				rockchip,pins =
++					<1 RK_PB6 3 &pcfg_pull_up_4ma>;
++			};
++
++			spi0_miso: spi0-miso {
++				rockchip,pins =
++					<1 RK_PB5 3 &pcfg_pull_up_4ma>;
++			};
++
++			spi0_mosi: spi0-mosi {
++				rockchip,pins =
++					<1 RK_PB4 3 &pcfg_pull_up_4ma>;
++			};
++
++			spi0_clk_hs: spi0-clk-hs {
++				rockchip,pins =
++					<1 RK_PB7 3 &pcfg_pull_up_8ma>;
++			};
++
++			spi0_miso_hs: spi0-miso-hs {
++				rockchip,pins =
++					<1 RK_PB5 3 &pcfg_pull_up_8ma>;
++			};
++
++			spi0_mosi_hs: spi0-mosi-hs {
++				rockchip,pins =
++					<1 RK_PB4 3 &pcfg_pull_up_8ma>;
++			};
++		};
++
++		spi1 {
++			spi1_clk: spi1-clk {
++				rockchip,pins =
++					<3 RK_PB7 4 &pcfg_pull_up_4ma>;
++			};
++
++			spi1_csn0: spi1-csn0 {
++				rockchip,pins =
++					<3 RK_PB1 4 &pcfg_pull_up_4ma>;
++			};
++
++			spi1_csn1: spi1-csn1 {
++				rockchip,pins =
++					<3 RK_PB2 2 &pcfg_pull_up_4ma>;
++			};
++
++			spi1_miso: spi1-miso {
++				rockchip,pins =
++					<3 RK_PB6 4 &pcfg_pull_up_4ma>;
++			};
++
++			spi1_mosi: spi1-mosi {
++				rockchip,pins =
++					<3 RK_PB4 4 &pcfg_pull_up_4ma>;
++			};
++
++			spi1_clk_hs: spi1-clk-hs {
++				rockchip,pins =
++					<3 RK_PB7 4 &pcfg_pull_up_8ma>;
++			};
++
++			spi1_miso_hs: spi1-miso-hs {
++				rockchip,pins =
++					<3 RK_PB6 4 &pcfg_pull_up_8ma>;
++			};
++
++			spi1_mosi_hs: spi1-mosi-hs {
++				rockchip,pins =
++					<3 RK_PB4 4 &pcfg_pull_up_8ma>;
++			};
++		};
++
++		pdm {
++			pdm_clk0m0: pdm-clk0m0 {
++				rockchip,pins =
++					<3 RK_PC6 2 &pcfg_pull_none>;
++			};
++
++			pdm_clk0m1: pdm-clk0m1 {
++				rockchip,pins =
++					<2 RK_PC6 1 &pcfg_pull_none>;
++			};
++
++			pdm_clk1: pdm-clk1 {
++				rockchip,pins =
++					<3 RK_PC7 2 &pcfg_pull_none>;
++			};
++
++			pdm_sdi0m0: pdm-sdi0m0 {
++				rockchip,pins =
++					<3 RK_PD3 2 &pcfg_pull_none>;
++			};
++
++			pdm_sdi0m1: pdm-sdi0m1 {
++				rockchip,pins =
++					<2 RK_PC5 2 &pcfg_pull_none>;
++			};
++
++			pdm_sdi1: pdm-sdi1 {
++				rockchip,pins =
++					<3 RK_PD0 2 &pcfg_pull_none>;
++			};
++
++			pdm_sdi2: pdm-sdi2 {
++				rockchip,pins =
++					<3 RK_PD1 2 &pcfg_pull_none>;
++			};
++
++			pdm_sdi3: pdm-sdi3 {
++				rockchip,pins =
++					<3 RK_PD2 2 &pcfg_pull_none>;
++			};
++
++			pdm_clk0m0_sleep: pdm-clk0m0-sleep {
++				rockchip,pins =
++					<3 RK_PC6 RK_FUNC_GPIO &pcfg_input_high>;
++			};
++
++			pdm_clk0m_sleep1: pdm-clk0m1-sleep {
++				rockchip,pins =
++					<2 RK_PC6 RK_FUNC_GPIO &pcfg_input_high>;
++			};
++
++			pdm_clk1_sleep: pdm-clk1-sleep {
++				rockchip,pins =
++					<3 RK_PC7 RK_FUNC_GPIO &pcfg_input_high>;
++			};
++
++			pdm_sdi0m0_sleep: pdm-sdi0m0-sleep {
++				rockchip,pins =
++					<3 RK_PD3 RK_FUNC_GPIO &pcfg_input_high>;
++			};
++
++			pdm_sdi0m1_sleep: pdm-sdi0m1-sleep {
++				rockchip,pins =
++					<2 RK_PC5 RK_FUNC_GPIO &pcfg_input_high>;
++			};
++
++			pdm_sdi1_sleep: pdm-sdi1-sleep {
++				rockchip,pins =
++					<3 RK_PD0 RK_FUNC_GPIO &pcfg_input_high>;
++			};
++
++			pdm_sdi2_sleep: pdm-sdi2-sleep {
++				rockchip,pins =
++					<3 RK_PD1 RK_FUNC_GPIO &pcfg_input_high>;
++			};
++
++			pdm_sdi3_sleep: pdm-sdi3-sleep {
++				rockchip,pins =
++					<3 RK_PD2 RK_FUNC_GPIO &pcfg_input_high>;
++			};
++		};
++
++		i2s0 {
++			i2s0_8ch_mclk: i2s0-8ch-mclk {
++				rockchip,pins =
++					<3 RK_PC1 2 &pcfg_pull_none>;
++			};
++
++			i2s0_8ch_sclktx: i2s0-8ch-sclktx {
++				rockchip,pins =
++					<3 RK_PC3 2 &pcfg_pull_none>;
++			};
++
++			i2s0_8ch_sclkrx: i2s0-8ch-sclkrx {
++				rockchip,pins =
++					<3 RK_PB4 2 &pcfg_pull_none>;
++			};
++
++			i2s0_8ch_lrcktx: i2s0-8ch-lrcktx {
++				rockchip,pins =
++					<3 RK_PC2 2 &pcfg_pull_none>;
++			};
++
++			i2s0_8ch_lrckrx: i2s0-8ch-lrckrx {
++				rockchip,pins =
++					<3 RK_PB5 2 &pcfg_pull_none>;
++			};
++
++			i2s0_8ch_sdo0: i2s0-8ch-sdo0 {
++				rockchip,pins =
++					<3 RK_PC4 2 &pcfg_pull_none>;
++			};
++
++			i2s0_8ch_sdo1: i2s0-8ch-sdo1 {
++				rockchip,pins =
++					<3 RK_PC0 2 &pcfg_pull_none>;
++			};
++
++			i2s0_8ch_sdo2: i2s0-8ch-sdo2 {
++				rockchip,pins =
++					<3 RK_PB7 2 &pcfg_pull_none>;
++			};
++
++			i2s0_8ch_sdo3: i2s0-8ch-sdo3 {
++				rockchip,pins =
++					<3 RK_PB6 2 &pcfg_pull_none>;
++			};
++
++			i2s0_8ch_sdi0: i2s0-8ch-sdi0 {
++				rockchip,pins =
++					<3 RK_PC5 2 &pcfg_pull_none>;
++			};
++
++			i2s0_8ch_sdi1: i2s0-8ch-sdi1 {
++				rockchip,pins =
++					<3 RK_PB3 2 &pcfg_pull_none>;
++			};
++
++			i2s0_8ch_sdi2: i2s0-8ch-sdi2 {
++				rockchip,pins =
++					<3 RK_PB1 2 &pcfg_pull_none>;
++			};
++
++			i2s0_8ch_sdi3: i2s0-8ch-sdi3 {
++				rockchip,pins =
++					<3 RK_PB0 2 &pcfg_pull_none>;
++			};
++		};
++
++		i2s1 {
++			i2s1_2ch_mclk: i2s1-2ch-mclk {
++				rockchip,pins =
++					<2 RK_PC3 1 &pcfg_pull_none>;
++			};
++
++			i2s1_2ch_sclk: i2s1-2ch-sclk {
++				rockchip,pins =
++					<2 RK_PC2 1 &pcfg_pull_none>;
++			};
++
++			i2s1_2ch_lrck: i2s1-2ch-lrck {
++				rockchip,pins =
++					<2 RK_PC1 1 &pcfg_pull_none>;
++			};
++
++			i2s1_2ch_sdi: i2s1-2ch-sdi {
++				rockchip,pins =
++					<2 RK_PC5 1 &pcfg_pull_none>;
++			};
++
++			i2s1_2ch_sdo: i2s1-2ch-sdo {
++				rockchip,pins =
++					<2 RK_PC4 1 &pcfg_pull_none>;
++			};
++		};
++
++		i2s2 {
++			i2s2_2ch_mclk: i2s2-2ch-mclk {
++				rockchip,pins =
++					<3 RK_PA1 2 &pcfg_pull_none>;
++			};
++
++			i2s2_2ch_sclk: i2s2-2ch-sclk {
++				rockchip,pins =
++					<3 RK_PA2 2 &pcfg_pull_none>;
++			};
++
++			i2s2_2ch_lrck: i2s2-2ch-lrck {
++				rockchip,pins =
++					<3 RK_PA3 2 &pcfg_pull_none>;
++			};
++
++			i2s2_2ch_sdi: i2s2-2ch-sdi {
++				rockchip,pins =
++					<3 RK_PA5 2 &pcfg_pull_none>;
++			};
++
++			i2s2_2ch_sdo: i2s2-2ch-sdo {
++				rockchip,pins =
++					<3 RK_PA7 2 &pcfg_pull_none>;
++			};
++		};
++
++		sdmmc {
++			sdmmc_clk: sdmmc-clk {
++				rockchip,pins =
++					<1 RK_PD6 1 &pcfg_pull_none_8ma>;
++			};
++
++			sdmmc_cmd: sdmmc-cmd {
++				rockchip,pins =
++					<1 RK_PD7 1 &pcfg_pull_up_8ma>;
++			};
++
++			sdmmc_det: sdmmc-det {
++				rockchip,pins =
++					<0 RK_PA3 1 &pcfg_pull_up_8ma>;
++			};
++
++			sdmmc_bus1: sdmmc-bus1 {
++				rockchip,pins =
++					<1 RK_PD2 1 &pcfg_pull_up_8ma>;
++			};
++
++			sdmmc_bus4: sdmmc-bus4 {
++				rockchip,pins =
++					<1 RK_PD2 1 &pcfg_pull_up_8ma>,
++					<1 RK_PD3 1 &pcfg_pull_up_8ma>,
++					<1 RK_PD4 1 &pcfg_pull_up_8ma>,
++					<1 RK_PD5 1 &pcfg_pull_up_8ma>;
++			};
++		};
++
++		sdio {
++			sdio_clk: sdio-clk {
++				rockchip,pins =
++					<1 RK_PC5 1 &pcfg_pull_none>;
++			};
++
++			sdio_cmd: sdio-cmd {
++				rockchip,pins =
++					<1 RK_PC4 1 &pcfg_pull_up>;
++			};
++
++			sdio_bus4: sdio-bus4 {
++				rockchip,pins =
++					<1 RK_PC6 1 &pcfg_pull_up>,
++					<1 RK_PC7 1 &pcfg_pull_up>,
++					<1 RK_PD0 1 &pcfg_pull_up>,
++					<1 RK_PD1 1 &pcfg_pull_up>;
++			};
++		};
++
++		emmc {
++			emmc_clk: emmc-clk {
++				rockchip,pins =
++					<1 RK_PB1 2 &pcfg_pull_none_8ma>;
++			};
++
++			emmc_cmd: emmc-cmd {
++				rockchip,pins =
++					<1 RK_PB2 2 &pcfg_pull_up_8ma>;
++			};
++
++			emmc_rstnout: emmc-rstnout {
++				rockchip,pins =
++					<1 RK_PB3 2 &pcfg_pull_none>;
++			};
++
++			emmc_bus1: emmc-bus1 {
++				rockchip,pins =
++					<1 RK_PA0 2 &pcfg_pull_up_8ma>;
++			};
++
++			emmc_bus4: emmc-bus4 {
++				rockchip,pins =
++					<1 RK_PA0 2 &pcfg_pull_up_8ma>,
++					<1 RK_PA1 2 &pcfg_pull_up_8ma>,
++					<1 RK_PA2 2 &pcfg_pull_up_8ma>,
++					<1 RK_PA3 2 &pcfg_pull_up_8ma>;
++			};
++
++			emmc_bus8: emmc-bus8 {
++				rockchip,pins =
++					<1 RK_PA0 2 &pcfg_pull_up_8ma>,
++					<1 RK_PA1 2 &pcfg_pull_up_8ma>,
++					<1 RK_PA2 2 &pcfg_pull_up_8ma>,
++					<1 RK_PA3 2 &pcfg_pull_up_8ma>,
++					<1 RK_PA4 2 &pcfg_pull_up_8ma>,
++					<1 RK_PA5 2 &pcfg_pull_up_8ma>,
++					<1 RK_PA6 2 &pcfg_pull_up_8ma>,
++					<1 RK_PA7 2 &pcfg_pull_up_8ma>;
++			};
++		};
++
++		flash {
++			flash_cs0: flash-cs0 {
++				rockchip,pins =
++					<1 RK_PB0 1 &pcfg_pull_none>;
++			};
++
++			flash_rdy: flash-rdy {
++				rockchip,pins =
++					<1 RK_PB1 1 &pcfg_pull_none>;
++			};
++
++			flash_dqs: flash-dqs {
++				rockchip,pins =
++					<1 RK_PB2 1 &pcfg_pull_none>;
++			};
++
++			flash_ale: flash-ale {
++				rockchip,pins =
++					<1 RK_PB3 1 &pcfg_pull_none>;
++			};
++
++			flash_cle: flash-cle {
++				rockchip,pins =
++					<1 RK_PB4 1 &pcfg_pull_none>;
++			};
++
++			flash_wrn: flash-wrn {
++				rockchip,pins =
++					<1 RK_PB5 1 &pcfg_pull_none>;
++			};
++
++			flash_csl: flash-csl {
++				rockchip,pins =
++					<1 RK_PB6 1 &pcfg_pull_none>;
++			};
++
++			flash_rdn: flash-rdn {
++				rockchip,pins =
++					<1 RK_PB7 1 &pcfg_pull_none>;
++			};
++
++			flash_bus8: flash-bus8 {
++				rockchip,pins =
++					<1 RK_PA0 1 &pcfg_pull_up_12ma>,
++					<1 RK_PA1 1 &pcfg_pull_up_12ma>,
++					<1 RK_PA2 1 &pcfg_pull_up_12ma>,
++					<1 RK_PA3 1 &pcfg_pull_up_12ma>,
++					<1 RK_PA4 1 &pcfg_pull_up_12ma>,
++					<1 RK_PA5 1 &pcfg_pull_up_12ma>,
++					<1 RK_PA6 1 &pcfg_pull_up_12ma>,
++					<1 RK_PA7 1 &pcfg_pull_up_12ma>;
++			};
++		};
++
++		lcdc {
++			lcdc_rgb_dclk_pin: lcdc-rgb-dclk-pin {
++				rockchip,pins =
++					<3 RK_PA0 1 &pcfg_pull_none_12ma>;
++			};
++
++			lcdc_rgb_m0_hsync_pin: lcdc-rgb-m0-hsync-pin {
++				rockchip,pins =
++					<3 RK_PA1 1 &pcfg_pull_none_12ma>;
++			};
++
++			lcdc_rgb_m0_vsync_pin: lcdc-rgb-m0-vsync-pin {
++				rockchip,pins =
++					<3 RK_PA2 1 &pcfg_pull_none_12ma>;
++			};
++
++			lcdc_rgb_m0_den_pin: lcdc-rgb-m0-den-pin {
++				rockchip,pins =
++					<3 RK_PA3 1 &pcfg_pull_none_12ma>;
++			};
++
++			lcdc_rgb888_m0_data_pins: lcdc-rgb888-m0-data-pins {
++				rockchip,pins =
++					<3 RK_PA7 1 &pcfg_pull_none_8ma>, /* lcdc_d3 */
++					<3 RK_PA6 1 &pcfg_pull_none_8ma>, /* lcdc_d2 */
++					<3 RK_PA5 1 &pcfg_pull_none_8ma>, /* lcdc_d1 */
++					<3 RK_PA4 1 &pcfg_pull_none_8ma>, /* lcdc_d0 */
++					<3 RK_PB3 1 &pcfg_pull_none_8ma>, /* lcdc_d7 */
++					<3 RK_PB2 1 &pcfg_pull_none_8ma>, /* lcdc_d6 */
++					<3 RK_PB1 1 &pcfg_pull_none_8ma>, /* lcdc_d5 */
++					<3 RK_PB0 1 &pcfg_pull_none_8ma>, /* lcdc_d4 */
++					<3 RK_PB7 1 &pcfg_pull_none_8ma>, /* lcdc_d11 */
++					<3 RK_PB6 1 &pcfg_pull_none_8ma>, /* lcdc_d10 */
++					<3 RK_PB5 1 &pcfg_pull_none_8ma>, /* lcdc_d9 */
++					<3 RK_PB4 1 &pcfg_pull_none_8ma>, /* lcdc_d8 */
++					<3 RK_PC3 1 &pcfg_pull_none_8ma>, /* lcdc_d15 */
++					<3 RK_PC2 1 &pcfg_pull_none_8ma>, /* lcdc_d14 */
++					<3 RK_PC1 1 &pcfg_pull_none_8ma>, /* lcdc_d13 */
++					<3 RK_PC0 1 &pcfg_pull_none_8ma>, /* lcdc_d12 */
++					<3 RK_PC7 1 &pcfg_pull_none_8ma>, /* lcdc_d19 */
++					<3 RK_PC6 1 &pcfg_pull_none_8ma>, /* lcdc_d18 */
++					<3 RK_PC5 1 &pcfg_pull_none_8ma>, /* lcdc_d17 */
++					<3 RK_PC4 1 &pcfg_pull_none_8ma>, /* lcdc_d16 */
++					<3 RK_PD3 1 &pcfg_pull_none_8ma>, /* lcdc_d23 */
++					<3 RK_PD2 1 &pcfg_pull_none_8ma>, /* lcdc_d22 */
++					<3 RK_PD1 1 &pcfg_pull_none_8ma>, /* lcdc_d21 */
++					<3 RK_PD0 1 &pcfg_pull_none_8ma>; /* lcdc_d20 */
++			};
++
++			lcdc_rgb666_m0_data_pins: lcdc-rgb666-m0-data-pins {
++				rockchip,pins =
++					<3 RK_PA7 1 &pcfg_pull_none_8ma>, /* lcdc_d3 */
++					<3 RK_PA6 1 &pcfg_pull_none_8ma>, /* lcdc_d2 */
++					<3 RK_PA5 1 &pcfg_pull_none_8ma>, /* lcdc_d1 */
++					<3 RK_PA4 1 &pcfg_pull_none_8ma>, /* lcdc_d0 */
++					<3 RK_PB3 1 &pcfg_pull_none_8ma>, /* lcdc_d7 */
++					<3 RK_PB2 1 &pcfg_pull_none_8ma>, /* lcdc_d6 */
++					<3 RK_PB1 1 &pcfg_pull_none_8ma>, /* lcdc_d5 */
++					<3 RK_PB0 1 &pcfg_pull_none_8ma>, /* lcdc_d4 */
++					<3 RK_PB7 1 &pcfg_pull_none_8ma>, /* lcdc_d11 */
++					<3 RK_PB6 1 &pcfg_pull_none_8ma>, /* lcdc_d10 */
++					<3 RK_PB5 1 &pcfg_pull_none_8ma>, /* lcdc_d9 */
++					<3 RK_PB4 1 &pcfg_pull_none_8ma>, /* lcdc_d8 */
++					<3 RK_PC3 1 &pcfg_pull_none_8ma>, /* lcdc_d15 */
++					<3 RK_PC2 1 &pcfg_pull_none_8ma>, /* lcdc_d14 */
++					<3 RK_PC1 1 &pcfg_pull_none_8ma>, /* lcdc_d13 */
++					<3 RK_PC0 1 &pcfg_pull_none_8ma>, /* lcdc_d12 */
++					<3 RK_PC5 1 &pcfg_pull_none_8ma>, /* lcdc_d17 */
++					<3 RK_PC4 1 &pcfg_pull_none_8ma>; /* lcdc_d16 */
++			};
++
++			lcdc_rgb565_m0_data_pins: lcdc-rgb565-m0-data-pins {
++				rockchip,pins =
++					<3 RK_PA7 1 &pcfg_pull_none_8ma>, /* lcdc_d3 */
++					<3 RK_PA6 1 &pcfg_pull_none_8ma>, /* lcdc_d2 */
++					<3 RK_PA5 1 &pcfg_pull_none_8ma>, /* lcdc_d1 */
++					<3 RK_PA4 1 &pcfg_pull_none_8ma>, /* lcdc_d0 */
++					<3 RK_PB3 1 &pcfg_pull_none_8ma>, /* lcdc_d7 */
++					<3 RK_PB2 1 &pcfg_pull_none_8ma>, /* lcdc_d6 */
++					<3 RK_PB1 1 &pcfg_pull_none_8ma>, /* lcdc_d5 */
++					<3 RK_PB0 1 &pcfg_pull_none_8ma>, /* lcdc_d4 */
++					<3 RK_PB7 1 &pcfg_pull_none_8ma>, /* lcdc_d11 */
++					<3 RK_PB6 1 &pcfg_pull_none_8ma>, /* lcdc_d10 */
++					<3 RK_PB5 1 &pcfg_pull_none_8ma>, /* lcdc_d9 */
++					<3 RK_PB4 1 &pcfg_pull_none_8ma>, /* lcdc_d8 */
++					<3 RK_PC3 1 &pcfg_pull_none_8ma>, /* lcdc_d15 */
++					<3 RK_PC2 1 &pcfg_pull_none_8ma>, /* lcdc_d14 */
++					<3 RK_PC1 1 &pcfg_pull_none_8ma>, /* lcdc_d13 */
++					<3 RK_PC0 1 &pcfg_pull_none_8ma>; /* lcdc_d12 */
++			};
++
++			lcdc_rgb888_m1_data_pins: lcdc-rgb888-m1-data-pins {
++				rockchip,pins =
++					<3 RK_PA6 1 &pcfg_pull_none_8ma>, /* lcdc_d2 */
++					<3 RK_PA4 1 &pcfg_pull_none_8ma>, /* lcdc_d0 */
++					<3 RK_PB3 1 &pcfg_pull_none_8ma>, /* lcdc_d7 */
++					<3 RK_PB2 1 &pcfg_pull_none_8ma>, /* lcdc_d6 */
++					<3 RK_PB5 1 &pcfg_pull_none_8ma>, /* lcdc_d9 */
++					<3 RK_PC3 1 &pcfg_pull_none_8ma>, /* lcdc_d15 */
++					<3 RK_PC2 1 &pcfg_pull_none_8ma>, /* lcdc_d14 */
++					<3 RK_PC1 1 &pcfg_pull_none_8ma>, /* lcdc_d13 */
++					<3 RK_PC0 1 &pcfg_pull_none_8ma>, /* lcdc_d12 */
++					<3 RK_PC7 1 &pcfg_pull_none_8ma>, /* lcdc_d19 */
++					<3 RK_PC6 1 &pcfg_pull_none_8ma>, /* lcdc_d18 */
++					<3 RK_PC5 1 &pcfg_pull_none_8ma>, /* lcdc_d17 */
++					<3 RK_PC4 1 &pcfg_pull_none_8ma>, /* lcdc_d16 */
++					<3 RK_PD3 1 &pcfg_pull_none_8ma>, /* lcdc_d23 */
++					<3 RK_PD2 1 &pcfg_pull_none_8ma>, /* lcdc_d22 */
++					<3 RK_PD1 1 &pcfg_pull_none_8ma>, /* lcdc_d21 */
++					<3 RK_PD0 1 &pcfg_pull_none_8ma>; /* lcdc_d20 */
++			};
++
++			lcdc_rgb666_m1_data_pins: lcdc-rgb666-m1-data-pins {
++				rockchip,pins =
++					<3 RK_PA6 1 &pcfg_pull_none_8ma>, /* lcdc_d2 */
++					<3 RK_PA4 1 &pcfg_pull_none_8ma>, /* lcdc_d0 */
++					<3 RK_PB3 1 &pcfg_pull_none_8ma>, /* lcdc_d7 */
++					<3 RK_PB2 1 &pcfg_pull_none_8ma>, /* lcdc_d6 */
++					<3 RK_PB5 1 &pcfg_pull_none_8ma>, /* lcdc_d9 */
++					<3 RK_PC3 1 &pcfg_pull_none_8ma>, /* lcdc_d15 */
++					<3 RK_PC2 1 &pcfg_pull_none_8ma>, /* lcdc_d14 */
++					<3 RK_PC1 1 &pcfg_pull_none_8ma>, /* lcdc_d13 */
++					<3 RK_PC0 1 &pcfg_pull_none_8ma>, /* lcdc_d12 */
++					<3 RK_PC5 1 &pcfg_pull_none_8ma>, /* lcdc_d17 */
++					<3 RK_PC4 1 &pcfg_pull_none_8ma>; /* lcdc_d16 */
++			};
++
++			lcdc_rgb565_m1_data_pins: lcdc-rgb565-m1-data-pins {
++				rockchip,pins =
++					<3 RK_PA6 1 &pcfg_pull_none_8ma>, /* lcdc_d2 */
++					<3 RK_PA4 1 &pcfg_pull_none_8ma>, /* lcdc_d0 */
++					<3 RK_PB3 1 &pcfg_pull_none_8ma>, /* lcdc_d7 */
++					<3 RK_PB2 1 &pcfg_pull_none_8ma>, /* lcdc_d6 */
++					<3 RK_PB5 1 &pcfg_pull_none_8ma>, /* lcdc_d9 */
++					<3 RK_PC3 1 &pcfg_pull_none_8ma>, /* lcdc_d15 */
++					<3 RK_PC2 1 &pcfg_pull_none_8ma>, /* lcdc_d14 */
++					<3 RK_PC1 1 &pcfg_pull_none_8ma>, /* lcdc_d13 */
++					<3 RK_PC0 1 &pcfg_pull_none_8ma>; /* lcdc_d12 */
++			};
++		};
++
++		pwm0 {
++			pwm0_pin: pwm0-pin {
++				rockchip,pins =
++					<0 RK_PB7 1 &pcfg_pull_none>;
++			};
++		};
++
++		pwm1 {
++			pwm1_pin: pwm1-pin {
++				rockchip,pins =
++					<0 RK_PC0 1 &pcfg_pull_none>;
++			};
++		};
++
++		pwm2 {
++			pwm2_pin: pwm2-pin {
++				rockchip,pins =
++					<2 RK_PB5 1 &pcfg_pull_none>;
++			};
++		};
++
++		pwm3 {
++			pwm3_pin: pwm3-pin {
++				rockchip,pins =
++					<0 RK_PC1 1 &pcfg_pull_none>;
++			};
++		};
++
++		pwm4 {
++			pwm4_pin: pwm4-pin {
++				rockchip,pins =
++					<3 RK_PC2 3 &pcfg_pull_none>;
++			};
++		};
++
++		pwm5 {
++			pwm5_pin: pwm5-pin {
++				rockchip,pins =
++					<3 RK_PC3 3 &pcfg_pull_none>;
++			};
++		};
++
++		pwm6 {
++			pwm6_pin: pwm6-pin {
++				rockchip,pins =
++					<3 RK_PC4 3 &pcfg_pull_none>;
++			};
++		};
++
++		pwm7 {
++			pwm7_pin: pwm7-pin {
++				rockchip,pins =
++					<3 RK_PC5 3 &pcfg_pull_none>;
++			};
++		};
++
++		gmac {
++			rmii_pins: rmii-pins {
++				rockchip,pins =
++					<2 RK_PA0 2 &pcfg_pull_none_12ma>, /* mac_txen */
++					<2 RK_PA1 2 &pcfg_pull_none_12ma>, /* mac_txd1 */
++					<2 RK_PA2 2 &pcfg_pull_none_12ma>, /* mac_txd0 */
++					<2 RK_PA3 2 &pcfg_pull_none>, /* mac_rxd0 */
++					<2 RK_PA4 2 &pcfg_pull_none>, /* mac_rxd1 */
++					<2 RK_PA5 2 &pcfg_pull_none>, /* mac_rxer */
++					<2 RK_PA6 2 &pcfg_pull_none>, /* mac_rxdv */
++					<2 RK_PA7 2 &pcfg_pull_none>, /* mac_mdio */
++					<2 RK_PB1 2 &pcfg_pull_none>; /* mac_mdc */
++			};
++
++			mac_refclk_12ma: mac-refclk-12ma {
++				rockchip,pins =
++					<2 RK_PB2 2 &pcfg_pull_none_12ma>;
++			};
++
++			mac_refclk: mac-refclk {
++				rockchip,pins =
++					<2 RK_PB2 2 &pcfg_pull_none>;
++			};
++		};
++
++		cif-m0 {
++			cif_clkout_m0: cif-clkout-m0 {
++				rockchip,pins =
++					<2 RK_PB3 1 &pcfg_pull_none>;
++			};
++
++			dvp_d2d9_m0: dvp-d2d9-m0 {
++				rockchip,pins =
++					<2 RK_PA0 1 &pcfg_pull_none>, /* cif_data2 */
++					<2 RK_PA1 1 &pcfg_pull_none>, /* cif_data3 */
++					<2 RK_PA2 1 &pcfg_pull_none>, /* cif_data4 */
++					<2 RK_PA3 1 &pcfg_pull_none>, /* cif_data5 */
++					<2 RK_PA4 1 &pcfg_pull_none>, /* cif_data6 */
++					<2 RK_PA5 1 &pcfg_pull_none>, /* cif_data7 */
++					<2 RK_PA6 1 &pcfg_pull_none>, /* cif_data8 */
++					<2 RK_PA7 1 &pcfg_pull_none>, /* cif_data9 */
++					<2 RK_PB0 1 &pcfg_pull_none>, /* cif_sync */
++					<2 RK_PB1 1 &pcfg_pull_none>, /* cif_href */
++					<2 RK_PB2 1 &pcfg_pull_none>, /* cif_clkin */
++					<2 RK_PB3 1 &pcfg_pull_none>; /* cif_clkout */
++			};
++
++			dvp_d0d1_m0: dvp-d0d1-m0 {
++				rockchip,pins =
++					<2 RK_PB4 1 &pcfg_pull_none>, /* cif_data0 */
++					<2 RK_PB6 1 &pcfg_pull_none>; /* cif_data1 */
++			};
++
++			dvp_d10d11_m0:d10-d11-m0 {
++				rockchip,pins =
++					<2 RK_PB7 1 &pcfg_pull_none>, /* cif_data10 */
++					<2 RK_PC0 1 &pcfg_pull_none>; /* cif_data11 */
++			};
++		};
++
++		cif-m1 {
++			cif_clkout_m1: cif-clkout-m1 {
++				rockchip,pins =
++					<3 RK_PD0 3 &pcfg_pull_none>;
++			};
++
++			dvp_d2d9_m1: dvp-d2d9-m1 {
++				rockchip,pins =
++					<3 RK_PA3 3 &pcfg_pull_none>, /* cif_data2 */
++					<3 RK_PA5 3 &pcfg_pull_none>, /* cif_data3 */
++					<3 RK_PA7 3 &pcfg_pull_none>, /* cif_data4 */
++					<3 RK_PB0 3 &pcfg_pull_none>, /* cif_data5 */
++					<3 RK_PB1 3 &pcfg_pull_none>, /* cif_data6 */
++					<3 RK_PB4 3 &pcfg_pull_none>, /* cif_data7 */
++					<3 RK_PB6 3 &pcfg_pull_none>, /* cif_data8 */
++					<3 RK_PB7 3 &pcfg_pull_none>, /* cif_data9 */
++					<3 RK_PD1 3 &pcfg_pull_none>, /* cif_sync */
++					<3 RK_PD2 3 &pcfg_pull_none>, /* cif_href */
++					<3 RK_PD3 3 &pcfg_pull_none>, /* cif_clkin */
++					<3 RK_PD0 3 &pcfg_pull_none>; /* cif_clkout */
++			};
++
++			dvp_d0d1_m1: dvp-d0d1-m1 {
++				rockchip,pins =
++					<3 RK_PA1 3 &pcfg_pull_none>, /* cif_data0 */
++					<3 RK_PA2 3 &pcfg_pull_none>; /* cif_data1 */
++			};
++
++			dvp_d10d11_m1:d10-d11-m1 {
++				rockchip,pins =
++					<3 RK_PC6 3 &pcfg_pull_none>, /* cif_data10 */
++					<3 RK_PC7 3 &pcfg_pull_none>; /* cif_data11 */
++			};
++		};
++
++		isp {
++			isp_prelight: isp-prelight {
++				rockchip,pins =
++					<3 RK_PD1 4 &pcfg_pull_none>;
++			};
++		};
++	};
++};
+
+From patchwork Thu Oct 24 23:28:02 2019
+Content-Type: text/plain; charset="utf-8"
+MIME-Version: 1.0
+Content-Transfer-Encoding: 7bit
+X-Patchwork-Submitter: =?utf-8?q?Heiko_St=C3=BCbner?= <heiko@sntech.de>
+X-Patchwork-Id: 1183663
+X-Patchwork-Delegate: ykai007@gmail.com
+Return-Path: <u-boot-bounces@lists.denx.de>
+X-Original-To: incoming@patchwork.ozlabs.org
+Delivered-To: patchwork-incoming@bilbo.ozlabs.org
+Authentication-Results: ozlabs.org;
+ spf=none (no SPF record) smtp.mailfrom=lists.denx.de
+ (client-ip=81.169.180.215; helo=lists.denx.de;
+ envelope-from=u-boot-bounces@lists.denx.de;
+ receiver=<UNKNOWN>)
+Authentication-Results: ozlabs.org;
+ dmarc=none (p=none dis=none) header.from=sntech.de
+Received: from lists.denx.de (dione.denx.de [81.169.180.215])
+ by ozlabs.org (Postfix) with ESMTP id 46zkT344zwz9sPk
+ for <incoming@patchwork.ozlabs.org>;
+ Fri, 25 Oct 2019 10:48:07 +1100 (AEDT)
+Received: by lists.denx.de (Postfix, from userid 105)
+ id 43CE0C21DCA; Thu, 24 Oct 2019 23:48:06 +0000 (UTC)
+X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on lists.denx.de
+X-Spam-Level: 
+X-Spam-Status: No, score=0.0 required=5.0 tests=none autolearn=unavailable
+ autolearn_force=no version=3.4.0
+Received: from lists.denx.de (localhost [IPv6:::1])
+ by lists.denx.de (Postfix) with ESMTP id 677B0C21D8A;
+ Thu, 24 Oct 2019 23:47:48 +0000 (UTC)
+Received: by lists.denx.de (Postfix, from userid 105)
+ id 7F9B4C21D8A; Thu, 24 Oct 2019 23:47:47 +0000 (UTC)
+Received: from gloria.sntech.de (gloria.sntech.de [185.11.138.130])
+ by lists.denx.de (Postfix) with ESMTPS id 62563C21C6A
+ for <u-boot@lists.denx.de>; Thu, 24 Oct 2019 23:47:46 +0000 (UTC)
+Received: from ip5f5a6266.dynamic.kabel-deutschland.de ([95.90.98.102]
+ helo=phil.fritz.box) by gloria.sntech.de with esmtpsa
+ (TLS1.2:ECDHE_RSA_AES_128_GCM_SHA256:128)
+ (Exim 4.89) (envelope-from <heiko@sntech.de>)
+ id 1iNmWh-0002cR-Cg; Fri, 25 Oct 2019 01:28:19 +0200
+From: Heiko Stuebner <heiko@sntech.de>
+To: u-boot@lists.denx.de
+Date: Fri, 25 Oct 2019 01:28:02 +0200
+Message-Id: <20191024232803.10338-12-heiko@sntech.de>
+X-Mailer: git-send-email 2.23.0
+In-Reply-To: <20191024232803.10338-1-heiko@sntech.de>
+References: <20191024232803.10338-1-heiko@sntech.de>
+MIME-Version: 1.0
+Cc: Heiko Stuebner <heiko.stuebner@theobroma-systems.com>,
+ joe.hershberger@ni.com, christoph.muellner@theobroma-systems.com
+Subject: [U-Boot] [PATCH 11/12] rockchip: add px30 architecture core
+X-BeenThere: u-boot@lists.denx.de
+X-Mailman-Version: 2.1.18
+Precedence: list
+List-Id: U-Boot discussion <u-boot.lists.denx.de>
+List-Unsubscribe: <https://lists.denx.de/options/u-boot>,
+ <mailto:u-boot-request@lists.denx.de?subject=unsubscribe>
+List-Archive: <http://lists.denx.de/pipermail/u-boot/>
+List-Post: <mailto:u-boot@lists.denx.de>
+List-Help: <mailto:u-boot-request@lists.denx.de?subject=help>
+List-Subscribe: <https://lists.denx.de/listinfo/u-boot>,
+ <mailto:u-boot-request@lists.denx.de?subject=subscribe>
+Errors-To: u-boot-bounces@lists.denx.de
+Sender: "U-Boot" <u-boot-bounces@lists.denx.de>
+
+From: Kever Yang <kever.yang@rock-chips.com>
+
+Add core architecture code to support the px30 soc.
+This includes a separate tpl board file due to very limited
+sram size as well as a non-dm sdram driver, as this also has
+to fit into the tiny sram.
+
+Signed-off-by: Kever Yang <kever.yang@rock-chips.com>
+Signed-off-by: Heiko Stuebner <heiko.stuebner@theobroma-systems.com>
+---
+ arch/arm/include/asm/arch-px30/boot0.h        |   11 +
+ arch/arm/include/asm/arch-px30/gpio.h         |   11 +
+ .../include/asm/arch-rockchip/sdram_px30.h    |  359 +++++
+ arch/arm/mach-rockchip/Kconfig                |   23 +
+ arch/arm/mach-rockchip/Makefile               |    2 +
+ arch/arm/mach-rockchip/px30-board-tpl.c       |   59 +
+ arch/arm/mach-rockchip/px30/Kconfig           |   48 +
+ arch/arm/mach-rockchip/px30/Makefile          |   14 +
+ arch/arm/mach-rockchip/px30/clk_px30.c        |   31 +
+ arch/arm/mach-rockchip/px30/px30.c            |  248 +++
+ .../px30/sdram-px30-ddr3-detect-333.inc       |   70 +
+ .../px30/sdram-px30-ddr4-detect-333.inc       |   73 +
+ .../px30/sdram-px30-ddr_skew.inc              |  121 ++
+ .../px30/sdram-px30-lpddr2-detect-333.inc     |   71 +
+ .../px30/sdram-px30-lpddr3-detect-333.inc     |   72 +
+ arch/arm/mach-rockchip/px30/sdram_px30.c      | 1405 +++++++++++++++++
+ arch/arm/mach-rockchip/px30/syscon_px30.c     |   53 +
+ 17 files changed, 2671 insertions(+)
+ create mode 100644 arch/arm/include/asm/arch-px30/boot0.h
+ create mode 100644 arch/arm/include/asm/arch-px30/gpio.h
+ create mode 100644 arch/arm/include/asm/arch-rockchip/sdram_px30.h
+ create mode 100644 arch/arm/mach-rockchip/px30-board-tpl.c
+ create mode 100644 arch/arm/mach-rockchip/px30/Kconfig
+ create mode 100644 arch/arm/mach-rockchip/px30/Makefile
+ create mode 100644 arch/arm/mach-rockchip/px30/clk_px30.c
+ create mode 100644 arch/arm/mach-rockchip/px30/px30.c
+ create mode 100644 arch/arm/mach-rockchip/px30/sdram-px30-ddr3-detect-333.inc
+ create mode 100644 arch/arm/mach-rockchip/px30/sdram-px30-ddr4-detect-333.inc
+ create mode 100644 arch/arm/mach-rockchip/px30/sdram-px30-ddr_skew.inc
+ create mode 100644 arch/arm/mach-rockchip/px30/sdram-px30-lpddr2-detect-333.inc
+ create mode 100644 arch/arm/mach-rockchip/px30/sdram-px30-lpddr3-detect-333.inc
+ create mode 100644 arch/arm/mach-rockchip/px30/sdram_px30.c
+ create mode 100644 arch/arm/mach-rockchip/px30/syscon_px30.c
+
+diff --git a/arch/arm/include/asm/arch-px30/boot0.h b/arch/arm/include/asm/arch-px30/boot0.h
+new file mode 100644
+index 0000000000..2e78b074ad
+--- /dev/null
++++ b/arch/arm/include/asm/arch-px30/boot0.h
+@@ -0,0 +1,11 @@
++/* SPDX-License-Identifier: GPL-2.0+ */
++/*
++ * (C) Copyright 2019 Rockchip Electronics Co., Ltd
++ */
++
++#ifndef __ASM_ARCH_BOOT0_H__
++#define __ASM_ARCH_BOOT0_H__
++
++#include <asm/arch-rockchip/boot0.h>
++
++#endif
+diff --git a/arch/arm/include/asm/arch-px30/gpio.h b/arch/arm/include/asm/arch-px30/gpio.h
+new file mode 100644
+index 0000000000..eca79d5159
+--- /dev/null
++++ b/arch/arm/include/asm/arch-px30/gpio.h
+@@ -0,0 +1,11 @@
++/* SPDX-License-Identifier: GPL-2.0+ */
++/*
++ * (C) Copyright 2019 Rockchip Electronics Co., Ltd
++ */
++
++#ifndef __ASM_ARCH_GPIO_H__
++#define __ASM_ARCH_GPIO_H__
++
++#include <asm/arch-rockchip/gpio.h>
++
++#endif
+diff --git a/arch/arm/include/asm/arch-rockchip/sdram_px30.h b/arch/arm/include/asm/arch-rockchip/sdram_px30.h
+new file mode 100644
+index 0000000000..e10eb97b89
+--- /dev/null
++++ b/arch/arm/include/asm/arch-rockchip/sdram_px30.h
+@@ -0,0 +1,359 @@
++/* SPDX-License-Identifier:     GPL-2.0+ */
++/*
++ * Copyright (C) 2018 Rockchip Electronics Co., Ltd
++ */
++
++#ifndef _ASM_ARCH_SDRAM_PX30_H
++#define _ASM_ARCH_SDRAM_PX30_H
++
++struct ddr_pctl_regs {
++	u32 pctl[30][2];
++};
++
++/* ddr pctl registers define */
++#define DDR_PCTL2_MSTR			0x0
++#define DDR_PCTL2_STAT			0x4
++#define DDR_PCTL2_MSTR1			0x8
++#define DDR_PCTL2_MRCTRL0		0x10
++#define DDR_PCTL2_MRCTRL1		0x14
++#define DDR_PCTL2_MRSTAT		0x18
++#define DDR_PCTL2_MRCTRL2		0x1c
++#define DDR_PCTL2_DERATEEN		0x20
++#define DDR_PCTL2_DERATEINT		0x24
++#define DDR_PCTL2_PWRCTL		0x30
++#define DDR_PCTL2_PWRTMG		0x34
++#define DDR_PCTL2_HWLPCTL		0x38
++#define DDR_PCTL2_RFSHCTL0		0x50
++#define DDR_PCTL2_RFSHCTL1		0x54
++#define DDR_PCTL2_RFSHCTL2		0x58
++#define DDR_PCTL2_RFSHCTL4		0x5c
++#define DDR_PCTL2_RFSHCTL3		0x60
++#define DDR_PCTL2_RFSHTMG		0x64
++#define DDR_PCTL2_RFSHTMG1		0x68
++#define DDR_PCTL2_RFSHCTL5		0x6c
++#define DDR_PCTL2_INIT0			0xd0
++#define DDR_PCTL2_INIT1			0xd4
++#define DDR_PCTL2_INIT2			0xd8
++#define DDR_PCTL2_INIT3			0xdc
++#define DDR_PCTL2_INIT4			0xe0
++#define DDR_PCTL2_INIT5			0xe4
++#define DDR_PCTL2_INIT6			0xe8
++#define DDR_PCTL2_INIT7			0xec
++#define DDR_PCTL2_DIMMCTL		0xf0
++#define DDR_PCTL2_RANKCTL		0xf4
++#define DDR_PCTL2_CHCTL			0xfc
++#define DDR_PCTL2_DRAMTMG0		0x100
++#define DDR_PCTL2_DRAMTMG1		0x104
++#define DDR_PCTL2_DRAMTMG2		0x108
++#define DDR_PCTL2_DRAMTMG3		0x10c
++#define DDR_PCTL2_DRAMTMG4		0x110
++#define DDR_PCTL2_DRAMTMG5		0x114
++#define DDR_PCTL2_DRAMTMG6		0x118
++#define DDR_PCTL2_DRAMTMG7		0x11c
++#define DDR_PCTL2_DRAMTMG8		0x120
++#define DDR_PCTL2_DRAMTMG9		0x124
++#define DDR_PCTL2_DRAMTMG10		0x128
++#define DDR_PCTL2_DRAMTMG11		0x12c
++#define DDR_PCTL2_DRAMTMG12		0x130
++#define DDR_PCTL2_DRAMTMG13		0x134
++#define DDR_PCTL2_DRAMTMG14		0x138
++#define DDR_PCTL2_DRAMTMG15		0x13c
++#define DDR_PCTL2_DRAMTMG16		0x140
++#define DDR_PCTL2_ZQCTL0		0x180
++#define DDR_PCTL2_ZQCTL1		0x184
++#define DDR_PCTL2_ZQCTL2		0x188
++#define DDR_PCTL2_ZQSTAT		0x18c
++#define DDR_PCTL2_DFITMG0		0x190
++#define DDR_PCTL2_DFITMG1		0x194
++#define DDR_PCTL2_DFILPCFG0		0x198
++#define DDR_PCTL2_DFILPCFG1		0x19c
++#define DDR_PCTL2_DFIUPD0		0x1a0
++#define DDR_PCTL2_DFIUPD1		0x1a4
++#define DDR_PCTL2_DFIUPD2		0x1a8
++#define DDR_PCTL2_DFIMISC		0x1b0
++#define DDR_PCTL2_DFITMG2		0x1b4
++#define DDR_PCTL2_DFITMG3		0x1b8
++#define DDR_PCTL2_DFISTAT		0x1bc
++#define DDR_PCTL2_DBICTL		0x1c0
++#define DDR_PCTL2_ADDRMAP0		0x200
++#define DDR_PCTL2_ADDRMAP1		0x204
++#define DDR_PCTL2_ADDRMAP2		0x208
++#define DDR_PCTL2_ADDRMAP3		0x20c
++#define DDR_PCTL2_ADDRMAP4		0x210
++#define DDR_PCTL2_ADDRMAP5		0x214
++#define DDR_PCTL2_ADDRMAP6		0x218
++#define DDR_PCTL2_ADDRMAP7		0x21c
++#define DDR_PCTL2_ADDRMAP8		0x220
++#define DDR_PCTL2_ADDRMAP9		0x224
++#define DDR_PCTL2_ADDRMAP10		0x228
++#define DDR_PCTL2_ADDRMAP11		0x22c
++#define DDR_PCTL2_ODTCFG		0x240
++#define DDR_PCTL2_ODTMAP		0x244
++#define DDR_PCTL2_SCHED			0x250
++#define DDR_PCTL2_SCHED1		0x254
++#define DDR_PCTL2_PERFHPR1		0x25c
++#define DDR_PCTL2_PERFLPR1		0x264
++#define DDR_PCTL2_PERFWR1		0x26c
++#define DDR_PCTL2_DQMAP0		0x280
++#define DDR_PCTL2_DQMAP1		0x284
++#define DDR_PCTL2_DQMAP2		0x288
++#define DDR_PCTL2_DQMAP3		0x28c
++#define DDR_PCTL2_DQMAP4		0x290
++#define DDR_PCTL2_DQMAP5		0x294
++#define DDR_PCTL2_DBG0			0x300
++#define DDR_PCTL2_DBG1			0x304
++#define DDR_PCTL2_DBGCAM		0x308
++#define DDR_PCTL2_DBGCMD		0x30c
++#define DDR_PCTL2_DBGSTAT		0x310
++#define DDR_PCTL2_SWCTL			0x320
++#define DDR_PCTL2_SWSTAT		0x324
++#define DDR_PCTL2_POISONCFG		0x36c
++#define DDR_PCTL2_POISONSTAT		0x370
++#define DDR_PCTL2_ADVECCINDEX		0x374
++#define DDR_PCTL2_ADVECCSTAT		0x378
++#define DDR_PCTL2_PSTAT			0x3fc
++#define DDR_PCTL2_PCCFG			0x400
++#define DDR_PCTL2_PCFGR_n		0x404
++#define DDR_PCTL2_PCFGW_n		0x408
++#define DDR_PCTL2_PCTRL_n		0x490
++
++/* PCTL2_MRSTAT */
++#define MR_WR_BUSY			BIT(0)
++
++#define PHY_DDR3_RON_RTT_DISABLE	(0)
++#define PHY_DDR3_RON_RTT_451ohm		(1)
++#define PHY_DDR3_RON_RTT_225ohm		(2)
++#define PHY_DDR3_RON_RTT_150ohm		(3)
++#define PHY_DDR3_RON_RTT_112ohm		(4)
++#define PHY_DDR3_RON_RTT_90ohm		(5)
++#define PHY_DDR3_RON_RTT_75ohm		(6)
++#define PHY_DDR3_RON_RTT_64ohm		(7)
++#define PHY_DDR3_RON_RTT_56ohm		(16)
++#define PHY_DDR3_RON_RTT_50ohm		(17)
++#define PHY_DDR3_RON_RTT_45ohm		(18)
++#define PHY_DDR3_RON_RTT_41ohm		(19)
++#define PHY_DDR3_RON_RTT_37ohm		(20)
++#define PHY_DDR3_RON_RTT_34ohm		(21)
++#define PHY_DDR3_RON_RTT_33ohm		(22)
++#define PHY_DDR3_RON_RTT_30ohm		(23)
++#define PHY_DDR3_RON_RTT_28ohm		(24)
++#define PHY_DDR3_RON_RTT_26ohm		(25)
++#define PHY_DDR3_RON_RTT_25ohm		(26)
++#define PHY_DDR3_RON_RTT_23ohm		(27)
++#define PHY_DDR3_RON_RTT_22ohm		(28)
++#define PHY_DDR3_RON_RTT_21ohm		(29)
++#define PHY_DDR3_RON_RTT_20ohm		(30)
++#define PHY_DDR3_RON_RTT_19ohm		(31)
++
++#define PHY_DDR4_LPDDR3_RON_RTT_DISABLE	(0)
++#define PHY_DDR4_LPDDR3_RON_RTT_480ohm	(1)
++#define PHY_DDR4_LPDDR3_RON_RTT_240ohm	(2)
++#define PHY_DDR4_LPDDR3_RON_RTT_160ohm	(3)
++#define PHY_DDR4_LPDDR3_RON_RTT_120ohm	(4)
++#define PHY_DDR4_LPDDR3_RON_RTT_96ohm	(5)
++#define PHY_DDR4_LPDDR3_RON_RTT_80ohm	(6)
++#define PHY_DDR4_LPDDR3_RON_RTT_68ohm	(7)
++#define PHY_DDR4_LPDDR3_RON_RTT_60ohm	(16)
++#define PHY_DDR4_LPDDR3_RON_RTT_53ohm	(17)
++#define PHY_DDR4_LPDDR3_RON_RTT_48ohm	(18)
++#define PHY_DDR4_LPDDR3_RON_RTT_43ohm	(19)
++#define PHY_DDR4_LPDDR3_RON_RTT_40ohm	(20)
++#define PHY_DDR4_LPDDR3_RON_RTT_37ohm	(21)
++#define PHY_DDR4_LPDDR3_RON_RTT_34ohm	(22)
++#define PHY_DDR4_LPDDR3_RON_RTT_32ohm	(23)
++#define PHY_DDR4_LPDDR3_RON_RTT_30ohm	(24)
++#define PHY_DDR4_LPDDR3_RON_RTT_28ohm	(25)
++#define PHY_DDR4_LPDDR3_RON_RTT_26ohm	(26)
++#define PHY_DDR4_LPDDR3_RON_RTT_25ohm	(27)
++#define PHY_DDR4_LPDDR3_RON_RTT_24ohm	(28)
++#define PHY_DDR4_LPDDR3_RON_RTT_22ohm	(29)
++#define PHY_DDR4_LPDDR3_RON_RTT_21ohm	(30)
++#define PHY_DDR4_LPDDR3_RON_RTT_20ohm	(31)
++
++struct ddr_phy_regs {
++	u32 phy[5][2];
++};
++
++#define PHY_REG(base, n)		((base) + 4 * (n))
++
++/* PHY_REG0 */
++#define DIGITAL_DERESET			BIT(3)
++#define ANALOG_DERESET			BIT(2)
++#define DIGITAL_RESET			(0 << 3)
++#define ANALOG_RESET			(0 << 2)
++
++/* PHY_REG1 */
++#define PHY_DDR2			(0)
++#define PHY_LPDDR2			(1)
++#define PHY_DDR3			(2)
++#define PHY_LPDDR3			(3)
++#define PHY_DDR4			(4)
++#define PHY_BL_4			(0 << 2)
++#define PHY_BL_8			BIT(2)
++
++/* PHY_REG2 */
++#define PHY_DTT_EN			BIT(0)
++#define PHY_DTT_DISB			(0 << 0)
++#define PHY_WRITE_LEVELING_EN		BIT(2)
++#define PHY_WRITE_LEVELING_DISB		(0 << 2)
++#define PHY_SELECT_CS0			(2)
++#define PHY_SELECT_CS1			(1)
++#define PHY_SELECT_CS0_1		(0)
++#define PHY_WRITE_LEVELING_SELECTCS(n)	((n) << 6)
++#define PHY_DATA_TRAINING_SELECTCS(n)	((n) << 4)
++
++struct ddr_phy_skew {
++	u32 a0_a1_skew[15];
++	u32 cs0_dm0_skew[11];
++	u32 cs0_dm1_skew[11];
++	u32 cs0_dm2_skew[11];
++	u32 cs0_dm3_skew[11];
++	u32 cs1_dm0_skew[11];
++	u32 cs1_dm1_skew[11];
++	u32 cs1_dm2_skew[11];
++	u32 cs1_dm3_skew[11];
++};
++
++#define SR_IDLE				93
++#define PD_IDLE				13
++
++/* PMUGRF */
++#define PMUGRF_OS_REG0			(0x200)
++#define PMUGRF_OS_REG(n)		(PMUGRF_OS_REG0 + (n) * 4)
++
++/* DDR GRF */
++#define DDR_GRF_CON(n)			(0 + (n) * 4)
++#define DDR_GRF_STATUS_BASE		(0X100)
++#define DDR_GRF_STATUS(n)		(DDR_GRF_STATUS_BASE + (n) * 4)
++#define DDR_GRF_LP_CON			(0x20)
++
++#define SPLIT_MODE_32_L16_VALID		(0)
++#define SPLIT_MODE_32_H16_VALID		(1)
++#define SPLIT_MODE_16_L8_VALID		(2)
++#define SPLIT_MODE_16_H8_VALID		(3)
++
++#define DDR_GRF_SPLIT_CON		(0x8)
++#define SPLIT_MODE_MASK			(0x3)
++#define SPLIT_MODE_OFFSET		(9)
++#define SPLIT_BYPASS_MASK		(1)
++#define SPLIT_BYPASS_OFFSET		(8)
++#define SPLIT_SIZE_MASK			(0xff)
++#define SPLIT_SIZE_OFFSET		(0)
++
++/* CRU define */
++/* CRU_PLL_CON0 */
++#define PB(n)				((0x1 << (15 + 16)) | ((n) << 15))
++#define POSTDIV1(n)			((0x7 << (12 + 16)) | ((n) << 12))
++#define FBDIV(n)			((0xFFF << 16) | (n))
++
++/* CRU_PLL_CON1 */
++#define RSTMODE(n)			((0x1 << (15 + 16)) | ((n) << 15))
++#define RST(n)				((0x1 << (14 + 16)) | ((n) << 14))
++#define PD(n)				((0x1 << (13 + 16)) | ((n) << 13))
++#define DSMPD(n)			((0x1 << (12 + 16)) | ((n) << 12))
++#define LOCK(n)				(((n) >> 10) & 0x1)
++#define POSTDIV2(n)			((0x7 << (6 + 16)) | ((n) << 6))
++#define REFDIV(n)			((0x3F << 16) | (n))
++
++/* CRU_MODE */
++#define CLOCK_FROM_XIN_OSC		(0)
++#define CLOCK_FROM_PLL			(1)
++#define CLOCK_FROM_RTC_32K		(2)
++#define DPLL_MODE(n)			((0x3 << (4 + 16)) | ((n) << 4))
++
++/* CRU_SOFTRESET_CON1 */
++#define upctl2_psrstn_req(n)		(((0x1 << 6) << 16) | ((n) << 6))
++#define upctl2_asrstn_req(n)		(((0x1 << 5) << 16) | ((n) << 5))
++#define upctl2_srstn_req(n)		(((0x1 << 4) << 16) | ((n) << 4))
++
++/* CRU_SOFTRESET_CON2 */
++#define ddrphy_psrstn_req(n)		(((0x1 << 2) << 16) | ((n) << 2))
++#define ddrphy_srstn_req(n)		(((0x1 << 0) << 16) | ((n) << 0))
++
++/* CRU register */
++#define CRU_PLL_CON(pll_id, n)		((pll_id)  * 0x20 + (n) * 4)
++#define CRU_MODE			(0xa0)
++#define CRU_GLB_CNT_TH			(0xb0)
++#define CRU_CLKSEL_CON_BASE		0x100
++#define CRU_CLKSELS_CON(i)		(CRU_CLKSEL_CON_BASE + ((i) * 4))
++#define CRU_CLKGATE_CON_BASE		0x200
++#define CRU_CLKGATE_CON(i)		(CRU_CLKGATE_CON_BASE + ((i) * 4))
++#define CRU_CLKSFTRST_CON_BASE		0x300
++#define CRU_CLKSFTRST_CON(i)		(CRU_CLKSFTRST_CON_BASE + ((i) * 4))
++
++struct px30_ddr_grf_regs {
++	u32 ddr_grf_con[4];
++	u32 reserved1[(0x20 - 0x10) / 4];
++	u32 ddr_grf_lp_con;
++	u32 reserved2[(0x100 - 0x24) / 4];
++	u32 ddr_grf_status[11];
++};
++
++struct px30_msch_timings {
++	u32 ddrtiminga0;
++	u32 ddrtimingb0;
++	u32 ddrtimingc0;
++	u32 devtodev0;
++	u32 ddrmode;
++	u32 ddr4timing;
++	u32 agingx0;
++};
++
++struct px30_sdram_channel {
++	unsigned int rank;
++	unsigned int col;
++	/* 3:8bank, 2:4bank */
++	unsigned int bk;
++	/* channel buswidth, 2:32bit, 1:16bit, 0:8bit */
++	unsigned int bw;
++	/* die buswidth, 2:32bit, 1:16bit, 0:8bit */
++	unsigned int dbw;
++	unsigned int row_3_4;
++	unsigned int cs0_row;
++	unsigned int cs1_row;
++	unsigned int cs0_high16bit_row;
++	unsigned int cs1_high16bit_row;
++	unsigned int ddrconfig;
++	struct px30_msch_timings noc_timings;
++};
++
++struct px30_base_params {
++	unsigned int ddr_freq;
++	unsigned int dramtype;
++	unsigned int num_channels;
++	unsigned int stride;
++	unsigned int odt;
++};
++
++struct px30_sdram_params {
++	struct px30_sdram_channel ch;
++	struct px30_base_params base;
++	struct ddr_pctl_regs pctl_regs;
++	struct ddr_phy_regs phy_regs;
++	struct ddr_phy_skew *skew;
++};
++
++struct px30_msch_regs {
++	u32 coreid;
++	u32 revisionid;
++	u32 deviceconf;
++	u32 devicesize;
++	u32 ddrtiminga0;
++	u32 ddrtimingb0;
++	u32 ddrtimingc0;
++	u32 devtodev0;
++	u32 reserved1[(0x110 - 0x20) / 4];
++	u32 ddrmode;
++	u32 ddr4timing;
++	u32 reserved2[(0x1000 - 0x118) / 4];
++	u32 agingx0;
++	u32 reserved3[(0x1040 - 0x1004) / 4];
++	u32 aging0;
++	u32 aging1;
++	u32 aging2;
++	u32 aging3;
++};
++
++int sdram_init(void);
++
++#endif
+diff --git a/arch/arm/mach-rockchip/Kconfig b/arch/arm/mach-rockchip/Kconfig
+index f5a80b4f0c..116b40a3c5 100644
+--- a/arch/arm/mach-rockchip/Kconfig
++++ b/arch/arm/mach-rockchip/Kconfig
+@@ -1,5 +1,27 @@
+ if ARCH_ROCKCHIP
+ 
++config ROCKCHIP_PX30
++	bool "Support Rockchip PX30"
++	select ARM64
++	select SUPPORT_SPL
++	select SUPPORT_TPL
++	select SPL
++	select TPL
++	select TPL_TINY_FRAMEWORK if TPL
++	select TPL_NEEDS_SEPARATE_TEXT_BASE if SPL
++	select TPL_NEEDS_SEPARATE_STACK if TPL
++	imply SPL_SEPARATE_BSS
++	select SPL_SERIAL_SUPPORT
++	select TPL_SERIAL_SUPPORT
++	select DEBUG_UART_BOARD_INIT
++	imply ROCKCHIP_COMMON_BOARD
++	imply SPL_ROCKCHIP_COMMON_BOARD
++	help
++	  The Rockchip PX30 is a ARM-based SoC with a quad-core Cortex-A35
++	  including NEON and GPU, Mali-400 graphics, several DDR3 options
++	  and video codec support. Peripherals include Gigabit Ethernet,
++	  USB2 host and OTG, SDIO, I2S, UART, SPI, I2C and PWMs.
++
+ config ROCKCHIP_RK3036
+ 	bool "Support Rockchip RK3036"
+ 	select CPU_V7A
+@@ -315,6 +337,7 @@ config TPL_ROCKCHIP_EARLYRETURN_TO_BROM
+ config SPL_MMC_SUPPORT
+ 	default y if !SPL_ROCKCHIP_BACK_TO_BROM
+ 
++source "arch/arm/mach-rockchip/px30/Kconfig"
+ source "arch/arm/mach-rockchip/rk3036/Kconfig"
+ source "arch/arm/mach-rockchip/rk3128/Kconfig"
+ source "arch/arm/mach-rockchip/rk3188/Kconfig"
+diff --git a/arch/arm/mach-rockchip/Makefile b/arch/arm/mach-rockchip/Makefile
+index 45d9b06233..ddff566dee 100644
+--- a/arch/arm/mach-rockchip/Makefile
++++ b/arch/arm/mach-rockchip/Makefile
+@@ -11,6 +11,7 @@ obj-spl-$(CONFIG_ROCKCHIP_BROM_HELPER) += bootrom.o
+ obj-spl-$(CONFIG_SPL_ROCKCHIP_COMMON_BOARD) += spl.o spl-boot-order.o
+ obj-tpl-$(CONFIG_ROCKCHIP_BROM_HELPER) += bootrom.o
+ obj-tpl-$(CONFIG_TPL_ROCKCHIP_COMMON_BOARD) += tpl.o
++obj-tpl-$(CONFIG_ROCKCHIP_PX30) += px30-board-tpl.o
+ 
+ obj-spl-$(CONFIG_ROCKCHIP_RK3036) += rk3036-board-spl.o
+ 
+@@ -27,6 +28,7 @@ endif
+ 
+ obj-$(CONFIG_$(SPL_TPL_)RAM) += sdram_common.o
+ 
++obj-$(CONFIG_ROCKCHIP_PX30) += px30/
+ obj-$(CONFIG_ROCKCHIP_RK3036) += rk3036/
+ obj-$(CONFIG_ROCKCHIP_RK3128) += rk3128/
+ obj-$(CONFIG_ROCKCHIP_RK3188) += rk3188/
+diff --git a/arch/arm/mach-rockchip/px30-board-tpl.c b/arch/arm/mach-rockchip/px30-board-tpl.c
+new file mode 100644
+index 0000000000..8c8976f61c
+--- /dev/null
++++ b/arch/arm/mach-rockchip/px30-board-tpl.c
+@@ -0,0 +1,59 @@
++// SPDX-License-Identifier: GPL-2.0+
++/*
++ * (C) Copyright 2019 Rockchip Electronics Co., Ltd
++ */
++
++#include <common.h>
++#include <debug_uart.h>
++#include <dm.h>
++#include <ram.h>
++#include <spl.h>
++#include <version.h>
++#include <asm/io.h>
++#include <asm/arch-rockchip/bootrom.h>
++#include <asm/arch-rockchip/sdram_px30.h>
++
++#define TIMER_LOAD_COUNT0	0x00
++#define TIMER_LOAD_COUNT1	0x04
++#define TIMER_CUR_VALUE0	0x08
++#define TIMER_CUR_VALUE1	0x0c
++#define TIMER_CONTROL_REG	0x10
++
++#define TIMER_EN	0x1
++#define	TIMER_FMODE	(0 << 1)
++#define	TIMER_RMODE	(1 << 1)
++
++void secure_timer_init(void)
++{
++	writel(0, CONFIG_ROCKCHIP_STIMER_BASE + TIMER_CONTROL_REG);
++	writel(0xffffffff, CONFIG_ROCKCHIP_STIMER_BASE + TIMER_LOAD_COUNT0);
++	writel(0xffffffff, CONFIG_ROCKCHIP_STIMER_BASE + TIMER_LOAD_COUNT1);
++	writel(TIMER_EN | TIMER_FMODE,
++	       CONFIG_ROCKCHIP_STIMER_BASE + TIMER_CONTROL_REG);
++}
++
++void board_init_f(ulong dummy)
++{
++	int ret;
++
++#ifdef CONFIG_DEBUG_UART
++	debug_uart_init();
++	/*
++	 * Debug UART can be used from here if required:
++	 *
++	 * debug_uart_init();
++	 * printch('a');
++	 * printhex8(0x1234);
++	 * printascii("string");
++	 */
++	printascii("U-Boot TPL board init\n");
++#endif
++
++	secure_timer_init();
++	ret = sdram_init();
++	if (ret)
++		printascii("sdram_init failed\n");
++
++	/* return to maskrom */
++	back_to_bootrom(BROM_BOOT_NEXTSTAGE);
++}
+diff --git a/arch/arm/mach-rockchip/px30/Kconfig b/arch/arm/mach-rockchip/px30/Kconfig
+new file mode 100644
+index 0000000000..ef04afca8d
+--- /dev/null
++++ b/arch/arm/mach-rockchip/px30/Kconfig
+@@ -0,0 +1,48 @@
++if ROCKCHIP_PX30
++
++config TARGET_EVB_PX30
++	bool "EVB_PX30"
++
++config ROCKCHIP_BOOT_MODE_REG
++	default 0xff010200
++
++config SYS_SOC
++	default "px30"
++
++config SYS_MALLOC_F_LEN
++	default 0x400
++
++config SPL_SERIAL_SUPPORT
++	default y
++
++config TPL_LDSCRIPT
++	default "arch/arm/mach-rockchip/u-boot-tpl-v8.lds"
++
++config TPL_TEXT_BASE
++	default 0xff0e1000
++
++config TPL_MAX_SIZE
++	default 10240
++
++config TPL_STACK
++	default 0xff0e4fff
++
++config ROCKCHIP_RK3326
++	bool "Support Rockchip RK3326 "
++	help
++	  RK3326 can use most code from PX30, but at some situations we have
++	  to distinguish between RK3326 and PX30, so this macro gives help.
++	  It is usually selected in rk3326 board defconfig.
++
++config DEBUG_UART2_CHANNEL
++	int "Mux channel to use for debug UART2"
++	depends on DEBUG_UART_BOARD_INIT
++	default 0
++	help
++	  UART2 can use two different set of pins to route the output.
++	  For using the UART for early debugging the route to use needs
++	  to be declared (0 or 1).
++
++source "board/rockchip/evb_px30/Kconfig"
++
++endif
+diff --git a/arch/arm/mach-rockchip/px30/Makefile b/arch/arm/mach-rockchip/px30/Makefile
+new file mode 100644
+index 0000000000..6d0742bcab
+--- /dev/null
++++ b/arch/arm/mach-rockchip/px30/Makefile
+@@ -0,0 +1,14 @@
++#
++# (C) Copyright 2017 Rockchip Electronics Co., Ltd.
++#
++# SPDX-License-Identifier:     GPL-2.0+
++#
++
++obj-y += clk_px30.o
++
++ifndef CONFIG_TPL_BUILD
++obj-y += syscon_px30.o
++endif
++
++obj-y += px30.o
++obj-y += sdram_px30.o
+diff --git a/arch/arm/mach-rockchip/px30/clk_px30.c b/arch/arm/mach-rockchip/px30/clk_px30.c
+new file mode 100644
+index 0000000000..0bd6b471da
+--- /dev/null
++++ b/arch/arm/mach-rockchip/px30/clk_px30.c
+@@ -0,0 +1,31 @@
++// SPDX-License-Identifier: GPL-2.0
++/*
++ * (C) Copyright 2017 Rockchip Electronics Co., Ltd.
++ */
++
++#include <common.h>
++#include <dm.h>
++#include <syscon.h>
++#include <asm/arch-rockchip/clock.h>
++#include <asm/arch-rockchip/cru_px30.h>
++
++int rockchip_get_clk(struct udevice **devp)
++{
++	return uclass_get_device_by_driver(UCLASS_CLK,
++			DM_GET_DRIVER(rockchip_px30_cru), devp);
++}
++
++void *rockchip_get_cru(void)
++{
++	struct px30_clk_priv *priv;
++	struct udevice *dev;
++	int ret;
++
++	ret = rockchip_get_clk(&dev);
++	if (ret)
++		return ERR_PTR(ret);
++
++	priv = dev_get_priv(dev);
++
++	return priv->cru;
++}
+diff --git a/arch/arm/mach-rockchip/px30/px30.c b/arch/arm/mach-rockchip/px30/px30.c
+new file mode 100644
+index 0000000000..7cd2292fe2
+--- /dev/null
++++ b/arch/arm/mach-rockchip/px30/px30.c
+@@ -0,0 +1,248 @@
++// SPDX-License-Identifier: GPL-2.0
++/*
++ * Copyright (c) 2017 Rockchip Electronics Co., Ltd
++ */
++#include <common.h>
++#include <clk.h>
++#include <dm.h>
++#include <asm/armv8/mmu.h>
++#include <asm/io.h>
++#include <asm/arch-rockchip/grf_px30.h>
++#include <asm/arch-rockchip/hardware.h>
++#include <asm/arch-rockchip/uart.h>
++#include <asm/arch-rockchip/clock.h>
++#include <asm/arch-rockchip/cru_px30.h>
++#include <dt-bindings/clock/px30-cru.h>
++
++static struct mm_region px30_mem_map[] = {
++	{
++		.virt = 0x0UL,
++		.phys = 0x0UL,
++		.size = 0xff000000UL,
++		.attrs = PTE_BLOCK_MEMTYPE(MT_NORMAL) |
++			 PTE_BLOCK_INNER_SHARE
++	}, {
++		.virt = 0xff000000UL,
++		.phys = 0xff000000UL,
++		.size = 0x01000000UL,
++		.attrs = PTE_BLOCK_MEMTYPE(MT_DEVICE_NGNRNE) |
++			 PTE_BLOCK_NON_SHARE |
++			 PTE_BLOCK_PXN | PTE_BLOCK_UXN
++	}, {
++		/* List terminator */
++		0,
++	}
++};
++
++struct mm_region *mem_map = px30_mem_map;
++
++#define PMU_PWRDN_CON			0xff000018
++#define GRF_BASE			0xff140000
++#define CRU_BASE			0xff2b0000
++#define VIDEO_PHY_BASE			0xff2e0000
++#define SERVICE_CORE_ADDR		0xff508000
++#define DDR_FW_BASE			0xff534000
++
++#define FW_DDR_CON			0x40
++
++#define QOS_PRIORITY			0x08
++
++#define QOS_PRIORITY_LEVEL(h, l)	((((h) & 3) << 8) | ((l) & 3))
++
++/* GRF_GPIO1CL_IOMUX */
++enum {
++	GPIO1C1_SHIFT		= 4,
++	GPIO1C1_MASK		= 0xf << GPIO1C1_SHIFT,
++	GPIO1C1_GPIO		= 0,
++	GPIO1C1_UART1_TX,
++
++	GPIO1C0_SHIFT		= 0,
++	GPIO1C0_MASK		= 0xf << GPIO1C0_SHIFT,
++	GPIO1C0_GPIO		= 0,
++	GPIO1C0_UART1_RX,
++};
++
++/* GRF_GPIO1DL_IOMUX */
++enum {
++	GPIO1D3_SHIFT		= 12,
++	GPIO1D3_MASK		= 0xf << GPIO1D3_SHIFT,
++	GPIO1D3_GPIO		= 0,
++	GPIO1D3_SDMMC_D1,
++	GPIO1D3_UART2_RXM0,
++
++	GPIO1D2_SHIFT		= 8,
++	GPIO1D2_MASK		= 0xf << GPIO1D2_SHIFT,
++	GPIO1D2_GPIO		= 0,
++	GPIO1D2_SDMMC_D0,
++	GPIO1D2_UART2_TXM0,
++};
++
++/* GRF_GPIO1DH_IOMUX */
++enum {
++	GPIO1D7_SHIFT		= 12,
++	GPIO1D7_MASK		= 0xf << GPIO1D7_SHIFT,
++	GPIO1D7_GPIO		= 0,
++	GPIO1D7_SDMMC_CMD,
++
++	GPIO1D6_SHIFT		= 8,
++	GPIO1D6_MASK		= 0xf << GPIO1D6_SHIFT,
++	GPIO1D6_GPIO		= 0,
++	GPIO1D6_SDMMC_CLK,
++
++	GPIO1D5_SHIFT		= 4,
++	GPIO1D5_MASK		= 0xf << GPIO1D5_SHIFT,
++	GPIO1D5_GPIO		= 0,
++	GPIO1D5_SDMMC_D3,
++
++	GPIO1D4_SHIFT		= 0,
++	GPIO1D4_MASK		= 0xf << GPIO1D4_SHIFT,
++	GPIO1D4_GPIO		= 0,
++	GPIO1D4_SDMMC_D2,
++};
++
++/* GRF_GPIO2BH_IOMUX */
++enum {
++	GPIO2B6_SHIFT		= 8,
++	GPIO2B6_MASK		= 0xf << GPIO2B6_SHIFT,
++	GPIO2B6_GPIO		= 0,
++	GPIO2B6_CIF_D1M0,
++	GPIO2B6_UART2_RXM1,
++
++	GPIO2B4_SHIFT		= 0,
++	GPIO2B4_MASK		= 0xf << GPIO2B4_SHIFT,
++	GPIO2B4_GPIO		= 0,
++	GPIO2B4_CIF_D0M0,
++	GPIO2B4_UART2_TXM1,
++};
++
++/* GRF_GPIO3AL_IOMUX */
++enum {
++	GPIO3A2_SHIFT		= 8,
++	GPIO3A2_MASK		= 0xf << GPIO3A2_SHIFT,
++	GPIO3A2_GPIO		= 0,
++	GPIO3A2_UART5_TX	= 4,
++
++	GPIO3A1_SHIFT		= 4,
++	GPIO3A1_MASK		= 0xf << GPIO3A1_SHIFT,
++	GPIO3A1_GPIO		= 0,
++	GPIO3A1_UART5_RX	= 4,
++};
++
++int arch_cpu_init(void)
++{
++	static struct px30_grf * const grf = (void *)GRF_BASE;
++	u32 __maybe_unused val;
++
++#ifdef CONFIG_SPL_BUILD
++	/* We do some SoC one time setting here. */
++	/* Disable the ddr secure region setting to make it non-secure */
++	writel(0x0, DDR_FW_BASE + FW_DDR_CON);
++
++	/* Set cpu qos priority */
++	writel(QOS_PRIORITY_LEVEL(1, 1), SERVICE_CORE_ADDR + QOS_PRIORITY);
++
++#if !defined(CONFIG_DEBUG_UART_BOARD_INIT) || \
++    (CONFIG_DEBUG_UART_BASE != 0xff160000) || \
++    (CONFIG_DEBUG_UART_CHANNEL != 0)
++	/* fix sdmmc pinmux if not using uart2-channel0 as debug uart */
++	rk_clrsetreg(&grf->gpio1dl_iomux,
++		     GPIO1D3_MASK | GPIO1D2_MASK,
++		     GPIO1D3_SDMMC_D1 << GPIO1D3_SHIFT |
++		     GPIO1D2_SDMMC_D0 << GPIO1D2_SHIFT);
++	rk_clrsetreg(&grf->gpio1dh_iomux,
++		     GPIO1D7_MASK | GPIO1D6_MASK | GPIO1D5_MASK | GPIO1D4_MASK,
++		     GPIO1D7_SDMMC_CMD << GPIO1D7_SHIFT |
++		     GPIO1D6_SDMMC_CLK << GPIO1D6_SHIFT |
++		     GPIO1D5_SDMMC_D3 << GPIO1D5_SHIFT |
++		     GPIO1D4_SDMMC_D2 << GPIO1D4_SHIFT);
++#endif
++
++#endif
++
++	/* Enable PD_VO (default disable at reset) */
++	rk_clrreg(PMU_PWRDN_CON, 1 << 13);
++
++	/* Disable video phy bandgap by default */
++	writel(0x82, VIDEO_PHY_BASE + 0x0000);
++	writel(0x05, VIDEO_PHY_BASE + 0x03ac);
++
++	/* Clear the force_jtag */
++	rk_clrreg(&grf->cpu_con[1], 1 << 7);
++
++	return 0;
++}
++
++#ifdef CONFIG_DEBUG_UART_BOARD_INIT
++void board_debug_uart_init(void)
++{
++	static struct px30_grf * const grf = (void *)GRF_BASE;
++	static struct px30_cru * const cru = (void *)CRU_BASE;
++
++#if defined(CONFIG_DEBUG_UART_BASE) && (CONFIG_DEBUG_UART_BASE == 0xff158000)
++	/* uart_sel_clk default select 24MHz */
++	rk_clrsetreg(&cru->clksel_con[34],
++		     UART1_PLL_SEL_MASK | UART1_DIV_CON_MASK,
++		     UART1_PLL_SEL_24M << UART1_PLL_SEL_SHIFT | 0);
++	rk_clrsetreg(&cru->clksel_con[35],
++		     UART1_CLK_SEL_MASK,
++		     UART1_CLK_SEL_UART1 << UART1_CLK_SEL_SHIFT);
++
++	rk_clrsetreg(&grf->gpio1cl_iomux,
++		     GPIO1C1_MASK | GPIO1C0_MASK,
++		     GPIO1C1_UART1_TX << GPIO1C1_SHIFT |
++		     GPIO1C0_UART1_RX << GPIO1C0_SHIFT);
++#elif defined(CONFIG_DEBUG_UART_BASE) && (CONFIG_DEBUG_UART_BASE == 0xff178000)
++	/* uart_sel_clk default select 24MHz */
++	rk_clrsetreg(&cru->clksel_con[46],
++		     UART5_PLL_SEL_MASK | UART5_DIV_CON_MASK,
++		     UART5_PLL_SEL_24M << UART5_PLL_SEL_SHIFT | 0);
++	rk_clrsetreg(&cru->clksel_con[47],
++		     UART5_CLK_SEL_MASK,
++		     UART5_CLK_SEL_UART5 << UART5_CLK_SEL_SHIFT);
++
++	rk_clrsetreg(&grf->gpio3al_iomux,
++		     GPIO3A2_MASK | GPIO3A1_MASK,
++		     GPIO3A2_UART5_TX << GPIO3A2_SHIFT |
++		     GPIO3A1_UART5_RX << GPIO3A1_SHIFT);
++#else
++	/* GRF_IOFUNC_CON0 */
++	enum {
++		CON_IOMUX_UART2SEL_SHIFT	= 10,
++		CON_IOMUX_UART2SEL_MASK = 3 << CON_IOMUX_UART2SEL_SHIFT,
++		CON_IOMUX_UART2SEL_M0	= 0,
++		CON_IOMUX_UART2SEL_M1,
++		CON_IOMUX_UART2SEL_USBPHY,
++	};
++
++	/* uart_sel_clk default select 24MHz */
++	rk_clrsetreg(&cru->clksel_con[37],
++		     UART2_PLL_SEL_MASK | UART2_DIV_CON_MASK,
++		     UART2_PLL_SEL_24M << UART2_PLL_SEL_SHIFT | 0);
++	rk_clrsetreg(&cru->clksel_con[38],
++		     UART2_CLK_SEL_MASK,
++		     UART2_CLK_SEL_UART2 << UART2_CLK_SEL_SHIFT);
++
++#if (CONFIG_DEBUG_UART2_CHANNEL == 1)
++	/* Enable early UART2 */
++	rk_clrsetreg(&grf->iofunc_con0,
++		     CON_IOMUX_UART2SEL_MASK,
++		     CON_IOMUX_UART2SEL_M1 << CON_IOMUX_UART2SEL_SHIFT);
++
++	rk_clrsetreg(&grf->gpio2bh_iomux,
++		     GPIO2B6_MASK | GPIO2B4_MASK,
++		     GPIO2B6_UART2_RXM1 << GPIO2B6_SHIFT |
++		     GPIO2B4_UART2_TXM1 << GPIO2B4_SHIFT);
++#else
++	rk_clrsetreg(&grf->iofunc_con0,
++		     CON_IOMUX_UART2SEL_MASK,
++		     CON_IOMUX_UART2SEL_M0 << CON_IOMUX_UART2SEL_SHIFT);
++
++	rk_clrsetreg(&grf->gpio1dl_iomux,
++		     GPIO1D3_MASK | GPIO1D2_MASK,
++		     GPIO1D3_UART2_RXM0 << GPIO1D3_SHIFT |
++		     GPIO1D2_UART2_TXM0 << GPIO1D2_SHIFT);
++#endif /* CONFIG_DEBUG_UART2_CHANNEL == 1 */
++
++#endif /* CONFIG_DEBUG_UART_BASE && CONFIG_DEBUG_UART_BASE == ... */
++}
++#endif /* CONFIG_DEBUG_UART_BOARD_INIT */
+diff --git a/arch/arm/mach-rockchip/px30/sdram-px30-ddr3-detect-333.inc b/arch/arm/mach-rockchip/px30/sdram-px30-ddr3-detect-333.inc
+new file mode 100644
+index 0000000000..e17b2ed86c
+--- /dev/null
++++ b/arch/arm/mach-rockchip/px30/sdram-px30-ddr3-detect-333.inc
+@@ -0,0 +1,70 @@
++{
++	{
++		.rank = 0x1,
++		.col = 0xC,
++		.bk = 0x3,
++		.bw = 0x1,
++		.dbw = 0x0,
++		.row_3_4 = 0x0,
++		.cs0_row = 0x10,
++		.cs1_row = 0x10,
++		.cs0_high16bit_row = 0x10,
++		.cs1_high16bit_row = 0x10,
++		.ddrconfig = 0,
++		{
++			0x290b0609,
++			0x08020401,
++			0x00000002,
++			0x00001111,
++			0x0000000c,
++			0x00000222,
++			0x000000ff
++		}
++	},
++	{
++		.ddr_freq = 333,
++		.dramtype = DDR3,
++		.num_channels = 1,
++		.stride = 0,
++		.odt = 0,
++	},
++	{
++		{
++			{0x00000000, 0x43041001},	/* MSTR */
++			{0x00000064, 0x0028003b},	/* RFSHTMG */
++			{0x000000d0, 0x00020053},	/* INIT0 */
++			{0x000000d4, 0x00020000},	/* INIT1 */
++			{0x000000d8, 0x00000100},	/* INIT2 */
++			{0x000000dc, 0x03200000},	/* INIT3 */
++			{0x000000e0, 0x00000000},	/* INIT4 */
++			{0x000000e4, 0x00090000},	/* INIT5 */
++			{0x000000f4, 0x000f012f},	/* RANKCTL */
++			{0x00000100, 0x07090b06},	/* DRAMTMG0 */
++			{0x00000104, 0x00050209},	/* DRAMTMG1 */
++			{0x00000108, 0x03030407},	/* DRAMTMG2 */
++			{0x0000010c, 0x00202006},	/* DRAMTMG3 */
++			{0x00000110, 0x03020204},	/* DRAMTMG4 */
++			{0x00000114, 0x03030202},	/* DRAMTMG5 */
++			{0x00000120, 0x00000903},	/* DRAMTMG8 */
++			{0x00000180, 0x00800020},	/* ZQCTL0 */
++			{0x00000184, 0x00000000},	/* ZQCTL1 */
++			{0x00000190, 0x07010001},	/* DFITMG0 */
++			{0x00000198, 0x07000101},	/* DFILPCFG0 */
++			{0x000001a0, 0xc0400003},	/* DFIUPD0 */
++			{0x00000240, 0x06000604},	/* ODTCFG */
++			{0x00000244, 0x00000201},	/* ODTMAP */
++			{0x00000250, 0x00001f00},	/* SCHED */
++			{0x00000490, 0x00000001},	/* PCTRL_0 */
++			{0xffffffff, 0xffffffff}
++		}
++	},
++	{
++		{
++			{0x00000004, 0x0000000a},	/* PHYREG01 */
++			{0x00000028, 0x00000006},	/* PHYREG0A */
++			{0x0000002c, 0x00000000},	/* PHYREG0B */
++			{0x00000030, 0x00000005},	/* PHYREG0C */
++			{0xffffffff, 0xffffffff}
++		}
++	}
++},
+diff --git a/arch/arm/mach-rockchip/px30/sdram-px30-ddr4-detect-333.inc b/arch/arm/mach-rockchip/px30/sdram-px30-ddr4-detect-333.inc
+new file mode 100644
+index 0000000000..cdc417405a
+--- /dev/null
++++ b/arch/arm/mach-rockchip/px30/sdram-px30-ddr4-detect-333.inc
+@@ -0,0 +1,73 @@
++{
++	{
++		.rank = 0x1,
++		.col = 0xA,
++		.bk = 0x2,
++		.bw = 0x1,
++		.dbw = 0x0,
++		.row_3_4 = 0x0,
++		.cs0_row = 0x11,
++		.cs1_row = 0x0,
++		.cs0_high16bit_row = 0x11,
++		.cs1_high16bit_row = 0x0,
++		.ddrconfig = 0,
++		{
++			0x4d110a08,
++			0x06020501,
++			0x00000002,
++			0x00001111,
++			0x0000000c,
++			0x0000022a,
++			0x000000ff
++		}
++	},
++	{
++		.ddr_freq = 333,
++		.dramtype = DDR4,
++		.num_channels = 1,
++		.stride = 0,
++		.odt = 0,
++	},
++	{
++		{
++			{0x00000000, 0x43049010},	/* MSTR */
++			{0x00000064, 0x0028003b},	/* RFSHTMG */
++			{0x000000d0, 0x00020053},	/* INIT0 */
++			{0x000000d4, 0x00220000},	/* INIT1 */
++			{0x000000d8, 0x00000100},	/* INIT2 */
++			{0x000000dc, 0x00040000},	/* INIT3 */
++			{0x000000e0, 0x00000000},	/* INIT4 */
++			{0x000000e4, 0x00110000},	/* INIT5 */
++			{0x000000e8, 0x00000420},	/* INIT6 */
++			{0x000000ec, 0x00000400},	/* INIT7 */
++			{0x000000f4, 0x000f012f},	/* RANKCTL */
++			{0x00000100, 0x09060b06},	/* DRAMTMG0 */
++			{0x00000104, 0x00020209},	/* DRAMTMG1 */
++			{0x00000108, 0x0505040a},	/* DRAMTMG2 */
++			{0x0000010c, 0x0040400c},	/* DRAMTMG3 */
++			{0x00000110, 0x05030206},	/* DRAMTMG4 */
++			{0x00000114, 0x03030202},	/* DRAMTMG5 */
++			{0x00000120, 0x03030b03},	/* DRAMTMG8 */
++			{0x00000124, 0x00020208},	/* DRAMTMG9 */
++			{0x00000180, 0x01000040},	/* ZQCTL0 */
++			{0x00000184, 0x00000000},	/* ZQCTL1 */
++			{0x00000190, 0x07030003},	/* DFITMG0 */
++			{0x00000198, 0x07000101},	/* DFILPCFG0 */
++			{0x000001a0, 0xc0400003},	/* DFIUPD0 */
++			{0x00000240, 0x06000604},	/* ODTCFG */
++			{0x00000244, 0x00000201},	/* ODTMAP */
++			{0x00000250, 0x00001f00},	/* SCHED */
++			{0x00000490, 0x00000001},	/* PCTRL_0 */
++			{0xffffffff, 0xffffffff}
++		}
++	},
++	{
++		{
++			{0x00000004, 0x0000000c},	/* PHYREG01 */
++			{0x00000028, 0x0000000a},	/* PHYREG0A */
++			{0x0000002c, 0x00000000},	/* PHYREG0B */
++			{0x00000030, 0x00000009},	/* PHYREG0C */
++			{0xffffffff, 0xffffffff}
++		}
++	}
++},
+\ No newline at end of file
+diff --git a/arch/arm/mach-rockchip/px30/sdram-px30-ddr_skew.inc b/arch/arm/mach-rockchip/px30/sdram-px30-ddr_skew.inc
+new file mode 100644
+index 0000000000..f24343dda1
+--- /dev/null
++++ b/arch/arm/mach-rockchip/px30/sdram-px30-ddr_skew.inc
+@@ -0,0 +1,121 @@
++		{
++			0x77,
++			0x88,
++			0x79,
++			0x79,
++			0x87,
++			0x97,
++			0x87,
++			0x78,
++			0x77,
++			0x78,
++			0x87,
++			0x88,
++			0x87,
++			0x87,
++			0x77
++		},
++		{
++			0x78,
++			0x78,
++			0x78,
++			0x78,
++			0x78,
++			0x78,
++			0x78,
++			0x78,
++			0x78,
++			0x69,
++			0x9,
++		},
++		{
++			0x77,
++			0x78,
++			0x77,
++			0x78,
++			0x77,
++			0x78,
++			0x77,
++			0x78,
++			0x77,
++			0x79,
++			0x9,
++		},
++		{
++			0x78,
++			0x78,
++			0x78,
++			0x78,
++			0x78,
++			0x78,
++			0x78,
++			0x78,
++			0x78,
++			0x69,
++			0x9,
++		},
++		{
++			0x77,
++			0x78,
++			0x77,
++			0x77,
++			0x77,
++			0x77,
++			0x77,
++			0x77,
++			0x77,
++			0x79,
++			0x9,
++		},
++		{
++			0x78,
++			0x78,
++			0x78,
++			0x78,
++			0x78,
++			0x78,
++			0x78,
++			0x78,
++			0x78,
++			0x69,
++			0x9,
++		},
++		{
++			0x77,
++			0x78,
++			0x77,
++			0x78,
++			0x77,
++			0x78,
++			0x77,
++			0x78,
++			0x77,
++			0x79,
++			0x9,
++		},
++		{
++			0x78,
++			0x78,
++			0x78,
++			0x78,
++			0x78,
++			0x78,
++			0x78,
++			0x78,
++			0x78,
++			0x69,
++			0x9,
++		},
++		{
++			0x77,
++			0x78,
++			0x77,
++			0x77,
++			0x77,
++			0x77,
++			0x77,
++			0x77,
++			0x77,
++			0x79,
++			0x9,
++		}
+diff --git a/arch/arm/mach-rockchip/px30/sdram-px30-lpddr2-detect-333.inc b/arch/arm/mach-rockchip/px30/sdram-px30-lpddr2-detect-333.inc
+new file mode 100644
+index 0000000000..3bde062d62
+--- /dev/null
++++ b/arch/arm/mach-rockchip/px30/sdram-px30-lpddr2-detect-333.inc
+@@ -0,0 +1,71 @@
++{
++	{
++		.rank = 0x1,
++		.col = 0xC,
++		.bk = 0x3,
++		.bw = 0x1,
++		.dbw = 0x0,
++		.row_3_4 = 0x0,
++		.cs0_row = 0xF,
++		.cs1_row = 0xF,
++		.cs0_high16bit_row = 0xF,
++		.cs1_high16bit_row = 0xF,
++		.ddrconfig = 0,
++		{
++			0x2b0c070a,
++			0x08020303,
++			0x00000002,
++			0x00001111,
++			0x0000000c,
++			0x00000219,
++			0x000000ff
++		}
++	},
++	{
++		.ddr_freq = 333,
++		.dramtype = LPDDR2,
++		.num_channels = 1,
++		.stride = 0,
++		.odt = 0,
++	},
++	{
++		{
++			{0x00000000, 0x41041004},	/* MSTR */
++			{0x00000064, 0x00140023},	/* RFSHTMG */
++			{0x000000d0, 0x00220002},	/* INIT0 */
++			{0x000000d4, 0x00010000},	/* INIT1 */
++			{0x000000d8, 0x00000703},	/* INIT2 */
++			{0x000000dc, 0x00630005},	/* INIT3 */
++			{0x000000e0, 0x00010000},	/* INIT4 */
++			{0x000000e4, 0x00070003},	/* INIT5 */
++			{0x000000f4, 0x000f012f},	/* RANKCTL */
++			{0x00000100, 0x07090b07},	/* DRAMTMG0 */
++			{0x00000104, 0x0002010b},	/* DRAMTMG1 */
++			{0x00000108, 0x02040506},	/* DRAMTMG2 */
++			{0x0000010c, 0x00303000},	/* DRAMTMG3 */
++			{0x00000110, 0x04010204},	/* DRAMTMG4 */
++			{0x00000114, 0x01010303},	/* DRAMTMG5 */
++			{0x00000118, 0x02020003},	/* DRAMTMG6 */
++			{0x00000120, 0x00000303},	/* DRAMTMG8 */
++			{0x00000138, 0x00000025},	/* DRAMTMG14 */
++			{0x00000180, 0x003c000f},	/* ZQCTL0 */
++			{0x00000184, 0x00900000},	/* ZQCTL1 */
++			{0x00000190, 0x07020001},	/* DFITMG0 */
++			{0x00000198, 0x07000101},	/* DFILPCFG0 */
++			{0x000001a0, 0xc0400003},	/* DFIUPD0 */
++			{0x00000240, 0x07030718},	/* ODTCFG */
++			{0x00000250, 0x00001f00},	/* SCHED */
++			{0x00000490, 0x00000001},	/* PCTRL_0 */
++			{0xffffffff, 0xffffffff}
++		}
++	},
++	{
++		{
++			{0x00000004, 0x00000009},	/* PHYREG01 */
++			{0x00000028, 0x00000007},	/* PHYREG0A */
++			{0x0000002c, 0x00000000},	/* PHYREG0B */
++			{0x00000030, 0x00000004},	/* PHYREG0C */
++			{0xffffffff, 0xffffffff}
++		}
++	}
++},
+diff --git a/arch/arm/mach-rockchip/px30/sdram-px30-lpddr3-detect-333.inc b/arch/arm/mach-rockchip/px30/sdram-px30-lpddr3-detect-333.inc
+new file mode 100644
+index 0000000000..a205fc9332
+--- /dev/null
++++ b/arch/arm/mach-rockchip/px30/sdram-px30-lpddr3-detect-333.inc
+@@ -0,0 +1,72 @@
++{
++	{
++		.rank = 0x1,
++		.col = 0xC,
++		.bk = 0x3,
++		.bw = 0x1,
++		.dbw = 0x0,
++		.row_3_4 = 0x0,
++		.cs0_row = 0x10,
++		.cs1_row = 0x10,
++		.cs0_high16bit_row = 0x10,
++		.cs1_high16bit_row = 0x10,
++		.ddrconfig = 0,
++		{
++			0x290a060a,
++			0x08020303,
++			0x00000002,
++			0x00001111,
++			0x0000000c,
++			0x0000021a,
++			0x000000ff
++		}
++	},
++	{
++		.ddr_freq = 333,
++		.dramtype = LPDDR3,
++		.num_channels = 1,
++		.stride = 0,
++		.odt = 0,
++	},
++	{
++		{
++			{0x00000000, 0x43041008},	/* MSTR */
++			{0x00000064, 0x00140023},	/* RFSHTMG */
++			{0x000000d0, 0x00220002},	/* INIT0 */
++			{0x000000d4, 0x00010000},	/* INIT1 */
++			{0x000000d8, 0x00000703},	/* INIT2 */
++			{0x000000dc, 0x00830004},	/* INIT3 */
++			{0x000000e0, 0x00010000},	/* INIT4 */
++			{0x000000e4, 0x00070003},	/* INIT5 */
++			{0x000000f4, 0x000f012f},	/* RANKCTL */
++			{0x00000100, 0x06090b07},	/* DRAMTMG0 */
++			{0x00000104, 0x0002020b},	/* DRAMTMG1 */
++			{0x00000108, 0x02030506},	/* DRAMTMG2 */
++			{0x0000010c, 0x00505000},	/* DRAMTMG3 */
++			{0x00000110, 0x03020204},	/* DRAMTMG4 */
++			{0x00000114, 0x01010303},	/* DRAMTMG5 */
++			{0x00000118, 0x02020003},	/* DRAMTMG6 */
++			{0x00000120, 0x00000303},	/* DRAMTMG8 */
++			{0x00000138, 0x00000025},	/* DRAMTMG14 */
++			{0x00000180, 0x003c000f},	/* ZQCTL0 */
++			{0x00000184, 0x00900000},	/* ZQCTL1 */
++			{0x00000190, 0x07020000},	/* DFITMG0 */
++			{0x00000198, 0x07000101},	/* DFILPCFG0 */
++			{0x000001a0, 0xc0400003},	/* DFIUPD0 */
++			{0x00000240, 0x0900090c},	/* ODTCFG */
++			{0x00000244, 0x00000101},	/* ODTMAP */
++			{0x00000250, 0x00001f00},	/* SCHED */
++			{0x00000490, 0x00000001},	/* PCTRL_0 */
++			{0xffffffff, 0xffffffff}
++		}
++	},
++	{
++		{
++			{0x00000004, 0x0000000b},	/* PHYREG01 */
++			{0x00000028, 0x00000006},	/* PHYREG0A */
++			{0x0000002c, 0x00000000},	/* PHYREG0B */
++			{0x00000030, 0x00000003},	/* PHYREG0C */
++			{0xffffffff, 0xffffffff}
++		}
++	}
++},
+diff --git a/arch/arm/mach-rockchip/px30/sdram_px30.c b/arch/arm/mach-rockchip/px30/sdram_px30.c
+new file mode 100644
+index 0000000000..2590d9366e
+--- /dev/null
++++ b/arch/arm/mach-rockchip/px30/sdram_px30.c
+@@ -0,0 +1,1405 @@
++// SPDX-License-Identifier: GPL-2.0
++/*
++ * (C) Copyright 2018 Rockchip Electronics Co., Ltd.
++ */
++
++#include <common.h>
++#include <debug_uart.h>
++#include <dm.h>
++#include <ram.h>
++#include <syscon.h>
++#include <asm/io.h>
++#include <asm/arch-rockchip/clock.h>
++#include <asm/arch-rockchip/cru_px30.h>
++#include <asm/arch-rockchip/grf_px30.h>
++#include <asm/arch-rockchip/hardware.h>
++#include <asm/arch-rockchip/sdram_common.h>
++#include <asm/arch-rockchip/sdram_px30.h>
++
++#define TIMER_CUR_VALUE0	0x08
++#define TIMER_CUR_VALUE1	0x0c
++
++static u64 rockchip_get_ticks(void)
++{
++	u64 timebase_h, timebase_l;
++
++	timebase_l = readl(CONFIG_ROCKCHIP_STIMER_BASE + TIMER_CUR_VALUE0);
++	timebase_h = readl(CONFIG_ROCKCHIP_STIMER_BASE + TIMER_CUR_VALUE1);
++
++	return timebase_h << 32 | timebase_l;
++}
++
++void rockchip_udelay(unsigned int usec)
++{
++	u64 tmp;
++
++	/* get timestamp */
++	tmp = rockchip_get_ticks() + usec_to_tick(usec);
++
++	/* loop till event */
++	while (rockchip_get_ticks() < tmp + 1)
++		;
++}
++
++u8 ddr_cfg_2_rbc[] = {
++	/*
++	 * [6:4] max row: 13+n
++	 * [3]  bank(0:4bank,1:8bank)
++	 * [2:0]    col(10+n)
++	 */
++	((5 << 4) | (1 << 3) | 0), /* 0 */
++	((5 << 4) | (1 << 3) | 1), /* 1 */
++	((4 << 4) | (1 << 3) | 2), /* 2 */
++	((3 << 4) | (1 << 3) | 3), /* 3 */
++	((2 << 4) | (1 << 3) | 4), /* 4 */
++	((5 << 4) | (0 << 3) | 2), /* 5 */
++	((4 << 4) | (1 << 3) | 2), /* 6 */
++};
++
++#ifdef CONFIG_TPL_BUILD
++
++/*
++ * for ddr4 if ddrconfig=7, upctl should set 7 and noc should
++ * set to 1 for more efficient.
++ * noc ddrconf, upctl addrmap
++ * 1  7
++ * 2  8
++ * 3  9
++ * 12 10
++ * 5  11
++ */
++static u8 d4_rbc_2_d3_rbc[] = {
++	1, /* 7 */
++	2, /* 8 */
++	3, /* 9 */
++	12, /* 10 */
++	5, /* 11 */
++};
++
++/*
++ * row higher than cs should be disabled by set to 0xf
++ * rank addrmap calculate by real cap.
++ */
++static u32 addrmap[][8] = {
++	/* map0 map1,   map2,       map3,       map4,      map5
++	 * map6,        map7,       map8
++	 * -------------------------------------------------------
++	 * bk2-0       col 5-2     col 9-6    col 11-10   row 11-0
++	 * row 15-12   row 17-16   bg1,0
++	 * -------------------------------------------------------
++	 * 4,3,2       5-2         9-6                    6
++	 *                         3,2
++	 */
++	{0x00060606, 0x00000000, 0x1f1f0000, 0x00001f1f, 0x05050505,
++		0x05050505, 0x00000505, 0x3f3f}, /* 0 */
++	{0x00070707, 0x00000000, 0x1f000000, 0x00001f1f, 0x06060606,
++		0x06060606, 0x06060606, 0x3f3f}, /* 1 */
++	{0x00080808, 0x00000000, 0x00000000, 0x00001f1f, 0x07070707,
++		0x07070707, 0x00000f07, 0x3f3f}, /* 2 */
++	{0x00090909, 0x00000000, 0x00000000, 0x00001f00, 0x08080808,
++		0x08080808, 0x00000f0f, 0x3f3f}, /* 3 */
++	{0x000a0a0a, 0x00000000, 0x00000000, 0x00000000, 0x09090909,
++		0x0f090909, 0x00000f0f, 0x3f3f}, /* 4 */
++	{0x00080808, 0x00000000, 0x00000000, 0x00001f1f, 0x06060606,
++		0x06060606, 0x00000606, 0x3f3f}, /* 5 */
++	{0x00080808, 0x00000000, 0x00000000, 0x00001f1f, 0x07070707,
++		0x07070707, 0x00000f0f, 0x3f3f}, /* 6 */
++	{0x003f0808, 0x00000006, 0x1f1f0000, 0x00001f1f, 0x06060606,
++		0x06060606, 0x00000606, 0x0600}, /* 7 */
++	{0x003f0909, 0x00000007, 0x1f000000, 0x00001f1f, 0x07070707,
++		0x07070707, 0x00000f07, 0x0700}, /* 8 */
++	{0x003f0a0a, 0x01010100, 0x01010101, 0x00001f1f, 0x08080808,
++		0x08080808, 0x00000f0f, 0x0801}, /* 9 */
++	{0x003f0909, 0x01010100, 0x01010101, 0x00001f1f, 0x07070707,
++		0x07070707, 0x00000f07, 0x3f01}, /* 10 */
++	{0x003f0808, 0x00000007, 0x1f000000, 0x00001f1f, 0x06060606,
++		0x06060606, 0x00000606, 0x3f00}, /* 11 */
++	/* when ddr4 12 map to 10, when ddr3 12 unused */
++	{0x003f0909, 0x01010100, 0x01010101, 0x00001f1f, 0x07070707,
++		0x07070707, 0x00000f07, 0x3f01}, /* 10 */
++	{0x00070706, 0x00000000, 0x1f010000, 0x00001f1f, 0x06060606,
++		0x06060606, 0x00000606, 0x3f3f}, /* 13 */
++};
++
++DECLARE_GLOBAL_DATA_PTR;
++struct dram_info {
++	struct ddr_pctl_regs *pctl;
++	struct ddr_phy_regs *phy;
++	struct px30_cru *cru;
++	struct px30_msch_regs *msch;
++	struct px30_ddr_grf_regs *ddr_grf;
++	struct px30_grf *grf;
++	struct ram_info info;
++	struct px30_pmugrf *pmugrf;
++};
++
++#define PMUGRF_BASE_ADDR		0xFF010000
++#define CRU_BASE_ADDR			0xFF2B0000
++#define GRF_BASE_ADDR			0xFF140000
++#define DDRC_BASE_ADDR			0xFF600000
++#define DDR_PHY_BASE_ADDR		0xFF2A0000
++#define SERVER_MSCH0_BASE_ADDR		0xFF530000
++#define DDR_GRF_BASE_ADDR		0xff630000
++
++struct dram_info dram_info;
++
++struct px30_sdram_params sdram_configs[] = {
++#include	"sdram-px30-ddr3-detect-333.inc"
++};
++
++struct ddr_phy_skew skew = {
++#include	"sdram-px30-ddr_skew.inc"
++};
++
++#define PATTERN				(0x5aa5f00f)
++
++/*
++ * cs: 0:cs0
++ *	   1:cs1
++ *     else cs0+cs1
++ * note: it didn't consider about row_3_4
++ */
++u64 sdram_get_cs_cap(struct px30_sdram_channel *cap_info, u32 cs, u32 dram_type)
++{
++	u32 bg;
++	u64 cap[2];
++
++	if (dram_type == DDR4)
++		/* DDR4 8bit dram BG = 2(4bank groups),
++		 * 16bit dram BG = 1 (2 bank groups)
++		 */
++		bg = (cap_info->dbw == 0) ? 2 : 1;
++	else
++		bg = 0;
++	cap[0] = 1llu << (cap_info->bw + cap_info->col +
++		bg + cap_info->bk + cap_info->cs0_row);
++
++	if (cap_info->rank == 2)
++		cap[1] = 1llu << (cap_info->bw + cap_info->col +
++			bg + cap_info->bk + cap_info->cs1_row);
++	else
++		cap[1] = 0;
++
++	if (cs == 0)
++		return cap[0];
++	else if (cs == 1)
++		return cap[1];
++	else
++		return (cap[0] + cap[1]);
++}
++
++/* n: Unit bytes */
++void sdram_copy_to_reg(u32 *dest, const u32 *src, u32 n)
++{
++	int i;
++
++	for (i = 0; i < n / sizeof(u32); i++) {
++		writel(*src, dest);
++		src++;
++		dest++;
++	}
++}
++
++static void sdram_phy_dll_bypass_set(void __iomem *phy_base, u32 freq)
++{
++	u32 tmp;
++	u32 i, j;
++
++	setbits_le32(PHY_REG(phy_base, 0x13), 1 << 4);
++	clrbits_le32(PHY_REG(phy_base, 0x14), 1 << 3);
++	for (i = 0; i < 4; i++) {
++		j = 0x26 + i * 0x10;
++		setbits_le32(PHY_REG(phy_base, j), 1 << 4);
++		clrbits_le32(PHY_REG(phy_base, j + 0x1), 1 << 3);
++	}
++
++	if (freq <= (400000000))
++		/* DLL bypass */
++		setbits_le32(PHY_REG(phy_base, 0xa4), 0x1f);
++	else
++		clrbits_le32(PHY_REG(phy_base, 0xa4), 0x1f);
++
++	if (freq <= (801000000))
++		tmp = 2;
++	else
++		tmp = 1;
++
++	for (i = 0; i < 4; i++) {
++		j = 0x28 + i * 0x10;
++		writel(tmp, PHY_REG(phy_base, j));
++	}
++}
++
++static void sdram_phy_set_ds_odt(void __iomem *phy_base,
++				 u32 dram_type)
++{
++	u32 cmd_drv, clk_drv, dqs_drv, dqs_odt;
++	u32 i, j;
++
++	if (dram_type == DDR3) {
++		cmd_drv = PHY_DDR3_RON_RTT_34ohm;
++		clk_drv = PHY_DDR3_RON_RTT_45ohm;
++		dqs_drv = PHY_DDR3_RON_RTT_34ohm;
++		dqs_odt = PHY_DDR3_RON_RTT_225ohm;
++	} else {
++		cmd_drv = PHY_DDR4_LPDDR3_RON_RTT_34ohm;
++		clk_drv = PHY_DDR4_LPDDR3_RON_RTT_43ohm;
++		dqs_drv = PHY_DDR4_LPDDR3_RON_RTT_34ohm;
++		if (dram_type == LPDDR2)
++			dqs_odt = PHY_DDR4_LPDDR3_RON_RTT_DISABLE;
++		else
++			dqs_odt = PHY_DDR4_LPDDR3_RON_RTT_240ohm;
++	}
++	/* DS */
++	writel(cmd_drv, PHY_REG(phy_base, 0x11));
++	clrsetbits_le32(PHY_REG(phy_base, 0x12), 0x1f << 3, cmd_drv << 3);
++	writel(clk_drv, PHY_REG(phy_base, 0x16));
++	writel(clk_drv, PHY_REG(phy_base, 0x18));
++
++	for (i = 0; i < 4; i++) {
++		j = 0x20 + i * 0x10;
++		writel(dqs_drv, PHY_REG(phy_base, j));
++		writel(dqs_drv, PHY_REG(phy_base, j + 0xf));
++		/* ODT */
++		writel(dqs_odt, PHY_REG(phy_base, j + 0x1));
++		writel(dqs_odt, PHY_REG(phy_base, j + 0xe));
++	}
++}
++
++static void phy_soft_reset(void __iomem *phy_base)
++{
++	clrbits_le32(PHY_REG(phy_base, 0), 0x3 << 2);
++	udelay(1);
++	setbits_le32(PHY_REG(phy_base, 0), ANALOG_DERESET);
++	udelay(5);
++	setbits_le32(PHY_REG(phy_base, 0), DIGITAL_DERESET);
++	udelay(1);
++}
++
++static void phy_dram_set_bw(void __iomem *phy_base, u32 bw)
++{
++	if (bw == 2) {
++		clrsetbits_le32(PHY_REG(phy_base, 0), 0xf << 4, 0xf << 4);
++		setbits_le32(PHY_REG(phy_base, 0x46), 1 << 3);
++		setbits_le32(PHY_REG(phy_base, 0x56), 1 << 3);
++	} else if (bw == 1) {
++		clrsetbits_le32(PHY_REG(phy_base, 0), 0xf << 4, 3 << 4);
++		clrbits_le32(PHY_REG(phy_base, 0x46), 1 << 3);
++		clrbits_le32(PHY_REG(phy_base, 0x56), 1 << 3);
++	} else if (bw == 0) {
++		clrsetbits_le32(PHY_REG(phy_base, 0), 0xf << 4, 1 << 4);
++		clrbits_le32(PHY_REG(phy_base, 0x36), 1 << 3);
++		clrbits_le32(PHY_REG(phy_base, 0x46), 1 << 3);
++		clrbits_le32(PHY_REG(phy_base, 0x56), 1 << 3);
++	}
++
++	phy_soft_reset(phy_base);
++}
++
++static int phy_data_training(void __iomem *phy_base, u32 cs, u32 dramtype)
++{
++	u32 ret;
++	u32 odt_val;
++	u32 i, j;
++
++	odt_val = readl(PHY_REG(phy_base, 0x2e));
++
++	for (i = 0; i < 4; i++) {
++		j = 0x20 + i * 0x10;
++		writel(PHY_DDR3_RON_RTT_225ohm, PHY_REG(phy_base, j + 0x1));
++		writel(0, PHY_REG(phy_base, j + 0xe));
++	}
++
++	if (dramtype == DDR4) {
++		clrsetbits_le32(PHY_REG(phy_base, 0x29), 0x3, 0);
++		clrsetbits_le32(PHY_REG(phy_base, 0x39), 0x3, 0);
++		clrsetbits_le32(PHY_REG(phy_base, 0x49), 0x3, 0);
++		clrsetbits_le32(PHY_REG(phy_base, 0x59), 0x3, 0);
++	}
++	/* choose training cs */
++	clrsetbits_le32(PHY_REG(phy_base, 2), 0x33, (0x20 >> cs));
++	/* enable gate training */
++	clrsetbits_le32(PHY_REG(phy_base, 2), 0x33, (0x20 >> cs) | 1);
++	udelay(50);
++	ret = readl(PHY_REG(phy_base, 0xff));
++	/* disable gate training */
++	clrsetbits_le32(PHY_REG(phy_base, 2), 0x33, (0x20 >> cs) | 0);
++	clrbits_le32(PHY_REG(phy_base, 2), 0x30);
++
++	if (dramtype == DDR4) {
++		clrsetbits_le32(PHY_REG(phy_base, 0x29), 0x3, 0x2);
++		clrsetbits_le32(PHY_REG(phy_base, 0x39), 0x3, 0x2);
++		clrsetbits_le32(PHY_REG(phy_base, 0x49), 0x3, 0x2);
++		clrsetbits_le32(PHY_REG(phy_base, 0x59), 0x3, 0x2);
++	}
++
++	if (ret & 0x10) {
++		ret = -1;
++	} else {
++		ret = (ret & 0xf) ^ (readl(PHY_REG(phy_base, 0)) >> 4);
++		ret = (ret == 0) ? 0 : -1;
++	}
++
++	for (i = 0; i < 4; i++) {
++		j = 0x20 + i * 0x10;
++		writel(odt_val, PHY_REG(phy_base, j + 0x1));
++		writel(odt_val, PHY_REG(phy_base, j + 0xe));
++	}
++
++	return ret;
++}
++
++static void phy_cfg(void __iomem *phy_base,
++		    struct ddr_phy_regs *phy_regs, struct ddr_phy_skew *skew,
++		    struct px30_base_params *base, u32 bw)
++{
++	u32 i;
++
++	sdram_phy_dll_bypass_set(phy_base, base->ddr_freq);
++	for (i = 0; phy_regs->phy[i][0] != 0xFFFFFFFF; i++) {
++		writel(phy_regs->phy[i][1],
++		       phy_base + phy_regs->phy[i][0]);
++	}
++	if (bw == 2) {
++		clrsetbits_le32(PHY_REG(phy_base, 0), 0xf << 4, 0xf << 4);
++	} else if (bw == 1) {
++		clrsetbits_le32(PHY_REG(phy_base, 0), 0xf << 4, 3 << 4);
++		/* disable DQS2,DQS3 tx dll  for saving power */
++		clrbits_le32(PHY_REG(phy_base, 0x46), 1 << 3);
++		clrbits_le32(PHY_REG(phy_base, 0x56), 1 << 3);
++	} else {
++		clrsetbits_le32(PHY_REG(phy_base, 0), 0xf << 4, 1 << 4);
++		/* disable DQS2,DQS3 tx dll  for saving power */
++		clrbits_le32(PHY_REG(phy_base, 0x36), 1 << 3);
++		clrbits_le32(PHY_REG(phy_base, 0x46), 1 << 3);
++		clrbits_le32(PHY_REG(phy_base, 0x56), 1 << 3);
++	}
++	sdram_phy_set_ds_odt(phy_base, base->dramtype);
++
++	/* deskew */
++	setbits_le32(PHY_REG(phy_base, 2), 8);
++	sdram_copy_to_reg(PHY_REG(phy_base, 0xb0),
++			  &skew->a0_a1_skew[0], 15 * 4);
++	sdram_copy_to_reg(PHY_REG(phy_base, 0x70),
++			  &skew->cs0_dm0_skew[0], 44 * 4);
++	sdram_copy_to_reg(PHY_REG(phy_base, 0xc0),
++			  &skew->cs1_dm0_skew[0], 44 * 4);
++}
++
++void sdram_org_config(struct px30_sdram_channel *info,
++		      struct px30_base_params *base,
++		      u32 *p_os_reg2, u32 *p_os_reg3, u32 channel)
++{
++	*p_os_reg2 |= base->dramtype << SYS_REG_DDRTYPE_SHIFT;
++	*p_os_reg2 |= (base->num_channels - 1) << SYS_REG_NUM_CH_SHIFT;
++	*p_os_reg2 |= info->row_3_4 << SYS_REG_ROW_3_4_SHIFT(channel);
++	*p_os_reg2 |= 1 << SYS_REG_CHINFO_SHIFT(channel);
++	*p_os_reg2 |= (info->rank - 1) << SYS_REG_RANK_SHIFT(channel);
++	*p_os_reg2 |= (info->col - 9) << SYS_REG_COL_SHIFT(channel);
++	*p_os_reg2 |= info->bk == 3 ? 0 : 1 << SYS_REG_BK_SHIFT(channel);
++	*p_os_reg2 |= (info->cs0_row - 13) << SYS_REG_CS0_ROW_SHIFT(channel);
++	if (info->cs1_row >= 13)
++		*p_os_reg2 |= (info->cs1_row - 13) << SYS_REG_CS1_ROW_SHIFT(channel);
++	*p_os_reg2 |= (2 >> info->bw) << SYS_REG_BW_SHIFT(channel);
++	*p_os_reg2 |= (2 >> info->dbw) << SYS_REG_DBW_SHIFT(channel);
++}
++
++void sdram_msch_config(struct px30_msch_regs *msch,
++		       struct px30_msch_timings *noc_timings,
++		       struct px30_sdram_channel *cap_info,
++		       struct px30_base_params *base)
++{
++	u64 cs_cap[2];
++
++	cs_cap[0] = sdram_get_cs_cap(cap_info, 0, base->dramtype);
++	cs_cap[1] = sdram_get_cs_cap(cap_info, 1, base->dramtype);
++	writel(((((cs_cap[1] >> 20) / 64) & 0xff) << 8) |
++			(((cs_cap[0] >> 20) / 64) & 0xff),
++			&msch->devicesize);
++
++	writel(noc_timings->ddrtiminga0, &msch->ddrtiminga0);
++	writel(noc_timings->ddrtimingb0, &msch->ddrtimingb0);
++	writel(noc_timings->ddrtimingc0, &msch->ddrtimingc0);
++	writel(noc_timings->devtodev0, &msch->devtodev0);
++	writel(noc_timings->ddrmode, &msch->ddrmode);
++	writel(noc_timings->ddr4timing, &msch->ddr4timing);
++	writel(noc_timings->agingx0, &msch->agingx0);
++	writel(noc_timings->agingx0, &msch->aging0);
++	writel(noc_timings->agingx0, &msch->aging1);
++	writel(noc_timings->agingx0, &msch->aging2);
++	writel(noc_timings->agingx0, &msch->aging3);
++}
++
++int sdram_detect_bw(struct px30_sdram_channel *cap_info)
++{
++	return 0;
++}
++
++int sdram_detect_cs(struct px30_sdram_channel *cap_info)
++{
++	return 0;
++}
++
++int sdram_detect_col(struct px30_sdram_channel *cap_info,
++		     u32 coltmp)
++{
++	void __iomem *test_addr;
++	u32 col;
++	u32 bw = cap_info->bw;
++
++	for (col = coltmp; col >= 9; col -= 1) {
++		writel(0, CONFIG_SYS_SDRAM_BASE);
++		test_addr = (void __iomem *)(CONFIG_SYS_SDRAM_BASE +
++				(1ul << (col + bw - 1ul)));
++		writel(PATTERN, test_addr);
++		if ((readl(test_addr) == PATTERN) &&
++		    (readl(CONFIG_SYS_SDRAM_BASE) == 0))
++			break;
++	}
++	if (col == 8) {
++		printascii("col error\n");
++		return -1;
++	}
++
++	cap_info->col = col;
++
++	return 0;
++}
++
++int sdram_detect_bank(struct px30_sdram_channel *cap_info,
++		      u32 coltmp, u32 bktmp)
++{
++	void __iomem *test_addr;
++	u32 bk;
++	u32 bw = cap_info->bw;
++
++	test_addr = (void __iomem *)(CONFIG_SYS_SDRAM_BASE +
++			(1ul << (coltmp + bktmp + bw - 1ul)));
++	writel(0, CONFIG_SYS_SDRAM_BASE);
++	writel(PATTERN, test_addr);
++	if ((readl(test_addr) == PATTERN) &&
++	    (readl(CONFIG_SYS_SDRAM_BASE) == 0))
++		bk = 3;
++	else
++		bk = 2;
++
++	cap_info->bk = bk;
++
++	return 0;
++}
++
++/* detect bg for ddr4 */
++int sdram_detect_bg(struct px30_sdram_channel *cap_info,
++		    u32 coltmp)
++{
++	void __iomem *test_addr;
++	u32 dbw;
++	u32 bw = cap_info->bw;
++
++	test_addr = (void __iomem *)(CONFIG_SYS_SDRAM_BASE +
++			(1ul << (coltmp + bw + 1ul)));
++	writel(0, CONFIG_SYS_SDRAM_BASE);
++	writel(PATTERN, test_addr);
++	if ((readl(test_addr) == PATTERN) &&
++	    (readl(CONFIG_SYS_SDRAM_BASE) == 0))
++		dbw = 0;
++	else
++		dbw = 1;
++
++	cap_info->dbw = dbw;
++
++	return 0;
++}
++
++/* detect dbw for ddr3,lpddr2,lpddr3,lpddr4 */
++int sdram_detect_dbw(struct px30_sdram_channel *cap_info, u32 dram_type)
++{
++	u32 row, col, bk, bw, cs_cap, cs;
++	u32 die_bw_0 = 0, die_bw_1 = 0;
++
++	if (dram_type == DDR3 || dram_type == LPDDR4) {
++		cap_info->dbw = 1;
++	} else if (dram_type == LPDDR3 || dram_type == LPDDR2) {
++		row = cap_info->cs0_row;
++		col = cap_info->col;
++		bk = cap_info->bk;
++		cs = cap_info->rank;
++		bw = cap_info->bw;
++		cs_cap = (1 << (row + col + bk + bw - 20));
++		if (bw == 2) {
++			if (cs_cap <= 0x2000000) /* 256Mb */
++				die_bw_0 = (col < 9) ? 2 : 1;
++			else if (cs_cap <= 0x10000000) /* 2Gb */
++				die_bw_0 = (col < 10) ? 2 : 1;
++			else if (cs_cap <= 0x40000000) /* 8Gb */
++				die_bw_0 = (col < 11) ? 2 : 1;
++			else
++				die_bw_0 = (col < 12) ? 2 : 1;
++			if (cs > 1) {
++				row = cap_info->cs1_row;
++				cs_cap = (1 << (row + col + bk + bw - 20));
++				if (cs_cap <= 0x2000000) /* 256Mb */
++					die_bw_0 = (col < 9) ? 2 : 1;
++				else if (cs_cap <= 0x10000000) /* 2Gb */
++					die_bw_0 = (col < 10) ? 2 : 1;
++				else if (cs_cap <= 0x40000000) /* 8Gb */
++					die_bw_0 = (col < 11) ? 2 : 1;
++				else
++					die_bw_0 = (col < 12) ? 2 : 1;
++			}
++		} else {
++			die_bw_1 = 1;
++			die_bw_0 = 1;
++		}
++		cap_info->dbw = (die_bw_0 > die_bw_1) ? die_bw_0 : die_bw_1;
++	}
++
++	return 0;
++}
++
++int sdram_detect_row(struct px30_sdram_channel *cap_info,
++		     u32 coltmp, u32 bktmp, u32 rowtmp)
++{
++	u32 row;
++	u32 bw = cap_info->bw;
++	void __iomem *test_addr;
++
++	for (row = rowtmp; row > 12; row--) {
++		writel(0, CONFIG_SYS_SDRAM_BASE);
++		test_addr = (void __iomem *)(CONFIG_SYS_SDRAM_BASE +
++				(1ul << (row + bktmp + coltmp + bw - 1ul)));
++		writel(PATTERN, test_addr);
++		if ((readl(test_addr) == PATTERN) &&
++		    (readl(CONFIG_SYS_SDRAM_BASE) == 0))
++			break;
++	}
++	if (row == 12) {
++		printascii("row error");
++		return -1;
++	}
++
++	cap_info->cs0_row = row;
++
++	return 0;
++}
++
++int sdram_detect_row_3_4(struct px30_sdram_channel *cap_info,
++			 u32 coltmp, u32 bktmp)
++{
++	u32 row_3_4;
++	u32 bw = cap_info->bw;
++	u32 row = cap_info->cs0_row;
++	void __iomem *test_addr, *test_addr1;
++
++	test_addr = CONFIG_SYS_SDRAM_BASE;
++	test_addr1 = (void __iomem *)(CONFIG_SYS_SDRAM_BASE +
++			(0x3ul << (row + bktmp + coltmp + bw - 1ul - 1ul)));
++
++	writel(0, test_addr);
++	writel(PATTERN, test_addr1);
++	if ((readl(test_addr) == 0) && (readl(test_addr1) == PATTERN))
++		row_3_4 = 0;
++	else
++		row_3_4 = 1;
++
++	cap_info->row_3_4 = row_3_4;
++
++	return 0;
++}
++
++int sdram_detect_high_row(struct px30_sdram_channel *cap_info)
++{
++	cap_info->cs0_high16bit_row = cap_info->cs0_row;
++	cap_info->cs1_high16bit_row = cap_info->cs1_row;
++
++	return 0;
++}
++
++int sdram_detect_cs1_row(struct px30_sdram_channel *cap_info, u32 dram_type)
++{
++	void __iomem *test_addr;
++	u32 row = 0, bktmp, coltmp, bw;
++	ulong cs0_cap;
++	u32 byte_mask;
++
++	if (cap_info->rank == 2) {
++		cs0_cap = sdram_get_cs_cap(cap_info, 0, dram_type);
++
++		if (dram_type == DDR4) {
++			if (cap_info->dbw == 0)
++				bktmp = cap_info->bk + 2;
++			else
++				bktmp = cap_info->bk + 1;
++		} else {
++			bktmp = cap_info->bk;
++		}
++		bw = cap_info->bw;
++		coltmp = cap_info->col;
++
++		/*
++		 * because px30 support axi split,min bandwidth
++		 * is 8bit. if cs0 is 32bit, cs1 may 32bit or 16bit
++		 * so we check low 16bit data when detect cs1 row.
++		 * if cs0 is 16bit/8bit, we check low 8bit data.
++		 */
++		if (bw == 2)
++			byte_mask = 0xFFFF;
++		else
++			byte_mask = 0xFF;
++
++		/* detect cs1 row */
++		for (row = cap_info->cs0_row; row > 12; row--) {
++			test_addr = (void __iomem *)(CONFIG_SYS_SDRAM_BASE +
++				    cs0_cap +
++				    (1ul << (row + bktmp + coltmp + bw - 1ul)));
++			writel(0, CONFIG_SYS_SDRAM_BASE + cs0_cap);
++			writel(PATTERN, test_addr);
++
++			if (((readl(test_addr) & byte_mask) ==
++			     (PATTERN & byte_mask)) &&
++			    ((readl(CONFIG_SYS_SDRAM_BASE + cs0_cap) &
++			      byte_mask) == 0)) {
++				break;
++			}
++		}
++	}
++
++	cap_info->cs1_row = row;
++
++	return 0;
++}
++
++static void rkclk_ddr_reset(struct dram_info *dram,
++			    u32 ctl_srstn, u32 ctl_psrstn,
++			    u32 phy_srstn, u32 phy_psrstn)
++{
++	writel(upctl2_srstn_req(ctl_srstn) | upctl2_psrstn_req(ctl_psrstn) |
++	       upctl2_asrstn_req(ctl_srstn),
++	       &dram->cru->softrst_con[1]);
++	writel(ddrphy_srstn_req(phy_srstn) | ddrphy_psrstn_req(phy_psrstn),
++	       &dram->cru->softrst_con[2]);
++}
++
++static void rkclk_set_dpll(struct dram_info *dram, unsigned int hz)
++{
++	unsigned int refdiv, postdiv1, postdiv2, fbdiv;
++	int delay = 1000;
++	u32 mhz = hz / MHz;
++
++	refdiv = 1;
++	if (mhz <= 300) {
++		postdiv1 = 4;
++		postdiv2 = 2;
++	} else if (mhz <= 400) {
++		postdiv1 = 6;
++		postdiv2 = 1;
++	} else if (mhz <= 600) {
++		postdiv1 = 4;
++		postdiv2 = 1;
++	} else if (mhz <= 800) {
++		postdiv1 = 3;
++		postdiv2 = 1;
++	} else if (mhz <= 1600) {
++		postdiv1 = 2;
++		postdiv2 = 1;
++	} else {
++		postdiv1 = 1;
++		postdiv2 = 1;
++	}
++	fbdiv = (mhz * refdiv * postdiv1 * postdiv2) / 24;
++
++	writel(DPLL_MODE(CLOCK_FROM_XIN_OSC), &dram->cru->mode);
++
++	writel(POSTDIV1(postdiv1) | FBDIV(fbdiv), &dram->cru->pll[1].con0);
++	writel(DSMPD(1) | POSTDIV2(postdiv2) | REFDIV(refdiv),
++	       &dram->cru->pll[1].con1);
++
++	while (delay > 0) {
++		rockchip_udelay(1);
++		if (LOCK(readl(&dram->cru->pll[1].con1)))
++			break;
++		delay--;
++	}
++
++	writel(DPLL_MODE(CLOCK_FROM_PLL), &dram->cru->mode);
++}
++
++static void rkclk_configure_ddr(struct dram_info *dram,
++				struct px30_sdram_params *sdram_params)
++{
++	/* for inno ddr phy need 2*freq */
++	rkclk_set_dpll(dram,  sdram_params->base.ddr_freq * MHz * 2);
++}
++
++/* return ddrconfig value
++ *       (-1), find ddrconfig fail
++ *       other, the ddrconfig value
++ * only support cs0_row >= cs1_row
++ */
++static unsigned int calculate_ddrconfig(struct px30_sdram_params *sdram_params)
++{
++	struct px30_sdram_channel *cap_info = &sdram_params->ch;
++	u32 bw, die_bw, col, bank;
++	u32 i, tmp;
++	u32 ddrconf = -1;
++
++	bw = cap_info->bw;
++	die_bw = cap_info->dbw;
++	col = cap_info->col;
++	bank = cap_info->bk;
++
++	if (sdram_params->base.dramtype == DDR4) {
++		if (die_bw == 0)
++			ddrconf = 7 + bw;
++		else
++			ddrconf = 12 - bw;
++		ddrconf = d4_rbc_2_d3_rbc[ddrconf - 7];
++	} else {
++		tmp = ((bank - 2) << 3) | (col + bw - 10);
++		for (i = 0; i < 7; i++)
++			if ((ddr_cfg_2_rbc[i] & 0xf) == tmp) {
++				ddrconf = i;
++				break;
++			}
++		if (i > 6)
++			printascii("calculate ddrconfig error\n");
++	}
++
++	return ddrconf;
++}
++
++/*
++ * rank = 1: cs0
++ * rank = 2: cs1
++ */
++static void pctl_read_mr(void __iomem *pctl_base, u32 rank, u32 mr_num)
++{
++	writel((rank << 4) | (1 << 0), pctl_base + DDR_PCTL2_MRCTRL0);
++	writel((mr_num << 8), pctl_base + DDR_PCTL2_MRCTRL1);
++	setbits_le32(pctl_base + DDR_PCTL2_MRCTRL0, 1u << 31);
++	while (readl(pctl_base + DDR_PCTL2_MRCTRL0) & (1u << 31))
++		continue;
++	while (readl(pctl_base + DDR_PCTL2_MRSTAT) & MR_WR_BUSY)
++		continue;
++}
++
++/* rank = 1: cs0
++ * rank = 2: cs1
++ * rank = 3: cs0 & cs1
++ * note: be careful of keep mr original val
++ */
++static int pctl_write_mr(void __iomem *pctl_base, u32 rank, u32 mr_num, u32 arg,
++			 u32 dramtype)
++{
++	while (readl(pctl_base + DDR_PCTL2_MRSTAT) & MR_WR_BUSY)
++		continue;
++	if (dramtype == DDR3 || dramtype == DDR4) {
++		writel((mr_num << 12) | (rank << 4) | (0 << 0),
++		       pctl_base + DDR_PCTL2_MRCTRL0);
++		writel(arg, pctl_base + DDR_PCTL2_MRCTRL1);
++	} else {
++		writel((rank << 4) | (0 << 0),
++		       pctl_base + DDR_PCTL2_MRCTRL0);
++		writel((mr_num << 8) | (arg & 0xff),
++		       pctl_base + DDR_PCTL2_MRCTRL1);
++	}
++
++	setbits_le32(pctl_base + DDR_PCTL2_MRCTRL0, 1u << 31);
++	while (readl(pctl_base + DDR_PCTL2_MRCTRL0) & (1u << 31))
++		continue;
++	while (readl(pctl_base + DDR_PCTL2_MRSTAT) & MR_WR_BUSY)
++		continue;
++
++	return 0;
++}
++
++static int upctl2_update_ref_reg(void __iomem *pctl_base)
++{
++	u32 ret;
++
++	ret = readl(pctl_base + DDR_PCTL2_RFSHCTL3) ^ (1 << 1);
++	writel(ret, pctl_base + DDR_PCTL2_RFSHCTL3);
++
++	return 0;
++}
++
++static u32 pctl_dis_zqcs_aref(void __iomem *pctl_base)
++{
++	u32 dis_auto_zq = 0;
++
++	/* disable zqcs */
++	if (!(readl(pctl_base + DDR_PCTL2_ZQCTL0) &
++		(1ul << 31))) {
++		dis_auto_zq = 1;
++		setbits_le32(pctl_base + DDR_PCTL2_ZQCTL0, 1 << 31);
++	}
++
++	/* disable auto refresh */
++	setbits_le32(pctl_base + DDR_PCTL2_RFSHCTL3, 1);
++
++	upctl2_update_ref_reg(pctl_base);
++
++	return dis_auto_zq;
++}
++
++static void pctl_rest_zqcs_aref(void __iomem *pctl_base, u32 dis_auto_zq)
++{
++	/* restore zqcs */
++	if (dis_auto_zq)
++		clrbits_le32(pctl_base + DDR_PCTL2_ZQCTL0, 1 << 31);
++
++	/* restore auto refresh */
++	clrbits_le32(pctl_base + DDR_PCTL2_RFSHCTL3, 1);
++
++	upctl2_update_ref_reg(pctl_base);
++}
++
++/*
++ * rank : 1:cs0, 2:cs1, 3:cs0&cs1
++ * vrefrate: 4500: 45%,
++ */
++static int pctl_write_vrefdq(void __iomem *pctl_base, u32 rank, u32 vrefrate,
++			     u32 dramtype)
++{
++	u32 tccd_l, value;
++	u32 dis_auto_zq = 0;
++
++	if (dramtype != DDR4 || vrefrate < 4500 ||
++	    vrefrate > 9200)
++		return (-1);
++
++	tccd_l = (readl(pctl_base + DDR_PCTL2_DRAMTMG4) >> 16) & 0xf;
++	tccd_l = (tccd_l - 4) << 10;
++
++	if (vrefrate > 7500) {
++		/* range 1 */
++		value = ((vrefrate - 6000) / 65) | tccd_l;
++	} else {
++		/* range 2 */
++		value = ((vrefrate - 4500) / 65) | tccd_l | (1 << 6);
++	}
++
++	dis_auto_zq = pctl_dis_zqcs_aref(pctl_base);
++
++	/* enable vrefdq calibratin */
++	pctl_write_mr(pctl_base, rank, 6, value | (1 << 7), dramtype);
++	udelay(1);/* tvrefdqe */
++	/* write vrefdq value */
++	pctl_write_mr(pctl_base, rank, 6, value | (1 << 7), dramtype);
++	udelay(1);/* tvref_time */
++	pctl_write_mr(pctl_base, rank, 6, value | (0 << 7), dramtype);
++	udelay(1);/* tvrefdqx */
++
++	pctl_rest_zqcs_aref(pctl_base, dis_auto_zq);
++
++	return 0;
++}
++
++static u32 pctl_remodify_sdram_params(struct ddr_pctl_regs *pctl_regs,
++				      struct px30_sdram_channel *cap_info,
++			       u32 dram_type)
++{
++	u32 tmp = 0, tmp_adr = 0, i;
++
++	for (i = 0; pctl_regs->pctl[i][0] != 0xFFFFFFFF; i++) {
++		if (pctl_regs->pctl[i][0] == 0) {
++			tmp = pctl_regs->pctl[i][1];/* MSTR */
++			tmp_adr = i;
++		}
++	}
++
++	tmp &= ~((3ul << 30) | (3ul << 24) | (3ul << 12));
++
++	switch (cap_info->dbw) {
++	case 2:
++		tmp |= (3ul << 30);
++		break;
++	case 1:
++		tmp |= (2ul << 30);
++		break;
++	case 0:
++	default:
++		tmp |= (1ul << 30);
++		break;
++	}
++
++	/*
++	 * If DDR3 or DDR4 MSTR.active_ranks=1,
++	 * it will gate memory clock when enter power down.
++	 * Force set active_ranks to 3 to workaround it.
++	 */
++	if (cap_info->rank == 2 || dram_type == DDR3 ||
++	    dram_type == DDR4)
++		tmp |= 3 << 24;
++	else
++		tmp |= 1 << 24;
++
++	tmp |= (2 - cap_info->bw) << 12;
++
++	pctl_regs->pctl[tmp_adr][1] = tmp;
++
++	return 0;
++}
++
++static int pctl_cfg(void __iomem *pctl_base, struct ddr_pctl_regs *pctl_regs,
++		    u32 sr_idle, u32 pd_idle)
++{
++	u32 i;
++
++	for (i = 0; pctl_regs->pctl[i][0] != 0xFFFFFFFF; i++) {
++		writel(pctl_regs->pctl[i][1],
++		       pctl_base + pctl_regs->pctl[i][0]);
++	}
++	clrsetbits_le32(pctl_base + DDR_PCTL2_PWRTMG,
++			(0xff << 16) | 0x1f,
++			((sr_idle & 0xff) << 16) | (pd_idle & 0x1f));
++
++	clrsetbits_le32(pctl_base + DDR_PCTL2_HWLPCTL,
++			0xfff << 16,
++			5 << 16);
++	/* disable zqcs */
++	setbits_le32(pctl_base + DDR_PCTL2_ZQCTL0, 1u << 31);
++
++	return 0;
++}
++
++/*
++ * calculate controller dram address map, and setting to register.
++ * argument sdram_params->ch.ddrconf must be right value before
++ * call this function.
++ */
++static void set_ctl_address_map(struct dram_info *dram,
++				struct px30_sdram_params *sdram_params)
++{
++	struct px30_sdram_channel *cap_info = &sdram_params->ch;
++	void __iomem *pctl_base = dram->pctl;
++	u32 cs_pst, bg, max_row, ddrconf;
++	u32 i;
++
++	if (sdram_params->base.dramtype == DDR4)
++		/*
++		 * DDR4 8bit dram BG = 2(4bank groups),
++		 * 16bit dram BG = 1 (2 bank groups)
++		 */
++		bg = (cap_info->dbw == 0) ? 2 : 1;
++	else
++		bg = 0;
++
++	cs_pst = cap_info->bw + cap_info->col +
++		bg + cap_info->bk + cap_info->cs0_row;
++	if (cs_pst >= 32 || cap_info->rank == 1)
++		writel(0x1f, pctl_base + DDR_PCTL2_ADDRMAP0);
++	else
++		writel(cs_pst - 8, pctl_base + DDR_PCTL2_ADDRMAP0);
++
++	ddrconf = cap_info->ddrconfig;
++	if (sdram_params->base.dramtype == DDR4) {
++		for (i = 0; i < ARRAY_SIZE(d4_rbc_2_d3_rbc); i++) {
++			if (d4_rbc_2_d3_rbc[i] == ddrconf) {
++				ddrconf = 7 + i;
++				break;
++			}
++		}
++	}
++
++	sdram_copy_to_reg((u32 *)(pctl_base + DDR_PCTL2_ADDRMAP1),
++			  &addrmap[ddrconf][0], 8 * 4);
++	max_row = cs_pst - 1 - 8 - (addrmap[ddrconf][5] & 0xf);
++
++	if (max_row < 12)
++		printascii("set addrmap fail\n");
++	/* need to disable row ahead of rank by set to 0xf */
++	for (i = 17; i > max_row; i--)
++		clrsetbits_le32(pctl_base + DDR_PCTL2_ADDRMAP6 +
++			((i - 12) * 8 / 32) * 4,
++			0xf << ((i - 12) * 8 % 32),
++			0xf << ((i - 12) * 8 % 32));
++
++	if ((sdram_params->base.dramtype == LPDDR3 ||
++	     sdram_params->base.dramtype == LPDDR2) &&
++		 cap_info->row_3_4)
++		setbits_le32(pctl_base + DDR_PCTL2_ADDRMAP6, 1 << 31);
++	if (sdram_params->base.dramtype == DDR4 && cap_info->bw != 0x2)
++		setbits_le32(pctl_base + DDR_PCTL2_PCCFG, 1 << 8);
++}
++
++/*
++ * rank = 1: cs0
++ * rank = 2: cs1
++ */
++int read_mr(struct dram_info *dram, u32 rank, u32 mr_num)
++{
++	void __iomem *ddr_grf_base = dram->ddr_grf;
++
++	pctl_read_mr(dram->pctl, rank, mr_num);
++
++	return (readl(ddr_grf_base + DDR_GRF_STATUS(0)) & 0xff);
++}
++
++#define MIN(a, b)	(((a) > (b)) ? (b) : (a))
++#define MAX(a, b)	(((a) > (b)) ? (a) : (b))
++static u32 check_rd_gate(struct dram_info *dram)
++{
++	void __iomem *phy_base = dram->phy;
++
++	u32 max_val = 0;
++	u32 min_val = 0xff;
++	u32 gate[4];
++	u32 i, bw;
++
++	bw = (readl(PHY_REG(phy_base, 0x0)) >> 4) & 0xf;
++	switch (bw) {
++	case 0x1:
++		bw = 1;
++		break;
++	case 0x3:
++		bw = 2;
++		break;
++	case 0xf:
++	default:
++		bw = 4;
++		break;
++	}
++
++	for (i = 0; i < bw; i++) {
++		gate[i] = readl(PHY_REG(phy_base, 0xfb + i));
++		max_val = MAX(max_val, gate[i]);
++		min_val = MIN(min_val, gate[i]);
++	}
++
++	if (max_val > 0x80 || min_val < 0x20)
++		return -1;
++	else
++		return 0;
++}
++
++static int data_training(struct dram_info *dram, u32 cs, u32 dramtype)
++{
++	void __iomem *pctl_base = dram->pctl;
++	u32 dis_auto_zq = 0;
++	u32 pwrctl;
++	u32 ret;
++
++	/* disable auto low-power */
++	pwrctl = readl(pctl_base + DDR_PCTL2_PWRCTL);
++	writel(0, pctl_base + DDR_PCTL2_PWRCTL);
++
++	dis_auto_zq = pctl_dis_zqcs_aref(dram->pctl);
++
++	ret = phy_data_training(dram->phy, cs, dramtype);
++
++	pctl_rest_zqcs_aref(dram->pctl, dis_auto_zq);
++
++	/* restore auto low-power */
++	writel(pwrctl, pctl_base + DDR_PCTL2_PWRCTL);
++
++	return ret;
++}
++
++static void dram_set_bw(struct dram_info *dram, u32 bw)
++{
++	phy_dram_set_bw(dram->phy, bw);
++}
++
++static void set_ddrconfig(struct dram_info *dram, u32 ddrconfig)
++{
++	writel(ddrconfig | (ddrconfig << 8), &dram->msch->deviceconf);
++	rk_clrsetreg(&dram->grf->soc_noc_con[1], 0x3 << 14, 0 << 14);
++}
++
++static void dram_all_config(struct dram_info *dram,
++			    struct px30_sdram_params *sdram_params)
++{
++	struct px30_sdram_channel *cap_info = &sdram_params->ch;
++	u32 sys_reg2 = 0;
++	u32 sys_reg3 = 0;
++
++	set_ddrconfig(dram, cap_info->ddrconfig);
++	sdram_org_config(cap_info, &sdram_params->base, &sys_reg2,
++			 &sys_reg3, 0);
++	writel(sys_reg2, &dram->pmugrf->os_reg[2]);
++	writel(sys_reg3, &dram->pmugrf->os_reg[3]);
++	sdram_msch_config(dram->msch, &sdram_params->ch.noc_timings, cap_info,
++			  &sdram_params->base);
++}
++
++static void enable_low_power(struct dram_info *dram,
++			     struct px30_sdram_params *sdram_params)
++{
++	void __iomem *pctl_base = dram->pctl;
++	void __iomem *phy_base = dram->phy;
++	void __iomem *ddr_grf_base = dram->ddr_grf;
++	u32 grf_lp_con;
++
++	/*
++	 * bit0: grf_upctl_axi_cg_en = 1 enable upctl2 axi clk auto gating
++	 * bit1: grf_upctl_apb_cg_en = 1 ungated axi,core clk for apb access
++	 * bit2: grf_upctl_core_cg_en = 1 enable upctl2 core clk auto gating
++	 * bit3: grf_selfref_type2_en = 0 disable core clk gating when type2 sr
++	 * bit4: grf_upctl_syscreq_cg_en = 1
++	 *       ungating coreclk when c_sysreq assert
++	 * bit8-11: grf_auto_sr_dly = 6
++	 */
++	writel(0x1f1f0617, &dram->ddr_grf->ddr_grf_con[1]);
++
++	if (sdram_params->base.dramtype == DDR4)
++		grf_lp_con = (0x7 << 16) | (1 << 1);
++	else if (sdram_params->base.dramtype == DDR3)
++		grf_lp_con = (0x7 << 16) | (1 << 0);
++	else
++		grf_lp_con = (0x7 << 16) | (1 << 2);
++
++	/* en lpckdis_en */
++	grf_lp_con = grf_lp_con | (0x1 << (9 + 16)) | (0x1 << 9);
++	writel(grf_lp_con, ddr_grf_base + DDR_GRF_LP_CON);
++
++	/* off digit module clock when enter power down */
++	setbits_le32(PHY_REG(phy_base, 7), 1 << 7);
++
++	/* enable sr, pd */
++	if (PD_IDLE == 0)
++		clrbits_le32(pctl_base + DDR_PCTL2_PWRCTL, (1 << 1));
++	else
++		setbits_le32(pctl_base + DDR_PCTL2_PWRCTL, (1 << 1));
++	if (SR_IDLE == 0)
++		clrbits_le32(pctl_base + DDR_PCTL2_PWRCTL, 1);
++	else
++		setbits_le32(pctl_base + DDR_PCTL2_PWRCTL, 1);
++	setbits_le32(pctl_base + DDR_PCTL2_PWRCTL, (1 << 3));
++}
++
++/*
++ * pre_init: 0: pre init for dram cap detect
++ * 1: detect correct cap(except cs1 row)info, than reinit
++ * 2: after reinit, we detect cs1_row, if cs1_row not equal
++ *    to cs0_row and cs is in middle on ddrconf map, we need
++ *    to reinit dram, than set the correct ddrconf.
++ */
++static int sdram_init_(struct dram_info *dram,
++		       struct px30_sdram_params *sdram_params, u32 pre_init)
++{
++	struct px30_sdram_channel *cap_info = &sdram_params->ch;
++	void __iomem *pctl_base = dram->pctl;
++
++	rkclk_ddr_reset(dram, 1, 1, 1, 1);
++	rockchip_udelay(10);
++	/*
++	 * dereset ddr phy psrstn to config pll,
++	 * if using phy pll psrstn must be dereset
++	 * before config pll
++	 */
++	rkclk_ddr_reset(dram, 1, 1, 1, 0);
++	rkclk_configure_ddr(dram, sdram_params);
++
++	/* release phy srst to provide clk to ctrl */
++	rkclk_ddr_reset(dram, 1, 1, 0, 0);
++	rockchip_udelay(10);
++	phy_soft_reset(dram->phy);
++
++	/* release ctrl presetn, and config ctl registers */
++	rkclk_ddr_reset(dram, 1, 0, 0, 0);
++	pctl_cfg(dram->pctl, &sdram_params->pctl_regs, SR_IDLE, PD_IDLE);
++	cap_info->ddrconfig = calculate_ddrconfig(sdram_params);
++	set_ctl_address_map(dram, sdram_params);
++	phy_cfg(dram->phy, &sdram_params->phy_regs, sdram_params->skew,
++		&sdram_params->base, cap_info->bw);
++
++	/* enable dfi_init_start to init phy after ctl srstn deassert */
++	setbits_le32(pctl_base + DDR_PCTL2_DFIMISC, (1 << 5) | (1 << 4));
++
++	rkclk_ddr_reset(dram, 0, 0, 0, 0);
++	/* wait for dfi_init_done and dram init complete */
++	while ((readl(pctl_base + DDR_PCTL2_STAT) & 0x7) == 0)
++		continue;
++
++	if (sdram_params->base.dramtype == LPDDR3)
++		pctl_write_mr(dram->pctl, 3, 11, 3, LPDDR3);
++
++	/* do ddr gate training */
++redo_cs0_training:
++	if (data_training(dram, 0, sdram_params->base.dramtype) != 0) {
++		if (pre_init != 0)
++			printascii("DTT cs0 error\n");
++		return -1;
++	}
++	if (check_rd_gate(dram)) {
++		printascii("re training cs0");
++		goto redo_cs0_training;
++	}
++
++	if (sdram_params->base.dramtype == LPDDR3) {
++		if ((read_mr(dram, 1, 8) & 0x3) != 0x3)
++			return -1;
++	} else if (sdram_params->base.dramtype == LPDDR2) {
++		if ((read_mr(dram, 1, 8) & 0x3) != 0x0)
++			return -1;
++	}
++
++	/* for px30: when 2cs, both 2 cs should be training */
++	if (pre_init != 0 && cap_info->rank == 2) {
++redo_cs1_training:
++		if (data_training(dram, 1, sdram_params->base.dramtype) != 0) {
++			printascii("DTT cs1 error\n");
++			return -1;
++		}
++		if (check_rd_gate(dram)) {
++			printascii("re training cs1");
++			goto redo_cs1_training;
++		}
++	}
++
++	if (sdram_params->base.dramtype == DDR4)
++		pctl_write_vrefdq(dram->pctl, 0x3, 5670,
++				  sdram_params->base.dramtype);
++
++	dram_all_config(dram, sdram_params);
++	enable_low_power(dram, sdram_params);
++
++	return 0;
++}
++
++static int dram_detect_cap(struct dram_info *dram,
++			   struct px30_sdram_params *sdram_params,
++			   unsigned char channel)
++{
++	struct px30_sdram_channel *cap_info = &sdram_params->ch;
++
++	/*
++	 * for ddr3: ddrconf = 3
++	 * for ddr4: ddrconf = 12
++	 * for lpddr3: ddrconf = 3
++	 * default bw = 1
++	 */
++	u32 bk, bktmp;
++	u32 col, coltmp;
++	u32 rowtmp;
++	u32 cs;
++	u32 bw = 1;
++	u32 dram_type = sdram_params->base.dramtype;
++
++	if (dram_type != DDR4) {
++		/* detect col and bk for ddr3/lpddr3 */
++		coltmp = 12;
++		bktmp = 3;
++		if (dram_type == LPDDR2)
++			rowtmp = 15;
++		else
++			rowtmp = 16;
++
++		if (sdram_detect_col(cap_info, coltmp) != 0)
++			goto cap_err;
++		sdram_detect_bank(cap_info, coltmp, bktmp);
++		sdram_detect_dbw(cap_info, dram_type);
++	} else {
++		/* detect bg for ddr4 */
++		coltmp = 10;
++		bktmp = 4;
++		rowtmp = 17;
++
++		col = 10;
++		bk = 2;
++		cap_info->col = col;
++		cap_info->bk = bk;
++		sdram_detect_bg(cap_info, coltmp);
++	}
++
++	/* detect row */
++	if (sdram_detect_row(cap_info, coltmp, bktmp, rowtmp) != 0)
++		goto cap_err;
++
++	/* detect row_3_4 */
++	sdram_detect_row_3_4(cap_info, coltmp, bktmp);
++
++	/* bw and cs detect using data training */
++	if (data_training(dram, 1, dram_type) == 0)
++		cs = 1;
++	else
++		cs = 0;
++	cap_info->rank = cs + 1;
++
++	dram_set_bw(dram, 2);
++	if (data_training(dram, 0, dram_type) == 0)
++		bw = 2;
++	else
++		bw = 1;
++	cap_info->bw = bw;
++
++	cap_info->cs0_high16bit_row = cap_info->cs0_row;
++	if (cs) {
++		cap_info->cs1_row = cap_info->cs0_row;
++		cap_info->cs1_high16bit_row = cap_info->cs0_row;
++	} else {
++		cap_info->cs1_row = 0;
++		cap_info->cs1_high16bit_row = 0;
++	}
++
++	return 0;
++cap_err:
++	return -1;
++}
++
++static int sdram_init_detect(struct dram_info *dram,
++			     struct px30_sdram_params *sdram_params)
++{
++	struct px30_sdram_channel *cap_info = &sdram_params->ch;
++	u32 ret;
++	u32 sys_reg = 0;
++	u32 sys_reg3 = 0;
++
++	if (sdram_init_(dram, sdram_params, 0) != 0)
++		return -1;
++
++	if (dram_detect_cap(dram, sdram_params, 0) != 0)
++		return -1;
++
++	/* modify bw, cs related timing */
++	pctl_remodify_sdram_params(&sdram_params->pctl_regs, cap_info,
++				   sdram_params->base.dramtype);
++	/* reinit sdram by real dram cap */
++	ret = sdram_init_(dram, sdram_params, 1);
++	if (ret != 0)
++		goto out;
++
++	/* redetect cs1 row */
++	sdram_detect_cs1_row(cap_info, sdram_params->base.dramtype);
++	if (cap_info->cs1_row) {
++		sys_reg = readl(&dram->pmugrf->os_reg[2]);
++		sys_reg3 = readl(&dram->pmugrf->os_reg[3]);
++		writel(sys_reg, &dram->pmugrf->os_reg[2]);
++		writel(sys_reg3, &dram->pmugrf->os_reg[3]);
++	}
++
++	ret = sdram_detect_high_row(cap_info);
++
++out:
++	return ret;
++}
++
++struct px30_sdram_params *get_default_sdram_config(void)
++{
++	sdram_configs[0].skew = &skew;
++
++	return &sdram_configs[0];
++}
++
++int sdram_init(void)
++{
++	struct px30_sdram_params *sdram_params;
++	int ret = 0;
++
++	dram_info.phy = (void *)DDR_PHY_BASE_ADDR;
++	dram_info.pctl = (void *)DDRC_BASE_ADDR;
++	dram_info.grf = (void *)GRF_BASE_ADDR;
++	dram_info.cru = (void *)CRU_BASE_ADDR;
++	dram_info.msch = (void *)SERVER_MSCH0_BASE_ADDR;
++	dram_info.ddr_grf = (void *)DDR_GRF_BASE_ADDR;
++	dram_info.pmugrf = (void *)PMUGRF_BASE_ADDR;
++
++	sdram_params = get_default_sdram_config();
++	ret = sdram_init_detect(&dram_info, sdram_params);
++	if (ret)
++		return ret;
++
++	return ret;
++}
++#endif /* CONFIG_TPL_BUILD */
+diff --git a/arch/arm/mach-rockchip/px30/syscon_px30.c b/arch/arm/mach-rockchip/px30/syscon_px30.c
+new file mode 100644
+index 0000000000..0331491b40
+--- /dev/null
++++ b/arch/arm/mach-rockchip/px30/syscon_px30.c
+@@ -0,0 +1,53 @@
++// SPDX-License-Identifier: GPL-2.0
++/*
++ * (C) Copyright 2017 Rockchip Electronics Co., Ltd
++ */
++
++#include <common.h>
++#include <dm.h>
++#include <syscon.h>
++#include <asm/arch-rockchip/clock.h>
++
++static const struct udevice_id px30_syscon_ids[] = {
++	{ .compatible = "rockchip,px30-pmu", .data = ROCKCHIP_SYSCON_PMU },
++	{ .compatible = "rockchip,px30-pmugrf", .data = ROCKCHIP_SYSCON_PMUGRF },
++	{ .compatible = "rockchip,px30-grf", .data = ROCKCHIP_SYSCON_GRF },
++	{ }
++};
++
++U_BOOT_DRIVER(syscon_px30) = {
++	.id = UCLASS_SYSCON,
++	.name = "px30_syscon",
++	.of_match = px30_syscon_ids,
++};
++
++#if CONFIG_IS_ENABLED(OF_PLATDATA)
++static int px30_syscon_bind_of_platdata(struct udevice *dev)
++{
++	dev->driver_data = dev->driver->of_match->data;
++	debug("syscon: %s %d\n", dev->name, (uint)dev->driver_data);
++
++	return 0;
++}
++
++U_BOOT_DRIVER(rockchip_px30_pmu) = {
++	.name = "rockchip_px30_pmu",
++	.id = UCLASS_SYSCON,
++	.of_match = px30_syscon_ids,
++	.bind = px30_syscon_bind_of_platdata,
++};
++
++U_BOOT_DRIVER(rockchip_px30_pmugrf) = {
++	.name = "rockchip_px30_pmugrf",
++	.id = UCLASS_SYSCON,
++	.of_match = px30_syscon_ids + 1,
++	.bind = px30_syscon_bind_of_platdata,
++};
++
++U_BOOT_DRIVER(rockchip_px30_grf) = {
++	.name = "rockchip_px30_grf",
++	.id = UCLASS_SYSCON,
++	.of_match = px30_syscon_ids + 2,
++	.bind = px30_syscon_bind_of_platdata,
++};
++#endif
+
+From patchwork Thu Oct 24 23:28:03 2019
+Content-Type: text/plain; charset="utf-8"
+MIME-Version: 1.0
+Content-Transfer-Encoding: 7bit
+X-Patchwork-Submitter: =?utf-8?q?Heiko_St=C3=BCbner?= <heiko@sntech.de>
+X-Patchwork-Id: 1183664
+X-Patchwork-Delegate: ykai007@gmail.com
+Return-Path: <u-boot-bounces@lists.denx.de>
+X-Original-To: incoming@patchwork.ozlabs.org
+Delivered-To: patchwork-incoming@bilbo.ozlabs.org
+Authentication-Results: ozlabs.org;
+ spf=none (no SPF record) smtp.mailfrom=lists.denx.de
+ (client-ip=81.169.180.215; helo=lists.denx.de;
+ envelope-from=u-boot-bounces@lists.denx.de;
+ receiver=<UNKNOWN>)
+Authentication-Results: ozlabs.org;
+ dmarc=none (p=none dis=none) header.from=sntech.de
+Received: from lists.denx.de (dione.denx.de [81.169.180.215])
+ by ozlabs.org (Postfix) with ESMTP id 46zkVl3sCMz9sQm
+ for <incoming@patchwork.ozlabs.org>;
+ Fri, 25 Oct 2019 10:49:35 +1100 (AEDT)
+Received: by lists.denx.de (Postfix, from userid 105)
+ id 3FFE4C21DD7; Thu, 24 Oct 2019 23:49:31 +0000 (UTC)
+X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on lists.denx.de
+X-Spam-Level: 
+X-Spam-Status: No, score=0.0 required=5.0 tests=none autolearn=unavailable
+ autolearn_force=no version=3.4.0
+Received: from lists.denx.de (localhost [IPv6:::1])
+ by lists.denx.de (Postfix) with ESMTP id C5CA9C21E1A;
+ Thu, 24 Oct 2019 23:48:20 +0000 (UTC)
+Received: by lists.denx.de (Postfix, from userid 105)
+ id 1C9F3C21E16; Thu, 24 Oct 2019 23:48:19 +0000 (UTC)
+Received: from gloria.sntech.de (gloria.sntech.de [185.11.138.130])
+ by lists.denx.de (Postfix) with ESMTPS id 4A74FC21DD9
+ for <u-boot@lists.denx.de>; Thu, 24 Oct 2019 23:47:55 +0000 (UTC)
+Received: from ip5f5a6266.dynamic.kabel-deutschland.de ([95.90.98.102]
+ helo=phil.fritz.box) by gloria.sntech.de with esmtpsa
+ (TLS1.2:ECDHE_RSA_AES_128_GCM_SHA256:128)
+ (Exim 4.89) (envelope-from <heiko@sntech.de>)
+ id 1iNmWh-0002cR-Qb; Fri, 25 Oct 2019 01:28:19 +0200
+From: Heiko Stuebner <heiko@sntech.de>
+To: u-boot@lists.denx.de
+Date: Fri, 25 Oct 2019 01:28:03 +0200
+Message-Id: <20191024232803.10338-13-heiko@sntech.de>
+X-Mailer: git-send-email 2.23.0
+In-Reply-To: <20191024232803.10338-1-heiko@sntech.de>
+References: <20191024232803.10338-1-heiko@sntech.de>
+MIME-Version: 1.0
+Cc: Heiko Stuebner <heiko.stuebner@theobroma-systems.com>,
+ joe.hershberger@ni.com, christoph.muellner@theobroma-systems.com
+Subject: [U-Boot] [PATCH 12/12] rockchip: add px30-evb board
+X-BeenThere: u-boot@lists.denx.de
+X-Mailman-Version: 2.1.18
+Precedence: list
+List-Id: U-Boot discussion <u-boot.lists.denx.de>
+List-Unsubscribe: <https://lists.denx.de/options/u-boot>,
+ <mailto:u-boot-request@lists.denx.de?subject=unsubscribe>
+List-Archive: <http://lists.denx.de/pipermail/u-boot/>
+List-Post: <mailto:u-boot@lists.denx.de>
+List-Help: <mailto:u-boot-request@lists.denx.de?subject=help>
+List-Subscribe: <https://lists.denx.de/listinfo/u-boot>,
+ <mailto:u-boot-request@lists.denx.de?subject=subscribe>
+Errors-To: u-boot-bounces@lists.denx.de
+Sender: "U-Boot" <u-boot-bounces@lists.denx.de>
+
+From: Heiko Stuebner <heiko.stuebner@theobroma-systems.com>
+
+The px30 evb is an evaluation board for the px30 together with a dsi-
+connected display. This adds board and config files for it.
+
+Signed-off-by: Heiko Stuebner <heiko.stuebner@theobroma-systems.com>
+Reviewed-by: Kever Yang<kever.yang@rock-chips.com>
+---
+ board/rockchip/evb_px30/Kconfig     |  15 ++++
+ board/rockchip/evb_px30/MAINTAINERS |   6 ++
+ board/rockchip/evb_px30/Makefile    |   7 ++
+ board/rockchip/evb_px30/evb_px30.c  |   4 +
+ configs/evb-px30_defconfig          | 113 ++++++++++++++++++++++++++++
+ include/configs/evb_px30.h          |  19 +++++
+ 6 files changed, 164 insertions(+)
+ create mode 100644 board/rockchip/evb_px30/Kconfig
+ create mode 100644 board/rockchip/evb_px30/MAINTAINERS
+ create mode 100644 board/rockchip/evb_px30/Makefile
+ create mode 100644 board/rockchip/evb_px30/evb_px30.c
+ create mode 100644 configs/evb-px30_defconfig
+ create mode 100644 include/configs/evb_px30.h
+
+diff --git a/board/rockchip/evb_px30/Kconfig b/board/rockchip/evb_px30/Kconfig
+new file mode 100644
+index 0000000000..0042c8e4db
+--- /dev/null
++++ b/board/rockchip/evb_px30/Kconfig
+@@ -0,0 +1,15 @@
++if TARGET_EVB_PX30
++
++config SYS_BOARD
++	default "evb_px30"
++
++config SYS_VENDOR
++	default "rockchip"
++
++config SYS_CONFIG_NAME
++	default "evb_px30"
++
++config BOARD_SPECIFIC_OPTIONS # dummy
++	def_bool y
++
++endif
+diff --git a/board/rockchip/evb_px30/MAINTAINERS b/board/rockchip/evb_px30/MAINTAINERS
+new file mode 100644
+index 0000000000..cf13f2419e
+--- /dev/null
++++ b/board/rockchip/evb_px30/MAINTAINERS
+@@ -0,0 +1,6 @@
++EVB-PX30
++M:      Kever Yang <kever.yang@rock-chips.com>
++S:      Maintained
++F:      board/rockchip/evb_px30
++F:      include/configs/evb_px30.h
++F:      configs/evb-px30_defconfig
+diff --git a/board/rockchip/evb_px30/Makefile b/board/rockchip/evb_px30/Makefile
+new file mode 100644
+index 0000000000..74b0b9f44f
+--- /dev/null
++++ b/board/rockchip/evb_px30/Makefile
+@@ -0,0 +1,7 @@
++#
++# (C) Copyright 2017 Rockchip Electronics Co., Ltd
++#
++# SPDX-License-Identifier:     GPL-2.0+
++#
++
++obj-y	+= evb_px30.o
+diff --git a/board/rockchip/evb_px30/evb_px30.c b/board/rockchip/evb_px30/evb_px30.c
+new file mode 100644
+index 0000000000..29464ae63e
+--- /dev/null
++++ b/board/rockchip/evb_px30/evb_px30.c
+@@ -0,0 +1,4 @@
++// SPDX-License-Identifier: GPL-2.0+
++/*
++ * (C) Copyright 2019 Rockchip Electronics Co., Ltd
++ */
+diff --git a/configs/evb-px30_defconfig b/configs/evb-px30_defconfig
+new file mode 100644
+index 0000000000..d1cc1788c9
+--- /dev/null
++++ b/configs/evb-px30_defconfig
+@@ -0,0 +1,113 @@
++CONFIG_ARM=y
++CONFIG_ARCH_ROCKCHIP=y
++CONFIG_SYS_TEXT_BASE=0x00200000
++CONFIG_SPL_LIBCOMMON_SUPPORT=y
++CONFIG_SPL_LIBGENERIC_SUPPORT=y
++CONFIG_SYS_MALLOC_F_LEN=0x2000
++CONFIG_ROCKCHIP_PX30=y
++CONFIG_TARGET_EVB_PX30=y
++CONFIG_TPL_LIBGENERIC_SUPPORT=y
++CONFIG_SPL_DRIVERS_MISC_SUPPORT=y
++CONFIG_NR_DRAM_BANKS=1
++CONFIG_SPL_STACK_R_ADDR=0x600000
++CONFIG_DEBUG_UART_BASE=0xFF178000
++CONFIG_DEBUG_UART_CLOCK=24000000
++CONFIG_DEBUG_UART=y
++CONFIG_TPL_SYS_MALLOC_F_LEN=0x600
++# CONFIG_ANDROID_BOOT_IMAGE is not set
++CONFIG_FIT=y
++CONFIG_FIT_VERBOSE=y
++CONFIG_SPL_LOAD_FIT=y
++# CONFIG_CONSOLE_MUX is not set
++CONFIG_DEFAULT_FDT_FILE="rockchip/px30-evb.dtb"
++CONFIG_MISC_INIT_R=y
++# CONFIG_DISPLAY_CPUINFO is not set
++CONFIG_DISPLAY_BOARDINFO_LATE=y
++CONFIG_SPL_BOUNCE_BUFFER_STATIC=y
++CONFIG_SPL_TEXT_BASE=0x00000000
++# CONFIG_SPL_BOARD_INIT is not set
++CONFIG_SPL_BOOTROM_SUPPORT=y
++# CONFIG_SPL_RAW_IMAGE_SUPPORT is not set
++# CONFIG_SPL_LEGACY_IMAGE_SUPPORT is not set
++CONFIG_SPL_STACK_R=y
++# CONFIG_TPL_BANNER_PRINT is not set
++CONFIG_SPL_CRC32_SUPPORT=y
++CONFIG_SPL_ATF=y
++# CONFIG_TPL_FRAMEWORK is not set
++# CONFIG_CMD_BOOTD is not set
++# CONFIG_CMD_ELF is not set
++# CONFIG_CMD_IMI is not set
++# CONFIG_CMD_XIMG is not set
++# CONFIG_CMD_LZMADEC is not set
++# CONFIG_CMD_UNZIP is not set
++# CONFIG_CMD_FLASH is not set
++CONFIG_CMD_GPT=y
++# CONFIG_CMD_LOADB is not set
++# CONFIG_CMD_LOADS is not set
++CONFIG_CMD_MMC=y
++CONFIG_CMD_USB=y
++CONFIG_CMD_USB_MASS_STORAGE=y
++# CONFIG_CMD_ITEST is not set
++# CONFIG_CMD_SETEXPR is not set
++# CONFIG_CMD_MISC is not set
++# CONFIG_SPL_DOS_PARTITION is not set
++# CONFIG_ISO_PARTITION is not set
++CONFIG_EFI_PARTITION_ENTRIES_NUMBERS=64
++CONFIG_SPL_OF_CONTROL=y
++CONFIG_OF_LIVE=y
++CONFIG_DEFAULT_DEVICE_TREE="px30-evb"
++CONFIG_OF_SPL_REMOVE_PROPS="pinctrl-0 pinctrl-names interrupt-parent assigned-clocks assigned-clock-rates assigned-clock-parents"
++CONFIG_ENV_IS_IN_MMC=y
++CONFIG_REGMAP=y
++CONFIG_SPL_REGMAP=y
++CONFIG_SYSCON=y
++CONFIG_SPL_SYSCON=y
++CONFIG_CLK=y
++CONFIG_SPL_CLK=y
++CONFIG_FASTBOOT_BUF_ADDR=0x800800
++CONFIG_FASTBOOT_BUF_SIZE=0x04000000
++CONFIG_FASTBOOT_FLASH=y
++CONFIG_FASTBOOT_FLASH_MMC_DEV=0
++CONFIG_ROCKCHIP_GPIO=y
++CONFIG_SYS_I2C_ROCKCHIP=y
++CONFIG_MISC=y
++CONFIG_ROCKCHIP_OTP=y
++CONFIG_MMC_DW=y
++CONFIG_MMC_DW_ROCKCHIP=y
++CONFIG_DM_ETH=y
++CONFIG_ETH_DESIGNWARE=y
++CONFIG_GMAC_ROCKCHIP=y
++CONFIG_PHY_REALTEK=y
++CONFIG_PINCTRL=y
++CONFIG_DM_PMIC=y
++CONFIG_PMIC_RK8XX=y
++CONFIG_REGULATOR_PWM=y
++CONFIG_DM_REGULATOR_FIXED=y
++CONFIG_REGULATOR_RK8XX=y
++CONFIG_PWM_ROCKCHIP=y
++CONFIG_RAM=y
++CONFIG_SPL_RAM=y
++CONFIG_DM_RESET=y
++# CONFIG_SPECIFY_CONSOLE_INDEX is not set
++# CONFIG_TPL_DM_SERIAL is not set
++CONFIG_DEBUG_UART_SHIFT=2
++CONFIG_DEBUG_UART_SKIP_INIT=y
++CONFIG_SOUND=y
++CONFIG_SYSRESET=y
++CONFIG_OPTEE=y
++CONFIG_DM_THERMAL=y
++CONFIG_USB=y
++CONFIG_USB_EHCI_HCD=y
++CONFIG_USB_EHCI_GENERIC=y
++CONFIG_USB_GADGET=y
++CONFIG_USB_GADGET_DWC2_OTG=y
++CONFIG_DM_VIDEO=y
++CONFIG_DISPLAY=y
++CONFIG_LCD=y
++CONFIG_USE_TINY_PRINTF=y
++CONFIG_SPL_TINY_MEMSET=y
++CONFIG_TPL_TINY_MEMSET=y
++CONFIG_LZ4=y
++CONFIG_LZO=y
++CONFIG_ERRNO_STR=y
++# CONFIG_EFI_LOADER is not set
+diff --git a/include/configs/evb_px30.h b/include/configs/evb_px30.h
+new file mode 100644
+index 0000000000..e761c7c519
+--- /dev/null
++++ b/include/configs/evb_px30.h
+@@ -0,0 +1,19 @@
++/* SPDX-License-Identifier: GPL-2.0+ */
++/*
++ * (C) Copyright 2017 Rockchip Electronics Co., Ltd
++ */
++
++#ifndef __EVB_PX30_H
++#define __EVB_PX30_H
++
++#include <configs/px30_common.h>
++
++#define CONFIG_SYS_MMC_ENV_DEV 0
++
++#define ROCKCHIP_DEVICE_SETTINGS \
++		"stdout=serial,vidconsole\0" \
++		"stderr=serial,vidconsole\0"
++
++#define CONFIG_SUPPORT_EMMC_RPMB
++
++#endif
+
diff --git a/layers/meta-balena-nanopc-t4/recipes-bsp/u-boot/files/0001-lec-px30.patch b/layers/meta-balena-nanopc-t4/recipes-bsp/u-boot/files/0001-lec-px30.patch
new file mode 100644
index 000000000..def3234da
--- /dev/null
+++ b/layers/meta-balena-nanopc-t4/recipes-bsp/u-boot/files/0001-lec-px30.patch
@@ -0,0 +1,2310 @@
+From 7f97b6f09036cadff3055010b631b01b3b6caea2 Mon Sep 17 00:00:00 2001
+From: Alexandru Costache <alexandru@balena.io>
+Date: Mon, 18 Jan 2021 09:37:18 +0100
+Subject: [PATCH] Add lec-px30 support
+
+Upstream-status: Inappropriate[backport]
+Signed-off-by: David Tischler
+---
+ arch/arm/dts/lec-px30.dtsi | 2275 ++++++++++++++++++++++++++++++++++++
+ configs/evb-px30_defconfig |    5 +
+ 2 files changed, 2280 insertions(+)
+ create mode 100644 arch/arm/dts/lec-px30.dtsi
+
+diff --git a/arch/arm/dts/lec-px30.dtsi b/arch/arm/dts/lec-px30.dtsi
+new file mode 100644
+index 0000000000..5b830093d1
+--- /dev/null
++++ b/arch/arm/dts/lec-px30.dtsi
+@@ -0,0 +1,2275 @@
++/*
++ * Copyright (c) 2017 Fuzhou Rockchip Electronics Co., Ltd
++ *
++ * SPDX-License-Identifier: (GPL-2.0+ OR MIT)
++ */
++
++#include <dt-bindings/clock/px30-cru.h>
++#include <dt-bindings/gpio/gpio.h>
++#include <dt-bindings/interrupt-controller/arm-gic.h>
++#include <dt-bindings/interrupt-controller/irq.h>
++#include <dt-bindings/pinctrl/rockchip.h>
++#include <dt-bindings/power/px30-power.h>
++#include <dt-bindings/soc/rockchip,boot-mode.h>
++
++/ {
++	compatible = "rockchip,lec-px30";
++
++	interrupt-parent = <&gic>;
++	#address-cells = <2>;
++	#size-cells = <2>;
++
++	aliases {
++		serial0 = &uart0;
++		serial1 = &uart1;
++		serial2 = &uart2;
++		i2c0 = &i2c0;
++		i2c1 = &i2c1;
++		i2c2 = &i2c2;
++		i2c3 = &i2c3;
++	};
++
++	cpus {
++		#address-cells = <2>;
++		#size-cells = <0>;
++
++		cpu0: cpu@0 {
++			device_type = "cpu";
++			compatible = "arm,cortex-a35", "arm,armv8";
++			reg = <0x0 0x0>;
++			enable-method = "psci";
++		};
++
++		cpu1: cpu@1 {
++			device_type = "cpu";
++			compatible = "arm,cortex-a35", "arm,armv8";
++			reg = <0x0 0x1>;
++			enable-method = "psci";
++		};
++		cpu2: cpu@2 {
++			device_type = "cpu";
++			compatible = "arm,cortex-a35", "arm,armv8";
++			reg = <0x0 0x2>;
++			enable-method = "psci";
++		};
++		cpu3: cpu@3 {
++			device_type = "cpu";
++			compatible = "arm,cortex-a35", "arm,armv8";
++			reg = <0x0 0x3>;
++			enable-method = "psci";
++		};
++	};
++
++	arm-pmu {
++		compatible = "arm,cortex-a53-pmu";
++		interrupts = <GIC_SPI 100 IRQ_TYPE_LEVEL_HIGH>,
++			     <GIC_SPI 101 IRQ_TYPE_LEVEL_HIGH>,
++			     <GIC_SPI 102 IRQ_TYPE_LEVEL_HIGH>,
++			     <GIC_SPI 103 IRQ_TYPE_LEVEL_HIGH>;
++		interrupt-affinity = <&cpu0>, <&cpu1>, <&cpu2>, <&cpu3>;
++	};
++
++	dmc: dmc {
++		compatible = "rockchip,px30-dmc", "syscon";
++		reg = <0x0 0xff2a0000 0x0 0x1000>;
++	};
++
++	display_subsystem: display-subsystem {
++		compatible = "rockchip,display-subsystem";
++		ports = <&vopb_out>, <&vopl_out>;
++		status = "disabled";
++	};
++
++	firmware {
++		optee {
++			compatible = "linaro,optee-tz";
++			method = "smc";
++		};
++	};
++
++	gmac_clkin: external-gmac-clock {
++		compatible = "fixed-clock";
++		clock-frequency = <50000000>;
++		clock-output-names = "gmac_clkin";
++		#clock-cells = <0>;
++	};
++
++	psci {
++		compatible = "arm,psci-1.0";
++		method = "smc";
++	};
++
++	timer {
++		compatible = "arm,armv8-timer";
++		interrupts = <GIC_PPI 13 (GIC_CPU_MASK_SIMPLE(4) | IRQ_TYPE_LEVEL_HIGH)>,
++			     <GIC_PPI 14 (GIC_CPU_MASK_SIMPLE(4) | IRQ_TYPE_LEVEL_HIGH)>,
++			     <GIC_PPI 11 (GIC_CPU_MASK_SIMPLE(4) | IRQ_TYPE_LEVEL_HIGH)>,
++			     <GIC_PPI 10 (GIC_CPU_MASK_SIMPLE(4) | IRQ_TYPE_LEVEL_HIGH)>;
++	};
++
++	xin24m: xin24m {
++		compatible = "fixed-clock";
++		#clock-cells = <0>;
++		clock-frequency = <24000000>;
++		clock-output-names = "xin24m";
++	};
++
++	pmu: power-management@ff000000 {
++		compatible = "rockchip,px30-pmu", "syscon", "simple-mfd";
++		reg = <0x0 0xff000000 0x0 0x1000>;
++
++		power: power-controller {
++			compatible = "rockchip,px30-power-controller";
++			#power-domain-cells = <1>;
++			#address-cells = <1>;
++			#size-cells = <0>;
++			status = "disabled";
++
++			/* These power domains are grouped by VD_LOGIC */
++			pd_usb@PX30_PD_USB {
++				reg = <PX30_PD_USB>;
++				clocks = <&cru HCLK_HOST>,
++					 <&cru HCLK_OTG>,
++					 <&cru SCLK_OTG_ADP>;
++			};
++			pd_sdcard@PX30_PD_SDCARD {
++				reg = <PX30_PD_SDCARD>;
++				clocks = <&cru HCLK_SDMMC>,
++					 <&cru SCLK_SDMMC>;
++			};
++			pd_gmac@PX30_PD_GMAC {
++				reg = <PX30_PD_GMAC>;
++				clocks = <&cru ACLK_GMAC>,
++					 <&cru PCLK_GMAC>,
++					 <&cru SCLK_MAC_REF>,
++					 <&cru SCLK_GMAC_RX_TX>;
++			};
++			pd_mmc_nand@PX30_PD_MMC_NAND {
++				reg = <PX30_PD_MMC_NAND>;
++				clocks =  <&cru HCLK_NANDC>,
++					  <&cru HCLK_EMMC>,
++					  <&cru HCLK_SDIO>,
++					  <&cru HCLK_SFC>,
++					  <&cru SCLK_EMMC>,
++					  <&cru SCLK_NANDC>,
++					  <&cru SCLK_SDIO>,
++					  <&cru SCLK_SFC>;
++			};
++			pd_vpu@PX30_PD_VPU {
++				reg = <PX30_PD_VPU>;
++				clocks = <&cru ACLK_VPU>,
++					 <&cru HCLK_VPU>,
++					 <&cru SCLK_CORE_VPU>;
++			};
++			pd_vo@PX30_PD_VO {
++				reg = <PX30_PD_VO>;
++				clocks = <&cru ACLK_RGA>,
++					 <&cru ACLK_VOPB>,
++					 <&cru ACLK_VOPL>,
++					 <&cru DCLK_VOPB>,
++					 <&cru DCLK_VOPL>,
++					 <&cru HCLK_RGA>,
++					 <&cru HCLK_VOPB>,
++					 <&cru HCLK_VOPL>,
++					 <&cru PCLK_MIPI_DSI>,
++					 <&cru SCLK_RGA_CORE>,
++					 <&cru SCLK_VOPB_PWM>;
++			};
++			pd_vi@PX30_PD_VI {
++				reg = <PX30_PD_VI>;
++				clocks = <&cru ACLK_CIF>,
++					 <&cru ACLK_ISP>,
++					 <&cru HCLK_CIF>,
++					 <&cru HCLK_ISP>,
++					 <&cru SCLK_ISP>;
++			};
++			pd_gpu@PX30_PD_GPU {
++				reg = <PX30_PD_GPU>;
++				clocks = <&cru ACLK_GPU>;
++			};
++		};
++	};
++
++	pmugrf: syscon@ff010000 {
++		compatible = "rockchip,px30-pmugrf", "syscon", "simple-mfd";
++		reg = <0x0 0xff010000 0x0 0x1000>;
++		#address-cells = <1>;
++		#size-cells = <1>;
++
++		pmu_io_domains: io-domains {
++			compatible = "rockchip,px30-pmu-io-voltage-domain";
++			status = "disabled";
++		};
++
++		reboot-mode {
++			compatible = "syscon-reboot-mode";
++			offset = <0x200>;
++			mode-bootloader = <BOOT_BL_DOWNLOAD>;
++			mode-charge = <BOOT_CHARGING>;
++			mode-fastboot = <BOOT_FASTBOOT>;
++			mode-loader = <BOOT_BL_DOWNLOAD>;
++			mode-normal = <BOOT_NORMAL>;
++			mode-recovery = <BOOT_RECOVERY>;
++			mode-ums = <BOOT_UMS>;
++		};
++
++		pmu_pvtm: pmu-pvtm {
++			compatible = "rockchip,px30-pmu-pvtm";
++			clocks = <&pmucru SCLK_PVTM_PMU>;
++			clock-names = "pmu";
++			status = "disabled";
++		};
++	};
++
++	uart0: serial@ff030000 {
++		compatible = "rockchip,px30-uart", "snps,dw-apb-uart";
++		reg = <0x0 0xff030000 0x0 0x100>;
++		interrupts = <GIC_SPI 15 IRQ_TYPE_LEVEL_HIGH>;
++		clocks = <&cru SCLK_UART0_PMU>, <&cru PCLK_UART0_PMU>;
++		clock-names = "baudclk", "apb_pclk";
++		reg-shift = <2>;
++		reg-io-width = <4>;
++		dmas = <&dmac 0>, <&dmac 1>;
++		#dma-cells = <2>;
++		pinctrl-names = "default";
++		pinctrl-0 = <&uart0_xfer &uart0_cts &uart0_rts>;
++		status = "disabled";
++	};
++
++	i2s0_8ch: i2s@ff060000 {
++		compatible = "rockchip,px30-i2s", "rockchip,rk3066-i2s";
++		reg = <0x0 0xff060000 0x0 0x1000>;
++		interrupts = <GIC_SPI 12 IRQ_TYPE_LEVEL_HIGH>;
++		clocks = <&cru SCLK_I2S0_TX>, <&cru HCLK_I2S0>;
++		clock-names = "i2s_clk", "i2s_hclk";
++		dmas = <&dmac 16>, <&dmac 17>;
++		dma-names = "tx", "rx";
++		status = "disabled";
++	};
++
++	i2s1_2ch: i2s@ff070000 {
++		compatible = "rockchip,px30-i2s", "rockchip,rk3066-i2s";
++		reg = <0x0 0xff070000 0x0 0x1000>;
++		interrupts = <GIC_SPI 13 IRQ_TYPE_LEVEL_HIGH>;
++		clocks = <&cru SCLK_I2S1>, <&cru HCLK_I2S1>;
++		clock-names = "i2s_clk", "i2s_hclk";
++		dmas = <&dmac 18>, <&dmac 19>;
++		dma-names = "tx", "rx";
++		status = "disabled";
++	};
++
++	i2s2_2ch: i2s@ff080000 {
++		compatible = "rockchip,px30-i2s", "rockchip,rk3066-i2s";
++		reg = <0x0 0xff080000 0x0 0x1000>;
++		interrupts = <GIC_SPI 14 IRQ_TYPE_LEVEL_HIGH>;
++		clocks = <&cru SCLK_I2S2>, <&cru HCLK_I2S2>;
++		clock-names = "i2s_clk", "i2s_hclk";
++		dmas = <&dmac 20>, <&dmac 21>;
++		dma-names = "tx", "rx";
++		status = "disabled";
++	};
++
++	pdm: pdm@ff0a0000 {
++		compatible = "rockchip,pdm";
++		reg = <0x0 0xff0a0000 0x0 0x1000>;
++		clocks = <&cru SCLK_PDM>, <&cru HCLK_PDM>;
++		clock-names = "pdm_clk", "pdm_hclk";
++		dmas = <&dmac 24>;
++		dma-names = "rx";
++		status = "disabled";
++	};
++
++	gic: interrupt-controller@ff131000 {
++		compatible = "arm,gic-400";
++		#interrupt-cells = <3>;
++		#address-cells = <0>;
++		interrupt-controller;
++		reg = <0x0 0xff131000 0 0x1000>,
++		      <0x0 0xff132000 0 0x2000>,
++		      <0x0 0xff134000 0 0x2000>,
++		      <0x0 0xff136000 0 0x2000>;
++		interrupts = <GIC_PPI 9
++		      (GIC_CPU_MASK_SIMPLE(4) | IRQ_TYPE_LEVEL_HIGH)>;
++	};
++
++	grf: syscon@ff140000 {
++		compatible = "rockchip,px30-grf", "syscon", "simple-mfd";
++		reg = <0x0 0xff140000 0x0 0x1000>;
++		#address-cells = <1>;
++		#size-cells = <1>;
++
++		io_domains: io-domains {
++			compatible = "rockchip,px30-io-voltage-domain";
++			status = "disabled";
++		};
++	};
++
++	core_grf: syscon@ff148000 {
++		compatible = "syscon", "simple-mfd";
++		reg = <0x0 0xff148000 0x0 0x1000>;
++		#address-cells = <1>;
++		#size-cells = <1>;
++
++		pvtm: pvtm {
++			compatible = "rockchip,px30-pvtm";
++			clocks = <&cru SCLK_PVTM>;
++			clock-names = "core";
++			status = "disabled";
++		};
++	};
++
++	uart1: serial@ff158000 {
++		compatible = "rockchip,px30-uart", "snps,dw-apb-uart";
++		reg = <0x0 0xff158000 0x0 0x100>;
++		interrupts = <GIC_SPI 16 IRQ_TYPE_LEVEL_HIGH>;
++		clocks = <&cru SCLK_UART1>, <&cru PCLK_UART1>;
++		clock-names = "sclk_uart", "pclk_uart";
++		reg-shift = <2>;
++		reg-io-width = <4>;
++		dmas = <&dmac 2>, <&dmac 3>;
++		#dma-cells = <2>;
++		pinctrl-names = "default";
++		pinctrl-0 = <&uart1_xfer &uart1_cts &uart1_rts>;
++		status = "disabled";
++	};
++
++	uart2: serial@ff160000 {
++		compatible = "rockchip,px30-uart", "snps,dw-apb-uart";
++		reg = <0x0 0xff160000 0x0 0x100>;
++		interrupts = <GIC_SPI 17 IRQ_TYPE_LEVEL_HIGH>;
++		clocks = <&cru SCLK_UART2>, <&cru PCLK_UART2>;
++		clock-names = "baudclk", "apb_pclk";
++		reg-shift = <2>;
++		reg-io-width = <4>;
++		dmas = <&dmac 4>, <&dmac 5>;
++		#dma-cells = <2>;
++		pinctrl-names = "default";
++		pinctrl-0 = <&uart2m0_xfer>;
++		status = "disabled";
++	};
++
++	uart3: serial@ff168000 {
++		compatible = "rockchip,px30-uart", "snps,dw-apb-uart";
++		reg = <0x0 0xff168000 0x0 0x100>;
++		interrupts = <GIC_SPI 18 IRQ_TYPE_LEVEL_HIGH>;
++		clocks = <&cru SCLK_UART3>, <&cru PCLK_UART3>;
++		clock-names = "baudclk", "apb_pclk";
++		reg-shift = <2>;
++		reg-io-width = <4>;
++		dmas = <&dmac 6>, <&dmac 7>;
++		#dma-cells = <2>;
++		pinctrl-names = "default";
++		pinctrl-0 = <&uart3m1_xfer &uart3m1_cts &uart3m1_rts>;
++		status = "disabled";
++	};
++
++	uart4: serial@ff170000 {
++		compatible = "rockchip,px30-uart", "snps,dw-apb-uart";
++		reg = <0x0 0xff170000 0x0 0x100>;
++		interrupts = <GIC_SPI 19 IRQ_TYPE_LEVEL_HIGH>;
++		clocks = <&cru SCLK_UART4>, <&cru PCLK_UART4>;
++		clock-names = "baudclk", "apb_pclk";
++		reg-shift = <2>;
++		reg-io-width = <4>;
++		dmas = <&dmac 8>, <&dmac 9>;
++		#dma-cells = <2>;
++		pinctrl-names = "default";
++		pinctrl-0 = <&uart4_xfer &uart4_cts &uart4_rts>;
++		status = "disabled";
++	};
++
++	uart5: serial@ff178000 {
++		compatible = "rockchip,px30-uart", "snps,dw-apb-uart";
++		reg = <0x0 0xff178000 0x0 0x100>;
++		interrupts = <GIC_SPI 20 IRQ_TYPE_LEVEL_HIGH>;
++		clocks = <&cru SCLK_UART5>, <&cru PCLK_UART5>;
++		clock-names = "baudclk", "apb_pclk";
++		reg-shift = <2>;
++		reg-io-width = <4>;
++		dmas = <&dmac 10>, <&dmac 11>;
++		#dma-cells = <2>;
++		pinctrl-names = "default";
++		pinctrl-0 = <&uart5_xfer &uart5_cts &uart5_rts>;
++		status = "disabled";
++	};
++
++	i2c0: i2c@ff180000 {
++		compatible = "rockchip,rk3399-i2c";
++		reg = <0x0 0xff180000 0x0 0x1000>;
++		clocks =  <&cru SCLK_I2C0>, <&cru PCLK_I2C0>;
++		clock-names = "i2c", "pclk";
++		interrupts = <GIC_SPI 7 IRQ_TYPE_LEVEL_HIGH>;
++		pinctrl-names = "default";
++		pinctrl-0 = <&i2c0_xfer>;
++		#address-cells = <1>;
++		#size-cells = <0>;
++		status = "disabled";
++	};
++
++	i2c1: i2c@ff190000 {
++		compatible = "rockchip,rk3399-i2c";
++		reg = <0x0 0xff190000 0x0 0x1000>;
++		clocks = <&cru SCLK_I2C1>, <&cru PCLK_I2C1>;
++		clock-names = "i2c", "pclk";
++		interrupts = <GIC_SPI 8 IRQ_TYPE_LEVEL_HIGH>;
++		pinctrl-names = "default";
++		pinctrl-0 = <&i2c1_xfer>;
++		#address-cells = <1>;
++		#size-cells = <0>;
++		status = "disabled";
++	};
++
++	i2c2: i2c@ff1a0000 {
++		compatible = "rockchip,rk3399-i2c";
++		reg = <0x0 0xff1a0000 0x0 0x1000>;
++		clocks = <&cru SCLK_I2C2>, <&cru PCLK_I2C2>;
++		clock-names = "i2c", "pclk";
++		interrupts = <GIC_SPI 9 IRQ_TYPE_LEVEL_HIGH>;
++		pinctrl-names = "default";
++		pinctrl-0 = <&i2c2_xfer>;
++		#address-cells = <1>;
++		#size-cells = <0>;
++		status = "disabled";
++	};
++
++	i2c3: i2c@ff1b0000 {
++		compatible = "rockchip,rk3399-i2c";
++		reg = <0x0 0xff1b0000 0x0 0x1000>;
++		clocks = <&cru SCLK_I2C3>, <&cru PCLK_I2C3>;
++		clock-names = "i2c", "pclk";
++		interrupts = <GIC_SPI 10 IRQ_TYPE_LEVEL_HIGH>;
++		pinctrl-names = "default";
++		pinctrl-0 = <&i2c3_xfer>;
++		#address-cells = <1>;
++		#size-cells = <0>;
++		status = "disabled";
++	};
++
++	spi0: spi@ff1d0000 {
++		compatible = "rockchip,px30-spi", "rockchip,rk3066-spi";
++		reg = <0x0 0xff1d0000 0x0 0x1000>;
++		interrupts = <GIC_SPI 26 IRQ_TYPE_LEVEL_HIGH>;
++		#address-cells = <1>;
++		#size-cells = <0>;
++		clocks = <&cru SCLK_SPI0>, <&cru PCLK_SPI0>;
++		clock-names = "spiclk", "apb_pclk";
++		dmas = <&dmac 12>, <&dmac 13>;
++		#dma-cells = <2>;
++		dma-names = "tx", "rx";
++		pinctrl-names = "default";
++		pinctrl-0 = <&spi0_clk &spi0_csn &spi0_miso &spi0_mosi>;
++		status = "disabled";
++	};
++
++	spi1: spi@ff1d8000 {
++		compatible = "rockchip,px30-spi", "rockchip,rk3066-spi";
++		reg = <0x0 0xff1d8000 0x0 0x1000>;
++		interrupts = <GIC_SPI 27 IRQ_TYPE_LEVEL_HIGH>;
++		#address-cells = <1>;
++		#size-cells = <0>;
++		clocks = <&cru SCLK_SPI1>, <&cru PCLK_SPI1>;
++		clock-names = "spiclk", "apb_pclk";
++		dmas = <&dmac 14>, <&dmac 15>;
++		#dma-cells = <2>;
++		dma-names = "tx", "rx";
++		pinctrl-names = "default";
++		pinctrl-0 = <&spi1_clk &spi1_csn &spi1_miso &spi1_mosi>;
++		status = "disabled";
++	};
++
++	wdt: watchdog@ff1e0000 {
++		compatible = "snps,dw-wdt";
++		reg = <0x0 0xff1e0000 0x0 0x100>;
++		interrupts = <GIC_SPI 37 IRQ_TYPE_LEVEL_HIGH>;
++		status = "disabled";
++	};
++
++	pwm0: pwm@ff200000 {
++		compatible = "rockchip,px30-pwm", "rockchip,rk3328-pwm";
++		reg = <0x0 0xff200000 0x0 0x10>;
++		#pwm-cells = <3>;
++		pinctrl-names = "default";
++		pinctrl-0 = <&pwm0_pin>;
++		clocks = <&cru SCLK_PWM0>, <&cru PCLK_PWM0>;
++		clock-names = "pwm", "pclk";
++		status = "disabled";
++	};
++
++	pwm1: pwm@ff200010 {
++		compatible = "rockchip,px30-pwm", "rockchip,rk3328-pwm";
++		reg = <0x0 0xff200010 0x0 0x10>;
++		#pwm-cells = <3>;
++		pinctrl-names = "default";
++		pinctrl-0 = <&pwm1_pin>;
++		clocks = <&cru SCLK_PWM0>, <&cru PCLK_PWM0>;
++		clock-names = "pwm", "pclk";
++		status = "disabled";
++	};
++
++	pwm2: pwm@ff200020 {
++		compatible = "rockchip,px30-pwm", "rockchip,rk3328-pwm";
++		reg = <0x0 0xff200020 0x0 0x10>;
++		#pwm-cells = <3>;
++		pinctrl-names = "default";
++		pinctrl-0 = <&pwm2_pin>;
++		clocks = <&cru SCLK_PWM0>, <&cru PCLK_PWM0>;
++		clock-names = "pwm", "pclk";
++		status = "disabled";
++	};
++
++	pwm3: pwm@ff200030 {
++		compatible = "rockchip,px30-pwm", "rockchip,rk3328-pwm";
++		reg = <0x0 0xff200030 0x0 0x10>;
++		#pwm-cells = <3>;
++		pinctrl-names = "default";
++		pinctrl-0 = <&pwm3_pin>;
++		clocks = <&cru SCLK_PWM0>, <&cru PCLK_PWM0>;
++		clock-names = "pwm", "pclk";
++		status = "disabled";
++	};
++
++	pwm4: pwm@ff208000 {
++		compatible = "rockchip,px30-pwm", "rockchip,rk3328-pwm";
++		reg = <0x0 0xff208000 0x0 0x10>;
++		#pwm-cells = <3>;
++		pinctrl-names = "default";
++		pinctrl-0 = <&pwm4_pin>;
++		clocks = <&cru SCLK_PWM1>, <&cru PCLK_PWM1>;
++		clock-names = "pwm", "pclk";
++		status = "disabled";
++	};
++
++	pwm5: pwm@ff208010 {
++		compatible = "rockchip,px30-pwm", "rockchip,rk3328-pwm";
++		reg = <0x0 0xff208010 0x0 0x10>;
++		#pwm-cells = <3>;
++		pinctrl-names = "default";
++		pinctrl-0 = <&pwm5_pin>;
++		clocks = <&cru SCLK_PWM1>, <&cru PCLK_PWM1>;
++		clock-names = "pwm", "pclk";
++		status = "disabled";
++	};
++
++	pwm6: pwm@ff208020 {
++		compatible = "rockchip,px30-pwm", "rockchip,rk3328-pwm";
++		reg = <0x0 0xff208020 0x0 0x10>;
++		#pwm-cells = <3>;
++		pinctrl-names = "default";
++		pinctrl-0 = <&pwm6_pin>;
++		clocks = <&cru SCLK_PWM1>, <&cru PCLK_PWM1>;
++		clock-names = "pwm", "pclk";
++		status = "disabled";
++	};
++
++	pwm7: pwm@ff208030 {
++		compatible = "rockchip,px30-pwm", "rockchip,rk3328-pwm";
++		reg = <0x0 0xff208030 0x0 0x10>;
++		#pwm-cells = <3>;
++		pinctrl-names = "default";
++		pinctrl-0 = <&pwm7_pin>;
++		clocks = <&cru SCLK_PWM1>, <&cru PCLK_PWM1>;
++		clock-names = "pwm", "pclk";
++		status = "disabled";
++	};
++
++	amba {
++		compatible = "simple-bus";
++		#address-cells = <2>;
++		#size-cells = <2>;
++		ranges;
++
++		dmac: dmac@ff240000 {
++			compatible = "arm,pl330", "arm,primecell";
++			reg = <0x0 0xff240000 0x0 0x4000>;
++			interrupts = <GIC_SPI 1 IRQ_TYPE_LEVEL_HIGH>,
++				     <GIC_SPI 2 IRQ_TYPE_LEVEL_HIGH>;
++			clocks = <&cru ACLK_DMAC>;
++			clock-names = "apb_pclk";
++			#dma-cells = <1>;
++			peripherals-req-type-burst;
++		};
++	};
++
++	tsadc: tsadc@ff280000 {
++		compatible = "rockchip,px30-tsadc";
++		reg = <0x0 0xff280000 0x0 0x100>;
++		interrupts = <GIC_SPI 36 IRQ_TYPE_LEVEL_HIGH>;
++		rockchip,grf = <&grf>;
++		clocks = <&cru SCLK_TSADC>, <&cru PCLK_TSADC>;
++		clock-names = "tsadc", "apb_pclk";
++		assigned-clocks = <&cru SCLK_TSADC>;
++		assigned-clock-rates = <50000>;
++		resets = <&cru SRST_TSADC_P>;
++		reset-names = "tsadc-apb";
++		pinctrl-names = "init", "default", "sleep";
++		pinctrl-0 = <&tsadc_otp_gpio>;
++		pinctrl-1 = <&tsadc_otp_out>;
++		pinctrl-2 = <&tsadc_otp_gpio>;
++		#thermal-sensor-cells = <1>;
++		rockchip,hw-tshut-temp = <100000>;
++		status = "disabled";
++	};
++
++	saradc: saradc@ff288000 {
++		compatible = "rockchip,px30-saradc", "rockchip,rk3399-saradc";
++		reg = <0x0 0xff288000 0x0 0x100>;
++		interrupts = <GIC_SPI 84 IRQ_TYPE_LEVEL_HIGH>;
++		#io-channel-cells = <1>;
++		clocks = <&cru SCLK_SARADC>, <&cru PCLK_SARADC>;
++		clock-names = "saradc", "apb_pclk";
++		resets = <&cru SRST_SARADC_P>;
++		reset-names = "saradc-apb";
++		status = "disabled";
++	};
++
++	cru: clock-controller@ff2b0000 {
++		compatible = "rockchip,px30-cru";
++		reg = <0x0 0xff2b0000 0x0 0x9000>;
++		rockchip,grf = <&grf>;
++		#clock-cells = <1>;
++		#reset-cells = <1>;
++
++		assigned-clocks =
++			<&cru APLL_BOOST_H>, <&cru APLL_BOOST_L>,
++			<&cru PLL_NPLL>, <&cru PLL_CPLL>,
++			<&cru ARMCLK>;
++		assigned-clock-rates =
++			<1608000000>, <1416000000>,
++			<1188000000>, <1188000000>,
++			<816000000>;
++	};
++
++	pmucru: pmu-clock-controller@ff2bc000 {
++		compatible = "rockchip,px30-pmucru";
++		reg = <0x0 0xff2bc000 0x0 0x1000>;
++		rockchip,grf = <&grf>;
++		#clock-cells = <1>;
++		#reset-cells = <1>;
++
++		assigned-clocks =
++			<&pmucru PLL_GPLL>, <&pmucru PCLK_PMU_PRE>,
++			<&pmucru SCLK_WIFI_PMU>, <&cru ACLK_BUS_PRE>,
++			<&cru ACLK_PERI_PRE>, <&cru HCLK_BUS_PRE>,
++			<&cru HCLK_PERI_PRE>, <&cru PCLK_BUS_PRE>;
++		assigned-clock-rates =
++			<1200000000>, <100000000>,
++			<26000000>, <300000000>,
++			<300000000>, <150000000>,
++			<150000000>, <75000000>;
++	};
++
++	usb2phy_grf: syscon@ff2c0000 {
++		compatible = "rockchip,px30-usb2phy-grf", "syscon",
++			     "simple-mfd";
++		reg = <0x0 0xff2c0000 0x0 0x10000>;
++		#address-cells = <1>;
++		#size-cells = <1>;
++
++		u2phy: usb2-phy@100 {
++			compatible = "rockchip,px30-usb2phy",
++				     "rockchip,rk3328-usb2phy";
++			reg = <0x100 0x10>;
++			clocks = <&pmucru SCLK_USBPHY_REF>;
++			clock-names = "phyclk";
++			#clock-cells = <0>;
++			assigned-clocks = <&cru USB480M>;
++			assigned-clock-parents = <&u2phy>;
++			clock-output-names = "usb480m_phy";
++			status = "disabled";
++
++			u2phy_host: host-port {
++				#phy-cells = <0>;
++				interrupts = <GIC_SPI 68 IRQ_TYPE_LEVEL_HIGH>;
++				interrupt-names = "linestate";
++				status = "disabled";
++			};
++
++			u2phy_otg: otg-port {
++				#phy-cells = <0>;
++				interrupts = <GIC_SPI 66 IRQ_TYPE_LEVEL_HIGH>,
++					     <GIC_SPI 65 IRQ_TYPE_LEVEL_HIGH>,
++					     <GIC_SPI 64 IRQ_TYPE_LEVEL_HIGH>;
++				interrupt-names = "otg-bvalid", "otg-id",
++						  "linestate";
++				status = "disabled";
++			};
++		};
++	};
++
++	mipi_dphy: mipi-dphy@ff2e0000 {
++		compatible = "rockchip,px30-mipi-dphy";
++		reg = <0x0 0xff2e0000 0x0 0x10000>;
++		clocks = <&cru SCLK_MIPIDSIPHY_REF>, <&cru PCLK_MIPIDSIPHY>;
++		clock-names = "ref", "pclk";
++		clock-output-names = "mipi_dphy_pll";
++		#clock-cells = <0>;
++		resets = <&cru SRST_MIPIDSIPHY_P>;
++		reset-names = "apb";
++		power-domains = <&power PX30_PD_VO>;
++		#phy-cells = <0>;
++		rockchip,grf = <&grf>;
++		status = "disabled";
++	};
++
++	lvds: lvds@ff2e0000 {
++		compatible = "rockchip,px30-lvds";
++		reg = <0x0 0xff2e0000 0x0 0x100>, <0x0 0xff2e0100 0x0 0x100>;
++		reg-names = "mipi_lvds_phy", "mipi_lvds_ctl";
++		clocks = <&cru PCLK_MIPIDSIPHY>, <&cru PCLK_MIPI_DSI>;
++		clock-names = "pclk_lvds", "pclk_lvds_ctl";
++		power-domains = <&power PX30_PD_VO>;
++		rockchip,grf = <&grf>;
++		status = "disabled";
++
++		ports {
++			#address-cells = <1>;
++			#size-cells = <0>;
++
++			port@0 {
++				reg = <0>;
++				#address-cells = <1>;
++				#size-cells = <0>;
++
++				lvds_in_vopl: endpoint@0 {
++					reg = <0>;
++					remote-endpoint = <&vopl_out_lvds>;
++				};
++
++				lvds_in_vopb: endpoint@1 {
++					reg = <1>;
++					remote-endpoint = <&vopb_out_lvds>;
++				};
++			};
++		};
++	};
++
++	usb20_otg: usb@ff300000 {
++		compatible = "rockchip,px30-usb", "rockchip,rk3066-usb",
++			     "snps,dwc2";
++		reg = <0x0 0xff300000 0x0 0x40000>;
++		interrupts = <GIC_SPI 62 IRQ_TYPE_LEVEL_HIGH>;
++		clocks = <&cru HCLK_OTG>;
++		clock-names = "otg";
++		dr_mode = "otg";
++		g-np-tx-fifo-size = <16>;
++		g-rx-fifo-size = <275>;
++		g-tx-fifo-size = <256 128 128 64 64 32>;
++		g-use-dma;
++		phys = <&u2phy_otg>;
++		phy-names = "usb2-phy";
++		status = "disabled";
++	};
++
++	usb_host0_ehci: usb@ff340000 {
++		compatible = "generic-ehci";
++		reg = <0x0 0xff340000 0x0 0x10000>;
++		interrupts = <GIC_SPI 60 IRQ_TYPE_LEVEL_HIGH>;
++		clocks = <&cru HCLK_HOST>, <&cru HCLK_HOST_ARB>,
++			 <&u2phy>;
++		clock-names = "usbhost", "arbiter", "utmi";
++		phys = <&u2phy_host>;
++		phy-names = "usb";
++		status = "disabled";
++	};
++
++	usb_host0_ohci: usb@ff350000 {
++		compatible = "generic-ohci";
++		reg = <0x0 0xff350000 0x0 0x10000>;
++		interrupts = <GIC_SPI 61 IRQ_TYPE_LEVEL_HIGH>;
++		clocks = <&cru HCLK_HOST>, <&cru HCLK_HOST_ARB>,
++			 <&u2phy>;
++		clock-names = "usbhost", "arbiter", "utmi";
++		phys = <&u2phy_host>;
++		phy-names = "usb";
++	};
++
++	gmac: ethernet@ff360000 {
++		compatible = "rockchip,px30-gmac";
++		reg = <0x0 0xff360000 0x0 0x10000>;
++		rockchip,grf = <&grf>;
++		interrupts = <GIC_SPI 43 IRQ_TYPE_LEVEL_HIGH>;
++		interrupt-names = "macirq";
++		clocks = <&cru SCLK_GMAC>, <&cru SCLK_GMAC_RX_TX>,
++			 <&cru SCLK_GMAC_RX_TX>, <&cru SCLK_MAC_REF>,
++			 <&cru SCLK_MAC_REFOUT>, <&cru ACLK_GMAC>,
++			 <&cru PCLK_GMAC>, <&cru SCLK_GMAC_RMII>;
++		clock-names = "stmmaceth", "mac_clk_rx",
++			      "mac_clk_tx", "clk_mac_ref",
++			      "clk_mac_refout", "aclk_mac",
++			      "pclk_mac", "clk_mac_speed";
++		phy-mode = "rmii";
++		pinctrl-names = "default";
++		pinctrl-0 = <&rmii_pins &mac_refclk_12ma>;
++		resets = <&cru SRST_GMAC_A>;
++		reset-names = "stmmaceth";
++		power-domains = <&power PX30_PD_GMAC>;
++		status = "disabled";
++	};
++
++	sdmmc: dwmmc@ff370000 {
++		compatible = "rockchip,px30-dw-mshc", "rockchip,rk3288-dw-mshc";
++		reg = <0x0 0xff370000 0x0 0x4000>;
++		max-frequency = <150000000>;
++		clocks = <&cru HCLK_SDMMC>, <&cru SCLK_SDMMC>,
++			 <&cru SCLK_SDMMC_DRV>, <&cru SCLK_SDMMC_SAMPLE>;
++		clock-names = "biu", "ciu", "ciu-drv", "ciu-sample";
++		fifo-depth = <0x100>;
++		cd-gpios = <&gpio0 RK_PA3 GPIO_ACTIVE_HIGH>;
++		interrupts = <GIC_SPI 54 IRQ_TYPE_LEVEL_HIGH>;
++		pinctrl-names = "default";
++		pinctrl-0 = <&sdmmc_clk &sdmmc_cmd &sdmmc_det &sdmmc_bus4>;
++		status = "disabled";
++	};
++
++	sdio: dwmmc@ff380000 {
++		compatible = "rockchip,px30-dw-mshc", "rockchip,rk3288-dw-mshc";
++		reg = <0x0 0xff380000 0x0 0x4000>;
++		max-frequency = <150000000>;
++		clocks = <&cru HCLK_SDIO>, <&cru SCLK_SDIO>,
++			 <&cru SCLK_SDIO_DRV>, <&cru SCLK_SDIO_SAMPLE>;
++		clock-names = "biu", "ciu", "ciu-drv", "ciu-sample";
++		fifo-depth = <0x100>;
++		interrupts = <GIC_SPI 54 IRQ_TYPE_LEVEL_HIGH>;
++		status = "disabled";
++	};
++
++	emmc: dwmmc@ff390000 {
++		compatible = "rockchip,px30-dw-mshc", "rockchip,rk3288-dw-mshc";
++		reg = <0x0 0xff390000 0x0 0x4000>;
++		max-frequency = <150000000>;
++		clocks = <&cru HCLK_EMMC>, <&cru SCLK_EMMC>,
++			 <&cru SCLK_EMMC_DRV>, <&cru SCLK_EMMC_SAMPLE>;
++		clock-names = "biu", "ciu", "ciu-drv", "ciu-sample";
++		fifo-depth = <0x100>;
++		interrupts = <GIC_SPI 53 IRQ_TYPE_LEVEL_HIGH>;
++		status = "disabled";
++	};
++
++	nandc0: nandc@ff3b0000 {
++		compatible = "rockchip,rk-nandc";
++		reg = <0x0 0xff3b0000 0x0 0x4000>;
++		interrupts = <GIC_SPI 57 IRQ_TYPE_LEVEL_HIGH>;
++		nandc_id = <0>;
++		clocks = <&cru SCLK_NANDC>, <&cru HCLK_NANDC>;
++		clock-names = "clk_nandc", "hclk_nandc";
++		status = "disabled";
++	};
++
++	gpu: gpu@ff400000 {
++		compatible = "arm,malit602", "arm,malit60x", "arm,malit6xx", "arm,mali-midgard";
++		reg = <0x0 0xff400000 0x0 0x4000>;
++
++		interrupts = <GIC_SPI 45 IRQ_TYPE_LEVEL_HIGH>,
++			     <GIC_SPI 46 IRQ_TYPE_LEVEL_HIGH>,
++			     <GIC_SPI 47 IRQ_TYPE_LEVEL_HIGH>;
++		interrupt-names = "GPU", "MMU", "JOB";
++
++		clocks = <&cru ACLK_GPU>;
++		clock-names = "clk_mali";
++
++		status = "disabled";
++	};
++
++	hevc: hevc_service@ff440000 {
++		compatible = "rockchip,hevc_sub";
++		iommu_enabled = <1>;
++		reg = <0x0 0xff440000 0x0 0x400>;
++		interrupts = <GIC_SPI 49 IRQ_TYPE_LEVEL_HIGH>;
++		interrupt-names = "irq_dec";
++		dev_mode = <1>;
++		iommus = <&hevc_mmu>;
++		name = "hevc_service";
++		allocator = <1>;
++	};
++
++	vpu: vpu_service@ff442000 {
++		compatible = "rockchip,vpu_sub";
++		iommu_enabled = <1>;
++		reg = <0x0 0xff442000 0x0 0x800>;
++		interrupts = <GIC_SPI 80 IRQ_TYPE_LEVEL_HIGH>,
++			<GIC_SPI 79 IRQ_TYPE_LEVEL_HIGH>;
++		interrupt-names = "irq_enc", "irq_dec";
++		dev_mode = <0>;
++		iommus = <&vpu_mmu>;
++		name = "vpu_service";
++		allocator = <1>;
++	};
++
++	vpu_combo: vpu_combo {
++		compatible = "rockchip,vpu_combo";
++		subcnt = <2>;
++		rockchip,grf = <&grf>;
++		rockchip,sub = <&vpu>, <&hevc>;
++		clocks = <&cru ACLK_VPU>, <&cru HCLK_VPU>, <&cru SCLK_CORE_VPU>;
++		clock-names = "aclk_vcodec", "hclk_vcodec", "clk_core";
++		resets = <&cru SRST_VPU_A>, <&cru SRST_VPU_H>,
++			<&cru SRST_VPU_NIU_A>, <&cru SRST_VPU_NIU_H>,
++			<&cru SRST_VPU_CORE>;
++		reset-names = "video_a", "video_h", "niu_a", "niu_h",
++			"video_core";
++		mode_bit = <15>;
++		mode_ctrl = <0x410>;
++		name = "vpu_combo";
++		status = "disabled";
++	};
++
++	hevc_mmu: iommu@ff440440 {
++		compatible = "rockchip,iommu";
++		reg = <0x0 0xff440440 0x0 0x40>, <0x0 0xff440480 0x0 0x40>;
++		interrupts = <GIC_SPI 50 IRQ_TYPE_LEVEL_HIGH>;
++		interrupt-names = "hevc_mmu";
++		clocks = <&cru ACLK_VPU>, <&cru HCLK_VPU>;
++		clock-names = "aclk", "hclk";
++		#iommu-cells = <0>;
++	};
++
++	vpu_mmu: iommu@ff442800 {
++		compatible = "rockchip,iommu";
++		reg = <0x0 0xff442800 0x0 0x100>;
++		interrupts = <GIC_SPI 81 IRQ_TYPE_LEVEL_HIGH>;
++		interrupt-names = "vpu_mmu";
++		clocks = <&cru ACLK_VPU>, <&cru HCLK_VPU>;
++		clock-names = "aclk", "hclk";
++		#iommu-cells = <0>;
++	};
++
++	dsi: dsi@ff450000 {
++		compatible = "rockchip,px30-mipi-dsi";
++		reg = <0x0 0xff450000 0x0 0x10000>;
++		interrupts = <GIC_SPI 75 IRQ_TYPE_LEVEL_HIGH>;
++		clocks = <&cru PCLK_MIPI_DSI>, <&mipi_dphy>;
++		clock-names = "pclk", "hs_clk";
++		resets = <&cru SRST_MIPIDSI_HOST_P>;
++		reset-names = "apb";
++		phys = <&mipi_dphy>;
++		phy-names = "mipi_dphy";
++		power-domains = <&power PX30_PD_VO>;
++		rockchip,grf = <&grf>;
++		#address-cells = <1>;
++		#size-cells = <0>;
++		status = "disabled";
++
++		ports {
++			port {
++				#address-cells = <1>;
++				#size-cells = <0>;
++
++				dsi_in_vopl: endpoint@0 {
++					reg = <0>;
++					remote-endpoint = <&vopl_out_dsi>;
++				};
++
++				dsi_in_vopb: endpoint@1 {
++					reg = <1>;
++					remote-endpoint = <&vopb_out_dsi>;
++				};
++			};
++		};
++	};
++
++	vopb: vop@ff460000 {
++		compatible = "rockchip,px30-vop-big";
++		reg = <0x0 0xff460000 0x0 0x1fc>, <0x0 0xff460a00 0x0 0x400>;
++		reg-names = "regs", "gamma_lut";
++		interrupts = <GIC_SPI 77 IRQ_TYPE_LEVEL_HIGH>;
++		clocks = <&cru ACLK_VOPB>, <&cru DCLK_VOPB>,
++			 <&cru HCLK_VOPB>;
++		clock-names = "aclk_vop", "dclk_vop", "hclk_vop";
++		iommus = <&vopb_mmu>;
++		status = "disabled";
++
++		vopb_out: port {
++			#address-cells = <1>;
++			#size-cells = <0>;
++
++			vopb_out_lvds: endpoint@0 {
++				reg = <0>;
++				remote-endpoint = <&lvds_in_vopb>;
++			};
++
++			vopb_out_dsi: endpoint@1 {
++				reg = <1>;
++				remote-endpoint = <&dsi_in_vopb>;
++			};
++		};
++	};
++
++	vopb_mmu: iommu@ff460f00 {
++		compatible = "rockchip,iommu";
++		reg = <0x0 0xff460f00 0x0 0x100>;
++		interrupts = <GIC_SPI 77 IRQ_TYPE_LEVEL_HIGH>;
++		interrupt-names = "vopb_mmu";
++		clocks = <&cru ACLK_VOPB>, <&cru HCLK_VOPB>;
++		clock-names = "aclk", "hclk";
++		#iommu-cells = <0>;
++		status = "disabled";
++	};
++
++	vopl: vop@ff470000 {
++		compatible = "rockchip,px30-vop-lit";
++		reg = <0x0 0xff470000 0x0 0x1fc>, <0x0 0xff470a00 0x0 0x400>;
++		reg-names = "regs", "gamma_lut";
++		interrupts = <GIC_SPI 78 IRQ_TYPE_LEVEL_HIGH>;
++		clocks = <&cru ACLK_VOPL>, <&cru DCLK_VOPL>,
++			 <&cru HCLK_VOPL>;
++		clock-names = "aclk_vop", "dclk_vop", "hclk_vop";
++		iommus = <&vopl_mmu>;
++		status = "disabled";
++
++		vopl_out: port {
++			#address-cells = <1>;
++			#size-cells = <0>;
++
++			vopl_out_lvds: endpoint@0 {
++				reg = <0>;
++				remote-endpoint = <&lvds_in_vopl>;
++			};
++
++			vopl_out_dsi: endpoint@1 {
++				reg = <1>;
++				remote-endpoint = <&dsi_in_vopl>;
++			};
++		};
++	};
++
++	vopl_mmu: iommu@ff470f00 {
++		compatible = "rockchip,iommu";
++		reg = <0x0 0xff470f00 0x0 0x100>;
++		interrupts = <GIC_SPI 79 IRQ_TYPE_LEVEL_HIGH>;
++		interrupt-names = "vopl_mmu";
++		clocks = <&cru ACLK_VOPL>, <&cru HCLK_VOPL>;
++		clock-names = "aclk", "hclk";
++		#iommu-cells = <0>;
++		status = "disabled";
++	};
++
++	rk_rga: rk_rga@ff480000 {
++		compatible = "rockchip,rga2";
++		//dev_mode = <1>;
++		reg = <0x0 0xff480000 0x0 0x1000>;
++		interrupts = <GIC_SPI 76 IRQ_TYPE_LEVEL_HIGH>;
++		clocks = <&cru ACLK_RGA>, <&cru HCLK_RGA>;
++		clock-names = "aclk_rga", "hclk_rga";
++		dma-coherent;
++		status = "disabled";
++	};
++
++	cif: cif@ff490000 {
++		compatible = "rockchip,cif";
++		reg = <0x0 0xff490000 0x0 0x200>;
++		interrupts = <GIC_SPI 69 IRQ_TYPE_LEVEL_HIGH>;
++		clocks = <&cru ACLK_CIF>, <&cru HCLK_CIF>, <&cru PCLK_CIF>, <&cru SCLK_CIF_OUT>;
++		clock-names = "aclk_cif0", "hclk_cif0", "pclk_cif", "cif0_out";
++		resets = <&cru SRST_CIF_A>, <&cru SRST_CIF_H>, <&cru SRST_CIF_PCLKIN>;
++		reset-names = "rst_cif_a", "rst_cif_h", "rst_cif_pclkin";
++		pinctrl-names = "cif_pin_all";
++		pinctrl-0 = <&dvp_d2d9_m0>;
++		status = "disabled";
++	};
++
++	vip_mmu: iommu@ff490800{
++		compatible = "rockchip,iommu";
++		reg = <0x0 0xff490800 0x0 0x100>;
++		interrupts = <GIC_SPI 69 IRQ_TYPE_LEVEL_HIGH>;
++		interrupt-names = "vip_mmu";
++		clocks = <&cru ACLK_CIF>, <&cru HCLK_CIF>;
++		clock-names = "aclk", "hclk";
++		rk_iommu,disable_reset_quirk;
++		#iommu-cells = <0>;
++		status = "disabled";
++	};
++
++	rk_isp: rk_isp@ff4a0000 {
++		compatible = "rockchip,px30-isp", "rockchip,isp";
++		reg = <0x0 0xff4a0000 0x0 0x4000>;
++		interrupts = <GIC_SPI 70 IRQ_TYPE_LEVEL_HIGH>;
++		clocks = <&cru ACLK_ISP>, <&cru HCLK_ISP>, <&cru SCLK_ISP>, <&cru SCLK_ISP>,
++			<&cru PCLK_ISP>, <&cru SCLK_CIF_OUT>, <&cru SCLK_CIF_OUT>, <&cru PCLK_MIPICSIPHY>;
++		clock-names = "aclk_isp", "hclk_isp", "clk_isp", "clk_isp_jpe",
++			"pclkin_isp", "clk_cif_pll", "clk_cif_out", "pclk_dphyrx";
++		resets = <&cru SRST_ISP>, <&cru SRST_MIPICSIPHY_P>;
++		reset-names = "rst_isp", "rst_mipicsiphy";
++		pinctrl-names = "default";
++		pinctrl-0 = <&cif_clkout_m0>;
++		rockchip,isp,mipiphy = <0>;
++		rockchip,isp,csiphy,reg = <0xff2f0000 0x4000>;
++		rockchip,grf = <&grf>;
++		rockchip,cru = <&cru>;
++		rockchip,isp,iommu-enable = <1>;
++		iommus = <&isp_mmu>;
++		status = "disabled";
++	};
++
++	isp_mmu: iommu@ff4a8000 {
++		compatible = "rockchip,iommu";
++		reg = <0x0 0xff4a8000 0x0 0x100>;
++		interrupts = <GIC_SPI 70 IRQ_TYPE_LEVEL_HIGH>;
++		interrupt-names = "isp_mmu";
++		clocks = <&cru ACLK_ISP>, <&cru HCLK_ISP>;
++		clock-names = "aclk", "hclk";
++		rk_iommu,disable_reset_quirk;
++		#iommu-cells = <0>;
++		status = "disabled";
++	};
++
++	qos_gmac: qos@ff518000 {
++		compatible = "syscon";
++		reg = <0x0 0xff518000 0x0 0x20>;
++	};
++
++	qos_gpu: qos@ff520000 {
++		compatible = "syscon";
++		reg = <0x0 0xff520000 0x0 0x20>;
++	};
++
++	qos_sdmmc: qos@ff52c000 {
++		compatible = "syscon";
++		reg = <0x0 0xff52c000 0x0 0x20>;
++	};
++
++	qos_emmc: qos@ff538000 {
++		compatible = "syscon";
++		reg = <0x0 0xff538000 0x0 0x20>;
++	};
++
++	qos_nand: qos@ff538080 {
++		compatible = "syscon";
++		reg = <0x0 0xff538080 0x0 0x20>;
++	};
++
++	qos_sdio: qos@ff538100 {
++		compatible = "syscon";
++		reg = <0x0 0xff538100 0x0 0x20>;
++	};
++
++	qos_sfc: qos@ff538180 {
++		compatible = "syscon";
++		reg = <0x0 0xff538180 0x0 0x20>;
++	};
++
++	qos_usb_host: qos@ff540000 {
++		compatible = "syscon";
++		reg = <0x0 0xff540000 0x0 0x20>;
++	};
++
++	qos_usb_otg: qos@ff540080 {
++		compatible = "syscon";
++		reg = <0x0 0xff540080 0x0 0x20>;
++	};
++
++	qos_isp_128: qos@ff548000 {
++		compatible = "syscon";
++		reg = <0x0 0xff548000 0x0 0x20>;
++	};
++
++	qos_isp_rd: qos@ff548080 {
++		compatible = "syscon";
++		reg = <0x0 0xff548080 0x0 0x20>;
++	};
++
++	qos_isp_wr: qos@ff548100 {
++		compatible = "syscon";
++		reg = <0x0 0xff548100 0x0 0x20>;
++	};
++
++	qos_isp_m1: qos@ff548180 {
++		compatible = "syscon";
++		reg = <0x0 0xff548180 0x0 0x20>;
++	};
++
++	qos_vip: qos@ff548200 {
++		compatible = "syscon";
++		reg = <0x0 0xff548200 0x0 0x20>;
++	};
++
++	qos_rga_rd: qos@ff550000 {
++		compatible = "syscon";
++		reg = <0x0 0xff550000 0x0 0x20>;
++	};
++
++	qos_rga_wr: qos@ff550080 {
++		compatible = "syscon";
++		reg = <0x0 0xff550080 0x0 0x20>;
++	};
++
++	qos_vop_m0: qos@ff550100 {
++		compatible = "syscon";
++		reg = <0x0 0xff550100 0x0 0x20>;
++	};
++
++	qos_vop_m1: qos@ff550180 {
++		compatible = "syscon";
++		reg = <0x0 0xff550180 0x0 0x20>;
++	};
++
++	qos_vpu: qos@ff558000 {
++		compatible = "syscon";
++		reg = <0x0 0xff558000 0x0 0x20>;
++	};
++
++	qos_vpu_r128: qos@ff558080 {
++		compatible = "syscon";
++		reg = <0x0 0xff558080 0x0 0x20>;
++	};
++
++	pinctrl: pinctrl {
++		compatible = "rockchip,px30-pinctrl";
++		rockchip,grf = <&grf>;
++		rockchip,pmu = <&pmugrf>;
++		#address-cells = <2>;
++		#size-cells = <2>;
++		ranges;
++
++		gpio0: gpio0@ff040000 {
++			compatible = "rockchip,gpio-bank";
++			reg = <0x0 0xff040000 0x0 0x100>;
++			interrupts = <GIC_SPI 3 IRQ_TYPE_LEVEL_HIGH>;
++			clocks = <&cru PCLK_GPIO0_PMU>;
++			gpio-controller;
++			#gpio-cells = <2>;
++
++			interrupt-controller;
++			#interrupt-cells = <2>;
++		};
++
++		gpio1: gpio1@ff250000 {
++			compatible = "rockchip,gpio-bank";
++			reg = <0x0 0xff250000 0x0 0x100>;
++			interrupts = <GIC_SPI 4 IRQ_TYPE_LEVEL_HIGH>;
++			clocks = <&cru PCLK_GPIO1>;
++			gpio-controller;
++			#gpio-cells = <2>;
++
++			interrupt-controller;
++			#interrupt-cells = <2>;
++		};
++
++		gpio2: gpio2@ff260000 {
++			compatible = "rockchip,gpio-bank";
++			reg = <0x0 0xff260000 0x0 0x100>;
++			interrupts = <GIC_SPI 5 IRQ_TYPE_LEVEL_HIGH>;
++			clocks = <&cru PCLK_GPIO2>;
++			gpio-controller;
++			#gpio-cells = <2>;
++
++			interrupt-controller;
++			#interrupt-cells = <2>;
++		};
++
++		gpio3: gpio3@ff270000 {
++			compatible = "rockchip,gpio-bank";
++			reg = <0x0 0xff270000 0x0 0x100>;
++			interrupts = <GIC_SPI 6 IRQ_TYPE_LEVEL_HIGH>;
++			clocks = <&cru PCLK_GPIO3>;
++			gpio-controller;
++			#gpio-cells = <2>;
++
++			interrupt-controller;
++			#interrupt-cells = <2>;
++		};
++
++		pcfg_pull_up: pcfg-pull-up {
++			bias-pull-up;
++		};
++
++		pcfg_pull_down: pcfg-pull-down {
++			bias-pull-down;
++		};
++
++		pcfg_pull_none: pcfg-pull-none {
++			bias-disable;
++		};
++
++		pcfg_pull_none_2ma: pcfg-pull-none-2ma {
++			bias-disable;
++			drive-strength = <2>;
++		};
++
++		pcfg_pull_up_2ma: pcfg-pull-up-2ma {
++			bias-pull-up;
++			drive-strength = <2>;
++		};
++
++		pcfg_pull_up_4ma: pcfg-pull-up-4ma {
++			bias-pull-up;
++			drive-strength = <4>;
++		};
++
++		pcfg_pull_none_4ma: pcfg-pull-none-4ma {
++			bias-disable;
++			drive-strength = <4>;
++		};
++
++		pcfg_pull_down_4ma: pcfg-pull-down-4ma {
++			bias-pull-down;
++			drive-strength = <4>;
++		};
++
++		pcfg_pull_none_8ma: pcfg-pull-none-8ma {
++			bias-disable;
++			drive-strength = <8>;
++		};
++
++		pcfg_pull_up_8ma: pcfg-pull-up-8ma {
++			bias-pull-up;
++			drive-strength = <8>;
++		};
++
++		pcfg_pull_none_12ma: pcfg-pull-none-12ma {
++			bias-disable;
++			drive-strength = <12>;
++		};
++
++		pcfg_pull_up_12ma: pcfg-pull-up-12ma {
++			bias-pull-up;
++			drive-strength = <12>;
++		};
++
++		pcfg_pull_none_smt: pcfg-pull-none-smt {
++			bias-disable;
++			input-schmitt-enable;
++		};
++
++		pcfg_output_high: pcfg-output-high {
++			output-high;
++		};
++
++		pcfg_output_low: pcfg-output-low {
++			output-low;
++		};
++
++		pcfg_input_high: pcfg-input-high {
++			bias-pull-up;
++			input-enable;
++		};
++
++		pcfg_input: pcfg-input {
++			input-enable;
++		};
++
++		i2c0 {
++			i2c0_xfer: i2c0-xfer {
++				rockchip,pins =
++					<0 RK_PB0 RK_FUNC_1 &pcfg_pull_none_smt>,
++					<0 RK_PB1 RK_FUNC_1 &pcfg_pull_none_smt>;
++			};
++		};
++
++		i2c1 {
++			i2c1_xfer: i2c1-xfer {
++				rockchip,pins =
++					<0 RK_PC2 RK_FUNC_1 &pcfg_pull_none_smt>,
++					<0 RK_PC3 RK_FUNC_1 &pcfg_pull_none_smt>;
++			};
++		};
++
++		i2c2 {
++			i2c2_xfer: i2c2-xfer {
++				rockchip,pins =
++					<2 RK_PB7 RK_FUNC_2 &pcfg_pull_none_smt>,
++					<2 RK_PC0 RK_FUNC_2 &pcfg_pull_none_smt>;
++			};
++		};
++
++		i2c3 {
++			i2c3_xfer: i2c3-xfer {
++				rockchip,pins =
++					<1 RK_PB4 RK_FUNC_4 &pcfg_pull_none_smt>,
++					<1 RK_PB5 RK_FUNC_4 &pcfg_pull_none_smt>;
++			};
++		};
++
++		tsadc {
++			tsadc_otp_gpio: tsadc-otp-gpio {
++				rockchip,pins =
++					<0 RK_PA6 RK_FUNC_GPIO &pcfg_pull_none>;
++			};
++
++			tsadc_otp_out: tsadc-otp-out {
++				rockchip,pins =
++					<0 RK_PA6 RK_FUNC_1 &pcfg_pull_none>;
++			};
++		};
++
++		uart0 {
++			uart0_xfer: uart0-xfer {
++				rockchip,pins =
++					<0 RK_PB2 RK_FUNC_1 &pcfg_pull_up>,
++					<0 RK_PB3 RK_FUNC_1 &pcfg_pull_none>;
++			};
++
++			uart0_cts: uart0-cts {
++				rockchip,pins =
++					<0 RK_PB4 RK_FUNC_1 &pcfg_pull_none>;
++			};
++
++			uart0_rts: uart0-rts {
++				rockchip,pins =
++					<0 RK_PB5 RK_FUNC_1 &pcfg_pull_none>;
++			};
++
++			uart0_rts_gpio: uart0-rts-gpio {
++				rockchip,pins =
++					<0 RK_PB5 RK_FUNC_GPIO &pcfg_pull_none>;
++			};
++		};
++
++		uart1 {
++			uart1_xfer: uart1-xfer {
++				rockchip,pins =
++					<1 RK_PC1 RK_FUNC_1 &pcfg_pull_up>,
++					<1 RK_PC0 RK_FUNC_1 &pcfg_pull_none>;
++			};
++
++			uart1_cts: uart1-cts {
++				rockchip,pins =
++					<1 RK_PC2 RK_FUNC_1 &pcfg_pull_none>;
++			};
++
++			uart1_rts: uart1-rts {
++				rockchip,pins =
++					<1 RK_PC3 RK_FUNC_1 &pcfg_pull_none>;
++			};
++
++			uart1_rts_gpio: uart1-rts-gpio {
++				rockchip,pins =
++					<1 RK_PC3 RK_FUNC_GPIO &pcfg_pull_none>;
++			};
++		};
++
++		uart2-m0 {
++			uart2m0_xfer: uart2m0-xfer {
++				rockchip,pins =
++					<1 RK_PD2 RK_FUNC_2 &pcfg_pull_up>,
++					<1 RK_PD3 RK_FUNC_2 &pcfg_pull_none>;
++			};
++		};
++
++		uart2-m1 {
++			uart2m1_xfer: uart2m1-xfer {
++				rockchip,pins =
++					<2 RK_PB4 RK_FUNC_2 &pcfg_pull_up>,
++					<2 RK_PB6 RK_FUNC_2 &pcfg_pull_none>;
++			};
++		};
++
++		uart3-m0 {
++			uart3m0_xfer: uart3m0-xfer {
++				rockchip,pins =
++					<0 RK_PC0 RK_FUNC_2 &pcfg_pull_up>,
++					<0 RK_PC1 RK_FUNC_2 &pcfg_pull_none>;
++			};
++
++			uart3m0_cts: uart3m0-cts {
++				rockchip,pins =
++					<0 RK_PC2 RK_FUNC_2 &pcfg_pull_none>;
++			};
++
++			uart3m0_rts: uart3m0-rts {
++				rockchip,pins =
++					<0 RK_PC3 RK_FUNC_2 &pcfg_pull_none>;
++			};
++
++			uart3m0_rts_gpio: uart3m0-rts-gpio {
++				rockchip,pins =
++					<0 RK_PC3 RK_FUNC_GPIO &pcfg_pull_none>;
++			};
++		};
++
++		uart3-m1 {
++			uart3m1_xfer: uart3m1-xfer {
++				rockchip,pins =
++					<1 RK_PB6 RK_FUNC_2 &pcfg_pull_up>,
++					<1 RK_PB7 RK_FUNC_2 &pcfg_pull_none>;
++			};
++
++			uart3m1_cts: uart3m1-cts {
++				rockchip,pins =
++					<1 RK_PB4 RK_FUNC_2 &pcfg_pull_none>;
++			};
++
++			uart3m1_rts: uart3m1-rts {
++				rockchip,pins =
++					<1 RK_PB5 RK_FUNC_2 &pcfg_pull_none>;
++			};
++
++			uart3m1_rts_gpio: uart3m1-rts-gpio {
++				rockchip,pins =
++					<1 RK_PB5 RK_FUNC_GPIO &pcfg_pull_none>;
++			};
++		};
++
++		uart4 {
++
++			uart4_xfer: uart4-xfer {
++				rockchip,pins =
++					<1 RK_PD4 RK_FUNC_2 &pcfg_pull_up>,
++					<1 RK_PD5 RK_FUNC_2 &pcfg_pull_none>;
++			};
++
++			uart4_cts: uart4-cts {
++				rockchip,pins =
++					<1 RK_PD6 RK_FUNC_2 &pcfg_pull_none>;
++
++			};
++
++			uart4_rts: uart4-rts {
++				rockchip,pins =
++					<1 RK_PD7 RK_FUNC_2 &pcfg_pull_none>;
++			};
++		};
++
++		uart5 {
++
++			uart5_xfer: uart5-xfer {
++				rockchip,pins =
++					<3 RK_PA2 RK_FUNC_4 &pcfg_pull_up>,
++					<3 RK_PA1 RK_FUNC_4 &pcfg_pull_none>;
++			};
++
++			uart5_cts: uart5-cts {
++				rockchip,pins =
++					<3 RK_PA3 RK_FUNC_4 &pcfg_pull_none>;
++
++			};
++
++			uart5_rts: uart5-rts {
++				rockchip,pins =
++					<3 RK_PA5 RK_FUNC_4 &pcfg_pull_none>;
++			};
++		};
++
++		spi0 {
++			spi0_clk: spi0-clk {
++				rockchip,pins =
++					<1 RK_PB7 RK_FUNC_3 &pcfg_pull_up>;
++			};
++
++			spi0_csn: spi0-csn {
++				rockchip,pins =
++					<1 RK_PB6 RK_FUNC_3 &pcfg_pull_up>;
++			};
++
++			spi0_miso: spi0-miso {
++				rockchip,pins =
++					<1 RK_PB5 RK_FUNC_3 &pcfg_pull_up>;
++			};
++
++			spi0_mosi: spi0-mosi {
++				rockchip,pins =
++					<1 RK_PB4 RK_FUNC_3 &pcfg_pull_up>;
++			};
++		};
++
++		spi1 {
++			spi1_clk: spi1-clk {
++				rockchip,pins =
++					<3 RK_PB7 RK_FUNC_4 &pcfg_pull_up>;
++			};
++
++			spi1_csn: spi1-csn {
++				rockchip,pins =
++					<3 RK_PB1 RK_FUNC_4 &pcfg_pull_up>;
++			};
++
++			spi1_miso: spi1-miso {
++				rockchip,pins =
++					<3 RK_PB6 RK_FUNC_4 &pcfg_pull_up>;
++			};
++
++			spi1_mosi: spi1-mosi {
++				rockchip,pins =
++					<3 RK_PB4 RK_FUNC_4 &pcfg_pull_up>;
++			};
++		};
++
++		pdm {
++			pdm_clk0m0: pdm-clk0m0 {
++				rockchip,pins =
++					<3 RK_PC6 RK_FUNC_2 &pcfg_pull_none>;
++			};
++
++			pdm_clk0m1: pdm-clk0m1 {
++				rockchip,pins =
++					<2 RK_PC6 RK_FUNC_1 &pcfg_pull_none>;
++			};
++
++			pdm_clk1: pdm-clk1 {
++				rockchip,pins =
++					<3 RK_PC7 RK_FUNC_2 &pcfg_pull_none>;
++			};
++
++			pdm_sdi0m0: pdm-sdi0m0 {
++				rockchip,pins =
++					<3 RK_PD3 RK_FUNC_4 &pcfg_pull_none>;
++			};
++
++			pdm_sdi0m1: pdm-sdi0m1 {
++				rockchip,pins =
++					<2 RK_PC5 RK_FUNC_2 &pcfg_pull_none>;
++			};
++
++			pdm_sdi1: pdm-sdi1 {
++				rockchip,pins =
++					<3 RK_PD0 RK_FUNC_2 &pcfg_pull_none>;
++			};
++
++			pdm_sdi2: pdm-sdi2 {
++				rockchip,pins =
++					<3 RK_PD1 RK_FUNC_2 &pcfg_pull_none>;
++			};
++
++			pdm_sdi3: pdm-sdi3 {
++				rockchip,pins =
++					<3 RK_PD2 RK_FUNC_4 &pcfg_pull_none>;
++			};
++
++			pdm_clk0m0_sleep: pdm-clk0m0-sleep {
++				rockchip,pins =
++					<3 RK_PC6 RK_FUNC_GPIO &pcfg_input_high>;
++			};
++
++			pdm_clk0m_sleep1: pdm-clk0m1-sleep {
++				rockchip,pins =
++					<2 RK_PC6 RK_FUNC_GPIO &pcfg_input_high>;
++			};
++
++			pdm_clk1_sleep: pdm-clk1-sleep {
++				rockchip,pins =
++					<3 RK_PC7 RK_FUNC_GPIO &pcfg_input_high>;
++			};
++
++			pdm_sdi0m0_sleep: pdm-sdi0m0-sleep {
++				rockchip,pins =
++					<3 RK_PD3 RK_FUNC_GPIO &pcfg_input_high>;
++			};
++
++			pdm_sdi0m1_sleep: pdm-sdi0m1-sleep {
++				rockchip,pins =
++					<2 RK_PC5 RK_FUNC_GPIO &pcfg_input_high>;
++			};
++
++			pdm_sdi1_sleep: pdm-sdi1-sleep {
++				rockchip,pins =
++					<3 RK_PD0 RK_FUNC_GPIO &pcfg_input_high>;
++			};
++
++			pdm_sdi2_sleep: pdm-sdi2-sleep {
++				rockchip,pins =
++					<3 RK_PD1 RK_FUNC_GPIO &pcfg_input_high>;
++			};
++
++			pdm_sdi3_sleep: pdm-sdi3-sleep {
++				rockchip,pins =
++					<3 RK_PD2 RK_FUNC_GPIO &pcfg_input_high>;
++			};
++		};
++
++		i2s0 {
++			i2s0_8ch_mclk: i2s0-8ch-mclk {
++				rockchip,pins =
++					<3 RK_PC1 RK_FUNC_2 &pcfg_pull_none>;
++			};
++
++			i2s0_8ch_sclktx: i2s0-8ch-sclktx {
++				rockchip,pins =
++					<3 RK_PC3 RK_FUNC_2 &pcfg_pull_none>;
++			};
++
++			i2s0_8ch_sclkrx: i2s0-8ch-sclkrx {
++				rockchip,pins =
++					<3 RK_PB4 RK_FUNC_2 &pcfg_pull_none>;
++			};
++
++			i2s0_8ch_lrcktx: i2s0-8ch-lrcktx {
++				rockchip,pins =
++					<3 RK_PC2 RK_FUNC_2 &pcfg_pull_none>;
++			};
++
++			i2s0_8ch_lrckrx: i2s0-8ch-lrckrx {
++				rockchip,pins =
++					<3 RK_PB5 RK_FUNC_2 &pcfg_pull_none>;
++			};
++
++			i2s0_8ch_sdo: i2s0-8ch-sdo {
++				rockchip,pins =
++					<3 RK_PD2 RK_FUNC_3 &pcfg_pull_none>;
++			};
++
++			i2s0_8ch_sdo0: i2s0-8ch-sdo0 {
++				rockchip,pins =
++					<3 RK_PC4 RK_FUNC_2 &pcfg_pull_none>;
++			};
++
++			i2s0_8ch_sdo1: i2s0-8ch-sdo1 {
++				rockchip,pins =
++					<3 RK_PC0 RK_FUNC_2 &pcfg_pull_none>;
++			};
++
++			i2s0_8ch_sdo2: i2s0-8ch-sdo2 {
++				rockchip,pins =
++					<3 RK_PB7 RK_FUNC_2 &pcfg_pull_none>;
++			};
++
++			i2s0_8ch_sdo3: i2s0-8ch-sdo3 {
++				rockchip,pins =
++					<3 RK_PB6 RK_FUNC_2 &pcfg_pull_none>;
++			};
++
++			i2s0_8ch_sdi: i2s0-8ch-sdi {
++				rockchip,pins =
++					<3 RK_PD3 RK_FUNC_3 &pcfg_pull_none>;
++			};
++
++			i2s0_8ch_sdi0: i2s0-8ch-sdi0 {
++				rockchip,pins =
++					<3 RK_PC5 RK_FUNC_2 &pcfg_pull_none>;
++			};
++
++			i2s0_8ch_sdi1: i2s0-8ch-sdi1 {
++				rockchip,pins =
++					<3 RK_PB3 RK_FUNC_2 &pcfg_pull_none>;
++			};
++
++			i2s0_8ch_sdi2: i2s0-8ch-sdi2 {
++				rockchip,pins =
++					<3 RK_PB1 RK_FUNC_2 &pcfg_pull_none>;
++			};
++
++			i2s0_8ch_sdi3: i2s0-8ch-sdi3 {
++				rockchip,pins =
++					<3 RK_PB0 RK_FUNC_2 &pcfg_pull_none>;
++			};
++		};
++
++		i2s1 {
++			i2s1_2ch_mclk: i2s1-2ch-mclk {
++				rockchip,pins =
++					<2 RK_PC3 RK_FUNC_1 &pcfg_pull_none>;
++			};
++
++			i2s1_2ch_sclk: i2s1-2ch-sclk {
++				rockchip,pins =
++					<2 RK_PC2 RK_FUNC_1 &pcfg_pull_none>;
++			};
++
++			i2s1_2ch_lrck: i2s1-2ch-lrck {
++				rockchip,pins =
++					<2 RK_PC1 RK_FUNC_1 &pcfg_pull_none>;
++			};
++
++			i2s1_2ch_sdi: i2s1-2ch-sdi {
++				rockchip,pins =
++					<2 RK_PC5 RK_FUNC_1 &pcfg_pull_none>;
++			};
++
++			i2s1_2ch_sdo: i2s1-2ch-sdo {
++				rockchip,pins =
++					<2 RK_PC4 RK_FUNC_1 &pcfg_pull_none>;
++			};
++		};
++
++		i2s2 {
++			i2s2_2ch_mclk: i2s2-2ch-mclk {
++				rockchip,pins =
++					<3 RK_PA1 RK_FUNC_2 &pcfg_pull_none>;
++			};
++
++			i2s2_2ch_sclk: i2s2-2ch-sclk {
++				rockchip,pins =
++					<3 RK_PA2 RK_FUNC_2 &pcfg_pull_none>;
++			};
++
++			i2s2_2ch_lrck: i2s2-2ch-lrck {
++				rockchip,pins =
++					<3 RK_PA3 RK_FUNC_2 &pcfg_pull_none>;
++			};
++
++			i2s2_2ch_sdi: i2s2-2ch-sdi {
++				rockchip,pins =
++					<3 RK_PA5 RK_FUNC_2 &pcfg_pull_none>;
++			};
++
++			i2s2_2ch_sdo: i2s2-2ch-sdo {
++				rockchip,pins =
++					<3 RK_PA7 RK_FUNC_2 &pcfg_pull_none>;
++			};
++		};
++
++		sdmmc {
++			sdmmc_clk: sdmmc-clk {
++				rockchip,pins =
++					<1 RK_PD6 RK_FUNC_1 &pcfg_pull_none_8ma>;
++			};
++
++			sdmmc_cmd: sdmmc-cmd {
++				rockchip,pins =
++					<1 RK_PD7 RK_FUNC_1 &pcfg_pull_up_8ma>;
++			};
++
++			sdmmc_det: sdmmc-det {
++				rockchip,pins =
++					<0 RK_PA3 RK_FUNC_1 &pcfg_pull_up_8ma>;
++			};
++
++			sdmmc_bus1: sdmmc-bus1 {
++				rockchip,pins =
++					<1 RK_PD2 RK_FUNC_1 &pcfg_pull_up_8ma>;
++			};
++
++			sdmmc_bus4: sdmmc-bus4 {
++				rockchip,pins =
++					<1 RK_PD2 RK_FUNC_1 &pcfg_pull_up_8ma>,
++					<1 RK_PD3 RK_FUNC_1 &pcfg_pull_up_8ma>,
++					<1 RK_PD4 RK_FUNC_1 &pcfg_pull_up_8ma>,
++					<1 RK_PD5 RK_FUNC_1 &pcfg_pull_up_8ma>;
++			};
++
++			sdmmc_gpio: sdmmc-gpio {
++				rockchip,pins =
++					<1 RK_PD2 RK_FUNC_GPIO &pcfg_pull_up_4ma>,
++					<1 RK_PD3 RK_FUNC_GPIO &pcfg_pull_up_4ma>,
++					<1 RK_PD4 RK_FUNC_GPIO &pcfg_pull_up_4ma>,
++					<1 RK_PD5 RK_FUNC_GPIO &pcfg_pull_up_4ma>,
++					<1 RK_PD6 RK_FUNC_GPIO &pcfg_pull_up_4ma>,
++					<1 RK_PD7 RK_FUNC_GPIO &pcfg_pull_up_4ma>;
++			};
++		};
++
++		sdio {
++			sdio_clk: sdio-clk {
++				rockchip,pins =
++					<1 RK_PC5 RK_FUNC_1 &pcfg_pull_none>;
++			};
++
++			sdio_cmd: sdio-cmd {
++				rockchip,pins =
++					<1 RK_PC4 RK_FUNC_1 &pcfg_pull_up>;
++			};
++
++			sdio_bus4: sdio-bus4 {
++				rockchip,pins =
++					<1 RK_PC6 RK_FUNC_1 &pcfg_pull_up>,
++					<1 RK_PC7 RK_FUNC_1 &pcfg_pull_up>,
++					<1 RK_PD0 RK_FUNC_1 &pcfg_pull_up>,
++					<1 RK_PD1 RK_FUNC_1 &pcfg_pull_up>;
++			};
++
++			sdio_gpio: sdio-gpio {
++				rockchip,pins =
++					<1 RK_PC6 RK_FUNC_GPIO &pcfg_pull_up>,
++					<1 RK_PC7 RK_FUNC_GPIO &pcfg_pull_up>,
++					<1 RK_PD0 RK_FUNC_GPIO &pcfg_pull_up>,
++					<1 RK_PD1 RK_FUNC_GPIO &pcfg_pull_up>,
++					<1 RK_PC4 RK_FUNC_GPIO &pcfg_pull_up>,
++					<1 RK_PC5 RK_FUNC_GPIO &pcfg_pull_up>;
++			};
++		};
++
++		emmc {
++			emmc_clk: emmc-clk {
++				rockchip,pins =
++					<1 RK_PB1 RK_FUNC_2 &pcfg_pull_none_8ma>;
++			};
++
++			emmc_cmd: emmc-cmd {
++				rockchip,pins =
++					<1 RK_PB2 RK_FUNC_2 &pcfg_pull_up_8ma>;
++			};
++
++			emmc_pwren: emmc-pwren {
++				rockchip,pins =
++					<1 RK_PB0 RK_FUNC_2 &pcfg_pull_none>;
++			};
++
++			emmc_rstnout: emmc-rstnout {
++				rockchip,pins =
++					<1 RK_PB3 RK_FUNC_2 &pcfg_pull_none>;
++			};
++
++			emmc_bus1: emmc-bus1 {
++				rockchip,pins =
++					<1 RK_PA0 RK_FUNC_2 &pcfg_pull_up_8ma>;
++			};
++
++			emmc_bus4: emmc-bus4 {
++				rockchip,pins =
++					<1 RK_PA0 RK_FUNC_2 &pcfg_pull_up_8ma>,
++					<1 RK_PA1 RK_FUNC_2 &pcfg_pull_up_8ma>,
++					<1 RK_PA2 RK_FUNC_2 &pcfg_pull_up_8ma>,
++					<1 RK_PA3 RK_FUNC_2 &pcfg_pull_up_8ma>;
++			};
++
++			emmc_bus8: emmc-bus8 {
++				rockchip,pins =
++					<1 RK_PA0 RK_FUNC_2 &pcfg_pull_up_8ma>,
++					<1 RK_PA1 RK_FUNC_2 &pcfg_pull_up_8ma>,
++					<1 RK_PA2 RK_FUNC_2 &pcfg_pull_up_8ma>,
++					<1 RK_PA3 RK_FUNC_2 &pcfg_pull_up_8ma>,
++					<1 RK_PA4 RK_FUNC_2 &pcfg_pull_up_8ma>,
++					<1 RK_PA5 RK_FUNC_2 &pcfg_pull_up_8ma>,
++					<1 RK_PA6 RK_FUNC_2 &pcfg_pull_up_8ma>,
++					<1 RK_PA7 RK_FUNC_2 &pcfg_pull_up_8ma>;
++			};
++		};
++
++		flash {
++			flash_cs0: flash-cs0 {
++				rockchip,pins =
++					<1 RK_PB0 RK_FUNC_1 &pcfg_pull_none>;
++			};
++
++			flash_rdy: flash-rdy {
++				rockchip,pins =
++					<1 RK_PB1 RK_FUNC_1 &pcfg_pull_none>;
++			};
++
++			flash_dqs: flash-dqs {
++				rockchip,pins =
++					<1 RK_PB2 RK_FUNC_1 &pcfg_pull_none>;
++			};
++
++			flash_ale: flash-ale {
++				rockchip,pins =
++					<1 RK_PB3 RK_FUNC_1 &pcfg_pull_none>;
++			};
++
++			flash_cle: flash-cle {
++				rockchip,pins =
++					<1 RK_PB4 RK_FUNC_1 &pcfg_pull_none>;
++			};
++
++			flash_wrn: flash-wrn {
++				rockchip,pins =
++					<1 RK_PB5 RK_FUNC_1 &pcfg_pull_none>;
++			};
++
++			flash_csl: flash-csl {
++				rockchip,pins =
++					<1 RK_PB6 RK_FUNC_1 &pcfg_pull_none>;
++			};
++
++			flash_rdn: flash-rdn {
++				rockchip,pins =
++					<1 RK_PB7 RK_FUNC_1 &pcfg_pull_none>;
++			};
++
++			flash_bus8: flash-bus8 {
++				rockchip,pins =
++					<1 RK_PA0 RK_FUNC_1 &pcfg_pull_up_12ma>,
++					<1 RK_PA1 RK_FUNC_1 &pcfg_pull_up_12ma>,
++					<1 RK_PA2 RK_FUNC_1 &pcfg_pull_up_12ma>,
++					<1 RK_PA3 RK_FUNC_1 &pcfg_pull_up_12ma>,
++					<1 RK_PA4 RK_FUNC_1 &pcfg_pull_up_12ma>,
++					<1 RK_PA5 RK_FUNC_1 &pcfg_pull_up_12ma>,
++					<1 RK_PA6 RK_FUNC_1 &pcfg_pull_up_12ma>,
++					<1 RK_PA7 RK_FUNC_1 &pcfg_pull_up_12ma>;
++			};
++		};
++
++		lcdc {
++			lcdc_rgb_dclk_pin: lcdc-rgb-dclk-pin {
++				rockchip,pins =
++					<3 RK_PA0 RK_FUNC_1 &pcfg_pull_none>;
++			};
++
++			lcdc_rgb_m0_hsync_pin: lcdc-rgb-m0-hsync-pin {
++				rockchip,pins =
++					<3 RK_PA1 RK_FUNC_1 &pcfg_pull_none>;
++			};
++
++			lcdc_rgb_m0_vsync_pin: lcdc-rgb-m0-vsync-pin {
++				rockchip,pins =
++					<3 RK_PA2 RK_FUNC_1 &pcfg_pull_none>;
++			};
++
++			lcdc_rgb_m0_den_pin: lcdc-rgb-m0-den-pin {
++				rockchip,pins =
++					<3 RK_PA3 RK_FUNC_1 &pcfg_pull_none>;
++			};
++
++			lcdc_rgb888_m0_data_pins: lcdc-rgb888-m0-data-pins {
++				rockchip,pins =
++					<3 RK_PA7 RK_FUNC_1 &pcfg_pull_none>,	/* lcdc_d3 */
++					<3 RK_PA6 RK_FUNC_1 &pcfg_pull_none>,	/* lcdc_d2 */
++					<3 RK_PA5 RK_FUNC_1 &pcfg_pull_none>,	/* lcdc_d1 */
++					<3 RK_PA4 RK_FUNC_1 &pcfg_pull_none>,	/* lcdc_d0 */
++					<3 RK_PB3 RK_FUNC_1 &pcfg_pull_none>,	/* lcdc_d7 */
++					<3 RK_PB2 RK_FUNC_1 &pcfg_pull_none>,	/* lcdc_d6 */
++					<3 RK_PB1 RK_FUNC_1 &pcfg_pull_none>,	/* lcdc_d5 */
++					<3 RK_PB0 RK_FUNC_1 &pcfg_pull_none>,	/* lcdc_d4 */
++					<3 RK_PB7 RK_FUNC_1 &pcfg_pull_none>,	/* lcdc_d11 */
++					<3 RK_PB6 RK_FUNC_1 &pcfg_pull_none>,	/* lcdc_d10 */
++					<3 RK_PB5 RK_FUNC_1 &pcfg_pull_none>,	/* lcdc_d9 */
++					<3 RK_PB4 RK_FUNC_1 &pcfg_pull_none>,	/* lcdc_d8 */
++					<3 RK_PC3 RK_FUNC_1 &pcfg_pull_none>,	/* lcdc_d15 */
++					<3 RK_PC2 RK_FUNC_1 &pcfg_pull_none>,	/* lcdc_d14 */
++					<3 RK_PC1 RK_FUNC_1 &pcfg_pull_none>,	/* lcdc_d13 */
++					<3 RK_PC0 RK_FUNC_1 &pcfg_pull_none>,	/* lcdc_d12 */
++					<3 RK_PC7 RK_FUNC_1 &pcfg_pull_none>,	/* lcdc_d19 */
++					<3 RK_PC6 RK_FUNC_1 &pcfg_pull_none>,	/* lcdc_d18 */
++					<3 RK_PC5 RK_FUNC_1 &pcfg_pull_none>,	/* lcdc_d17 */
++					<3 RK_PC4 RK_FUNC_1 &pcfg_pull_none>,	/* lcdc_d16 */
++					<3 RK_PD3 RK_FUNC_1 &pcfg_pull_none>,	/* lcdc_d23 */
++					<3 RK_PD2 RK_FUNC_1 &pcfg_pull_none>,	/* lcdc_d22 */
++					<3 RK_PD1 RK_FUNC_1 &pcfg_pull_none>,	/* lcdc_d21 */
++					<3 RK_PD0 RK_FUNC_1 &pcfg_pull_none>;	/* lcdc_d20 */
++			};
++
++			lcdc_rgb666_m0_data_pins: lcdc-rgb666-m0-data-pins {
++				rockchip,pins =
++					<3 RK_PA7 RK_FUNC_1 &pcfg_pull_none>,	/* lcdc_d3 */
++					<3 RK_PA6 RK_FUNC_1 &pcfg_pull_none>,	/* lcdc_d2 */
++					<3 RK_PA5 RK_FUNC_1 &pcfg_pull_none>,	/* lcdc_d1 */
++					<3 RK_PA4 RK_FUNC_1 &pcfg_pull_none>,	/* lcdc_d0 */
++					<3 RK_PB3 RK_FUNC_1 &pcfg_pull_none>,	/* lcdc_d7 */
++					<3 RK_PB2 RK_FUNC_1 &pcfg_pull_none>,	/* lcdc_d6 */
++					<3 RK_PB1 RK_FUNC_1 &pcfg_pull_none>,	/* lcdc_d5 */
++					<3 RK_PB0 RK_FUNC_1 &pcfg_pull_none>,	/* lcdc_d4 */
++					<3 RK_PB7 RK_FUNC_1 &pcfg_pull_none>,	/* lcdc_d11 */
++					<3 RK_PB6 RK_FUNC_1 &pcfg_pull_none>,	/* lcdc_d10 */
++					<3 RK_PB5 RK_FUNC_1 &pcfg_pull_none>,	/* lcdc_d9 */
++					<3 RK_PB4 RK_FUNC_1 &pcfg_pull_none>,	/* lcdc_d8 */
++					<3 RK_PC3 RK_FUNC_1 &pcfg_pull_none>,	/* lcdc_d15 */
++					<3 RK_PC2 RK_FUNC_1 &pcfg_pull_none>,	/* lcdc_d14 */
++					<3 RK_PC1 RK_FUNC_1 &pcfg_pull_none>,	/* lcdc_d13 */
++					<3 RK_PC0 RK_FUNC_1 &pcfg_pull_none>,	/* lcdc_d12 */
++					<3 RK_PC5 RK_FUNC_1 &pcfg_pull_none>,	/* lcdc_d17 */
++					<3 RK_PC4 RK_FUNC_1 &pcfg_pull_none>;	/* lcdc_d16 */
++			};
++
++			lcdc_rgb565_m0_data_pins: lcdc-rgb565-m0-data-pins {
++				rockchip,pins =
++					<3 RK_PA7 RK_FUNC_1 &pcfg_pull_none>,	/* lcdc_d3 */
++					<3 RK_PA6 RK_FUNC_1 &pcfg_pull_none>,	/* lcdc_d2 */
++					<3 RK_PA5 RK_FUNC_1 &pcfg_pull_none>,	/* lcdc_d1 */
++					<3 RK_PA4 RK_FUNC_1 &pcfg_pull_none>,	/* lcdc_d0 */
++					<3 RK_PB3 RK_FUNC_1 &pcfg_pull_none>,	/* lcdc_d7 */
++					<3 RK_PB2 RK_FUNC_1 &pcfg_pull_none>,	/* lcdc_d6 */
++					<3 RK_PB1 RK_FUNC_1 &pcfg_pull_none>,	/* lcdc_d5 */
++					<3 RK_PB0 RK_FUNC_1 &pcfg_pull_none>,	/* lcdc_d4 */
++					<3 RK_PB7 RK_FUNC_1 &pcfg_pull_none>,	/* lcdc_d11 */
++					<3 RK_PB6 RK_FUNC_1 &pcfg_pull_none>,	/* lcdc_d10 */
++					<3 RK_PB5 RK_FUNC_1 &pcfg_pull_none>,	/* lcdc_d9 */
++					<3 RK_PB4 RK_FUNC_1 &pcfg_pull_none>,	/* lcdc_d8 */
++					<3 RK_PC3 RK_FUNC_1 &pcfg_pull_none>,	/* lcdc_d15 */
++					<3 RK_PC2 RK_FUNC_1 &pcfg_pull_none>,	/* lcdc_d14 */
++					<3 RK_PC1 RK_FUNC_1 &pcfg_pull_none>,	/* lcdc_d13 */
++					<3 RK_PC0 RK_FUNC_1 &pcfg_pull_none>;	/* lcdc_d12 */
++			};
++
++			lcdc_rgb888_m1_data_pins: lcdc-rgb888-m1-data-pins {
++				rockchip,pins =
++					<3 RK_PA6 RK_FUNC_1 &pcfg_pull_none>,	/* lcdc_d2 */
++					<3 RK_PA4 RK_FUNC_1 &pcfg_pull_none>,	/* lcdc_d0 */
++					<3 RK_PB3 RK_FUNC_1 &pcfg_pull_none>,	/* lcdc_d7 */
++					<3 RK_PB2 RK_FUNC_1 &pcfg_pull_none>,	/* lcdc_d6 */
++					<3 RK_PB5 RK_FUNC_1 &pcfg_pull_none>,	/* lcdc_d9 */
++					<3 RK_PC3 RK_FUNC_1 &pcfg_pull_none>,	/* lcdc_d15 */
++					<3 RK_PC2 RK_FUNC_1 &pcfg_pull_none>,	/* lcdc_d14 */
++					<3 RK_PC1 RK_FUNC_1 &pcfg_pull_none>,	/* lcdc_d13 */
++					<3 RK_PC0 RK_FUNC_1 &pcfg_pull_none>,	/* lcdc_d12 */
++					<3 RK_PC7 RK_FUNC_1 &pcfg_pull_none>,	/* lcdc_d19 */
++					<3 RK_PC6 RK_FUNC_1 &pcfg_pull_none>,	/* lcdc_d18 */
++					<3 RK_PC5 RK_FUNC_1 &pcfg_pull_none>,	/* lcdc_d17 */
++					<3 RK_PC4 RK_FUNC_1 &pcfg_pull_none>,	/* lcdc_d16 */
++					<3 RK_PD3 RK_FUNC_1 &pcfg_pull_none>,	/* lcdc_d23 */
++					<3 RK_PD2 RK_FUNC_1 &pcfg_pull_none>,	/* lcdc_d22 */
++					<3 RK_PD1 RK_FUNC_1 &pcfg_pull_none>,	/* lcdc_d21 */
++					<3 RK_PD0 RK_FUNC_1 &pcfg_pull_none>;	/* lcdc_d20 */
++			};
++
++			lcdc_rgb666_m1_data_pins: lcdc-rgb666-m1-data-pins {
++				rockchip,pins =
++					<3 RK_PA6 RK_FUNC_1 &pcfg_pull_none>,	/* lcdc_d2 */
++					<3 RK_PA4 RK_FUNC_1 &pcfg_pull_none>,	/* lcdc_d0 */
++					<3 RK_PB3 RK_FUNC_1 &pcfg_pull_none>,	/* lcdc_d7 */
++					<3 RK_PB2 RK_FUNC_1 &pcfg_pull_none>,	/* lcdc_d6 */
++					<3 RK_PB5 RK_FUNC_1 &pcfg_pull_none>,	/* lcdc_d9 */
++					<3 RK_PC3 RK_FUNC_1 &pcfg_pull_none>,	/* lcdc_d15 */
++					<3 RK_PC2 RK_FUNC_1 &pcfg_pull_none>,	/* lcdc_d14 */
++					<3 RK_PC1 RK_FUNC_1 &pcfg_pull_none>,	/* lcdc_d13 */
++					<3 RK_PC0 RK_FUNC_1 &pcfg_pull_none>,	/* lcdc_d12 */
++					<3 RK_PC5 RK_FUNC_1 &pcfg_pull_none>,	/* lcdc_d17 */
++					<3 RK_PC4 RK_FUNC_1 &pcfg_pull_none>;	/* lcdc_d16 */
++			};
++
++			lcdc_rgb565_m1_data_pins: lcdc-rgb565-m1-data-pins {
++				rockchip,pins =
++					<3 RK_PA6 RK_FUNC_1 &pcfg_pull_none>,	/* lcdc_d2 */
++					<3 RK_PA4 RK_FUNC_1 &pcfg_pull_none>,	/* lcdc_d0 */
++					<3 RK_PB3 RK_FUNC_1 &pcfg_pull_none>,	/* lcdc_d7 */
++					<3 RK_PB2 RK_FUNC_1 &pcfg_pull_none>,	/* lcdc_d6 */
++					<3 RK_PB5 RK_FUNC_1 &pcfg_pull_none>,	/* lcdc_d9 */
++					<3 RK_PC3 RK_FUNC_1 &pcfg_pull_none>,	/* lcdc_d15 */
++					<3 RK_PC2 RK_FUNC_1 &pcfg_pull_none>,	/* lcdc_d14 */
++					<3 RK_PC1 RK_FUNC_1 &pcfg_pull_none>,	/* lcdc_d13 */
++					<3 RK_PC0 RK_FUNC_1 &pcfg_pull_none>;	/* lcdc_d12 */
++			};
++		};
++
++		pwm0 {
++			pwm0_pin: pwm0-pin {
++				rockchip,pins =
++					<0 RK_PB7 RK_FUNC_1 &pcfg_pull_none>;
++			};
++		};
++
++		pwm1 {
++			pwm1_pin: pwm1-pin {
++				rockchip,pins =
++					<0 RK_PC0 RK_FUNC_1 &pcfg_pull_none>;
++			};
++		};
++
++		pwm2 {
++			pwm2_pin: pwm2-pin {
++				rockchip,pins =
++					<2 RK_PB5 RK_FUNC_1 &pcfg_pull_none>;
++			};
++		};
++
++		pwm3 {
++			pwm3_pin: pwm3-pin {
++				rockchip,pins =
++					<0 RK_PC1 RK_FUNC_1 &pcfg_pull_none>;
++			};
++		};
++
++		pwm4 {
++			pwm4_pin: pwm4-pin {
++				rockchip,pins =
++					<3 RK_PC2 RK_FUNC_3 &pcfg_pull_none>;
++			};
++		};
++
++		pwm5 {
++			pwm5_pin: pwm5-pin {
++				rockchip,pins =
++					<3 RK_PC3 RK_FUNC_3 &pcfg_pull_none>;
++			};
++		};
++
++		pwm6 {
++			pwm6_pin: pwm6-pin {
++				rockchip,pins =
++					<3 RK_PC4 RK_FUNC_3 &pcfg_pull_none>;
++			};
++		};
++
++		pwm7 {
++			pwm7_pin: pwm7-pin {
++				rockchip,pins =
++					<3 RK_PC5 RK_FUNC_3 &pcfg_pull_none>;
++			};
++		};
++
++		gmac {
++			rmii_pins: rmii-pins {
++				rockchip,pins =
++					/* mac_txen */
++					<2 RK_PA0 RK_FUNC_2 &pcfg_pull_none_12ma>,
++					/* mac_txd1 */
++					<2 RK_PA1 RK_FUNC_2 &pcfg_pull_none_12ma>,
++					/* mac_txd0 */
++					<2 RK_PA2 RK_FUNC_2 &pcfg_pull_none_12ma>,
++					/* mac_rxd0 */
++					<2 RK_PA3 RK_FUNC_2 &pcfg_pull_none>,
++					/* mac_rxd1 */
++					<2 RK_PA4 RK_FUNC_2 &pcfg_pull_none>,
++					/* mac_rxer */
++					<2 RK_PA5 RK_FUNC_2 &pcfg_pull_none>,
++					/* mac_rxdv */
++					<2 RK_PA6 RK_FUNC_2 &pcfg_pull_none>,
++					/* mac_mdio */
++					<2 RK_PA7 RK_FUNC_2 &pcfg_pull_none>,
++					/* mac_mdc */
++					<2 RK_PB1 RK_FUNC_2 &pcfg_pull_none>;
++			};
++
++			mac_refclk_12ma: mac-refclk-12ma {
++				rockchip,pins =
++					<2 RK_PB2 RK_FUNC_2 &pcfg_pull_none_12ma>;
++			};
++
++			mac_refclk: mac-refclk {
++				rockchip,pins =
++					<2 RK_PB2 RK_FUNC_2 &pcfg_pull_none>;
++			};
++		};
++
++		cif-m0 {
++			cif_clkout_m0: cif-clkout-m0 {
++				rockchip,pins = <2 RK_PB3 RK_FUNC_1 &pcfg_pull_none>;/* cif_clkout */
++			};
++
++			dvp_d2d9_m0: dvp-d2d9-m0 {
++				rockchip,pins =
++					<2 RK_PA0 RK_FUNC_1 &pcfg_pull_none>,/* cif_data2 */
++					<2 RK_PA1 RK_FUNC_1 &pcfg_pull_none>,/* cif_data3 */
++					<2 RK_PA2 RK_FUNC_1 &pcfg_pull_none>,/* cif_data4 */
++					<2 RK_PA3 RK_FUNC_1 &pcfg_pull_none>,/* cif_data5 */
++					<2 RK_PA4 RK_FUNC_1 &pcfg_pull_none>,/* cif_data6 */
++					<2 RK_PA5 RK_FUNC_1 &pcfg_pull_none>,/* cif_data7 */
++					<2 RK_PA6 RK_FUNC_1 &pcfg_pull_none>,/* cif_data8 */
++					<2 RK_PA7 RK_FUNC_1 &pcfg_pull_none>,/* cif_data9 */
++					<2 RK_PB0 RK_FUNC_1 &pcfg_pull_none>,/* cif_sync */
++					<2 RK_PB1 RK_FUNC_1 &pcfg_pull_none>,/* cif_href */
++					<2 RK_PB2 RK_FUNC_1 &pcfg_pull_none>,/* cif_clkin */
++					<2 RK_PB3 RK_FUNC_1 &pcfg_pull_none>;/* cif_clkout */
++			};
++
++			dvp_d0d1_m0: dvp-d0d1-m0 {
++				rockchip,pins =
++					<2 RK_PB4 RK_FUNC_1 &pcfg_pull_none>,/* cif_data0 */
++					<2 RK_PB6 RK_FUNC_1 &pcfg_pull_none>;/* cif_data1 */
++			};
++
++			dvp_d10d11_m0:d10-d11-m0 {
++				rockchip,pins =
++					<2 RK_PB7 RK_FUNC_1 &pcfg_pull_none>,/* cif_data10 */
++					<2 RK_PC0 RK_FUNC_1 &pcfg_pull_none>;/* cif_data11 */
++			};
++		};
++
++		cif-m1 {
++			cif_clkout_m1: cif-clkout-m1 {
++				rockchip,pins = <3 RK_PD0 RK_FUNC_3 &pcfg_pull_none>;/* cif_clkout */
++			};
++
++			dvp_d2d9_m1: dvp-d2d9-m1 {
++				rockchip,pins =
++					<3 RK_PA3 RK_FUNC_1 &pcfg_pull_none>,/* cif_data2 */
++					<3 RK_PA5 RK_FUNC_1 &pcfg_pull_none>,/* cif_data3 */
++					<3 RK_PA7 RK_FUNC_1 &pcfg_pull_none>,/* cif_data4 */
++					<3 RK_PB0 RK_FUNC_1 &pcfg_pull_none>,/* cif_data5 */
++					<3 RK_PB1 RK_FUNC_1 &pcfg_pull_none>,/* cif_data6 */
++					<3 RK_PB4 RK_FUNC_1 &pcfg_pull_none>,/* cif_data7 */
++					<3 RK_PB6 RK_FUNC_1 &pcfg_pull_none>,/* cif_data8 */
++					<3 RK_PB7 RK_FUNC_1 &pcfg_pull_none>,/* cif_data9 */
++					<3 RK_PD1 RK_FUNC_3 &pcfg_pull_none>,/* cif_sync */
++					<3 RK_PD2 RK_FUNC_2 &pcfg_pull_none>,/* cif_href */
++					<3 RK_PD3 RK_FUNC_2 &pcfg_pull_none>,/* cif_clkin */
++					<3 RK_PD0 RK_FUNC_3 &pcfg_pull_none>;/* cif_clkout */
++			};
++
++			dvp_d0d1_m1: dvp-d0d1-m1 {
++				rockchip,pins =
++					<3 RK_PA1 RK_FUNC_3 &pcfg_pull_none>,/* cif_data0 */
++					<3 RK_PA2 RK_FUNC_3 &pcfg_pull_none>;/* cif_data1 */
++			};
++
++			dvp_d10d11_m1:d10-d11-m1 {
++				rockchip,pins =
++					<3 RK_PC6 RK_FUNC_3 &pcfg_pull_none>,/* cif_data10 */
++					<3 RK_PC7 RK_FUNC_3 &pcfg_pull_none>;/* cif_data11 */
++			};
++		};
++
++		isp {
++			isp_prelight: isp-prelight {
++				rockchip,pins = <3 RK_PD1 RK_FUNC_4 &pcfg_pull_none>;/* ISP_PRELIGHTTRIG */
++			};
++		};
++	};
++};
+diff --git a/configs/evb-px30_defconfig b/configs/evb-px30_defconfig
+index d1cc1788c9..4a35f3f887 100644
+--- a/configs/evb-px30_defconfig
++++ b/configs/evb-px30_defconfig
+@@ -111,3 +111,8 @@ CONFIG_LZ4=y
+ CONFIG_LZO=y
+ CONFIG_ERRNO_STR=y
+ # CONFIG_EFI_LOADER is not set
++CONFIG_BOOTCOMMAND="setenv resin_kernel_load_addr ${kernel_addr_r}; run resin_set_kernel_root; run set_os_cmdline; setenv bootargs ${resin_kernel_root} rootwait console=ttyFIQ0,1500000 console=tty1  ${os_cmdline} panic=10 loglevel=7; load mmc ${resin_dev_index}:${resin_root_part} ${kernel_addr_r} /boot/Image; load mmc ${resin_dev_index}:${resin_root_part} ${fdt_addr_r} /boot/px30-evb-ddr3-v10-linux.dtb; booti ${kernel_addr_r} - ${fdt_addr_r}"
++CONFIG_CMD_FS_UUID=y
++CONFIG_CMD_EXPORTENV=y
++CONFIG_CMD_IMPORTENV=y
++CONFIG_CMD_SETEXPR=y
+-- 
+2.17.1
+
diff --git a/layers/meta-balena-nanopc-t4/recipes-bsp/u-boot/files/0001-resin-specific-env-integration-kconfig_REWORKED-lec-px30.patch b/layers/meta-balena-nanopc-t4/recipes-bsp/u-boot/files/0001-resin-specific-env-integration-kconfig_REWORKED-lec-px30.patch
new file mode 100644
index 000000000..d5b1c257e
--- /dev/null
+++ b/layers/meta-balena-nanopc-t4/recipes-bsp/u-boot/files/0001-resin-specific-env-integration-kconfig_REWORKED-lec-px30.patch
@@ -0,0 +1,19 @@
+--- a/include/env_default.h
++++ b/include/env_default.h
+@@ -8,7 +8,7 @@
+  */
+
+ #include <env_callback.h>
+-
++#include <env_resin.h>
+ #ifdef DEFAULT_ENV_INSTANCE_EMBEDDED
+ env_t embedded_environment __UBOOT_ENV_SECTION__(environment) = {
+ 	ENV_CRC,	/* CRC Sum */
+@@ -21,6 +21,7 @@
+ #else
+ const uchar default_environment[] = {
+ #endif
++     RESIN_ENV
+ #ifndef CONFIG_USE_DEFAULT_ENV_FILE
+ #ifdef	CONFIG_ENV_CALLBACK_LIST_DEFAULT
+ 	ENV_CALLBACK_VAR "=" CONFIG_ENV_CALLBACK_LIST_DEFAULT "\0"
diff --git a/layers/meta-balena-nanopc-t4/recipes-bsp/u-boot/u-boot-rockchip.bb b/layers/meta-balena-nanopc-t4/recipes-bsp/u-boot/u-boot-rockchip.bb
new file mode 100644
index 000000000..aa939a3de
--- /dev/null
+++ b/layers/meta-balena-nanopc-t4/recipes-bsp/u-boot/u-boot-rockchip.bb
@@ -0,0 +1,23 @@
+DESCRIPTION = "FriendlyElec NanoPC-T4 U-Boot"
+LICENSE = "GPLv2+"
+LIC_FILES_CHKSUM = "file://Licenses/README;md5=30503fd321432fc713238f582193b78e"
+
+require recipes-bsp/u-boot/u-boot.inc
+
+DEPENDS_append = " bison-native rkbin "
+
+SRC_URI = " \
+    git://github.com/u-boot/u-boot \
+"
+
+S = "${WORKDIR}/git"
+
+do_install_append() {
+    install -d ${D}/boot
+    install -c -m 0644 ${B}/idbloader.bin ${B}/uboot.img ${D}/boot
+}
+
+do_deploy_append() {
+    install ${B}/idbloader.bin ${DEPLOYDIR}
+    install ${B}/uboot.img ${DEPLOYDIR}
+}
diff --git a/layers/meta-balena-nanopc-t4/recipes-bsp/u-boot/u-boot-rockchip.bbappend b/layers/meta-balena-nanopc-t4/recipes-bsp/u-boot/u-boot-rockchip.bbappend
index 3c287526b..3478b3fb7 100644
--- a/layers/meta-balena-nanopc-t4/recipes-bsp/u-boot/u-boot-rockchip.bbappend
+++ b/layers/meta-balena-nanopc-t4/recipes-bsp/u-boot/u-boot-rockchip.bbappend
@@ -5,7 +5,29 @@ FILESEXTRAPATHS_append := ":${THISDIR}/files"
 
 # rework meta-resin patch whose context is different now in u-boot v2019.4
 SRC_URI_remove = "file://resin-specific-env-integration-kconfig.patch"
-SRC_URI += " \
+
+SRC_URI_append_lec-px30 = " \
+    file://0001-resin-specific-env-integration-kconfig_REWORKED-lec-px30.patch \
+    file://0000-rockchip-add-support-for-px30.patch \
+    file://0001-lec-px30.patch \
+"
+
+SRC_URI_append_nanopc-t4= " \
     file://0001-resin-specific-env-integration-kconfig_REWORKED.patch \
-    file://0002-NanoPC-T4-machine-specific-integration-of-resin-envi.patch \
+    file://nanopc-t4.patch \
 "
+
+SRCREV_nanopc-t4 = "v2019.04"
+SRCREV_lec-px30  = "v2019.10"
+
+do_compile_append_nanopc-t4() {
+    tools/mkimage -n rk3399 -T rksd -d ${DEPLOY_DIR_IMAGE}/rkbin/rk3399_ddr_800MHz_v1.14.bin idbloader.bin
+    cat ${DEPLOY_DIR_IMAGE}/rkbin/rk3399_miniloader_v1.15.bin >> idbloader.bin
+    ${DEPLOY_DIR_IMAGE}/rkbin/tools/loaderimage --pack --uboot ./u-boot-dtb.bin uboot.img 0x200000
+}
+
+do_compile_append_lec-px30() {
+    tools/mkimage -n px30 -T rksd -d ${DEPLOY_DIR_IMAGE}/rkbin/px30_ddr_333MHz_v1.10.bin idbloader.bin
+    cat ${DEPLOY_DIR_IMAGE}/rkbin/px30_miniloader_v1.15.bin >> idbloader.bin
+    ${DEPLOY_DIR_IMAGE}/rkbin/tools/loaderimage --pack --uboot ./u-boot-dtb.bin uboot.img 0x200000
+}
diff --git a/layers/meta-balena-nanopc-t4/recipes-kernel/linux/files/4.4.185/0001-Device-tree-for-LEC-PX30-A2.patch b/layers/meta-balena-nanopc-t4/recipes-kernel/linux/files/4.4.185/0001-Device-tree-for-LEC-PX30-A2.patch
new file mode 100644
index 000000000..a35046d11
--- /dev/null
+++ b/layers/meta-balena-nanopc-t4/recipes-kernel/linux/files/4.4.185/0001-Device-tree-for-LEC-PX30-A2.patch
@@ -0,0 +1,8638 @@
+From 673ce6623c876e1a8a7b91ee251d9a95baf2f374 Mon Sep 17 00:00:00 2001
+From: Katha Ashok <katha.ashok@adlinktech.com>
+Date: Thu, 19 Dec 2019 20:47:38 +0530
+Subject: [PATCH] Device tree for LEC-PX30 A2
+
+---
+ arch/arm64/boot/dts/rockchip/dsi2hdmi_lt9611.dtsi  |   48 +
+ arch/arm64/boot/dts/rockchip/lec-px30.dtsi         | 2920 +++++++++++++
+ .../boot/dts/rockchip/px30-evb-ddr3-v10-linux.dts  |  845 +++-
+ .../arm64/boot/dts/rockchip/px30-evb-ddr3-v10.dtsi |    4 +-
+ arch/arm64/boot/dts/rockchip/rk3326-linux.dtsi     |    8 +-
+ arch/arm64/configs/adlink-px30_config              | 4410 ++++++++++++++++++++
+ 6 files changed, 8147 insertions(+), 88 deletions(-)
+ create mode 100644 arch/arm64/boot/dts/rockchip/dsi2hdmi_lt9611.dtsi
+ create mode 100644 arch/arm64/boot/dts/rockchip/lec-px30.dtsi
+ create mode 100644 arch/arm64/configs/adlink-px30_config
+
+diff --git a/arch/arm64/boot/dts/rockchip/dsi2hdmi_lt9611.dtsi b/arch/arm64/boot/dts/rockchip/dsi2hdmi_lt9611.dtsi
+new file mode 100644
+index 0000000..bb00587
+--- /dev/null
++++ b/arch/arm64/boot/dts/rockchip/dsi2hdmi_lt9611.dtsi
+@@ -0,0 +1,48 @@
++&dsi {
++	status = "okay";
++	rockchip,lane-rate = <891>;
++
++    	panel@0 {
++		compatible = "simple-panel-dsi";
++		reg = <0>;
++		power-supply = <&vcc3v3_lcd>;
++		backlight = <&backlight>;
++		prepare-delay-ms = <2>;
++		reset-delay-ms = <1>;
++		init-delay-ms = <20>;
++		enable-delay-ms = <120>;
++		disable-delay-ms = <50>;
++		unprepare-delay-ms = <20>;
++
++		width-mm = <68>;
++		height-mm = <121>;
++
++		dsi,flags = <(MIPI_DSI_MODE_VIDEO | MIPI_DSI_MODE_VIDEO_BURST |
++			      MIPI_DSI_MODE_LPM | MIPI_DSI_MODE_EOT_PACKET)>;
++		dsi,format = <MIPI_DSI_FMT_RGB888>;
++		/* dsi,lanes = <2>;*/
++		dsi,lanes = <4>;
++
++		display-timings {
++			native-mode = <&timing0>;
++
++			timing0: timing0 {
++				/*clock-frequency = <74250000>;*/
++				clock-frequency=<148500000>;	
++				hactive = <1920>;
++				vactive = <1080>;
++				hfront-porch = <88>;
++				hsync-len = <44>;
++				hback-porch = <148>;
++				vfront-porch = <4>;
++				vsync-len = <5>;
++				vback-porch = <36>;
++				hsync-active = <0>;
++				vsync-active = <0>;
++				de-active = <0>;
++				pixelclk-active = <0>;
++			};
++		};
++	};
++};
++
+diff --git a/arch/arm64/boot/dts/rockchip/lec-px30.dtsi b/arch/arm64/boot/dts/rockchip/lec-px30.dtsi
+new file mode 100644
+index 0000000..708bc9c
+--- /dev/null
++++ b/arch/arm64/boot/dts/rockchip/lec-px30.dtsi
+@@ -0,0 +1,2920 @@
++/*
++ * Copyright (c) 2017 Fuzhou Rockchip Electronics Co., Ltd
++ *
++ * SPDX-License-Identifier: (GPL-2.0+ OR MIT)
++ */
++
++#include <dt-bindings/clock/px30-cru.h>
++#include <dt-bindings/display/media-bus-format.h>
++#include <dt-bindings/gpio/gpio.h>
++#include <dt-bindings/interrupt-controller/arm-gic.h>
++#include <dt-bindings/interrupt-controller/irq.h>
++#include <dt-bindings/pinctrl/rockchip.h>
++#include <dt-bindings/power/px30-power.h>
++#include <dt-bindings/soc/rockchip,boot-mode.h>
++#include <dt-bindings/soc/rockchip-system-status.h>
++#include <dt-bindings/suspend/rockchip-px30.h>
++#include <dt-bindings/thermal/thermal.h>
++#include "px30-dram-default-timing.dtsi"
++
++/ {
++	compatible = "rockchip,lec-px30";
++
++	interrupt-parent = <&gic>;
++	#address-cells = <2>;
++	#size-cells = <2>;
++
++	aliases {
++		ethernet0 = &gmac;
++		i2c0 = &i2c0;
++		i2c1 = &i2c1;
++		i2c2 = &i2c2;
++		i2c3 = &i2c3;
++		serial0 = &uart0;
++		serial1 = &uart1;
++		serial2 = &uart2;
++		serial3 = &uart3;
++		serial4 = &uart4;
++		serial5 = &uart5;
++		spi0 = &spi0;
++		spi1 = &spi1;
++	};
++
++	cpus {
++		#address-cells = <2>;
++		#size-cells = <0>;
++
++		cpu0: cpu@0 {
++			device_type = "cpu";
++			compatible = "arm,cortex-a35", "arm,armv8";
++			reg = <0x0 0x0>;
++			enable-method = "psci";
++			clocks = <&cru ARMCLK>;
++			#cooling-cells = <2>;
++			dynamic-power-coefficient = <90>;
++			operating-points-v2 = <&cpu0_opp_table>;
++			cpu-idle-states = <&CPU_SLEEP &CLUSTER_SLEEP>;
++		};
++
++		cpu1: cpu@1 {
++			device_type = "cpu";
++			compatible = "arm,cortex-a35", "arm,armv8";
++			reg = <0x0 0x1>;
++			enable-method = "psci";
++			operating-points-v2 = <&cpu0_opp_table>;
++			cpu-idle-states = <&CPU_SLEEP &CLUSTER_SLEEP>;
++		};
++		cpu2: cpu@2 {
++			device_type = "cpu";
++			compatible = "arm,cortex-a35", "arm,armv8";
++			reg = <0x0 0x2>;
++			enable-method = "psci";
++			operating-points-v2 = <&cpu0_opp_table>;
++			cpu-idle-states = <&CPU_SLEEP &CLUSTER_SLEEP>;
++		};
++		cpu3: cpu@3 {
++			device_type = "cpu";
++			compatible = "arm,cortex-a35", "arm,armv8";
++			reg = <0x0 0x3>;
++			enable-method = "psci";
++			operating-points-v2 = <&cpu0_opp_table>;
++			cpu-idle-states = <&CPU_SLEEP &CLUSTER_SLEEP>;
++		};
++
++		idle-states {
++			entry-method = "psci";
++
++			CPU_SLEEP: cpu-sleep {
++				compatible = "arm,idle-state";
++				local-timer-stop;
++				arm,psci-suspend-param = <0x0010000>;
++				entry-latency-us = <120>;
++				exit-latency-us = <250>;
++				min-residency-us = <900>;
++			};
++
++			CLUSTER_SLEEP: cluster-sleep {
++				compatible = "arm,idle-state";
++				local-timer-stop;
++				arm,psci-suspend-param = <0x1010000>;
++				entry-latency-us = <400>;
++				exit-latency-us = <500>;
++				min-residency-us = <2000>;
++			};
++		};
++	};
++
++	cpu0_opp_table: cpu0-opp-table {
++		compatible = "operating-points-v2";
++		opp-shared;
++
++		rockchip,temp-hysteresis = <5000>;
++		rockchip,low-temp = <0>;
++		rockchip,low-temp-min-volt = <1000000>;
++		rockchip,low-temp-adjust-volt = <
++			/* MHz    MHz    uV */
++			0      1512   50000
++		>;
++
++		clocks = <&cru PLL_APLL>;
++		rockchip,avs-scale = <4>;
++		rockchip,max-volt = <1350000>;
++		rockchip,evb-irdrop = <25000>;
++		nvmem-cells = <&cpu_leakage>, <&performance>;
++		nvmem-cell-names = "cpu_leakage", "performance";
++		rockchip,bin-scaling-sel = <
++			0               13
++			1               15
++		>;
++
++		rockchip,pvtm-voltage-sel = <
++			0        50000   0
++			50001    54000   1
++			54001    60000   2
++			60001    99999   3
++		>;
++		rockchip,pvtm-freq = <408000>;
++		rockchip,pvtm-volt = <1000000>;
++		rockchip,pvtm-ch = <0 0>;
++		rockchip,pvtm-sample-time = <1000>;
++		rockchip,pvtm-number = <10>;
++		rockchip,pvtm-error = <1000>;
++		rockchip,pvtm-ref-temp = <40>;
++		rockchip,pvtm-temp-prop = <(-56) (-56)>;
++		rockchip,thermal-zone = "soc-thermal";
++
++		opp-408000000 {
++			opp-hz = /bits/ 64 <408000000>;
++			opp-microvolt = <950000 950000 1350000>;
++			opp-microvolt-L0 = <950000 950000 1350000>;
++			opp-microvolt-L1 = <950000 950000 1350000>;
++			opp-microvolt-L2 = <950000 950000 1350000>;
++			opp-microvolt-L3 = <950000 950000 1350000>;
++			clock-latency-ns = <40000>;
++			opp-suspend;
++		};
++		opp-600000000 {
++			opp-hz = /bits/ 64 <600000000>;
++			opp-microvolt = <950000 950000 1350000>;
++			opp-microvolt-L0 = <950000 950000 1350000>;
++			opp-microvolt-L1 = <950000 950000 1350000>;
++			opp-microvolt-L2 = <950000 950000 1350000>;
++			opp-microvolt-L3 = <950000 950000 1350000>;
++			clock-latency-ns = <40000>;
++		};
++		opp-816000000 {
++			opp-hz = /bits/ 64 <816000000>;
++			opp-microvolt = <1050000 1050000 1350000>;
++			opp-microvolt-L0 = <1050000 1050000 1350000>;
++			opp-microvolt-L1 = <1000000 1000000 1350000>;
++			opp-microvolt-L2 = <1000000 1000000 1350000>;
++			opp-microvolt-L3 = <950000  950000  1350000>;
++			clock-latency-ns = <40000>;
++		};
++		opp-1008000000 {
++			opp-hz = /bits/ 64 <1008000000>;
++			opp-microvolt = <1175000 1175000 1350000>;
++			opp-microvolt-L0 = <1175000 1175000 1350000>;
++			opp-microvolt-L1 = <1125000 1125000 1350000>;
++			opp-microvolt-L2 = <1125000 1125000 1350000>;
++			opp-microvolt-L3 = <1050000 1050000 1350000>;
++			clock-latency-ns = <40000>;
++		};
++		opp-1200000000 {
++			opp-hz = /bits/ 64 <1200000000>;
++			opp-microvolt = <1300000 1300000 1350000>;
++			opp-microvolt-L0 = <1300000 1300000 1350000>;
++			opp-microvolt-L1 = <1275000 1275000 1350000>;
++			opp-microvolt-L2 = <1250000 1250000 1350000>;
++			opp-microvolt-L3 = <1200000 1200000 1350000>;
++			clock-latency-ns = <40000>;
++		};
++		opp-1248000000 {
++			opp-hz = /bits/ 64 <1248000000>;
++			opp-microvolt = <1350000 1350000 1350000>;
++			opp-microvolt-L0 = <1350000 1350000 1350000>;
++			opp-microvolt-L1 = <1300000 1300000 1350000>;
++			opp-microvolt-L2 = <1275000 1275000 1350000>;
++			opp-microvolt-L3 = <1225000 1225000 1350000>;
++			clock-latency-ns = <40000>;
++		};
++		opp-1296000000 {
++			opp-hz = /bits/ 64 <1296000000>;
++			opp-microvolt = <1350000 1350000 1350000>;
++			opp-microvolt-L0 = <1350000 1350000 1350000>;
++			opp-microvolt-L1 = <1350000 1350000 1350000>;
++			opp-microvolt-L2 = <1300000 1300000 1350000>;
++			opp-microvolt-L3 = <1250000 1250000 1350000>;
++			clock-latency-ns = <40000>;
++		};
++		opp-1416000000 {
++			opp-hz = /bits/ 64 <1416000000>;
++			opp-microvolt = <1350000 1350000 1350000>;
++			opp-microvolt-L0 = <1350000 1350000 1350000>;
++			opp-microvolt-L1 = <1350000 1350000 1350000>;
++			opp-microvolt-L2 = <1300000 1300000 1350000>;
++			opp-microvolt-L3 = <1250000 1250000 1350000>;
++			clock-latency-ns = <40000>;
++		};
++		opp-1512000000 {
++			opp-hz = /bits/ 64 <1512000000>;
++			opp-microvolt = <1350000 1350000 1350000>;
++			opp-microvolt-L0 = <1350000 1350000 1350000>;
++			opp-microvolt-L1 = <1350000 1350000 1350000>;
++			opp-microvolt-L2 = <1300000 1300000 1350000>;
++			opp-microvolt-L3 = <1250000 1250000 1350000>;
++			clock-latency-ns = <40000>;
++		};
++	};
++
++	arm-pmu {
++		compatible = "arm,cortex-a53-pmu";
++		interrupts = <GIC_SPI 100 IRQ_TYPE_LEVEL_HIGH>,
++			     <GIC_SPI 101 IRQ_TYPE_LEVEL_HIGH>,
++			     <GIC_SPI 102 IRQ_TYPE_LEVEL_HIGH>,
++			     <GIC_SPI 103 IRQ_TYPE_LEVEL_HIGH>;
++		interrupt-affinity = <&cpu0>, <&cpu1>, <&cpu2>, <&cpu3>;
++	};
++
++	bus_soc: bus-soc {
++		compatible = "rockchip,px30-bus";
++		rockchip,busfreq-policy = "autocs";
++		soc-bus0 {
++			bus-id = <0>;
++			timer-us = <20>;
++			enable-msk = <0x40f7>;
++			status = "disabled";
++		};
++		soc-bus1 {
++			bus-id = <1>;
++			timer-us = <200>;
++			enable-msk = <0x40bf>;
++			status = "disabled";
++		};
++		soc-bus2 {
++			bus-id = <2>;
++			timer-us = <200>;
++			enable-msk = <0x4007>;
++			status = "disabled";
++		};
++	};
++
++	bus_apll: bus-apll {
++		compatible = "rockchip,px30-bus";
++		rockchip,busfreq-policy = "clkfreq";
++		clocks = <&cru PLL_APLL>;
++		clock-names = "bus";
++		operating-points-v2 = <&bus_apll_opp_table>;
++		status = "disabled";
++	};
++
++	bus_apll_opp_table: bus-apll-opp-table {
++		compatible = "operating-points-v2";
++		opp-shared;
++
++		opp-1512000000 {
++			opp-hz = /bits/ 64 <1512000000>;
++			opp-microvolt = <1000000>;
++		};
++		opp-1008000000 {
++			opp-hz = /bits/ 64 <1008000000>;
++			opp-microvolt = <950000>;
++		};
++	};
++
++	cpuinfo {
++		compatible = "rockchip,cpuinfo";
++		nvmem-cells = <&otp_id>;
++		nvmem-cell-names = "id";
++	};
++
++	display_subsystem: display-subsystem {
++		compatible = "rockchip,display-subsystem";
++		ports = <&vopb_out>, <&vopl_out>;
++		status = "disabled";
++	};
++
++	firmware {
++		optee {
++			compatible = "linaro,optee-tz";
++			method = "smc";
++		};
++	};
++
++	gmac_clkin: external-gmac-clock {
++		compatible = "fixed-clock";
++		clock-frequency = <50000000>;
++		clock-output-names = "gmac_clkin";
++		#clock-cells = <0>;
++	};
++
++	psci {
++		compatible = "arm,psci-1.0";
++		method = "smc";
++	};
++
++	rockchip_suspend: rockchip-suspend {
++		compatible = "rockchip,pm-px30";
++		status = "disabled";
++		rockchip,sleep-debug-en = <0>;
++		rockchip,sleep-mode-config = <
++			(0
++			| RKPM_SLP_ARMOFF
++			| RKPM_SLP_PMU_HW_PLLS_PD
++			| RKPM_SLP_PMU_PMUALIVE_32K
++			| RKPM_SLP_PMU_DIS_OSC
++			| RKPM_SLP_PMIC_LP
++			)
++		>;
++		rockchip,wakeup-config = <
++			(0
++			| RKPM_CLUSTER_WKUP_EN
++			| RKPM_GPIO_WKUP_EN
++			| RKPM_USB_WKUP_EN
++			)
++		>;
++	};
++
++	timer {
++		compatible = "arm,armv8-timer";
++		interrupts = <GIC_PPI 13 (GIC_CPU_MASK_SIMPLE(4) | IRQ_TYPE_LEVEL_HIGH)>,
++			     <GIC_PPI 14 (GIC_CPU_MASK_SIMPLE(4) | IRQ_TYPE_LEVEL_HIGH)>,
++			     <GIC_PPI 11 (GIC_CPU_MASK_SIMPLE(4) | IRQ_TYPE_LEVEL_HIGH)>,
++			     <GIC_PPI 10 (GIC_CPU_MASK_SIMPLE(4) | IRQ_TYPE_LEVEL_HIGH)>;
++	};
++
++	xin24m: xin24m {
++		compatible = "fixed-clock";
++		#clock-cells = <0>;
++		clock-frequency = <24000000>;
++		clock-output-names = "xin24m";
++	};
++
++	xin32k: xin32k {
++		compatible = "fixed-clock";
++		#clock-cells = <0>;
++		clock-frequency = <32768>;
++		clock-output-names = "xin32k";
++	};
++
++	pmu: power-management@ff000000 {
++		compatible = "rockchip,px30-pmu", "syscon", "simple-mfd";
++		reg = <0x0 0xff000000 0x0 0x1000>;
++
++		power: power-controller {
++			compatible = "rockchip,px30-power-controller";
++			#power-domain-cells = <1>;
++			#address-cells = <1>;
++			#size-cells = <0>;
++
++			/* These power domains are grouped by VD_LOGIC */
++			pd_usb@PX30_PD_USB {
++				reg = <PX30_PD_USB>;
++				clocks = <&cru HCLK_HOST>,
++					 <&cru HCLK_OTG>,
++					 <&cru SCLK_OTG_ADP>;
++				pm_qos = <&qos_usb_host>, <&qos_usb_otg>;
++			};
++			pd_sdcard@PX30_PD_SDCARD {
++				reg = <PX30_PD_SDCARD>;
++				clocks = <&cru HCLK_SDMMC>,
++					 <&cru SCLK_SDMMC>;
++				pm_qos = <&qos_sdmmc>;
++			};
++			pd_gmac@PX30_PD_GMAC {
++				reg = <PX30_PD_GMAC>;
++				clocks = <&cru ACLK_GMAC>,
++					 <&cru PCLK_GMAC>,
++					 <&cru SCLK_MAC_REF>,
++					 <&cru SCLK_GMAC_RX_TX>;
++				pm_qos = <&qos_gmac>;
++			};
++			pd_mmc_nand@PX30_PD_MMC_NAND {
++				reg = <PX30_PD_MMC_NAND>;
++				clocks =  <&cru HCLK_NANDC>,
++					  <&cru HCLK_EMMC>,
++					  <&cru HCLK_SDIO>,
++					  <&cru HCLK_SFC>,
++					  <&cru SCLK_EMMC>,
++					  <&cru SCLK_NANDC>,
++					  <&cru SCLK_SDIO>,
++					  <&cru SCLK_SFC>;
++				pm_qos = <&qos_emmc>, <&qos_nand>,
++					 <&qos_sdio>, <&qos_sfc>;
++			};
++			pd_vpu@PX30_PD_VPU {
++				reg = <PX30_PD_VPU>;
++				clocks = <&cru ACLK_VPU>,
++					 <&cru HCLK_VPU>,
++					 <&cru SCLK_CORE_VPU>;
++				pm_qos = <&qos_vpu>, <&qos_vpu_r128>;
++			};
++			pd_vo@PX30_PD_VO {
++				reg = <PX30_PD_VO>;
++				clocks = <&cru ACLK_RGA>,
++					 <&cru ACLK_VOPB>,
++					 <&cru ACLK_VOPL>,
++					 <&cru DCLK_VOPB>,
++					 <&cru DCLK_VOPL>,
++					 <&cru HCLK_RGA>,
++					 <&cru HCLK_VOPB>,
++					 <&cru HCLK_VOPL>,
++					 <&cru PCLK_MIPI_DSI>,
++					 <&cru SCLK_RGA_CORE>,
++					 <&cru SCLK_VOPB_PWM>;
++				pm_qos = <&qos_rga_rd>, <&qos_rga_wr>,
++					 <&qos_vop_m0>, <&qos_vop_m1>;
++			};
++			pd_vi@PX30_PD_VI {
++				reg = <PX30_PD_VI>;
++				clocks = <&cru ACLK_CIF>,
++					 <&cru ACLK_ISP>,
++					 <&cru HCLK_CIF>,
++					 <&cru HCLK_ISP>,
++					 <&cru SCLK_ISP>;
++				pm_qos = <&qos_isp_128>, <&qos_isp_rd>,
++					 <&qos_isp_wr>, <&qos_isp_m1>,
++					 <&qos_vip>;
++			};
++			pd_gpu@PX30_PD_GPU {
++				reg = <PX30_PD_GPU>;
++				clocks = <&cru SCLK_GPU>;
++				pm_qos = <&qos_gpu>;
++			};
++		};
++	};
++
++	pmugrf: syscon@ff010000 {
++		compatible = "rockchip,px30-pmugrf", "syscon", "simple-mfd";
++		reg = <0x0 0xff010000 0x0 0x1000>;
++		#address-cells = <1>;
++		#size-cells = <1>;
++
++		pmu_io_domains: io-domains {
++			compatible = "rockchip,px30-pmu-io-voltage-domain";
++			status = "disabled";
++		};
++
++		reboot-mode {
++			compatible = "syscon-reboot-mode";
++			offset = <0x200>;
++			mode-bootloader = <BOOT_BL_DOWNLOAD>;
++			mode-charge = <BOOT_CHARGING>;
++			mode-fastboot = <BOOT_FASTBOOT>;
++			mode-loader = <BOOT_BL_DOWNLOAD>;
++			mode-normal = <BOOT_NORMAL>;
++			mode-recovery = <BOOT_RECOVERY>;
++			mode-ums = <BOOT_UMS>;
++		};
++
++		pmu_pvtm: pmu-pvtm {
++			compatible = "rockchip,px30-pmu-pvtm";
++			clocks = <&pmucru SCLK_PVTM_PMU>;
++			clock-names = "pmu";
++			status = "okay";
++		};
++	};
++
++	uart0: serial@ff030000 {
++		compatible = "rockchip,px30-uart", "snps,dw-apb-uart";
++		reg = <0x0 0xff030000 0x0 0x100>;
++		interrupts = <GIC_SPI 15 IRQ_TYPE_LEVEL_HIGH>;
++		clocks = <&pmucru SCLK_UART0_PMU>, <&pmucru PCLK_UART0_PMU>;
++		clock-names = "baudclk", "apb_pclk";
++		reg-shift = <2>;
++		reg-io-width = <4>;
++		dmas = <&dmac 0>, <&dmac 1>;
++		pinctrl-names = "default";
++		pinctrl-0 = <&uart0_xfer &uart0_cts &uart0_rts>;
++		status = "disabled";
++	};
++
++	i2s0_8ch: i2s@ff060000 {
++		compatible = "rockchip,px30-i2s-tdm";
++		reg = <0x0 0xff060000 0x0 0x1000>;
++		interrupts = <GIC_SPI 12 IRQ_TYPE_LEVEL_HIGH>;
++		clocks = <&cru SCLK_I2S0_TX>, <&cru SCLK_I2S0_RX>, <&cru HCLK_I2S0>;
++		clock-names = "mclk_tx", "mclk_rx", "hclk";
++		dmas = <&dmac 16>, <&dmac 17>;
++		dma-names = "tx", "rx";
++		resets = <&cru SRST_I2S0_TX>, <&cru SRST_I2S0_RX>;
++		reset-names = "tx-m", "rx-m";
++		rockchip,cru = <&cru>;
++		rockchip,grf = <&grf>;
++		pinctrl-names = "default";
++		pinctrl-0 = <&i2s0_8ch_sclktx
++			     &i2s0_8ch_sclkrx
++			     &i2s0_8ch_lrcktx
++			     &i2s0_8ch_lrckrx
++			     &i2s0_8ch_sdi0
++			     &i2s0_8ch_sdi1
++			     &i2s0_8ch_sdi2
++			     &i2s0_8ch_sdi3
++			     &i2s0_8ch_sdo0
++			     &i2s0_8ch_sdo1
++			     &i2s0_8ch_sdo2
++			     &i2s0_8ch_sdo3>;
++		status = "disabled";
++	};
++
++	i2s1_2ch: i2s@ff070000 {
++		compatible = "rockchip,px30-i2s", "rockchip,rk3066-i2s";
++		reg = <0x0 0xff070000 0x0 0x1000>;
++		interrupts = <GIC_SPI 13 IRQ_TYPE_LEVEL_HIGH>;
++		clocks = <&cru SCLK_I2S1>, <&cru HCLK_I2S1>;
++		clock-names = "i2s_clk", "i2s_hclk";
++		dmas = <&dmac 18>, <&dmac 19>;
++		dma-names = "tx", "rx";
++		resets = <&cru SRST_I2S1>, <&cru SRST_I2S1_H>;
++		reset-names = "reset-m", "reset-h";
++		pinctrl-names = "default";
++		pinctrl-0 = <&i2s1_2ch_sclk
++			     &i2s1_2ch_lrck
++			     &i2s1_2ch_sdi
++			     &i2s1_2ch_sdo>;
++		status = "disabled";
++	};
++
++	i2s2_2ch: i2s@ff080000 {
++		compatible = "rockchip,px30-i2s", "rockchip,rk3066-i2s";
++		reg = <0x0 0xff080000 0x0 0x1000>;
++		interrupts = <GIC_SPI 14 IRQ_TYPE_LEVEL_HIGH>;
++		clocks = <&cru SCLK_I2S2>, <&cru HCLK_I2S2>;
++		clock-names = "i2s_clk", "i2s_hclk";
++		dmas = <&dmac 20>, <&dmac 21>;
++		dma-names = "tx", "rx";
++		resets = <&cru SRST_I2S2>, <&cru SRST_I2S2_H>;
++		reset-names = "reset-m", "reset-h";
++		pinctrl-names = "default";
++		pinctrl-0 = <&i2s2_2ch_sclk
++			     &i2s2_2ch_lrck
++			     &i2s2_2ch_sdi
++			     &i2s2_2ch_sdo>;
++		status = "disabled";
++	};
++
++	pdm: pdm@ff0a0000 {
++		compatible = "rockchip,px30-pdm", "rockchip,pdm";
++		reg = <0x0 0xff0a0000 0x0 0x1000>;
++		clocks = <&cru SCLK_PDM>, <&cru HCLK_PDM>;
++		clock-names = "pdm_clk", "pdm_hclk";
++		dmas = <&dmac 24>;
++		dma-names = "rx";
++		resets = <&cru SRST_PDM>;
++		reset-names = "pdm-m";
++		pinctrl-names = "default";
++		pinctrl-0 = <&pdm_clk0m0
++			     &pdm_clk1
++			     &pdm_sdi0m0
++			     &pdm_sdi1
++			     &pdm_sdi2
++			     &pdm_sdi3>;
++		status = "disabled";
++	};
++
++	gic: interrupt-controller@ff131000 {
++		compatible = "arm,gic-400";
++		#interrupt-cells = <3>;
++		#address-cells = <0>;
++		interrupt-controller;
++		reg = <0x0 0xff131000 0 0x1000>,
++		      <0x0 0xff132000 0 0x2000>,
++		      <0x0 0xff134000 0 0x2000>,
++		      <0x0 0xff136000 0 0x2000>;
++		interrupts = <GIC_PPI 9
++		      (GIC_CPU_MASK_SIMPLE(4) | IRQ_TYPE_LEVEL_HIGH)>;
++	};
++
++	grf: syscon@ff140000 {
++		compatible = "rockchip,px30-grf", "syscon", "simple-mfd";
++		reg = <0x0 0xff140000 0x0 0x1000>;
++		#address-cells = <1>;
++		#size-cells = <1>;
++
++		io_domains: io-domains {
++			compatible = "rockchip,px30-io-voltage-domain";
++			status = "disabled";
++		};
++
++		lvds: lvds {
++			compatible = "rockchip,px30-lvds";
++			phys = <&video_phy>;
++			phy-names = "phy";
++			status = "disabled";
++
++			ports {
++				#address-cells = <1>;
++				#size-cells = <0>;
++
++				port@0 {
++					reg = <0>;
++					#address-cells = <1>;
++					#size-cells = <0>;
++
++					lvds_in_vopb: endpoint@0 {
++						reg = <0>;
++						remote-endpoint = <&vopb_out_lvds>;
++					};
++
++					lvds_in_vopl: endpoint@1 {
++						reg = <1>;
++						remote-endpoint = <&vopl_out_lvds>;
++					};
++				};
++			};
++		};
++
++		rgb: rgb {
++			compatible = "rockchip,px30-rgb";
++			pinctrl-names = "default", "sleep";
++			pinctrl-0 = <&lcdc_m0_rgb_pins>;
++			pinctrl-1 = <&lcdc_m0_sleep_pins>;
++			status = "disabled";
++
++			ports {
++				#address-cells = <1>;
++				#size-cells = <0>;
++
++				port@0 {
++					reg = <0>;
++					#address-cells = <1>;
++					#size-cells = <0>;
++
++					rgb_in_vopb: endpoint@0 {
++						reg = <0>;
++						remote-endpoint = <&vopb_out_rgb>;
++					};
++
++					rgb_in_vopl: endpoint@1 {
++						reg = <1>;
++						remote-endpoint = <&vopl_out_rgb>;
++					};
++				};
++			};
++		};
++	};
++
++	core_grf: syscon@ff148000 {
++		compatible = "syscon", "simple-mfd";
++		reg = <0x0 0xff148000 0x0 0x1000>;
++		#address-cells = <1>;
++		#size-cells = <1>;
++
++		pvtm: pvtm {
++			compatible = "rockchip,px30-pvtm";
++			clocks = <&cru SCLK_PVTM>;
++			clock-names = "core";
++			status = "okay";
++		};
++	};
++
++	uart1: serial@ff158000 {
++		compatible = "rockchip,px30-uart", "snps,dw-apb-uart";
++		reg = <0x0 0xff158000 0x0 0x100>;
++		interrupts = <GIC_SPI 16 IRQ_TYPE_LEVEL_HIGH>;
++		clocks = <&cru SCLK_UART1>, <&cru PCLK_UART1>;
++		clock-names = "baudclk", "apb_pclk";
++		reg-shift = <2>;
++		reg-io-width = <4>;
++		dmas = <&dmac 2>, <&dmac 3>;
++		pinctrl-names = "default";
++		pinctrl-0 = <&uart1_xfer &uart1_cts &uart1_rts>;
++		status = "disabled";
++	};
++
++	uart2: serial@ff160000 {
++		compatible = "rockchip,px30-uart", "snps,dw-apb-uart";
++		reg = <0x0 0xff160000 0x0 0x100>;
++		interrupts = <GIC_SPI 17 IRQ_TYPE_LEVEL_HIGH>;
++		clocks = <&cru SCLK_UART2>, <&cru PCLK_UART2>;
++		clock-names = "baudclk", "apb_pclk";
++		reg-shift = <2>;
++		reg-io-width = <4>;
++		dmas = <&dmac 4>, <&dmac 5>;
++		pinctrl-names = "default";
++		pinctrl-0 = <&uart2m0_xfer>;
++		status = "disabled";
++	};
++
++	uart3: serial@ff168000 {
++		compatible = "rockchip,px30-uart", "snps,dw-apb-uart";
++		reg = <0x0 0xff168000 0x0 0x100>;
++		interrupts = <GIC_SPI 18 IRQ_TYPE_LEVEL_HIGH>;
++		clocks = <&cru SCLK_UART3>, <&cru PCLK_UART3>;
++		clock-names = "baudclk", "apb_pclk";
++		reg-shift = <2>;
++		reg-io-width = <4>;
++		dmas = <&dmac 6>, <&dmac 7>;
++		pinctrl-names = "default";
++		pinctrl-0 = <&uart3m1_xfer &uart3m1_cts &uart3m1_rts>;
++		status = "disabled";
++	};
++
++	uart4: serial@ff170000 {
++		compatible = "rockchip,px30-uart", "snps,dw-apb-uart";
++		reg = <0x0 0xff170000 0x0 0x100>;
++		interrupts = <GIC_SPI 19 IRQ_TYPE_LEVEL_HIGH>;
++		clocks = <&cru SCLK_UART4>, <&cru PCLK_UART4>;
++		clock-names = "baudclk", "apb_pclk";
++		reg-shift = <2>;
++		reg-io-width = <4>;
++		dmas = <&dmac 8>, <&dmac 9>;
++		pinctrl-names = "default";
++		pinctrl-0 = <&uart4_xfer &uart4_cts &uart4_rts>;
++		status = "disabled";
++	};
++
++	uart5: serial@ff178000 {
++		compatible = "rockchip,px30-uart", "snps,dw-apb-uart";
++		reg = <0x0 0xff178000 0x0 0x100>;
++		interrupts = <GIC_SPI 20 IRQ_TYPE_LEVEL_HIGH>;
++		clocks = <&cru SCLK_UART5>, <&cru PCLK_UART5>;
++		clock-names = "baudclk", "apb_pclk";
++		reg-shift = <2>;
++		reg-io-width = <4>;
++		dmas = <&dmac 10>, <&dmac 11>;
++		pinctrl-names = "default";
++		pinctrl-0 = <&uart5_xfer &uart5_cts &uart5_rts>;
++		status = "disabled";
++	};
++
++	i2c0: i2c@ff180000 {
++		compatible = "rockchip,rk3399-i2c";
++		reg = <0x0 0xff180000 0x0 0x1000>;
++		clocks =  <&cru SCLK_I2C0>, <&cru PCLK_I2C0>;
++		clock-names = "i2c", "pclk";
++		interrupts = <GIC_SPI 7 IRQ_TYPE_LEVEL_HIGH>;
++		pinctrl-names = "default";
++		pinctrl-0 = <&i2c0_xfer>;
++		#address-cells = <1>;
++		#size-cells = <0>;
++		status = "disabled";
++	};
++
++	i2c1: i2c@ff190000 {
++		compatible = "rockchip,rk3399-i2c";
++		reg = <0x0 0xff190000 0x0 0x1000>;
++		clocks = <&cru SCLK_I2C1>, <&cru PCLK_I2C1>;
++		clock-names = "i2c", "pclk";
++		interrupts = <GIC_SPI 8 IRQ_TYPE_LEVEL_HIGH>;
++		pinctrl-names = "default";
++		pinctrl-0 = <&i2c1_xfer>;
++		#address-cells = <1>;
++		#size-cells = <0>;
++		status = "disabled";
++	};
++
++	i2c2: i2c@ff1a0000 {
++		compatible = "rockchip,rk3399-i2c";
++		reg = <0x0 0xff1a0000 0x0 0x1000>;
++		clocks = <&cru SCLK_I2C2>, <&cru PCLK_I2C2>;
++		clock-names = "i2c", "pclk";
++		interrupts = <GIC_SPI 9 IRQ_TYPE_LEVEL_HIGH>;
++		pinctrl-names = "default";
++		pinctrl-0 = <&i2c2_xfer>;
++		#address-cells = <1>;
++		#size-cells = <0>;
++		status = "disabled";
++	};
++
++	i2c3: i2c@ff1b0000 {
++		compatible = "rockchip,rk3399-i2c";
++		reg = <0x0 0xff1b0000 0x0 0x1000>;
++		clocks = <&cru SCLK_I2C3>, <&cru PCLK_I2C3>;
++		clock-names = "i2c", "pclk";
++		interrupts = <GIC_SPI 10 IRQ_TYPE_LEVEL_HIGH>;
++		pinctrl-names = "default";
++		pinctrl-0 = <&i2c3_xfer>;
++		#address-cells = <1>;
++		#size-cells = <0>;
++		status = "disabled";
++	};
++
++	spi0: spi@ff1d0000 {
++		compatible = "rockchip,px30-spi", "rockchip,rk3066-spi";
++		reg = <0x0 0xff1d0000 0x0 0x1000>;
++		interrupts = <GIC_SPI 26 IRQ_TYPE_LEVEL_HIGH>;
++		#address-cells = <1>;
++		#size-cells = <0>;
++		clocks = <&cru SCLK_SPI0>, <&cru PCLK_SPI0>;
++		clock-names = "spiclk", "apb_pclk";
++		dmas = <&dmac 12>, <&dmac 13>;
++		dma-names = "tx", "rx";
++		/*cs-gpios = <&gpio1 RK_PB6 GPIO_ACTIVE_LOW>;*/
++		pinctrl-names = "default", "high_speed";
++		pinctrl-0 = <&spi0_clk /*&spi0_csn*/ &spi0_miso &spi0_mosi>;
++		pinctrl-1 = <&spi0_clk_hs /*&spi0_csn*/ &spi0_miso_hs &spi0_mosi_hs>;
++		status = "disabled";
++	};
++
++	spi1: spi@ff1d8000 {
++		compatible = "rockchip,px30-spi", "rockchip,rk3066-spi";
++		reg = <0x0 0xff1d8000 0x0 0x1000>;
++		interrupts = <GIC_SPI 27 IRQ_TYPE_LEVEL_HIGH>;
++		#address-cells = <1>;
++		#size-cells = <0>;
++		clocks = <&cru SCLK_SPI1>, <&cru PCLK_SPI1>;
++		clock-names = "spiclk", "apb_pclk";
++		dmas = <&dmac 14>, <&dmac 15>;
++		dma-names = "tx", "rx";
++		pinctrl-names = "default", "high_speed";
++		pinctrl-0 = <&spi1_clk &spi1_csn0 &spi1_csn1 &spi1_miso &spi1_mosi>;
++		pinctrl-1 = <&spi1_clk_hs &spi1_csn0 &spi1_csn1 &spi1_miso_hs &spi1_mosi_hs>;
++		status = "disabled";
++	};
++
++	wdt: watchdog@ff1e0000 {
++		compatible = "snps,dw-wdt";
++		reg = <0x0 0xff1e0000 0x0 0x100>;
++		clocks = <&cru PCLK_WDT_NS>;
++		interrupts = <GIC_SPI 37 IRQ_TYPE_LEVEL_HIGH>;
++		resets = <&cru SRST_WDT_NS_P>;
++		reset-names = "reset";
++		status = "disabled";
++	};
++
++	pwm0: pwm@ff200000 {
++		compatible = "rockchip,px30-pwm", "rockchip,rk3328-pwm";
++		reg = <0x0 0xff200000 0x0 0x10>;
++		#pwm-cells = <3>;
++		pinctrl-names = "active";
++		pinctrl-0 = <&pwm0_pin>;
++		clocks = <&cru SCLK_PWM0>, <&cru PCLK_PWM0>;
++		clock-names = "pwm", "pclk";
++		status = "disabled";
++	};
++
++	pwm1: pwm@ff200010 {
++		compatible = "rockchip,px30-pwm", "rockchip,rk3328-pwm";
++		reg = <0x0 0xff200010 0x0 0x10>;
++		#pwm-cells = <3>;
++		pinctrl-names = "active";
++		pinctrl-0 = <&pwm1_pin>;
++		clocks = <&cru SCLK_PWM0>, <&cru PCLK_PWM0>;
++		clock-names = "pwm", "pclk";
++		status = "disabled";
++	};
++
++	pwm2: pwm@ff200020 {
++		compatible = "rockchip,px30-pwm", "rockchip,rk3328-pwm";
++		reg = <0x0 0xff200020 0x0 0x10>;
++		#pwm-cells = <3>;
++		pinctrl-names = "active";
++		pinctrl-0 = <&pwm2_pin>;
++		clocks = <&cru SCLK_PWM0>, <&cru PCLK_PWM0>;
++		clock-names = "pwm", "pclk";
++		status = "disabled";
++	};
++
++	pwm3: pwm@ff200030 {
++		compatible = "rockchip,px30-pwm", "rockchip,rk3328-pwm";
++		reg = <0x0 0xff200030 0x0 0x10>;
++		#pwm-cells = <3>;
++		pinctrl-names = "active";
++		pinctrl-0 = <&pwm3_pin>;
++		clocks = <&cru SCLK_PWM0>, <&cru PCLK_PWM0>;
++		clock-names = "pwm", "pclk";
++		status = "disabled";
++	};
++
++	pwm4: pwm@ff208000 {
++		compatible = "rockchip,px30-pwm", "rockchip,rk3328-pwm";
++		reg = <0x0 0xff208000 0x0 0x10>;
++		#pwm-cells = <3>;
++		pinctrl-names = "active";
++		pinctrl-0 = <&pwm4_pin>;
++		clocks = <&cru SCLK_PWM1>, <&cru PCLK_PWM1>;
++		clock-names = "pwm", "pclk";
++		status = "disabled";
++	};
++
++	pwm5: pwm@ff208010 {
++		compatible = "rockchip,px30-pwm", "rockchip,rk3328-pwm";
++		reg = <0x0 0xff208010 0x0 0x10>;
++		#pwm-cells = <3>;
++		pinctrl-names = "active";
++		pinctrl-0 = <&pwm5_pin>;
++		clocks = <&cru SCLK_PWM1>, <&cru PCLK_PWM1>;
++		clock-names = "pwm", "pclk";
++		status = "disabled";
++	};
++
++	pwm6: pwm@ff208020 {
++		compatible = "rockchip,px30-pwm", "rockchip,rk3328-pwm";
++		reg = <0x0 0xff208020 0x0 0x10>;
++		#pwm-cells = <3>;
++		pinctrl-names = "active";
++		pinctrl-0 = <&pwm6_pin>;
++		clocks = <&cru SCLK_PWM1>, <&cru PCLK_PWM1>;
++		clock-names = "pwm", "pclk";
++		status = "disabled";
++	};
++
++	pwm7: pwm@ff208030 {
++		compatible = "rockchip,px30-pwm", "rockchip,rk3328-pwm";
++		reg = <0x0 0xff208030 0x0 0x10>;
++		#pwm-cells = <3>;
++		pinctrl-names = "active";
++		pinctrl-0 = <&pwm7_pin>;
++		clocks = <&cru SCLK_PWM1>, <&cru PCLK_PWM1>;
++		clock-names = "pwm", "pclk";
++		status = "disabled";
++	};
++
++	rktimer: rktimer@ff210000 {
++		compatible = "rockchip,rk3288-timer";
++		reg = <0x0 0xff210000 0x0 0x1000>;
++		interrupts = <GIC_SPI 30 IRQ_TYPE_LEVEL_HIGH>;
++		clocks = <&cru PCLK_TIMER>, <&cru SCLK_TIMER0>;
++		clock-names = "pclk", "timer";
++	};
++
++	amba {
++		compatible = "simple-bus";
++		#address-cells = <2>;
++		#size-cells = <2>;
++		ranges;
++
++		dmac: dmac@ff240000 {
++			compatible = "arm,pl330", "arm,primecell";
++			reg = <0x0 0xff240000 0x0 0x4000>;
++			interrupts = <GIC_SPI 1 IRQ_TYPE_LEVEL_HIGH>,
++				     <GIC_SPI 2 IRQ_TYPE_LEVEL_HIGH>;
++			clocks = <&cru ACLK_DMAC>;
++			clock-names = "apb_pclk";
++			#dma-cells = <1>;
++			peripherals-req-type-burst;
++		};
++	};
++
++	thermal_zones: thermal-zones {
++
++		soc_thermal: soc-thermal {
++			polling-delay-passive = <20>;
++			polling-delay = <1000>;
++			sustainable-power = <750>;
++
++			thermal-sensors = <&tsadc 0>;
++
++			trips {
++				threshold: trip-point-0 {
++					temperature = <70000>;
++					hysteresis = <2000>;
++					type = "passive";
++				};
++				target: trip-point-1 {
++					temperature = <85000>;
++					hysteresis = <2000>;
++					type = "passive";
++				};
++				soc_crit: soc-crit {
++					temperature = <115000>;
++					hysteresis = <2000>;
++					type = "critical";
++				};
++			};
++
++			cooling-maps {
++				map0 {
++					trip = <&target>;
++					cooling-device = <&cpu0 THERMAL_NO_LIMIT THERMAL_NO_LIMIT>;
++					contribution = <4096>;
++				};
++				map1 {
++					trip = <&target>;
++					cooling-device = <&gpu THERMAL_NO_LIMIT THERMAL_NO_LIMIT>;
++					contribution = <4096>;
++				};
++			};
++		};
++
++		gpu_thermal: gpu-thermal {
++			polling-delay-passive = <100>; /* milliseconds */
++			polling-delay = <1000>; /* milliseconds */
++
++			thermal-sensors = <&tsadc 1>;
++		};
++	};
++
++	tsadc: tsadc@ff280000 {
++		compatible = "rockchip,px30-tsadc";
++		reg = <0x0 0xff280000 0x0 0x100>;
++		interrupts = <GIC_SPI 36 IRQ_TYPE_LEVEL_HIGH>;
++		rockchip,grf = <&grf>;
++		clocks = <&cru SCLK_TSADC>, <&cru PCLK_TSADC>;
++		clock-names = "tsadc", "apb_pclk";
++		assigned-clocks = <&cru SCLK_TSADC>;
++		assigned-clock-rates = <50000>;
++		resets = <&cru SRST_TSADC>;
++		reset-names = "tsadc-apb";
++		#thermal-sensor-cells = <1>;
++		rockchip,hw-tshut-temp = <120000>;
++		status = "disabled";
++	};
++
++	saradc: saradc@ff288000 {
++		compatible = "rockchip,px30-saradc", "rockchip,rk3399-saradc";
++		reg = <0x0 0xff288000 0x0 0x100>;
++		interrupts = <GIC_SPI 84 IRQ_TYPE_LEVEL_HIGH>;
++		#io-channel-cells = <1>;
++		clocks = <&cru SCLK_SARADC>, <&cru PCLK_SARADC>;
++		clock-names = "saradc", "apb_pclk";
++		resets = <&cru SRST_SARADC_P>;
++		reset-names = "saradc-apb";
++		status = "disabled";
++	};
++
++	otp: otp@ff290000 {
++		compatible = "rockchip,px30-otp";
++		reg = <0x0 0xff290000 0x0 0x4000>;
++		#address-cells = <1>;
++		#size-cells = <1>;
++		clocks = <&cru SCLK_OTP_USR>, <&cru PCLK_OTP_NS>,
++			 <&cru PCLK_OTP_PHY>;
++		clock-names = "clk_otp", "pclk_otp", "pclk_otp_phy";
++		resets = <&cru SRST_OTP_PHY>;
++		reset-names = "otp_phy";
++
++		/* Data cells */
++		otp_id: id@7 {
++			reg = <0x07 0x10>;
++		};
++		cpu_leakage: cpu-leakage@17 {
++			reg = <0x17 0x1>;
++		};
++		performance: performance@1e {
++			reg = <0x1e 0x1>;
++			bits = <4 3>;
++		};
++	};
++
++	cru: clock-controller@ff2b0000 {
++		compatible = "rockchip,px30-cru";
++		reg = <0x0 0xff2b0000 0x0 0x1000>;
++		rockchip,grf = <&grf>;
++		rockchip,boost = <&cpu_boost>;
++		#clock-cells = <1>;
++		#reset-cells = <1>;
++	};
++
++	cpu_boost: cpu-boost@ff2b8000 {
++		compatible = "syscon";
++		reg = <0x0 0xff2b8000 0x0 0x1000>;
++		rockchip,boost-low-con0 = <0x1032>;
++		rockchip,boost-low-con1 = <0x1441>;
++		rockchip,boost-high-con0 = <0x1036>;
++		rockchip,boost-high-con1 = <0x1441>;
++		rockchip,boost-backup-pll = <1>;
++		rockchip,boost-backup-pll-usage = <0>;
++		rockchip,boost-switch-threshold = <0x249f00>;
++		rockchip,boost-statis-threshold = <0x100>;
++		rockchip,boost-statis-enable = <0>;
++		rockchip,boost-enable = <0>;
++	};
++
++	pmucru: pmu-clock-controller@ff2bc000 {
++		compatible = "rockchip,px30-pmucru";
++		reg = <0x0 0xff2bc000 0x0 0x1000>;
++		rockchip,grf = <&grf>;
++		#clock-cells = <1>;
++		#reset-cells = <1>;
++
++		assigned-clocks =
++			<&pmucru PLL_GPLL>, <&pmucru PCLK_PMU_PRE>,
++			<&pmucru SCLK_WIFI_PMU>, <&cru ARMCLK>,
++			<&cru ACLK_BUS_PRE>, <&cru ACLK_PERI_PRE>,
++			<&cru HCLK_BUS_PRE>, <&cru HCLK_PERI_PRE>,
++			<&cru PCLK_BUS_PRE>, <&cru SCLK_GPU>;
++		assigned-clock-rates =
++			<1200000000>, <100000000>,
++			<26000000>, <600000000>,
++			<200000000>, <200000000>,
++			<150000000>, <150000000>,
++			<100000000>, <200000000>;
++	};
++
++	usb2phy_grf: syscon@ff2c0000 {
++		compatible = "rockchip,px30-usb2phy-grf", "syscon",
++			     "simple-mfd";
++		reg = <0x0 0xff2c0000 0x0 0x10000>;
++		#address-cells = <1>;
++		#size-cells = <1>;
++
++		u2phy: usb2-phy@100 {
++			compatible = "rockchip,px30-usb2phy",
++				     "rockchip,rk3328-usb2phy";
++			reg = <0x100 0x10>;
++			clocks = <&pmucru SCLK_USBPHY_REF>;
++			clock-names = "phyclk";
++			#clock-cells = <0>;
++			assigned-clocks = <&cru USB480M>, <&cru SCLK_UART1_SRC>;
++			assigned-clock-parents = <&u2phy>, <&cru USB480M>;
++			clock-output-names = "usb480m_phy";
++			status = "disabled";
++
++			u2phy_host: host-port {
++				#phy-cells = <0>;
++				interrupts = <GIC_SPI 68 IRQ_TYPE_LEVEL_HIGH>;
++				interrupt-names = "linestate";
++				status = "disabled";
++			};
++
++			u2phy_otg: otg-port {
++				#phy-cells = <0>;
++				interrupts = <GIC_SPI 66 IRQ_TYPE_LEVEL_HIGH>,
++					     <GIC_SPI 65 IRQ_TYPE_LEVEL_HIGH>,
++					     <GIC_SPI 64 IRQ_TYPE_LEVEL_HIGH>;
++				interrupt-names = "otg-bvalid", "otg-id",
++						  "linestate";
++				status = "disabled";
++			};
++		};
++	};
++
++	video_phy: video-phy@ff2e0000 {
++		compatible = "rockchip,px30-video-phy";
++		reg = <0x0 0xff2e0000 0x0 0x10000>,
++		      <0x0 0xff450000 0x0 0x10000>;
++		clocks = <&pmucru SCLK_MIPIDSIPHY_REF>,
++			 <&cru PCLK_MIPIDSIPHY>, <&cru PCLK_MIPI_DSI>;
++		clock-names = "ref", "pclk_phy", "pclk_host";
++		#clock-cells = <0>;
++		resets = <&cru SRST_MIPIDSIPHY_P>;
++		reset-names = "rst";
++		power-domains = <&power PX30_PD_VO>;
++		#phy-cells = <0>;
++		status = "disabled";
++	};
++
++	mipi_dphy_rx0: mipi-dphy-rx0@ff2f0000 {
++		compatible = "rockchip,rk3326-mipi-dphy";
++		reg = <0x0 0xff2f0000 0x0 0x4000>;
++		clocks = <&cru PCLK_MIPICSIPHY>;
++		clock-names = "dphy-ref";
++		power-domains = <&power PX30_PD_VI>;
++		rockchip,grf = <&grf>;
++		status = "disabled";
++	};
++
++	usb20_otg: usb@ff300000 {
++		compatible = "rockchip,px30-usb", "rockchip,rk3066-usb",
++			     "snps,dwc2";
++		reg = <0x0 0xff300000 0x0 0x40000>;
++		interrupts = <GIC_SPI 62 IRQ_TYPE_LEVEL_HIGH>;
++		clocks = <&cru HCLK_OTG>;
++		clock-names = "otg";
++		power-domains = <&power PX30_PD_USB>;
++		dr_mode = "otg";
++		g-np-tx-fifo-size = <16>;
++		g-rx-fifo-size = <280>;
++		g-tx-fifo-size = <256 128 128 64 32 16>;
++		g-use-dma;
++		phys = <&u2phy_otg>;
++		phy-names = "usb2-phy";
++		status = "disabled";
++	};
++
++	usb_host0_ehci: usb@ff340000 {
++		compatible = "generic-ehci";
++		reg = <0x0 0xff340000 0x0 0x10000>;
++		interrupts = <GIC_SPI 60 IRQ_TYPE_LEVEL_HIGH>;
++		clocks = <&cru HCLK_HOST>, <&u2phy>;
++		clock-names = "usbhost", "utmi";
++		power-domains = <&power PX30_PD_USB>;
++		phys = <&u2phy_host>;
++		phy-names = "usb";
++		status = "disabled";
++	};
++
++	usb_host0_ohci: usb@ff350000 {
++		compatible = "generic-ohci";
++		reg = <0x0 0xff350000 0x0 0x10000>;
++		interrupts = <GIC_SPI 61 IRQ_TYPE_LEVEL_HIGH>;
++		clocks = <&cru HCLK_HOST>, <&u2phy>;
++		clock-names = "usbhost", "utmi";
++		power-domains = <&power PX30_PD_USB>;
++		phys = <&u2phy_host>;
++		phy-names = "usb";
++		status = "disabled";
++	};
++
++	gmac: ethernet@ff360000 {
++		compatible = "rockchip,px30-gmac";
++		reg = <0x0 0xff360000 0x0 0x10000>;
++		rockchip,grf = <&grf>;
++		interrupts = <GIC_SPI 43 IRQ_TYPE_LEVEL_HIGH>;
++		interrupt-names = "macirq";
++		clocks = <&cru SCLK_GMAC>, <&cru SCLK_GMAC_RX_TX>,
++			 <&cru SCLK_GMAC_RX_TX>, <&cru SCLK_MAC_REF>,
++			 <&cru SCLK_MAC_REFOUT>, <&cru ACLK_GMAC>,
++			 <&cru PCLK_GMAC>, <&cru SCLK_GMAC_RMII>;
++		clock-names = "stmmaceth", "mac_clk_rx",
++			      "mac_clk_tx", "clk_mac_ref",
++			      "clk_mac_refout", "aclk_mac",
++			      "pclk_mac", "clk_mac_speed";
++		phy-mode = "rmii";
++		pinctrl-names = "default";
++		pinctrl-0 = <&rmii_pins &mac_refclk_12ma>;
++		resets = <&cru SRST_GMAC_A>;
++		reset-names = "stmmaceth";
++		power-domains = <&power PX30_PD_GMAC>;
++		status = "disabled";
++	};
++
++	sdmmc: dwmmc@ff370000 {
++		compatible = "rockchip,px30-dw-mshc", "rockchip,rk3288-dw-mshc";
++		reg = <0x0 0xff370000 0x0 0x4000>;
++		max-frequency = <150000000>;
++		clocks = <&cru HCLK_SDMMC>, <&cru SCLK_SDMMC>,
++			 <&cru SCLK_SDMMC_DRV>, <&cru SCLK_SDMMC_SAMPLE>;
++		clock-names = "biu", "ciu", "ciu-drv", "ciu-sample";
++		assigned-clocks = <&cru SCLK_SDMMC>;
++		assigned-clock-parents = <&cru SCLK_SDMMC_DIV50>;
++		power-domains = <&power PX30_PD_SDCARD>;
++		fifo-depth = <0x100>;
++		interrupts = <GIC_SPI 54 IRQ_TYPE_LEVEL_HIGH>;
++		pinctrl-names = "default";
++		pinctrl-0 = <&sdmmc_clk &sdmmc_cmd &sdmmc_det &sdmmc_bus4>;
++		/*pinctrl-0 = <&sdmmc_clk_4ma &sdmmc_cmd_4ma &sdmmc_det_4ma &sdmmc_bus4_4ma>;*/
++		status = "disabled";
++	};
++
++	sdio: dwmmc@ff380000 {
++		compatible = "rockchip,px30-dw-mshc", "rockchip,rk3288-dw-mshc";
++		reg = <0x0 0xff380000 0x0 0x4000>;
++		max-frequency = <150000000>;
++		clocks = <&cru HCLK_SDIO>, <&cru SCLK_SDIO>,
++			 <&cru SCLK_SDIO_DRV>, <&cru SCLK_SDIO_SAMPLE>;
++		clock-names = "biu", "ciu", "ciu-drv", "ciu-sample";
++		assigned-clocks = <&cru SCLK_SDIO>;
++		assigned-clock-parents = <&cru SCLK_SDIO_DIV50>;
++		power-domains = <&power PX30_PD_MMC_NAND>;
++		fifo-depth = <0x100>;
++		interrupts = <GIC_SPI 55 IRQ_TYPE_LEVEL_HIGH>;
++		pinctrl-names = "default";
++		pinctrl-0 = <&sdio_bus4 &sdio_cmd &sdio_clk>;
++		status = "disabled";
++	};
++
++	emmc: dwmmc@ff390000 {
++		compatible = "rockchip,px30-dw-mshc", "rockchip,rk3288-dw-mshc";
++		reg = <0x0 0xff390000 0x0 0x4000>;
++		max-frequency = <150000000>;
++		clocks = <&cru HCLK_EMMC>, <&cru SCLK_EMMC>,
++			 <&cru SCLK_EMMC_DRV>, <&cru SCLK_EMMC_SAMPLE>;
++		clock-names = "biu", "ciu", "ciu-drv", "ciu-sample";
++		assigned-clocks = <&cru SCLK_EMMC>;
++		assigned-clock-parents = <&cru SCLK_EMMC_DIV50>;
++		power-domains = <&power PX30_PD_MMC_NAND>;
++		fifo-depth = <0x100>;
++		interrupts = <GIC_SPI 53 IRQ_TYPE_LEVEL_HIGH>;
++		status = "disabled";
++	};
++
++	nandc0: nandc@ff3b0000 {
++		compatible = "rockchip,rk-nandc";
++		reg = <0x0 0xff3b0000 0x0 0x4000>;
++		interrupts = <GIC_SPI 57 IRQ_TYPE_LEVEL_HIGH>;
++		nandc_id = <0>;
++		clocks = <&cru SCLK_NANDC>, <&cru HCLK_NANDC>;
++		clock-names = "clk_nandc", "hclk_nandc";
++		assigned-clocks = <&cru SCLK_NANDC>;
++		assigned-clock-parents = <&cru SCLK_NANDC_DIV50>;
++		power-domains = <&power PX30_PD_MMC_NAND>;
++		status = "disabled";
++	};
++
++	gpu: gpu@ff400000 {
++		compatible = "arm,malit602", "arm,malit60x", "arm,malit6xx", "arm,mali-midgard";
++		reg = <0x0 0xff400000 0x0 0x4000>;
++
++		interrupts = <GIC_SPI 45 IRQ_TYPE_LEVEL_HIGH>,
++			     <GIC_SPI 46 IRQ_TYPE_LEVEL_HIGH>,
++			     <GIC_SPI 47 IRQ_TYPE_LEVEL_HIGH>;
++		interrupt-names = "GPU", "MMU", "JOB";
++
++		clocks = <&cru SCLK_GPU>;
++		clock-names = "clk_mali";
++		power-domains = <&power PX30_PD_GPU>;
++		#cooling-cells = <2>;
++		operating-points-v2 = <&gpu_opp_table>;
++
++		status = "disabled";
++		power_model {
++			compatible = "arm,mali-simple-power-model";
++			static-coefficient = <411000>;
++			dynamic-coefficient = <733>;
++			ts = <32000 4700 (-80) 2>;
++			thermal-zone = "gpu-thermal";
++		};
++
++	};
++
++	gpu_opp_table: gpu-opp-table {
++		compatible = "operating-points-v2";
++
++		rockchip,thermal-zone = "soc-thermal";
++		rockchip,temp-hysteresis = <5000>;
++		rockchip,low-temp = <0>;
++		rockchip,low-temp-min-volt = <1000000>;
++		rockchip,low-temp-adjust-volt = <
++			/* MHz    MHz    uV */
++			0      480     50000
++		>;
++
++		rockchip,max-volt = <1175000>;
++		rockchip,evb-irdrop = <25000>;
++
++		rockchip,pvtm-voltage-sel = <
++			0        50000   0
++			50001    54000   1
++			54001    60000   2
++			60001    99999   3
++		>;
++		rockchip,pvtm-ch = <0 0>;
++
++		opp-200000000 {
++			opp-hz = /bits/ 64 <200000000>;
++			opp-microvolt = <950000>;
++			opp-microvolt-L0 = <950000>;
++			opp-microvolt-L1 = <950000>;
++			opp-microvolt-L2 = <950000>;
++			opp-microvolt-L3 = <950000>;
++		};
++		opp-300000000 {
++			opp-hz = /bits/ 64 <300000000>;
++			opp-microvolt = <975000>;
++			opp-microvolt-L0 = <975000>;
++			opp-microvolt-L1 = <950000>;
++			opp-microvolt-L2 = <950000>;
++			opp-microvolt-L3 = <950000>;
++		};
++		opp-400000000 {
++			opp-hz = /bits/ 64 <400000000>;
++			opp-microvolt = <1050000>;
++			opp-microvolt-L0 = <1050000>;
++			opp-microvolt-L1 = <1025000>;
++			opp-microvolt-L2 = <975000>;
++			opp-microvolt-L3 = <950000>;
++		};
++		opp-480000000 {
++			opp-hz = /bits/ 64 <480000000>;
++			opp-microvolt = <1125000>;
++			opp-microvolt-L0 = <1125000>;
++			opp-microvolt-L1 = <1100000>;
++			opp-microvolt-L2 = <1050000>;
++			opp-microvolt-L3 = <1000000>;
++		};
++	};
++
++	hevc: hevc_service@ff440000 {
++		compatible = "rockchip,hevc_sub";
++		iommu_enabled = <1>;
++		reg = <0x0 0xff440000 0x0 0x400>;
++		interrupts = <GIC_SPI 49 IRQ_TYPE_LEVEL_HIGH>;
++		interrupt-names = "irq_dec";
++		dev_mode = <1>;
++		iommus = <&hevc_mmu>;
++		name = "hevc_service";
++		allocator = <1>;
++	};
++
++	vpu: vpu_service@ff442000 {
++		compatible = "rockchip,vpu_sub";
++		iommu_enabled = <1>;
++		reg = <0x0 0xff442000 0x0 0x800>;
++		interrupts = <GIC_SPI 80 IRQ_TYPE_LEVEL_HIGH>,
++			<GIC_SPI 79 IRQ_TYPE_LEVEL_HIGH>;
++		interrupt-names = "irq_enc", "irq_dec";
++		dev_mode = <0>;
++		iommus = <&vpu_mmu>;
++		name = "vpu_service";
++		allocator = <1>;
++	};
++
++	vpu_combo: vpu_combo {
++		compatible = "rockchip,vpu_combo";
++		subcnt = <2>;
++		rockchip,grf = <&grf>;
++		rockchip,sub = <&vpu>, <&hevc>;
++		clocks = <&cru ACLK_VPU>, <&cru HCLK_VPU>, <&cru SCLK_CORE_VPU>;
++		clock-names = "aclk_vcodec", "hclk_vcodec", "clk_core";
++		resets = <&cru SRST_VPU_A>, <&cru SRST_VPU_H>,
++			<&cru SRST_VPU_NIU_A>, <&cru SRST_VPU_NIU_H>,
++			<&cru SRST_VPU_CORE>;
++		reset-names = "video_a", "video_h", "niu_a", "niu_h",
++			"video_core";
++		power-domains = <&power PX30_PD_VPU>;
++		mode_bit = <15>;
++		mode_ctrl = <0x410>;
++		name = "vpu_combo";
++		status = "disabled";
++	};
++
++	hevc_mmu: iommu@ff440440 {
++		compatible = "rockchip,iommu";
++		reg = <0x0 0xff440440 0x0 0x40>, <0x0 0xff440480 0x0 0x40>;
++		interrupts = <GIC_SPI 50 IRQ_TYPE_LEVEL_HIGH>;
++		interrupt-names = "hevc_mmu";
++		clocks = <&cru ACLK_VPU>, <&cru HCLK_VPU>;
++		clock-names = "aclk", "hclk";
++		power-domains = <&power PX30_PD_VPU>;
++		#iommu-cells = <0>;
++	};
++
++	vpu_mmu: iommu@ff442800 {
++		compatible = "rockchip,iommu";
++		reg = <0x0 0xff442800 0x0 0x100>;
++		interrupts = <GIC_SPI 81 IRQ_TYPE_LEVEL_HIGH>;
++		interrupt-names = "vpu_mmu";
++		clocks = <&cru ACLK_VPU>, <&cru HCLK_VPU>;
++		clock-names = "aclk", "hclk";
++		power-domains = <&power PX30_PD_VPU>;
++		#iommu-cells = <0>;
++	};
++
++	dsi: dsi@ff450000 {
++		compatible = "rockchip,px30-mipi-dsi";
++		reg = <0x0 0xff450000 0x0 0x10000>;
++		interrupts = <GIC_SPI 75 IRQ_TYPE_LEVEL_HIGH>;
++		clocks = <&cru PCLK_MIPI_DSI>, <&video_phy>;
++		clock-names = "pclk", "hs_clk";
++		resets = <&cru SRST_MIPIDSI_HOST_P>;
++		reset-names = "apb";
++		phys = <&video_phy>;
++		phy-names = "mipi_dphy";
++		power-domains = <&power PX30_PD_VO>;
++		rockchip,grf = <&grf>;
++		#address-cells = <1>;
++		#size-cells = <0>;
++		status = "disabled";
++
++		ports {
++			#address-cells = <1>;
++			#size-cells = <0>;
++
++			port@0 {
++				reg = <0>;
++				#address-cells = <1>;
++				#size-cells = <0>;
++
++				dsi_in_vopb: endpoint@0 {
++					reg = <0>;
++					remote-endpoint = <&vopb_out_dsi>;
++				};
++
++				dsi_in_vopl: endpoint@1 {
++					reg = <1>;
++					remote-endpoint = <&vopl_out_dsi>;
++				};
++			};
++		};
++	};
++
++	vopb: vop@ff460000 {
++		compatible = "rockchip,px30-vop-big";
++		reg = <0x0 0xff460000 0x0 0x1fc>, <0x0 0xff460a00 0x0 0x400>;
++		rockchip,grf = <&grf>;
++		reg-names = "regs", "gamma_lut";
++		interrupts = <GIC_SPI 77 IRQ_TYPE_LEVEL_HIGH>;
++		clocks = <&cru ACLK_VOPB>, <&cru DCLK_VOPB>,
++			 <&cru HCLK_VOPB>;
++		clock-names = "aclk_vop", "dclk_vop", "hclk_vop";
++		power-domains = <&power PX30_PD_VO>;
++		iommus = <&vopb_mmu>;
++		status = "disabled";
++
++		vopb_out: port {
++			#address-cells = <1>;
++			#size-cells = <0>;
++
++			vopb_out_lvds: endpoint@0 {
++				reg = <0>;
++				remote-endpoint = <&lvds_in_vopb>;
++			};
++
++			vopb_out_dsi: endpoint@1 {
++				reg = <1>;
++				remote-endpoint = <&dsi_in_vopb>;
++			};
++
++			vopb_out_rgb: endpoint@2 {
++				reg = <2>;
++				remote-endpoint = <&rgb_in_vopb>;
++			};
++		};
++	};
++
++	vopb_mmu: iommu@ff460f00 {
++		compatible = "rockchip,iommu";
++		reg = <0x0 0xff460f00 0x0 0x100>;
++		interrupts = <GIC_SPI 77 IRQ_TYPE_LEVEL_HIGH>;
++		interrupt-names = "vopb_mmu";
++		clocks = <&cru ACLK_VOPB>, <&cru HCLK_VOPB>;
++		clock-names = "aclk", "hclk";
++		power-domains = <&power PX30_PD_VO>;
++		#iommu-cells = <0>;
++		status = "disabled";
++	};
++
++	vopl: vop@ff470000 {
++		compatible = "rockchip,px30-vop-lit";
++		reg = <0x0 0xff470000 0x0 0x1fc>, <0x0 0xff470a00 0x0 0x400>;
++		rockchip,grf = <&grf>;
++		reg-names = "regs", "gamma_lut";
++		interrupts = <GIC_SPI 78 IRQ_TYPE_LEVEL_HIGH>;
++		clocks = <&cru ACLK_VOPL>, <&cru DCLK_VOPL>,
++			 <&cru HCLK_VOPL>;
++		clock-names = "aclk_vop", "dclk_vop", "hclk_vop";
++		power-domains = <&power PX30_PD_VO>;
++		iommus = <&vopl_mmu>;
++		status = "disabled";
++
++		vopl_out: port {
++			#address-cells = <1>;
++			#size-cells = <0>;
++
++			vopl_out_lvds: endpoint@0 {
++				reg = <0>;
++				remote-endpoint = <&lvds_in_vopl>;
++			};
++
++			vopl_out_dsi: endpoint@1 {
++				reg = <1>;
++				remote-endpoint = <&dsi_in_vopl>;
++			};
++
++			vopl_out_rgb: endpoint@2 {
++				reg = <2>;
++				remote-endpoint = <&rgb_in_vopl>;
++			};
++		};
++	};
++
++	vopl_mmu: iommu@ff470f00 {
++		compatible = "rockchip,iommu";
++		reg = <0x0 0xff470f00 0x0 0x100>;
++		interrupts = <GIC_SPI 79 IRQ_TYPE_LEVEL_HIGH>;
++		interrupt-names = "vopl_mmu";
++		clocks = <&cru ACLK_VOPL>, <&cru HCLK_VOPL>;
++		clock-names = "aclk", "hclk";
++		power-domains = <&power PX30_PD_VO>;
++		#iommu-cells = <0>;
++		status = "disabled";
++	};
++
++	rk_rga: rk_rga@ff480000 {
++		compatible = "rockchip,rga2";
++		//dev_mode = <1>;
++		reg = <0x0 0xff480000 0x0 0x1000>;
++		interrupts = <GIC_SPI 76 IRQ_TYPE_LEVEL_HIGH>;
++		clocks = <&cru ACLK_RGA>, <&cru HCLK_RGA>, <&cru SCLK_RGA_CORE>;
++		clock-names = "aclk_rga", "hclk_rga", "clk_rga";
++		power-domains = <&power PX30_PD_VO>;
++		dma-coherent;
++		status = "disabled";
++	};
++
++	cif: cif@ff490000 {
++		compatible = "rockchip,cif";
++		reg = <0x0 0xff490000 0x0 0x200>;
++		interrupts = <GIC_SPI 69 IRQ_TYPE_LEVEL_HIGH>;
++		clocks = <&cru ACLK_CIF>, <&cru HCLK_CIF>, <&cru PCLK_CIF>, <&cru SCLK_CIF_OUT>;
++		clock-names = "aclk_cif0", "hclk_cif0", "pclk_cif", "cif0_out";
++		resets = <&cru SRST_CIF_A>, <&cru SRST_CIF_H>, <&cru SRST_CIF_PCLKIN>;
++		reset-names = "rst_cif_a", "rst_cif_h", "rst_cif_pclkin";
++		power-domains = <&power PX30_PD_VI>;
++		pinctrl-names = "cif_pin_all";
++		pinctrl-0 = <&dvp_d2d9_m0>;
++		iommus = <&vip_mmu>;
++		status = "disabled";
++	};
++
++	cif_new: cif-new@ff490000 {
++		compatible = "rockchip,px30-cif";
++		reg = <0x0 0xff490000 0x0 0x200>;
++		interrupts = <GIC_SPI 69 IRQ_TYPE_LEVEL_HIGH>;
++		clocks = <&cru ACLK_CIF>, <&cru HCLK_CIF>, <&cru PCLK_CIF>, <&cru SCLK_CIF_OUT>;
++		clock-names = "aclk_cif", "hclk_cif", "pclk_cif", "cif_out";
++		resets = <&cru SRST_CIF_A>, <&cru SRST_CIF_H>, <&cru SRST_CIF_PCLKIN>;
++		reset-names = "rst_cif_a", "rst_cif_h", "rst_cif_pclkin";
++		power-domains = <&power PX30_PD_VI>;
++		iommus = <&vip_mmu>;
++		status = "disabled";
++	};
++
++	vip_mmu: iommu@ff490800{
++		compatible = "rockchip,iommu";
++		reg = <0x0 0xff490800 0x0 0x100>;
++		interrupts = <GIC_SPI 69 IRQ_TYPE_LEVEL_HIGH>;
++		interrupt-names = "vip_mmu";
++		clocks = <&cru ACLK_CIF>, <&cru HCLK_CIF>;
++		clock-names = "aclk", "hclk";
++		power-domains = <&power PX30_PD_VI>;
++		rk_iommu,disable_reset_quirk;
++		#iommu-cells = <0>;
++		status = "disabled";
++	};
++
++	rk_isp: rk_isp@ff4a0000 {
++		compatible = "rockchip,px30-isp", "rockchip,isp";
++		reg = <0x0 0xff4a0000 0x0 0x8000>;
++		interrupts = <GIC_SPI 70 IRQ_TYPE_LEVEL_HIGH>;
++		clocks = <&cru ACLK_ISP>, <&cru HCLK_ISP>, <&cru SCLK_ISP>, <&cru SCLK_ISP>,
++			<&cru PCLK_ISP>, <&cru SCLK_CIF_OUT>, <&cru SCLK_CIF_OUT>, <&cru PCLK_MIPICSIPHY>;
++		clock-names = "aclk_isp", "hclk_isp", "clk_isp", "clk_isp_jpe",
++			"pclkin_isp", "clk_cif_pll", "clk_cif_out", "pclk_dphyrx";
++		resets = <&cru SRST_ISP>, <&cru SRST_MIPICSIPHY_P>;
++		reset-names = "rst_isp", "rst_mipicsiphy";
++		power-domains = <&power PX30_PD_VI>;
++		pinctrl-names = "default", "isp_dvp8bit2", "isp_dvp10bit", "isp_dvp12bit";
++		pinctrl-0 = <&cif_clkout_m0>;
++		pinctrl-1 = <&dvp_d2d9_m0>;
++		pinctrl-2 = <&dvp_d2d9_m0 &dvp_d10d11_m0>;
++		pinctrl-3 = <&dvp_d0d1_m0 &dvp_d2d9_m0 &dvp_d10d11_m0>;
++		rockchip,isp,mipiphy = <1>;
++		rockchip,isp,csiphy,reg = <0xff2f0000 0x4000>;
++		rockchip,grf = <&grf>;
++		rockchip,cru = <&cru>;
++		rockchip,isp,iommu-enable = <1>;
++		iommus = <&isp_mmu>;
++		status = "disabled";
++	};
++
++	rkisp1: rkisp1@ff4a0000 {
++		compatible = "rockchip,rk3326-rkisp1";
++		reg = <0x0 0xff4a0000 0x0 0x8000>;
++		interrupts = <GIC_SPI 70 IRQ_TYPE_LEVEL_HIGH>,
++			     <GIC_SPI 73 IRQ_TYPE_LEVEL_HIGH>,
++			     <GIC_SPI 74 IRQ_TYPE_LEVEL_HIGH>;
++		interrupt-names = "isp_irq", "mi_irq", "mipi_irq";
++		clocks = <&cru ACLK_ISP>, <&cru HCLK_ISP>,
++			<&cru SCLK_ISP>, <&cru PCLK_ISP>;
++		clock-names = "aclk_isp", "hclk_isp",
++			"clk_isp", "pclk_isp";
++		devfreq = <&dmc>;
++		power-domains = <&power PX30_PD_VI>;
++		iommus = <&isp_mmu>;
++		rockchip,grf = <&grf>;
++		status = "disabled";
++	};
++
++	isp_mmu: iommu@ff4a8000 {
++		compatible = "rockchip,iommu";
++		reg = <0x0 0xff4a8000 0x0 0x100>;
++		interrupts = <GIC_SPI 70 IRQ_TYPE_LEVEL_HIGH>;
++		interrupt-names = "isp_mmu";
++		clocks = <&cru ACLK_ISP>, <&cru HCLK_ISP>;
++		clock-names = "aclk", "hclk";
++		power-domains = <&power PX30_PD_VI>;
++		rk_iommu,disable_reset_quirk;
++		#iommu-cells = <0>;
++		status = "disabled";
++	};
++
++	qos_gmac: qos@ff518000 {
++		compatible = "syscon";
++		reg = <0x0 0xff518000 0x0 0x20>;
++	};
++
++	qos_gpu: qos@ff520000 {
++		compatible = "syscon";
++		reg = <0x0 0xff520000 0x0 0x20>;
++	};
++
++	qos_sdmmc: qos@ff52c000 {
++		compatible = "syscon";
++		reg = <0x0 0xff52c000 0x0 0x20>;
++	};
++
++	qos_emmc: qos@ff538000 {
++		compatible = "syscon";
++		reg = <0x0 0xff538000 0x0 0x20>;
++	};
++
++	qos_nand: qos@ff538080 {
++		compatible = "syscon";
++		reg = <0x0 0xff538080 0x0 0x20>;
++	};
++
++	qos_sdio: qos@ff538100 {
++		compatible = "syscon";
++		reg = <0x0 0xff538100 0x0 0x20>;
++	};
++
++	qos_sfc: qos@ff538180 {
++		compatible = "syscon";
++		reg = <0x0 0xff538180 0x0 0x20>;
++	};
++
++	qos_usb_host: qos@ff540000 {
++		compatible = "syscon";
++		reg = <0x0 0xff540000 0x0 0x20>;
++	};
++
++	qos_usb_otg: qos@ff540080 {
++		compatible = "syscon";
++		reg = <0x0 0xff540080 0x0 0x20>;
++	};
++
++	qos_isp_128: qos@ff548000 {
++		compatible = "syscon";
++		reg = <0x0 0xff548000 0x0 0x20>;
++	};
++
++	qos_isp_rd: qos@ff548080 {
++		compatible = "syscon";
++		reg = <0x0 0xff548080 0x0 0x20>;
++	};
++
++	qos_isp_wr: qos@ff548100 {
++		compatible = "syscon";
++		reg = <0x0 0xff548100 0x0 0x20>;
++	};
++
++	qos_isp_m1: qos@ff548180 {
++		compatible = "syscon";
++		reg = <0x0 0xff548180 0x0 0x20>;
++	};
++
++	qos_vip: qos@ff548200 {
++		compatible = "syscon";
++		reg = <0x0 0xff548200 0x0 0x20>;
++	};
++
++	qos_rga_rd: qos@ff550000 {
++		compatible = "syscon";
++		reg = <0x0 0xff550000 0x0 0x20>;
++	};
++
++	qos_rga_wr: qos@ff550080 {
++		compatible = "syscon";
++		reg = <0x0 0xff550080 0x0 0x20>;
++	};
++
++	qos_vop_m0: qos@ff550100 {
++		compatible = "syscon";
++		reg = <0x0 0xff550100 0x0 0x20>;
++	};
++
++	qos_vop_m1: qos@ff550180 {
++		compatible = "syscon";
++		reg = <0x0 0xff550180 0x0 0x20>;
++	};
++
++	qos_vpu: qos@ff558000 {
++		compatible = "syscon";
++		reg = <0x0 0xff558000 0x0 0x20>;
++	};
++
++	qos_vpu_r128: qos@ff558080 {
++		compatible = "syscon";
++		reg = <0x0 0xff558080 0x0 0x20>;
++	};
++
++	dfi: dfi@ff610000 {
++		reg = <0x00 0xff610000 0x00 0x400>;
++		compatible = "rockchip,px30-dfi";
++		rockchip,pmugrf = <&pmugrf>;
++		status = "disabled";
++	};
++
++	dmc: dmc {
++		compatible = "rockchip,px30-dmc";
++		interrupts = <GIC_SPI 105 IRQ_TYPE_LEVEL_HIGH>;
++		interrupt-names = "complete_irq";
++		devfreq-events = <&dfi>;
++		clocks = <&cru SCLK_DDRCLK>;
++		clock-names = "dmc_clk";
++		operating-points-v2 = <&dmc_opp_table>;
++		ddr_timing = <&ddr_timing>;
++		upthreshold = <40>;
++		downdifferential = <20>;
++		system-status-freq = <
++			/*system status         freq(KHz)*/
++			SYS_STATUS_NORMAL       528000
++			SYS_STATUS_REBOOT       450000
++			SYS_STATUS_SUSPEND      194000
++			SYS_STATUS_VIDEO_1080P  450000
++			SYS_STATUS_BOOST        528000
++			SYS_STATUS_ISP          666000
++			SYS_STATUS_PERFORMANCE  666000
++		>;
++		auto-min-freq = <328000>;
++		auto-freq-en = <1>;
++		#cooling-cells = <2>;
++		status = "disabled";
++
++		ddr_power_model: ddr_power_model {
++			compatible = "ddr_power_model";
++			dynamic-power-coefficient = <120>;
++			static-power-coefficient = <200>;
++			ts = <32000 4700 (-80) 2>;
++			thermal-zone = "soc-thermal";
++		};
++	};
++
++	dmc_opp_table: dmc-opp-table {
++		compatible = "operating-points-v2";
++
++		rockchip,max-volt = <1150000>;
++		rockchip,evb-irdrop = <25000>;
++
++		rockchip,pvtm-voltage-sel = <
++			0        50000   0
++			50001    54000   1
++			54001    60000   2
++			60001    99999   3
++		>;
++		rockchip,pvtm-ch = <0 0>;
++
++		opp-194000000 {
++			opp-hz = /bits/ 64 <194000000>;
++			opp-microvolt = <950000>;
++			opp-microvolt-L0 = <950000>;
++			opp-microvolt-L1 = <950000>;
++			opp-microvolt-L2 = <950000>;
++			opp-microvolt-L3 = <950000>;
++		};
++		opp-328000000 {
++			opp-hz = /bits/ 64 <328000000>;
++			opp-microvolt = <950000>;
++			opp-microvolt-L0 = <950000>;
++			opp-microvolt-L1 = <950000>;
++			opp-microvolt-L2 = <950000>;
++			opp-microvolt-L3 = <950000>;
++		};
++		opp-450000000 {
++			opp-hz = /bits/ 64 <450000000>;
++			opp-microvolt = <950000>;
++			opp-microvolt-L0 = <950000>;
++			opp-microvolt-L1 = <950000>;
++			opp-microvolt-L2 = <950000>;
++			opp-microvolt-L3 = <950000>;
++		};
++		opp-528000000 {
++			opp-hz = /bits/ 64 <528000000>;
++			opp-microvolt = <975000>;
++			opp-microvolt-L0 = <975000>;
++			opp-microvolt-L1 = <975000>;
++			opp-microvolt-L2 = <950000>;
++			opp-microvolt-L3 = <950000>;
++		};
++		opp-666000000 {
++			opp-hz = /bits/ 64 <666000000>;
++			opp-microvolt = <1050000>;
++			opp-microvolt-L0 = <1050000>;
++			opp-microvolt-L1 = <1000000>;
++			opp-microvolt-L2 = <975000>;
++			opp-microvolt-L3 = <950000>;
++		};
++		opp-786000000 {
++			opp-hz = /bits/ 64 <786000000>;
++			opp-microvolt = <1100000>;
++			opp-microvolt-L0 = <1100000>;
++			opp-microvolt-L1 = <1050000>;
++			opp-microvolt-L2 = <1025000>;
++			opp-microvolt-L3 = <1000000>;
++			status = "disabled";
++		};
++	};
++
++	pinctrl: pinctrl {
++		compatible = "rockchip,px30-pinctrl";
++		rockchip,grf = <&grf>;
++		rockchip,pmu = <&pmugrf>;
++		#address-cells = <2>;
++		#size-cells = <2>;
++		ranges;
++
++		gpio0: gpio0@ff040000 {
++			compatible = "rockchip,gpio-bank";
++			reg = <0x0 0xff040000 0x0 0x100>;
++			interrupts = <GIC_SPI 3 IRQ_TYPE_LEVEL_HIGH>;
++			clocks = <&pmucru PCLK_GPIO0_PMU>;
++			gpio-controller;
++			#gpio-cells = <2>;
++
++			interrupt-controller;
++			#interrupt-cells = <2>;
++		};
++
++		gpio1: gpio1@ff250000 {
++			compatible = "rockchip,gpio-bank";
++			reg = <0x0 0xff250000 0x0 0x100>;
++			interrupts = <GIC_SPI 4 IRQ_TYPE_LEVEL_HIGH>;
++			clocks = <&cru PCLK_GPIO1>;
++			gpio-controller;
++			#gpio-cells = <2>;
++
++			interrupt-controller;
++			#interrupt-cells = <2>;
++		};
++
++		gpio2: gpio2@ff260000 {
++			compatible = "rockchip,gpio-bank";
++			reg = <0x0 0xff260000 0x0 0x100>;
++			interrupts = <GIC_SPI 5 IRQ_TYPE_LEVEL_HIGH>;
++			clocks = <&cru PCLK_GPIO2>;
++			gpio-controller;
++			#gpio-cells = <2>;
++
++			interrupt-controller;
++			#interrupt-cells = <2>;
++		};
++
++		gpio3: gpio3@ff270000 {
++			compatible = "rockchip,gpio-bank";
++			reg = <0x0 0xff270000 0x0 0x100>;
++			interrupts = <GIC_SPI 6 IRQ_TYPE_LEVEL_HIGH>;
++			clocks = <&cru PCLK_GPIO3>;
++			gpio-controller;
++			#gpio-cells = <2>;
++
++			interrupt-controller;
++			#interrupt-cells = <2>;
++		};
++
++		pcfg_pull_up: pcfg-pull-up {
++			bias-pull-up;
++		};
++
++		pcfg_pull_down: pcfg-pull-down {
++			bias-pull-down;
++		};
++
++		pcfg_pull_none: pcfg-pull-none {
++			bias-disable;
++		};
++
++		pcfg_pull_none_2ma: pcfg-pull-none-2ma {
++			bias-disable;
++			drive-strength = <2>;
++		};
++
++		pcfg_pull_up_2ma: pcfg-pull-up-2ma {
++			bias-pull-up;
++			drive-strength = <2>;
++		};
++
++		pcfg_pull_up_4ma: pcfg-pull-up-4ma {
++			bias-pull-up;
++			drive-strength = <4>;
++		};
++
++		pcfg_pull_none_4ma: pcfg-pull-none-4ma {
++			bias-disable;
++			drive-strength = <4>;
++		};
++
++		pcfg_pull_down_4ma: pcfg-pull-down-4ma {
++			bias-pull-down;
++			drive-strength = <4>;
++		};
++
++		pcfg_pull_none_8ma: pcfg-pull-none-8ma {
++			bias-disable;
++			drive-strength = <8>;
++		};
++
++		pcfg_pull_up_8ma: pcfg-pull-up-8ma {
++			bias-pull-up;
++			drive-strength = <8>;
++		};
++
++		pcfg_pull_none_12ma: pcfg-pull-none-12ma {
++			bias-disable;
++			drive-strength = <12>;
++		};
++
++		pcfg_pull_up_12ma: pcfg-pull-up-12ma {
++			bias-pull-up;
++			drive-strength = <12>;
++		};
++
++		pcfg_pull_none_smt: pcfg-pull-none-smt {
++			bias-disable;
++			input-schmitt-enable;
++		};
++
++		pcfg_output_high: pcfg-output-high {
++			output-high;
++		};
++
++		pcfg_output_low: pcfg-output-low {
++			output-low;
++		};
++
++		pcfg_input_high: pcfg-input-high {
++			bias-pull-up;
++			input-enable;
++		};
++
++		pcfg_input: pcfg-input {
++			input-enable;
++		};
++
++		i2c0 {
++			i2c0_xfer: i2c0-xfer {
++				rockchip,pins =
++					<0 RK_PB0 RK_FUNC_1 &pcfg_pull_none_smt>,
++					<0 RK_PB1 RK_FUNC_1 &pcfg_pull_none_smt>;
++			};
++		};
++
++		i2c1 {
++			i2c1_xfer: i2c1-xfer {
++				rockchip,pins =
++					<0 RK_PC2 RK_FUNC_1 &pcfg_pull_none_smt>,
++					<0 RK_PC3 RK_FUNC_1 &pcfg_pull_none_smt>;
++			};
++		};
++
++		i2c2 {
++			i2c2_xfer: i2c2-xfer {
++				rockchip,pins =
++					<2 RK_PB7 RK_FUNC_2 &pcfg_pull_none_smt>,
++					<2 RK_PC0 RK_FUNC_2 &pcfg_pull_none_smt>;
++			};
++		};
++
++		i2c3 {
++			i2c3_xfer: i2c3-xfer {
++				rockchip,pins =
++					<1 RK_PB4 RK_FUNC_4 &pcfg_pull_none_smt>,
++					<1 RK_PB5 RK_FUNC_4 &pcfg_pull_none_smt>;
++			};
++		};
++
++		tsadc {
++			tsadc_otp_gpio: tsadc-otp-gpio {
++				rockchip,pins =
++					<0 RK_PA6 RK_FUNC_GPIO &pcfg_pull_none>;
++			};
++
++			tsadc_otp_out: tsadc-otp-out {
++				rockchip,pins =
++					<0 RK_PA6 RK_FUNC_1 &pcfg_pull_none>;
++			};
++		};
++
++		uart0 {
++			uart0_xfer: uart0-xfer {
++				rockchip,pins =
++					<0 RK_PB2 RK_FUNC_1 &pcfg_pull_up>,
++					<0 RK_PB3 RK_FUNC_1 &pcfg_pull_up>;
++			};
++
++			uart0_cts: uart0-cts {
++				rockchip,pins =
++					<0 RK_PB4 RK_FUNC_1 &pcfg_pull_none>;
++			};
++
++			uart0_rts: uart0-rts {
++				rockchip,pins =
++					<0 RK_PB5 RK_FUNC_1 &pcfg_pull_none>;
++			};
++
++			uart0_rts_gpio: uart0-rts-gpio {
++				rockchip,pins =
++					<0 RK_PB5 RK_FUNC_GPIO &pcfg_pull_none>;
++			};
++		};
++
++		uart1 {
++			uart1_xfer: uart1-xfer {
++				rockchip,pins =
++					<1 RK_PC1 RK_FUNC_1 &pcfg_pull_up>,
++					<1 RK_PC0 RK_FUNC_1 &pcfg_pull_up>;
++			};
++
++			uart1_cts: uart1-cts {
++				rockchip,pins =
++					<1 RK_PC2 RK_FUNC_1 &pcfg_pull_none>;
++			};
++
++			uart1_rts: uart1-rts {
++				rockchip,pins =
++					<1 RK_PC3 RK_FUNC_1 &pcfg_pull_none>;
++			};
++
++			uart1_rts_gpio: uart1-rts-gpio {
++				rockchip,pins =
++					<1 RK_PC3 RK_FUNC_GPIO &pcfg_pull_none>;
++			};
++		};
++
++		uart2-m0 {
++			uart2m0_xfer: uart2m0-xfer {
++				rockchip,pins =
++					<1 RK_PD2 RK_FUNC_2 &pcfg_pull_up>,
++					<1 RK_PD3 RK_FUNC_2 &pcfg_pull_up>;
++			};
++		};
++
++		uart2-m1 {
++			uart2m1_xfer: uart2m1-xfer {
++				rockchip,pins =
++					<2 RK_PB4 RK_FUNC_2 &pcfg_pull_up>,
++					<2 RK_PB6 RK_FUNC_2 &pcfg_pull_up>;
++			};
++		};
++
++		uart3-m0 {
++			uart3m0_xfer: uart3m0-xfer {
++				rockchip,pins =
++					<0 RK_PC0 RK_FUNC_2 &pcfg_pull_up>,
++					<0 RK_PC1 RK_FUNC_2 &pcfg_pull_up>;
++			};
++
++			uart3m0_cts: uart3m0-cts {
++				rockchip,pins =
++					<0 RK_PC2 RK_FUNC_2 &pcfg_pull_none>;
++			};
++
++			uart3m0_rts: uart3m0-rts {
++				rockchip,pins =
++					<0 RK_PC3 RK_FUNC_2 &pcfg_pull_none>;
++			};
++
++			uart3m0_rts_gpio: uart3m0-rts-gpio {
++				rockchip,pins =
++					<0 RK_PC3 RK_FUNC_GPIO &pcfg_pull_none>;
++			};
++		};
++
++		uart3-m1 {
++			uart3m1_xfer: uart3m1-xfer {
++				rockchip,pins =
++					<1 RK_PB6 RK_FUNC_2 &pcfg_pull_up>,
++					<1 RK_PB7 RK_FUNC_2 &pcfg_pull_up>;
++			};
++
++			uart3m1_cts: uart3m1-cts {
++				rockchip,pins =
++					<1 RK_PB4 RK_FUNC_2 &pcfg_pull_none>;
++			};
++
++			uart3m1_rts: uart3m1-rts {
++				rockchip,pins =
++					<1 RK_PB5 RK_FUNC_2 &pcfg_pull_none>;
++			};
++
++			uart3m1_rts_gpio: uart3m1-rts-gpio {
++				rockchip,pins =
++					<1 RK_PB5 RK_FUNC_GPIO &pcfg_pull_none>;
++			};
++		};
++
++		uart4 {
++
++			uart4_xfer: uart4-xfer {
++				rockchip,pins =
++					<1 RK_PD4 RK_FUNC_2 &pcfg_pull_up>,
++					<1 RK_PD5 RK_FUNC_2 &pcfg_pull_up>;
++			};
++
++			uart4_cts: uart4-cts {
++				rockchip,pins =
++					<1 RK_PD6 RK_FUNC_2 &pcfg_pull_none>;
++
++			};
++
++			uart4_rts: uart4-rts {
++				rockchip,pins =
++					<1 RK_PD7 RK_FUNC_2 &pcfg_pull_none>;
++			};
++		};
++
++		uart5 {
++
++			uart5_xfer: uart5-xfer {
++				rockchip,pins =
++					<3 RK_PA2 RK_FUNC_4 &pcfg_pull_up>,
++					<3 RK_PA1 RK_FUNC_4 &pcfg_pull_up>;
++			};
++
++			uart5_cts: uart5-cts {
++				rockchip,pins =
++					<3 RK_PA3 RK_FUNC_4 &pcfg_pull_none>;
++
++			};
++
++			uart5_rts: uart5-rts {
++				rockchip,pins =
++					<3 RK_PA5 RK_FUNC_4 &pcfg_pull_none>;
++			};
++		};
++
++		spi0 {
++			spi0_clk: spi0-clk {
++				rockchip,pins =
++					<1 RK_PB7 RK_FUNC_3 &pcfg_pull_up_4ma>;
++			};
++
++			spi0_csn: spi0-csn {
++				rockchip,pins =
++					<1 RK_PB6 RK_FUNC_3 &pcfg_pull_up_4ma>;
++			};
++
++			spi0_miso: spi0-miso {
++				rockchip,pins =
++					<1 RK_PB5 RK_FUNC_3 &pcfg_pull_up_4ma>;
++			};
++
++			spi0_mosi: spi0-mosi {
++				rockchip,pins =
++					<1 RK_PB4 RK_FUNC_3 &pcfg_pull_up_4ma>;
++			};
++
++			spi0_clk_hs: spi0-clk-hs {
++				rockchip,pins =
++					<1 RK_PB7 RK_FUNC_3 &pcfg_pull_up_8ma>;
++			};
++
++			spi0_miso_hs: spi0-miso-hs {
++				rockchip,pins =
++					<1 RK_PB5 RK_FUNC_3 &pcfg_pull_up_8ma>;
++			};
++
++			spi0_mosi_hs: spi0-mosi-hs {
++				rockchip,pins =
++					<1 RK_PB4 RK_FUNC_3 &pcfg_pull_up_8ma>;
++			};
++		};
++
++		spi1 {
++			spi1_clk: spi1-clk {
++				rockchip,pins =
++					<3 RK_PB7 RK_FUNC_4 &pcfg_pull_up_4ma>;
++			};
++
++			spi1_csn0: spi1-csn0 {
++				rockchip,pins =
++					<3 RK_PB1 RK_FUNC_4 &pcfg_pull_up_4ma>;
++			};
++
++			spi1_csn1: spi1-csn1 {
++				rockchip,pins =
++					<3 RK_PB2 RK_FUNC_2 &pcfg_pull_up_4ma>;
++			};
++
++			spi1_miso: spi1-miso {
++				rockchip,pins =
++					<3 RK_PB6 RK_FUNC_4 &pcfg_pull_up_4ma>;
++			};
++
++			spi1_mosi: spi1-mosi {
++				rockchip,pins =
++					<3 RK_PB4 RK_FUNC_4 &pcfg_pull_up_4ma>;
++			};
++
++			spi1_clk_hs: spi1-clk-hs {
++				rockchip,pins =
++					<3 RK_PB7 RK_FUNC_4 &pcfg_pull_up_8ma>;
++			};
++
++			spi1_miso_hs: spi1-miso-hs {
++				rockchip,pins =
++					<3 RK_PB6 RK_FUNC_4 &pcfg_pull_up_8ma>;
++			};
++
++			spi1_mosi_hs: spi1-mosi-hs {
++				rockchip,pins =
++					<3 RK_PB4 RK_FUNC_4 &pcfg_pull_up_8ma>;
++			};
++		};
++
++		pdm {
++			pdm_clk0m0: pdm-clk0m0 {
++				rockchip,pins =
++					<3 RK_PC6 RK_FUNC_2 &pcfg_pull_none>;
++			};
++
++			pdm_clk0m1: pdm-clk0m1 {
++				rockchip,pins =
++					<2 RK_PC6 RK_FUNC_1 &pcfg_pull_none>;
++			};
++
++			pdm_clk1: pdm-clk1 {
++				rockchip,pins =
++					<3 RK_PC7 RK_FUNC_2 &pcfg_pull_none>;
++			};
++
++			pdm_sdi0m0: pdm-sdi0m0 {
++				rockchip,pins =
++					<3 RK_PD3 RK_FUNC_2 &pcfg_pull_none>;
++			};
++
++			pdm_sdi0m1: pdm-sdi0m1 {
++				rockchip,pins =
++					<2 RK_PC5 RK_FUNC_2 &pcfg_pull_none>;
++			};
++
++			pdm_sdi1: pdm-sdi1 {
++				rockchip,pins =
++					<3 RK_PD0 RK_FUNC_2 &pcfg_pull_none>;
++			};
++
++			pdm_sdi2: pdm-sdi2 {
++				rockchip,pins =
++					<3 RK_PD1 RK_FUNC_2 &pcfg_pull_none>;
++			};
++
++			pdm_sdi3: pdm-sdi3 {
++				rockchip,pins =
++					<3 RK_PD2 RK_FUNC_2 &pcfg_pull_none>;
++			};
++
++			pdm_clk0m0_sleep: pdm-clk0m0-sleep {
++				rockchip,pins =
++					<3 RK_PC6 RK_FUNC_GPIO &pcfg_input_high>;
++			};
++
++			pdm_clk0m_sleep1: pdm-clk0m1-sleep {
++				rockchip,pins =
++					<2 RK_PC6 RK_FUNC_GPIO &pcfg_input_high>;
++			};
++
++			pdm_clk1_sleep: pdm-clk1-sleep {
++				rockchip,pins =
++					<3 RK_PC7 RK_FUNC_GPIO &pcfg_input_high>;
++			};
++
++			pdm_sdi0m0_sleep: pdm-sdi0m0-sleep {
++				rockchip,pins =
++					<3 RK_PD3 RK_FUNC_GPIO &pcfg_input_high>;
++			};
++
++			pdm_sdi0m1_sleep: pdm-sdi0m1-sleep {
++				rockchip,pins =
++					<2 RK_PC5 RK_FUNC_GPIO &pcfg_input_high>;
++			};
++
++			pdm_sdi1_sleep: pdm-sdi1-sleep {
++				rockchip,pins =
++					<3 RK_PD0 RK_FUNC_GPIO &pcfg_input_high>;
++			};
++
++			pdm_sdi2_sleep: pdm-sdi2-sleep {
++				rockchip,pins =
++					<3 RK_PD1 RK_FUNC_GPIO &pcfg_input_high>;
++			};
++
++			pdm_sdi3_sleep: pdm-sdi3-sleep {
++				rockchip,pins =
++					<3 RK_PD2 RK_FUNC_GPIO &pcfg_input_high>;
++			};
++		};
++
++		i2s0 {
++			i2s0_8ch_mclk: i2s0-8ch-mclk {
++				rockchip,pins =
++					<3 RK_PC1 RK_FUNC_2 &pcfg_pull_none>;
++			};
++
++			i2s0_8ch_sclktx: i2s0-8ch-sclktx {
++				rockchip,pins =
++					<3 RK_PC3 RK_FUNC_2 &pcfg_pull_none>;
++			};
++
++			i2s0_8ch_sclkrx: i2s0-8ch-sclkrx {
++				rockchip,pins =
++					<3 RK_PB4 RK_FUNC_2 &pcfg_pull_none>;
++			};
++
++			i2s0_8ch_lrcktx: i2s0-8ch-lrcktx {
++				rockchip,pins =
++					<3 RK_PC2 RK_FUNC_2 &pcfg_pull_none>;
++			};
++
++			i2s0_8ch_lrckrx: i2s0-8ch-lrckrx {
++				rockchip,pins =
++					<3 RK_PB5 RK_FUNC_2 &pcfg_pull_none>;
++			};
++
++			i2s0_8ch_sdo0: i2s0-8ch-sdo0 {
++				rockchip,pins =
++					<3 RK_PC4 RK_FUNC_2 &pcfg_pull_none>;
++			};
++
++			i2s0_8ch_sdo1: i2s0-8ch-sdo1 {
++				rockchip,pins =
++					<3 RK_PC0 RK_FUNC_2 &pcfg_pull_none>;
++			};
++
++			i2s0_8ch_sdo2: i2s0-8ch-sdo2 {
++				rockchip,pins =
++					<3 RK_PB7 RK_FUNC_2 &pcfg_pull_none>;
++			};
++
++			i2s0_8ch_sdo3: i2s0-8ch-sdo3 {
++				rockchip,pins =
++					<3 RK_PB6 RK_FUNC_2 &pcfg_pull_none>;
++			};
++
++			i2s0_8ch_sdi0: i2s0-8ch-sdi0 {
++				rockchip,pins =
++					<3 RK_PC5 RK_FUNC_2 &pcfg_pull_none>;
++			};
++
++			i2s0_8ch_sdi1: i2s0-8ch-sdi1 {
++				rockchip,pins =
++					<3 RK_PB3 RK_FUNC_2 &pcfg_pull_none>;
++			};
++
++			i2s0_8ch_sdi2: i2s0-8ch-sdi2 {
++				rockchip,pins =
++					<3 RK_PB1 RK_FUNC_2 &pcfg_pull_none>;
++			};
++
++			i2s0_8ch_sdi3: i2s0-8ch-sdi3 {
++				rockchip,pins =
++					<3 RK_PB0 RK_FUNC_2 &pcfg_pull_none>;
++			};
++		};
++
++		i2s1 {
++			i2s1_2ch_mclk: i2s1-2ch-mclk {
++				rockchip,pins =
++					<2 RK_PC3 RK_FUNC_1 &pcfg_pull_none>;
++			};
++
++			i2s1_2ch_sclk: i2s1-2ch-sclk {
++				rockchip,pins =
++					<2 RK_PC2 RK_FUNC_1 &pcfg_pull_none>;
++			};
++
++			i2s1_2ch_lrck: i2s1-2ch-lrck {
++				rockchip,pins =
++					<2 RK_PC1 RK_FUNC_1 &pcfg_pull_none>;
++			};
++
++			i2s1_2ch_sdi: i2s1-2ch-sdi {
++				rockchip,pins =
++					<2 RK_PC5 RK_FUNC_1 &pcfg_pull_none>;
++			};
++
++			i2s1_2ch_sdo: i2s1-2ch-sdo {
++				rockchip,pins =
++					<2 RK_PC4 RK_FUNC_1 &pcfg_pull_none>;
++			};
++		};
++
++		i2s2 {
++			i2s2_2ch_mclk: i2s2-2ch-mclk {
++				rockchip,pins =
++					<3 RK_PA1 RK_FUNC_2 &pcfg_pull_none>;
++			};
++
++			i2s2_2ch_sclk: i2s2-2ch-sclk {
++				rockchip,pins =
++					<3 RK_PA2 RK_FUNC_2 &pcfg_pull_none>;
++			};
++
++			i2s2_2ch_lrck: i2s2-2ch-lrck {
++				rockchip,pins =
++					<3 RK_PA3 RK_FUNC_2 &pcfg_pull_none>;
++			};
++
++			i2s2_2ch_sdi: i2s2-2ch-sdi {
++				rockchip,pins =
++					<3 RK_PA5 RK_FUNC_2 &pcfg_pull_none>;
++			};
++
++			i2s2_2ch_sdo: i2s2-2ch-sdo {
++				rockchip,pins =
++					<3 RK_PA7 RK_FUNC_2 &pcfg_pull_none>;
++			};
++		};
++
++		sdmmc {
++			sdmmc_clk: sdmmc-clk {
++				rockchip,pins =
++					<1 RK_PD6 RK_FUNC_1 &pcfg_pull_none_8ma>;
++			};
++
++			sdmmc_cmd: sdmmc-cmd {
++				rockchip,pins =
++					<1 RK_PD7 RK_FUNC_1 &pcfg_pull_up_8ma>;
++			};
++
++			sdmmc_det: sdmmc-det {
++				rockchip,pins =
++					<0 RK_PA3 RK_FUNC_1 &pcfg_pull_up_8ma>;
++			};
++
++			sdmmc_bus1: sdmmc-bus1 {
++				rockchip,pins =
++					<1 RK_PD2 RK_FUNC_1 &pcfg_pull_up_8ma>;
++			};
++
++			sdmmc_bus4: sdmmc-bus4 {
++				rockchip,pins =
++					<1 RK_PD2 RK_FUNC_1 &pcfg_pull_up_8ma>,
++					<1 RK_PD3 RK_FUNC_1 &pcfg_pull_up_8ma>,
++					<1 RK_PD4 RK_FUNC_1 &pcfg_pull_up_8ma>,
++					<1 RK_PD5 RK_FUNC_1 &pcfg_pull_up_8ma>;
++			};
++
++			sdmmc_clk_4ma: sdmmc-clk-4ma {
++                                rockchip,pins =
++                                        <1 RK_PD6 RK_FUNC_1 &pcfg_pull_none_4ma>;
++                        };
++
++                        sdmmc_cmd_4ma: sdmmc-cmd-4ma {
++                                rockchip,pins =
++                                        <1 RK_PD7 RK_FUNC_1 &pcfg_pull_up_4ma>;
++                        };
++
++                        sdmmc_det_4ma: sdmmc-det-4ma {
++                                rockchip,pins =
++                                        <0 RK_PA3 RK_FUNC_1 &pcfg_pull_up_4ma>;
++                        };
++
++                        sdmmc_bus1_4ma: sdmmc-bus1-4ma {
++                                rockchip,pins =
++                                        <1 RK_PD2 RK_FUNC_1 &pcfg_pull_up_4ma>;
++                        };
++
++                        sdmmc_bus4_4ma: sdmmc-bus4-4ma {
++                                rockchip,pins =
++                                        <1 RK_PD2 RK_FUNC_1 &pcfg_pull_up_4ma>,
++                                        <1 RK_PD3 RK_FUNC_1 &pcfg_pull_up_4ma>,
++                                        <1 RK_PD4 RK_FUNC_1 &pcfg_pull_up_4ma>,
++                                        <1 RK_PD5 RK_FUNC_1 &pcfg_pull_up_4ma>;
++                        };
++
++			sdmmc_gpio: sdmmc-gpio {
++				rockchip,pins =
++					<1 RK_PD2 RK_FUNC_GPIO &pcfg_pull_up_4ma>,
++					<1 RK_PD3 RK_FUNC_GPIO &pcfg_pull_up_4ma>,
++					<1 RK_PD4 RK_FUNC_GPIO &pcfg_pull_up_4ma>,
++					<1 RK_PD5 RK_FUNC_GPIO &pcfg_pull_up_4ma>,
++					<1 RK_PD6 RK_FUNC_GPIO &pcfg_pull_up_4ma>,
++					<1 RK_PD7 RK_FUNC_GPIO &pcfg_pull_up_4ma>;
++			};
++		};
++
++		sdio {
++			sdio_clk: sdio-clk {
++				rockchip,pins =
++					<1 RK_PC5 RK_FUNC_1 &pcfg_pull_none>;
++			};
++
++			sdio_cmd: sdio-cmd {
++				rockchip,pins =
++					<1 RK_PC4 RK_FUNC_1 &pcfg_pull_up>;
++			};
++
++			sdio_bus4: sdio-bus4 {
++				rockchip,pins =
++					<1 RK_PC6 RK_FUNC_1 &pcfg_pull_up>,
++					<1 RK_PC7 RK_FUNC_1 &pcfg_pull_up>,
++					<1 RK_PD0 RK_FUNC_1 &pcfg_pull_up>,
++					<1 RK_PD1 RK_FUNC_1 &pcfg_pull_up>;
++			};
++
++			sdio_gpio: sdio-gpio {
++				rockchip,pins =
++					<1 RK_PC6 RK_FUNC_GPIO &pcfg_pull_up>,
++					<1 RK_PC7 RK_FUNC_GPIO &pcfg_pull_up>,
++					<1 RK_PD0 RK_FUNC_GPIO &pcfg_pull_up>,
++					<1 RK_PD1 RK_FUNC_GPIO &pcfg_pull_up>,
++					<1 RK_PC4 RK_FUNC_GPIO &pcfg_pull_up>,
++					<1 RK_PC5 RK_FUNC_GPIO &pcfg_pull_up>;
++			};
++		};
++
++		emmc {
++			emmc_clk: emmc-clk {
++				rockchip,pins =
++					<1 RK_PB1 RK_FUNC_2 &pcfg_pull_none_8ma>;
++			};
++
++			emmc_cmd: emmc-cmd {
++				rockchip,pins =
++					<1 RK_PB2 RK_FUNC_2 &pcfg_pull_up_8ma>;
++			};
++
++			emmc_pwren: emmc-pwren {
++				rockchip,pins =
++					<1 RK_PB0 RK_FUNC_2 &pcfg_pull_none>;
++			};
++
++			emmc_rstnout: emmc-rstnout {
++				rockchip,pins =
++					<1 RK_PB3 RK_FUNC_2 &pcfg_pull_none>;
++			};
++
++			emmc_bus1: emmc-bus1 {
++				rockchip,pins =
++					<1 RK_PA0 RK_FUNC_2 &pcfg_pull_up_8ma>;
++			};
++
++			emmc_bus4: emmc-bus4 {
++				rockchip,pins =
++					<1 RK_PA0 RK_FUNC_2 &pcfg_pull_up_8ma>,
++					<1 RK_PA1 RK_FUNC_2 &pcfg_pull_up_8ma>,
++					<1 RK_PA2 RK_FUNC_2 &pcfg_pull_up_8ma>,
++					<1 RK_PA3 RK_FUNC_2 &pcfg_pull_up_8ma>;
++			};
++
++			emmc_bus8: emmc-bus8 {
++				rockchip,pins =
++					<1 RK_PA0 RK_FUNC_2 &pcfg_pull_up_8ma>,
++					<1 RK_PA1 RK_FUNC_2 &pcfg_pull_up_8ma>,
++					<1 RK_PA2 RK_FUNC_2 &pcfg_pull_up_8ma>,
++					<1 RK_PA3 RK_FUNC_2 &pcfg_pull_up_8ma>,
++					<1 RK_PA4 RK_FUNC_2 &pcfg_pull_up_8ma>,
++					<1 RK_PA5 RK_FUNC_2 &pcfg_pull_up_8ma>,
++					<1 RK_PA6 RK_FUNC_2 &pcfg_pull_up_8ma>,
++					<1 RK_PA7 RK_FUNC_2 &pcfg_pull_up_8ma>;
++			};
++		};
++
++		flash {
++			flash_cs0: flash-cs0 {
++				rockchip,pins =
++					<1 RK_PB0 RK_FUNC_1 &pcfg_pull_none>;
++			};
++
++			flash_rdy: flash-rdy {
++				rockchip,pins =
++					<1 RK_PB1 RK_FUNC_1 &pcfg_pull_none>;
++			};
++
++			flash_dqs: flash-dqs {
++				rockchip,pins =
++					<1 RK_PB2 RK_FUNC_1 &pcfg_pull_none>;
++			};
++
++			flash_ale: flash-ale {
++				rockchip,pins =
++					<1 RK_PB3 RK_FUNC_1 &pcfg_pull_none>;
++			};
++
++			flash_cle: flash-cle {
++				rockchip,pins =
++					<1 RK_PB4 RK_FUNC_1 &pcfg_pull_none>;
++			};
++
++			flash_wrn: flash-wrn {
++				rockchip,pins =
++					<1 RK_PB5 RK_FUNC_1 &pcfg_pull_none>;
++			};
++
++			flash_csl: flash-csl {
++				rockchip,pins =
++					<1 RK_PB6 RK_FUNC_1 &pcfg_pull_none>;
++			};
++
++			flash_rdn: flash-rdn {
++				rockchip,pins =
++					<1 RK_PB7 RK_FUNC_1 &pcfg_pull_none>;
++			};
++
++			flash_bus8: flash-bus8 {
++				rockchip,pins =
++					<1 RK_PA0 RK_FUNC_1 &pcfg_pull_up_12ma>,
++					<1 RK_PA1 RK_FUNC_1 &pcfg_pull_up_12ma>,
++					<1 RK_PA2 RK_FUNC_1 &pcfg_pull_up_12ma>,
++					<1 RK_PA3 RK_FUNC_1 &pcfg_pull_up_12ma>,
++					<1 RK_PA4 RK_FUNC_1 &pcfg_pull_up_12ma>,
++					<1 RK_PA5 RK_FUNC_1 &pcfg_pull_up_12ma>,
++					<1 RK_PA6 RK_FUNC_1 &pcfg_pull_up_12ma>,
++					<1 RK_PA7 RK_FUNC_1 &pcfg_pull_up_12ma>;
++			};
++		};
++
++		lcdc {
++			lcdc_m0_rgb_pins: lcdc-m0-rgb-pins {
++				rockchip,pins =
++					<3 RK_PA0 RK_FUNC_1 &pcfg_pull_none_8ma>,	/* LCDC_DCLK */
++					<3 RK_PA1 RK_FUNC_1 &pcfg_pull_none_8ma>,	/* LCDC_HSYNC */
++					<3 RK_PA2 RK_FUNC_1 &pcfg_pull_none_8ma>,	/* LCDC_VSYNC */
++					<3 RK_PA3 RK_FUNC_1 &pcfg_pull_none_8ma>,	/* LCDC_DEN */
++					<3 RK_PA4 RK_FUNC_1 &pcfg_pull_none_8ma>,	/* LCDC_D0 */
++					<3 RK_PA5 RK_FUNC_1 &pcfg_pull_none_8ma>,	/* LCDC_D1 */
++					<3 RK_PA6 RK_FUNC_1 &pcfg_pull_none_8ma>,	/* LCDC_D2 */
++					<3 RK_PA7 RK_FUNC_1 &pcfg_pull_none_8ma>,	/* LCDC_D3 */
++					<3 RK_PB0 RK_FUNC_1 &pcfg_pull_none_8ma>,	/* LCDC_D4 */
++					<3 RK_PB1 RK_FUNC_1 &pcfg_pull_none_8ma>,	/* LCDC_D5 */
++					<3 RK_PB2 RK_FUNC_1 &pcfg_pull_none_8ma>,	/* LCDC_D6 */
++					<3 RK_PB3 RK_FUNC_1 &pcfg_pull_none_8ma>,	/* LCDC_D7 */
++					<3 RK_PB4 RK_FUNC_1 &pcfg_pull_none_8ma>,	/* LCDC_D8 */
++					<3 RK_PB5 RK_FUNC_1 &pcfg_pull_none_8ma>,	/* LCDC_D9 */
++					<3 RK_PB6 RK_FUNC_1 &pcfg_pull_none_8ma>,	/* LCDC_D10 */
++					<3 RK_PB7 RK_FUNC_1 &pcfg_pull_none_8ma>,	/* LCDC_D11 */
++					<3 RK_PC0 RK_FUNC_1 &pcfg_pull_none_8ma>,	/* LCDC_D12 */
++					<3 RK_PC1 RK_FUNC_1 &pcfg_pull_none_8ma>,	/* LCDC_D13 */
++					<3 RK_PC2 RK_FUNC_1 &pcfg_pull_none_8ma>,	/* LCDC_D14 */
++					<3 RK_PC3 RK_FUNC_1 &pcfg_pull_none_8ma>,	/* LCDC_D15 */
++					<3 RK_PC4 RK_FUNC_1 &pcfg_pull_none_8ma>,	/* LCDC_D16 */
++					<3 RK_PC5 RK_FUNC_1 &pcfg_pull_none_8ma>,	/* LCDC_D17 */
++					<3 RK_PC6 RK_FUNC_1 &pcfg_pull_none_8ma>,	/* LCDC_D18 */
++					<3 RK_PC7 RK_FUNC_1 &pcfg_pull_none_8ma>,	/* LCDC_D19 */
++					<3 RK_PD0 RK_FUNC_1 &pcfg_pull_none_8ma>,	/* LCDC_D20 */
++					<3 RK_PD1 RK_FUNC_1 &pcfg_pull_none_8ma>,	/* LCDC_D21 */
++					<3 RK_PD2 RK_FUNC_1 &pcfg_pull_none_8ma>,	/* LCDC_D22 */
++					<3 RK_PD3 RK_FUNC_1 &pcfg_pull_none_8ma>;	/* LCDC_D23 */
++			};
++
++			lcdc_m0_sleep_pins: lcdc-m0-sleep-pins {
++				rockchip,pins =
++					<3 RK_PA0 RK_FUNC_GPIO &pcfg_pull_none>,	/* LCDC_DCLK */
++					<3 RK_PA1 RK_FUNC_GPIO &pcfg_pull_none>,	/* LCDC_HSYNC */
++					<3 RK_PA2 RK_FUNC_GPIO &pcfg_pull_none>,	/* LCDC_VSYNC */
++					<3 RK_PA3 RK_FUNC_GPIO &pcfg_pull_none>,	/* LCDC_DEN */
++					<3 RK_PA4 RK_FUNC_GPIO &pcfg_pull_none>,	/* LCDC_D0 */
++					<3 RK_PA5 RK_FUNC_GPIO &pcfg_pull_none>,	/* LCDC_D1 */
++					<3 RK_PA6 RK_FUNC_GPIO &pcfg_pull_none>,	/* LCDC_D2 */
++					<3 RK_PA7 RK_FUNC_GPIO &pcfg_pull_none>,	/* LCDC_D3 */
++					<3 RK_PB0 RK_FUNC_GPIO &pcfg_pull_none>,	/* LCDC_D4 */
++					<3 RK_PB1 RK_FUNC_GPIO &pcfg_pull_none>,	/* LCDC_D5 */
++					<3 RK_PB2 RK_FUNC_GPIO &pcfg_pull_none>,	/* LCDC_D6 */
++					<3 RK_PB3 RK_FUNC_GPIO &pcfg_pull_none>,	/* LCDC_D7 */
++					<3 RK_PB4 RK_FUNC_GPIO &pcfg_pull_none>,	/* LCDC_D8 */
++					<3 RK_PB5 RK_FUNC_GPIO &pcfg_pull_none>,	/* LCDC_D9 */
++					<3 RK_PB6 RK_FUNC_GPIO &pcfg_pull_none>,	/* LCDC_D10 */
++					<3 RK_PB7 RK_FUNC_GPIO &pcfg_pull_none>,	/* LCDC_D11 */
++					<3 RK_PC0 RK_FUNC_GPIO &pcfg_pull_none>,	/* LCDC_D12 */
++					<3 RK_PC1 RK_FUNC_GPIO &pcfg_pull_none>,	/* LCDC_D13 */
++					<3 RK_PC2 RK_FUNC_GPIO &pcfg_pull_none>,	/* LCDC_D14 */
++					<3 RK_PC3 RK_FUNC_GPIO &pcfg_pull_none>,	/* LCDC_D15 */
++					<3 RK_PC4 RK_FUNC_GPIO &pcfg_pull_none>,	/* LCDC_D16 */
++					<3 RK_PC5 RK_FUNC_GPIO &pcfg_pull_none>,	/* LCDC_D17 */
++					<3 RK_PC6 RK_FUNC_GPIO &pcfg_pull_none>,	/* LCDC_D18 */
++					<3 RK_PC7 RK_FUNC_GPIO &pcfg_pull_none>,	/* LCDC_D19 */
++					<3 RK_PD0 RK_FUNC_GPIO &pcfg_pull_none>,	/* LCDC_D20 */
++					<3 RK_PD1 RK_FUNC_GPIO &pcfg_pull_none>,	/* LCDC_D21 */
++					<3 RK_PD2 RK_FUNC_GPIO &pcfg_pull_none>,	/* LCDC_D22 */
++					<3 RK_PD3 RK_FUNC_GPIO &pcfg_pull_none>;	/* LCDC_D23 */
++			};
++		};
++
++		pwm0 {
++			pwm0_pin: pwm0-pin {
++				rockchip,pins =
++					<0 RK_PB7 RK_FUNC_1 &pcfg_pull_none>;
++			};
++		};
++
++		pwm1 {
++			pwm1_pin: pwm1-pin {
++				rockchip,pins =
++					<0 RK_PC0 RK_FUNC_1 &pcfg_pull_none>;
++			};
++		};
++
++		pwm2 {
++			pwm2_pin: pwm2-pin {
++				rockchip,pins =
++					<2 RK_PB5 RK_FUNC_1 &pcfg_pull_none>;
++			};
++		};
++
++		pwm3 {
++			pwm3_pin: pwm3-pin {
++				rockchip,pins =
++					<0 RK_PC1 RK_FUNC_1 &pcfg_pull_none>;
++			};
++		};
++
++		pwm4 {
++			pwm4_pin: pwm4-pin {
++				rockchip,pins =
++					<3 RK_PC2 RK_FUNC_3 &pcfg_pull_none>;
++			};
++		};
++
++		pwm5 {
++			pwm5_pin: pwm5-pin {
++				rockchip,pins =
++					<3 RK_PC3 RK_FUNC_3 &pcfg_pull_none>;
++			};
++		};
++
++		pwm6 {
++			pwm6_pin: pwm6-pin {
++				rockchip,pins =
++					<3 RK_PC4 RK_FUNC_3 &pcfg_pull_none>;
++			};
++		};
++
++		pwm7 {
++			pwm7_pin: pwm7-pin {
++				rockchip,pins =
++					<3 RK_PC5 RK_FUNC_3 &pcfg_pull_none>;
++			};
++		};
++
++		gmac {
++			rmii_pins: rmii-pins {
++				rockchip,pins =
++					/* mac_txen */
++					<2 RK_PA0 RK_FUNC_2 &pcfg_pull_none_12ma>,
++					/* mac_txd1 */
++					<2 RK_PA1 RK_FUNC_2 &pcfg_pull_none_12ma>,
++					/* mac_txd0 */
++					<2 RK_PA2 RK_FUNC_2 &pcfg_pull_none_12ma>,
++					/* mac_rxd0 */
++					<2 RK_PA3 RK_FUNC_2 &pcfg_pull_none>,
++					/* mac_rxd1 */
++					<2 RK_PA4 RK_FUNC_2 &pcfg_pull_none>,
++					/* mac_rxer */
++					<2 RK_PA5 RK_FUNC_2 &pcfg_pull_none>,
++					/* mac_rxdv */
++					<2 RK_PA6 RK_FUNC_2 &pcfg_pull_none>,
++					/* mac_mdio */
++					<2 RK_PA7 RK_FUNC_2 &pcfg_pull_none>,
++					/* mac_mdc */
++					<2 RK_PB1 RK_FUNC_2 &pcfg_pull_none>;
++			};
++
++			mac_refclk_12ma: mac-refclk-12ma {
++				rockchip,pins =
++					<2 RK_PB2 RK_FUNC_2 &pcfg_pull_none_12ma>;
++			};
++
++			mac_refclk: mac-refclk {
++				rockchip,pins =
++					<2 RK_PB2 RK_FUNC_2 &pcfg_pull_none>;
++			};
++		};
++
++		cif-m0 {
++			cif_clkout_m0: cif-clkout-m0 {
++				rockchip,pins = <2 RK_PB3 RK_FUNC_1 &pcfg_pull_none_12ma>;/* cif_clkout */
++			};
++
++			dvp_d2d9_m0: dvp-d2d9-m0 {
++				rockchip,pins =
++					<2 RK_PA0 RK_FUNC_1 &pcfg_pull_none>,/* cif_data2 */
++					<2 RK_PA1 RK_FUNC_1 &pcfg_pull_none>,/* cif_data3 */
++					<2 RK_PA2 RK_FUNC_1 &pcfg_pull_none>,/* cif_data4 */
++					<2 RK_PA3 RK_FUNC_1 &pcfg_pull_none>,/* cif_data5 */
++					<2 RK_PA4 RK_FUNC_1 &pcfg_pull_none>,/* cif_data6 */
++					<2 RK_PA5 RK_FUNC_1 &pcfg_pull_none>,/* cif_data7 */
++					<2 RK_PA6 RK_FUNC_1 &pcfg_pull_none>,/* cif_data8 */
++					<2 RK_PA7 RK_FUNC_1 &pcfg_pull_none>,/* cif_data9 */
++					<2 RK_PB0 RK_FUNC_1 &pcfg_pull_none>,/* cif_sync */
++					<2 RK_PB1 RK_FUNC_1 &pcfg_pull_none>,/* cif_href */
++					<2 RK_PB2 RK_FUNC_1 &pcfg_pull_none>,/* cif_clkin */
++					<2 RK_PB3 RK_FUNC_1 &pcfg_pull_none>;/* cif_clkout */
++			};
++
++			dvp_d0d1_m0: dvp-d0d1-m0 {
++				rockchip,pins =
++					<2 RK_PB4 RK_FUNC_1 &pcfg_pull_none>,/* cif_data0 */
++					<2 RK_PB6 RK_FUNC_1 &pcfg_pull_none>;/* cif_data1 */
++			};
++
++			dvp_d10d11_m0:d10-d11-m0 {
++				rockchip,pins =
++					<2 RK_PB7 RK_FUNC_1 &pcfg_pull_none>,/* cif_data10 */
++					<2 RK_PC0 RK_FUNC_1 &pcfg_pull_none>;/* cif_data11 */
++			};
++		};
++
++		cif-m1 {
++			cif_clkout_m1: cif-clkout-m1 {
++				rockchip,pins = <3 RK_PD0 RK_FUNC_3 &pcfg_pull_none>;/* cif_clkout */
++			};
++
++			dvp_d2d9_m1: dvp-d2d9-m1 {
++				rockchip,pins =
++					<3 RK_PA3 RK_FUNC_3 &pcfg_pull_none>,/* cif_data2 */
++					<3 RK_PA5 RK_FUNC_3 &pcfg_pull_none>,/* cif_data3 */
++					<3 RK_PA7 RK_FUNC_3 &pcfg_pull_none>,/* cif_data4 */
++					<3 RK_PB0 RK_FUNC_3 &pcfg_pull_none>,/* cif_data5 */
++					<3 RK_PB1 RK_FUNC_3 &pcfg_pull_none>,/* cif_data6 */
++					<3 RK_PB4 RK_FUNC_3 &pcfg_pull_none>,/* cif_data7 */
++					<3 RK_PB6 RK_FUNC_3 &pcfg_pull_none>,/* cif_data8 */
++					<3 RK_PB7 RK_FUNC_3 &pcfg_pull_none>,/* cif_data9 */
++					<3 RK_PD1 RK_FUNC_3 &pcfg_pull_none>,/* cif_sync */
++					<3 RK_PD2 RK_FUNC_3 &pcfg_pull_none>,/* cif_href */
++					<3 RK_PD3 RK_FUNC_3 &pcfg_pull_none>,/* cif_clkin */
++					<3 RK_PD0 RK_FUNC_3 &pcfg_pull_none>;/* cif_clkout */
++			};
++
++			dvp_d0d1_m1: dvp-d0d1-m1 {
++				rockchip,pins =
++					<3 RK_PA1 RK_FUNC_3 &pcfg_pull_none>,/* cif_data0 */
++					<3 RK_PA2 RK_FUNC_3 &pcfg_pull_none>;/* cif_data1 */
++			};
++
++			dvp_d10d11_m1:d10-d11-m1 {
++				rockchip,pins =
++					<3 RK_PC6 RK_FUNC_3 &pcfg_pull_none>,/* cif_data10 */
++					<3 RK_PC7 RK_FUNC_3 &pcfg_pull_none>;/* cif_data11 */
++			};
++		};
++
++		isp {
++			isp_prelight: isp-prelight {
++				rockchip,pins = <3 RK_PD1 RK_FUNC_4 &pcfg_pull_none>;/* ISP_PRELIGHTTRIG */
++			};
++		};
++	};
++};
+diff --git a/arch/arm64/boot/dts/rockchip/px30-evb-ddr3-v10-linux.dts b/arch/arm64/boot/dts/rockchip/px30-evb-ddr3-v10-linux.dts
+index f943c7f..653e560 100644
+--- a/arch/arm64/boot/dts/rockchip/px30-evb-ddr3-v10-linux.dts
++++ b/arch/arm64/boot/dts/rockchip/px30-evb-ddr3-v10-linux.dts
+@@ -3,18 +3,32 @@
+  * Copyright (c) 2018 Fuzhou Rockchip Electronics Co., Ltd
+  */
+ 
++/* 1 => ADV7535, 2 => IT9611 */
++#define DSI2HDMI_BRIDGE 2
++
+ /dts-v1/;
+ #include <dt-bindings/gpio/gpio.h>
+ #include <dt-bindings/pinctrl/rockchip.h>
+ #include <dt-bindings/input/input.h>
+ #include <dt-bindings/display/drm_mipi_dsi.h>
+ #include <dt-bindings/sensor-dev.h>
+-#include "px30.dtsi"
++#include "lec-px30.dtsi"
+ #include "rk3326-linux.dtsi"
++//#include "lcd_1024x600_mipi.dtsi"
++//#include "lcd_1920x1200_mipi.dtsi"
++//#include "lcd_720x1280_mipi.dtsi"
++//#include "lcd_1280x800_lvds.dtsi"
++#if DSI2HDMI_BRIDGE == 1
++#include "lcd_1920x1080_mipi.dtsi"
++#endif
++#if DSI2HDMI_BRIDGE == 2
++#include "dsi2hdmi_lt9611.dtsi"
++#endif
+ 
+ / {
+-	model = "Rockchip linux PX30 evb ddr3 board";
+-	compatible = "rockchip,px30-evb-ddr3-v10-linux", "rockchip,px30";
++
++	model = "ADLINK ARM, LEC-PX30";
++        compatible = "adlink,lec-px30";
+ 
+ 	adc-keys {
+ 		compatible = "adc-keys";
+@@ -54,6 +68,11 @@
+ 		};
+ 	};
+ 
++	 adc_test{
++                compatible = "rockchip,adc_test";
++                io-channels = <&saradc 0>;
++        };
++
+ 	backlight: backlight {
+ 		compatible = "pwm-backlight";
+ 		pwms = <&pwm1 0 25000 0>;
+@@ -91,6 +110,7 @@
+ 			240 241 242 243 244 245 246 247
+ 			248 249 250 251 252 253 254 255>;
+ 		default-brightness-level = <200>;
++		/*enable-gpios=<&gpio0 15 GPIO_ACTIVE_HIGH>*/
+ 	};
+ 
+ 	charge-animation {
+@@ -101,7 +121,7 @@
+ 		rockchip,screen-on-voltage = <3600>;
+ 		status = "okay";
+ 	};
+-
++#if 0
+ 	rk809-sound {
+ 		compatible = "simple-audio-card";
+ 		simple-audio-card,format = "i2s";
+@@ -122,37 +142,168 @@
+ 			sound-dai = <&rk809_codec>;
+ 		};
+ 	};
+-
+-	rk_headset {
++#endif
++
++#if 0
++	tlv320-sound {
++                compatible = "simple-audio-card";
++                simple-audio-card,format = "i2s";
++                simple-audio-card,name = "rockchip,tlv320-codec";
++                simple-audio-card,mclk-fs = <256>;
++		simple-audio-card,widgets =
++			"Microphone", "Mic Jack",
++			"Line", "Line In",
++			"Line", "Line Out",
++			"Speaker", "Speaker",
++			"Headphone", "Headphone Jack";
++		simple-audio-card,routing =
++			"Line Out", "LLOUT",
++			"Line Out", "RLOUT",
++			"Headphone Jack", "HPLOUT",
++			"Headphone Jack", "HPROUT",
++			"MIC3L", "Mic Jack",
++			"MIC3R", "Mic Jack",
++			"Mic Jack", "Mic Bias",
++			"LINE1L", "Line In",
++			"LINE1R", "Line In";
++
++                simple-audio-card,cpu {
++                        sound-dai = <&i2s2_2ch>;
++                };
++                simple-audio-card,codec {
++                        sound-dai = <&tlv320_codec>;
++                };
++        };
++
++#endif
++	rt5640-sound {
++                compatible = "simple-audio-card";
++                simple-audio-card,format = "i2s";
++                simple-audio-card,name = "rockchip,rt5640-codec";
++                simple-audio-card,mclk-fs = <256>;
++                simple-audio-card,widgets =
++                        "Microphone", "Mic Jack",
++                        "Headphone", "Headphone Jack";
++                simple-audio-card,routing =
++                        "Mic Jack", "MICBIAS1",
++                        "IN1P", "Mic Jack",
++                        "Headphone Jack", "HPOL",
++                        "Headphone Jack", "HPOR";
++                simple-audio-card,cpu {
++                        sound-dai = <&i2s1_2ch>;
++                };
++                simple-audio-card,codec {
++                        sound-dai = <&rt5640>;
++                };
++        };
++
++
++	px30_lanxus_gpioset {
++		compatible = "lanxus-px30,gpio";
++		pinctrl-names = "default";
++		pinctrl-0 = <&lanxus_gpioset>;
++		REBOOT_GPIO=<&gpio3 6  GPIO_ACTIVE_HIGH>;/*change to GPIO3_A6*/
++		/*PHY_PWR = <&gpio2 8  GPIO_ACTIVE_LOW>;*/
++		status = "okay";
++	};
++	/*
++	sgtl5000-sound {
++                compatible = "simple-audio-card";
++                simple-audio-card,format = "i2s";
++                simple-audio-card,name = "rockchip,sgtl5000-codec";
++                simple-audio-card,mclk-fs = <256>;
++		simple-audio-card,widgets =
++			"Microphone", "Mic Jack",
++			"Line", "Line In",
++			"Line", "Line Out",
++			"Headphone", "Headphone Jack";
++		simple-audio-card,routing =
++ 			"MIC_IN", "Mic Jack",
++ 			"Mic Jack", "Mic Bias",
++ 			"Headphone Jack", "HP_OUT";
++                simple-audio-card,cpu {
++                        sound-dai = <&i2s2_2ch>;
++                };
++                simple-audio-card,codec {
++                        sound-dai = <&sgtl5000_codec>;
++                };
++        };
++	*/
++
++	/*rk_headset {
+ 		compatible = "rockchip_headset";
+ 		headset_gpio = <&gpio2 RK_PB0 GPIO_ACTIVE_LOW>;
+ 		pinctrl-names = "default";
+ 		pinctrl-0 = <&hp_det>;
+ 		io-channels = <&saradc 1>;
+-	};
++	};*/
+ 
+-	sdio_pwrseq: sdio-pwrseq {
++/*	sdio_pwrseq: sdio-pwrseq {
+ 		compatible = "mmc-pwrseq-simple";
+-		/*clocks = <&rk809 1>;*/
+-		/*clock-names = "ext_clock";*/
++		clocks = <&rk809 1>;
++		clock-names = "ext_clock";
+ 		pinctrl-names = "default";
+ 		pinctrl-0 = <&wifi_enable_h>;
+-
++*/
+ 		/*
+ 		 * On the module itself this is one of these (depending
+ 		 * on the actual card populated):
+ 		 * - SDIO_RESET_L_WL_REG_ON
+ 		 * - PDN (power down when low)
+ 		 */
+-		reset-gpios = <&gpio0 RK_PA2 GPIO_ACTIVE_LOW>; /* GPIO3_A4 */
+-	};
++/*		reset-gpios = <&gpio0 RK_PA2 GPIO_ACTIVE_LOW>;
++	};*/
++
++
++	 clk20m: clk20m {
++                compatible = "fixed-clock";
++                #clock-cells = <0>;
++                clock-frequency = <20000000>;
++        };
+ 
+ 	vcc_phy: vcc-phy-regulator {
+ 		compatible = "regulator-fixed";
+ 		regulator-name = "vcc_phy";
++		/*gpio = <&gpio2 8 GPIO_ACTIVE_HIGH>;
++		pinctrl-name="default";
++		pinctrl-0=<&eth_phy_pwr>;*/
+ 		regulator-always-on;
+ 		regulator-boot-on;
++		regulator-min-microvolt = <3300000>;
++                regulator-max-microvolt = <3300000>;
++	};
++
++	//
++        vcc_sd_pwr: sdmmc-regulator {
++                compatible = "regulator-fixed";
++                pinctrl-names = "default";
++                pinctrl-0 = <&sdmmc_pwr>;
++              	/*gpio = <&gpio0 2 GPIO_ACTIVE_HIGH>;*/
++                regulator-name = "vcc_sd_pwr";
++                regulator-min-microvolt = <3300000>;
++                regulator-max-microvolt = <3300000>;
++                /*startup-delay-us = <100000>;*/
++        };
++
++
++
++	sound_1v8: sound_1v8 {
++		compatible = "regulator-fixed";
++                regulator-name = "sound_1v8";
++                regulator-always-on;
++                regulator-boot-on;
++                regulator-min-microvolt = <1800000>;
++                regulator-max-microvolt = <1800000>;
+ 	};
++	
++	sound_3v3: sound_3v3 {
++                compatible = "regulator-fixed";
++                regulator-name = "sound_3v3";
++                regulator-always-on;
++                regulator-boot-on;
++                regulator-min-microvolt = <3300000>;
++                regulator-max-microvolt = <3300000>;
++        };
+ 
+ 	vcc5v0_sys: vccsys {
+ 		compatible = "regulator-fixed";
+@@ -165,12 +316,12 @@
+ 
+ 	wireless-wlan {
+ 		compatible = "wlan-platdata";
+-		wifi_chip_type = "AP6210";
+-		WIFI,host_wake_irq = <&gpio0 RK_PB2 GPIO_ACTIVE_HIGH>;
++		wifi_chip_type = "rtl8723bu";
++		/*WIFI,host_wake_irq = <&gpio0 RK_PB2 GPIO_ACTIVE_HIGH>;*/
+ 		status = "okay";
+ 	};
+ 
+-	wireless-bluetooth {
++/*	wireless-bluetooth {
+ 		compatible = "bluetooth-platdata";
+ 		clocks = <&rk809 1>;
+ 		clock-names = "ext_clock";
+@@ -178,17 +329,17 @@
+ 		pinctrl-names = "default","rts_gpio";
+ 		pinctrl-0 = <&uart1_rts>;
+ 		pinctrl-1 = <&uart1_rts_gpio>;
+-		BT,reset_gpio = <&gpio0 RK_PA1 GPIO_ACTIVE_HIGH>;
+-		BT,wake_gpio = <&gpio2 RK_PB0 GPIO_ACTIVE_HIGH>;
++		BT,reset_gpio = <&gpio2 RK_PB0 GPIO_ACTIVE_HIGH>;
++		BT,wake_gpio = <&gpio0 RK_PA1 GPIO_ACTIVE_HIGH>;
+ 		BT,wake_host_irq = <&gpio0 RK_PB3 GPIO_ACTIVE_HIGH>;
+-		status = "okay";
+-	};
++		status = "disabled";
++	};*/
+ };
+ 
+ &display_subsystem {
+ 	status = "okay";
+ };
+-
++/* moved lcd_1920x1200_mipi.dtsi
+ &dsi {
+ 	status = "okay";
+ 
+@@ -211,8 +362,8 @@
+ 			      MIPI_DSI_MODE_LPM | MIPI_DSI_MODE_EOT_PACKET)>;
+ 		dsi,format = <MIPI_DSI_FMT_RGB888>;
+ 		dsi,lanes = <4>;
+-
+-		panel-init-sequence = [
++*/
++		/*panel-init-sequence = [
+ 			05 fa 01 11
+ 			39 00 04 b9 f1 12 83
+ 			39 00 1c ba 33 81 05 f9 0e 0e 00 00 00
+@@ -258,21 +409,21 @@
+ 		panel-exit-sequence = [
+ 			05 00 01 28
+ 			05 00 01 10
+-		];
++		];*/
+ 
+-		display-timings {
++/*		display-timings {
+ 			native-mode = <&timing0>;
+ 
+ 			timing0: timing0 {
+-				clock-frequency = <64000000>;
+-				hactive = <720>;
+-				vactive = <1280>;
+-				hfront-porch = <40>;
+-				hsync-len = <10>;
+-				hback-porch = <40>;
+-				vfront-porch = <22>;
+-				vsync-len = <4>;
+-				vback-porch = <11>;
++				clock-frequency = <60000000>;
++				hactive = <1024>;
++				vactive = <600>;
++				hfront-porch = <150>;
++				hsync-len = <20>;
++				hback-porch = <150>;
++				vfront-porch = <8>;
++				vsync-len = <3>;
++				vback-porch = <24>;
+ 				hsync-active = <0>;
+ 				vsync-active = <0>;
+ 				de-active = <0>;
+@@ -281,20 +432,7 @@
+ 		};
+ 	};
+ };
+-
+-&dsi_in_vopb {
+-	status = "okay";
+-};
+-
+-&dsi_in_vopl {
+-	status = "disabled";
+-};
+-
+-&route_dsi {
+-	connect = <&vopb_out_dsi>;
+-	status = "okay";
+-};
+-
++*/
+ &bus_apll {
+ 	bus-supply = <&vdd_logic>;
+ 	status = "okay";
+@@ -304,6 +442,11 @@
+ 	cpu-supply = <&vdd_arm>;
+ };
+ 
++/* move to moved lcd_1920x1200_mipi.dtsi
++&dsi_in_vopl {
++	status = "disabled";
++};
++*/
+ &dfi {
+ 	status = "okay";
+ };
+@@ -326,10 +469,16 @@
+ 
+ &gmac {
+ 	phy-supply = <&vcc_phy>;
+-	clock_in_out = "output";
++	clock_in_out = "input";
++        pinctrl-names = "default";
++        pinctrl-0 = <&rmii_pins &mac_refclk_12ma &eth_phy_pwr>;
++	snps,power-gpio= <&gpio2 8 GPIO_ACTIVE_HIGH>;
+ 	snps,reset-gpio = <&gpio2 13 GPIO_ACTIVE_LOW>;
+ 	snps,reset-active-low;
+-	snps,reset-delays-us = <0 50000 50000>;
++	snps,reset-delays-us = <0 100000 100000>;
++	max-speed=<100>;
++/*	tx_delay = <0x0>;
++	rx_delay=<0x0>; */
+ 	status = "okay";
+ };
+ 
+@@ -338,6 +487,66 @@
+ 	status = "okay";
+ };
+ 
++&spi0 {
++        status = "okay";
++        max-freq = <48000000>;
++	spi_dev@0 {
++              status = "okay";
++              compatible = "rockchip,spidev";
++              reg = <0>;
++              spi-max-frequency = <48000000>;
++	      spi-lsb-first;
++	      spi-gpio-cs= <&gpio1 RK_PB6 GPIO_ACTIVE_LOW>;
++          };
++
++ /*   spidemo@00 {
++        compatible = "lanxus,px30-spi";
++        reg = <0x00>;
++        spi-max-frequency = <48000000>;
++	spi-gpio-cs= <&gpio1 RK_PB6 GPIO_ACTIVE_LOW>;
++    };*/
++
++};
++
++
++&spi1 {
++        status = "okay";
++        max-freq = <50000000>;
++
++	can0: can@0 {
++                compatible = "microchip,mcp2517fd";
++                pinctrl-names = "default";
++                pinctrl-0 = <&can_int>;
++                reg = <0>;
++                clocks = <&clk20m>;
++                spi-max-frequency = <10000000>;
++		interrupt-parent = <&gpio0>;
++                interrupts = <17 IRQ_TYPE_LEVEL_LOW>;
++                
++        };
++
++	/*spidev@01 {
++              status = "okay";
++              compatible = "rockchip,spidev";
++              reg = <1>;
++              spi-max-frequency = <24000000>;
++          };*/
++/*	can2: can@2 {
++                compatible = "microchip,mcp2517fd";
++                pinctrl-names = "default";
++                pinctrl-0 = <&can_int>;
++                reg = <1>;
++                clocks = <&clk20m>;
++                spi-max-frequency = <10000000>;
++               interrupt-parent = <&gpio0>;
++                interrupts = <17 IRQ_TYPE_LEVEL_LOW>;
++
++        };*/
++
++
++};
++
++
+ &i2c0 {
+ 	status = "okay";
+ 
+@@ -507,7 +716,7 @@
+ 				regulator-always-on;
+ 				regulator-boot-on;
+ 				regulator-min-microvolt = <1800000>;
+-				regulator-max-microvolt = <3300000>;
++				regulator-max-microvolt = <3300000>;/*old 3300000*/
+ 
+ 				regulator-name = "vccio_sd";
+ 				regulator-state-mem {
+@@ -520,7 +729,7 @@
+ 				regulator-min-microvolt = <3300000>;
+ 				regulator-max-microvolt = <3300000>;
+ 				regulator-boot-on;
+-
++				regulator-always-on;/*add for test*/
+ 				regulator-name = "vcc_sd";
+ 				regulator-state-mem {
+ 					regulator-on-in-suspend;
+@@ -530,6 +739,7 @@
+ 			};
+ 
+ 			vcc2v8_dvp: LDO_REG7 {
++				regulator-always-on;
+ 				regulator-boot-on;
+ 				regulator-min-microvolt = <2800000>;
+ 				regulator-max-microvolt = <2800000>;
+@@ -542,6 +752,7 @@
+ 			};
+ 
+ 			vcc1v8_dvp: LDO_REG8 {
++				regulator-always-on;
+ 				regulator-boot-on;
+ 				regulator-min-microvolt = <1800000>;
+ 				regulator-max-microvolt = <1800000>;
+@@ -554,6 +765,7 @@
+ 			};
+ 
+ 			vdd1v5_dvp: LDO_REG9 {
++				regulator-always-on;
+ 				regulator-boot-on;
+ 				regulator-min-microvolt = <1500000>;
+ 				regulator-max-microvolt = <1500000>;
+@@ -588,7 +800,7 @@
+ 				regulator-name = "vcc5v0_host";
+ 			};
+ 		};
+-
++#if 0
+ 		rk809_codec: codec {
+ 			#sound-dai-cells = <0>;
+ 			compatible = "rockchip,rk809-codec", "rockchip,rk817-codec";
+@@ -600,14 +812,70 @@
+ 			spk-volume = <3>;
+ 			status = "okay";
+ 		};
++
++#endif
+ 	};
++
++#if 0
++	tlv320_codec: codec@18 {
++                        #sound-dai-cells = <0>;
++                        compatible = "ti,tlv320aic3x";
++ 			reg = <0x18>;
++                        clocks = <&cru SCLK_I2S2_OUT>;
++                        clock-names = "mclk";
++                        pinctrl-names = "default";
++                        pinctrl-0 = <&i2s2_2ch_mclk>;
++			ai31xx-micbias-vg=<2>;
++			gpio-reset=<&gpio3 23 GPIO_ACTIVE_LOW>;
++			/*clock-frequency = <12000000>;*/
++			AVDD-supply = <&sound_3v3>;
++			IOVDD-supply = <&sound_1v8>;
++			DRVDD-supply = <&sound_3v3>;
++			DVDD-supply = <&sound_1v8>;
++                        status = "okay";
++                };
++#endif
++	/*sgtl5000_codec: codec@0a {
++ 		compatible = "fsl,sgtl5000";
++		//#sound-dai-cells = <0>;
++ 		reg = <0x0a>;
++		clocks = <&cru SCLK_I2S2_OUT>;
++                clock-names = "mclk";
++                pinctrl-names = "default";
++                pinctrl-0 = <&i2s2_2ch_mclk>;
++ 		VDDA-supply = <&sound_3v3>;
++ 		VDDIO-supply = <&sound_1v8>;
++		VDDD-supply =  <&sound_1v8>;
++	};*/
++
++
++	/*atecc608a@01 {
++              status = "okay";
++              compatible = "atmel,atecc508a";
++              reg = <1>;
++              clock-frequency = <1000000>;
++          };*/
++
++
++
+ };
+ 
+ &i2c1 {
+ 	status = "okay";
++#if 0
++	gslx680@40 { 
++	status = "disabled";
++        compatible = "9tripod,gslx680";
++        reg = <0x40>;
++		power-supply = <&vcc3v3_lcd>;
++        touch-gpio = <&gpio0 5 IRQ_TYPE_EDGE_RISING>;
++        reset-gpio = <&gpio0 12 GPIO_ACTIVE_LOW>;
++        max-x = <1024>;
++        max-y = <600>;
++    	};
+ 
+ 	sensor@f {
+-		status = "okay";
++		status = "disabled";
+ 		compatible = "ak8963";
+ 		reg = <0x0f>;
+ 		type = <SENSOR_TYPE_COMPASS>;
+@@ -618,6 +886,7 @@
+ 	};
+ 
+ 	gt1x: gt1x@14 {
++		status = "disabled";
+ 		compatible = "goodix,gt1x";
+ 		reg = <0x14>;
+ 		power-supply = <&vcc3v3_lcd>;
+@@ -626,7 +895,7 @@
+ 	};
+ 
+ 	sensor@4c {
+-		status = "okay";
++		status = "disabled";
+ 		compatible = "gs_mma7660";
+ 		reg = <0x4c>;
+ 		type = <SENSOR_TYPE_ACCEL>;
+@@ -636,35 +905,220 @@
+ 		layout = <2>;
+ 		reprobe_en = <1>;
+ 	};
++#endif
++
++	/*rtc pcf8563 i2c0-->i2c1*/
++	rtc@51 {
++                compatible = "nxp,pcf8563";
++                reg = <0x51>;
++        };
++
++	/*atecc608a i2c0->i2c1*/
++
++	/*i2c1->stm32 BMC: PB7,PB8*/
++
++	i2c_gpio_expander@3e{
++		#gpio-cells = <2>;
++		#interrupt-cells = <2>;
++		compatible = "semtech,sx1509q";
++		pinctrl-names = "default";
++                pinctrl-0 = <&sx1509_int>;
++		reg = <0x3e>;
++		interrupt-parent = <&gpio3>;/*gpio3_c2*/
++		interrupts = <23 0>;
++		gpio-controller;
++		interrupt-controller;
++		/*oscio_is_gpo;
++		reset_during_probe;*/
++		pullup_ena = <0xffff>;
++		pulldn_ena = <0x0>;
++		open_drain_ena = <0x0>;
++		polarity = <0x0>;
++	};
++
++	ads1115@48{
++		compatible = "ti,ads1115";
++		reg = <0x48>;
++		#address-cells = <1>;
++		#size-cells = <0>;
++
++		channel@0 {
++			reg = <0>;
++			ti,gain = <0>;
++			ti,datarate = <6>;
++			};
++
++                channel@1 {
++                        reg = <1>;
++                        ti,gain = <0>;
++                        ti,datarate = <6>;
++                        };
++                channel@2 {
++                        reg = <2>;
++                        ti,gain = <0>;
++                        ti,datarate = <6>;
++                        };
++                channel@3 {
++                        reg = <3>;
++                        ti,gain = <0>;
++                        ti,datarate = <6>;
++                        };
++                channel@4 {
++                        reg = <4>;
++                        ti,gain = <0>;
++                        ti,datarate = <6>;
++                        };
++                channel@5 {
++                        reg = <5>;
++                        ti,gain = <0>;
++                        ti,datarate = <6>;
++                        };
++                channel@6 {
++                        reg = <6>;
++                        ti,gain = <0>;
++                        ti,datarate = <6>;
++                        };
++                channel@7 {
++                        reg = <7>;
++                        ti,gain = <0>;
++                        ti,datarate = <6>;
++                        };
++		};		
++
++
++/*	tlv320_codec: codec@18 {
++                        #sound-dai-cells = <0>;
++                        compatible = "ti,tlv320aic3x";
++                        reg = <0x18>;
++                        clocks = <&cru SCLK_I2S2_OUT>;
++                        clock-names = "mclk";
++                        pinctrl-names = "default";
++                        pinctrl-0 = <&i2s2_2ch_mclk>;
++                        ai31xx-micbias-vg=<2>;
++                        gpio-reset=<&gpio3 23 GPIO_ACTIVE_LOW>;
++                        AVDD-supply = <&sound_3v3>;
++                        IOVDD-supply = <&sound_1v8>;
++                        DRVDD-supply = <&sound_3v3>;
++                        DVDD-supply = <&sound_1v8>;
++                        status = "okay";
++                };
++	
++*/
++	rt5640: rt5640@1c {
++                #sound-dai-cells = <0>;
++                compatible = "realtek,rt5640";
++                reg = <0x1c>;
++                clocks = <&cru SCLK_I2S1_OUT>;
++                clock-names = "mclk";
++                //realtek,in1-differential;
++                pinctrl-names = "default";
++                pinctrl-0 = <&i2s1_2ch_mclk>;
++                //hp-con-gpio = <&gpio4 21 GPIO_ACTIVE_HIGH>;
++                //hp-det-gpio = <&gpio4 28 GPIO_ACTIVE_LOW>;
++                //io-channels = <&saradc 4>;
++                //hp-det-adc-value = <500>;
++
++        };
++
++	//ads1115
++/*
++-channel:
++  0: Voltage over AIN0 and AIN1.
++  1: Voltage over AIN0 and AIN3.
++  2: Voltage over AIN1 and AIN3.
++  3: Voltage over AIN2 and AIN3.
++  4: Voltage over AIN0 and GND.
++  5: Voltage over AIN1 and GND.
++  6: Voltage over AIN2 and GND.
++  7: Voltage over AIN3 and GND.
++-gain:
++    0: +/- 6.144 V
++    1: +/- 4.096 V
++    2: +/- 2.048 V (default)
++    3: +/- 1.024 V
++    4: +/- 0.512 V
++    5: +/- 0.256 V
++ - data_rate in samples per second
++    0: 128
++    1: 250
++    2: 490
++    3: 920
++    4: 1600 (default)
++    5: 2400
++    6: 3300
++*/
++	/*/sys/devices/platform/ff190000.i2c/i2c-1/1-0048/in0_input*/
++/*
++	ads1115@48 {
++            compatible = "ti,ads1115";
++            reg = <0x48>;
++            #address-cells = <1>;
++            #size-cells = <0>;
++	    channel@0 {
++            reg = <0>; 
++            ti,gain = <3>;
++            ti,datarate = <5>;
++            };
++	    channel@1 {
++            reg = <1>;
++            ti,gain = <3>;
++            ti,datarate = <5>;
++            };
++	    channel@2 {
++            reg = <2>;
++            ti,gain = <3>;
++            ti,datarate = <5>;
++            };
++	    channel@3 {
++            reg = <3>;
++            ti,gain = <3>;
++            ti,datarate = <5>;
++            };
++	    channel@4 {
++            reg = <4>;
++            ti,gain = <3>;
++            ti,datarate = <5>;
++            };
++            channel@5 {
++            reg = <5>;
++            ti,gain = <3>;
++            ti,datarate = <5>;
++            };
++            channel@6 {
++            reg = <6>;
++            ti,gain = <3>;
++            ti,datarate = <5>;
++            };  
++
++	    channel@7 {
++            reg = <7>;
++            ti,gain = <3>;
++            ti,datarate = <5>;
++    	    };   				
++            
++    	};
++*/
++
+ };
+ 
+ &i2c2 {
+ 	status = "okay";
+ 
+-	clock-frequency = <100000>;
++	/*clock-frequency = <100000>;*/
+ 
+ 	/* These are relatively safe rise/fall times; TODO: measure */
+-	i2c-scl-falling-time-ns = <50>;
+-	i2c-scl-rising-time-ns = <300>;
++	/*i2c-scl-falling-time-ns = <50>;
++	i2c-scl-rising-time-ns = <300>;*/
+ 
+-	ov5695: ov5695@36 {
++/*	ov5695: ov5695@36 {
+ 		compatible = "ovti,ov5695";
+ 		reg = <0x36>;
+ 		clocks = <&cru SCLK_CIF_OUT>;
+ 		clock-names = "xvclk";
+-
+-		avdd-supply = <&vcc2v8_dvp>;
+-		dovdd-supply = <&vcc1v8_dvp>;
+-		dvdd-supply = <&vdd1v5_dvp>;
+-
+-		/*reset-gpios = <&gpio2 14 GPIO_ACTIVE_HIGH>;*/
++		//reset-gpios = <&gpio2 14 GPIO_ACTIVE_HIGH>;
+ 		pwdn-gpios = <&gpio2 14 GPIO_ACTIVE_HIGH>;
+ 		pinctrl-names = "default";
+ 		pinctrl-0 = <&cif_clkout_m0>;
+-		rockchip,camera-module-index = <0>;
+-		rockchip,camera-module-facing = "back";
+-		rockchip,camera-module-name = "TongJu";
+-		rockchip,camera-module-lens-name = "CHT842-MD";
+ 		port {
+ 			ucam_out: endpoint {
+ 				remote-endpoint = <&mipi_in_ucam>;
+@@ -672,6 +1126,127 @@
+ 			};
+ 		};
+ 	};
++*/
++
++	/*vm149c: vm149c@0c {
++                compatible = "silicon touch,vm149c";
++                status = "okay";
++                reg = <0x0c>;
++                rockchip,camera-module-index = <0>;
++                rockchip,camera-module-facing = "back";
++        };*/
++#if 0
++	gt1x: gt1x@5d {
++                status = "okay";
++                compatible = "goodix,gt1x";
++                reg = <0x5d>;
++                power-supply = <&vcc3v3_lcd>;
++                //goodix,rst-gpio = <&gpio0 RK_PB4 GPIO_ACTIVE_HIGH>;
++                //goodix,irq-gpio = <&gpio0 RK_PA5 IRQ_TYPE_LEVEL_LOW>;
++        };
++#endif
++
++#if 0
++	ov13850: ov13850@10 {
++                compatible = "ovti,ov13850";
++                status = "okay";
++                reg = <0x10>;
++                clocks = <&cru SCLK_CIF_OUT>;
++                clock-names = "xvclk";
++                /* avdd-supply = <>; */
++                /* dvdd-supply = <>; */
++                /* dovdd-supply = <>; */
++                /* reset-gpios = <>; */
++                reset-gpios = <&gpio3 RK_PC3 GPIO_ACTIVE_HIGH>; 
++                pwdn-gpios = <&gpio3 RK_PC1 GPIO_ACTIVE_HIGH>;
++                pinctrl-names = "default";
++                pinctrl-0 = <&cif_clkout_m0 &cam_rst &cam_pwr>;
++		rockchip,camera-module-index = <0>;
++                rockchip,camera-module-facing = "back";
++                rockchip,camera-module-name = "TongJu";
++                rockchip,camera-module-lens-name = "CHT842-MD";
++		/*lens-focus = <&vm149c>;*/
++                port {
++                        ucam_out: endpoint {
++                                remote-endpoint = <&mipi_in_ucam>;
++                                data-lanes = <1 2>;
++                        };
++                };
++        };
++#endif
++	 imx219: imx219@10 {
++                compatible = "sony,imx219";
++                reg = <0x10>;
++                clocks = <&cru SCLK_CIF_OUT>;
++                clock-names = "xvclk";
++                /*avdd-supply = <&vcc2v8_dvp>;
++                dovdd-supply = <&vdd1v5_dvp>;
++                dvdd-supply = <&vcc1v8_dvp>;*/
++		reset-gpios = <&gpio3 RK_PC3 GPIO_ACTIVE_HIGH>;
++                pwdn-gpios = <&gpio3 RK_PC1 GPIO_ACTIVE_HIGH>;
++                pinctrl-names = "default";
++                pinctrl-0 = <&cif_clkout_m0 &cam_rst &cam_pwr>;
++                rockchip,camera-module-index = <0>;
++                rockchip,camera-module-facing = "back";
++                rockchip,camera-module-name = "TongJu";
++                rockchip,camera-module-lens-name = "CHT842-MD";
++                port {
++                        ucam_out: endpoint {
++                                remote-endpoint = <&mipi_in_ucam>;
++                                data-lanes = <1 2>;
++                        };
++                };
++        };
++
++#if DSI2HDMI_BRIDGE == 2
++	lt9611@3b {
++		compatible = "firefly,lt9611";
++		reg = <0x3b>;
++		reset-gpios = <&gpio0 RK_PB4 GPIO_ACTIVE_LOW>;
++		irq-gpios = <&gpio0 RK_PB5 GPIO_ACTIVE_LOW>;
++	};
++#endif
++#if DSI2HDMI_BRIDGE == 1
++	adv7535: adv7535@39 {
++                compatible = "lanxus_i2c_adv7535";
++                reg = <0x39>;
++        }; 
++#endif
++
++#if DSI2HDMI_BRIDGE == 1
++	adv_bridge: adv7535@3d {
++		compatible = "adi,adv7533";
++	// ok, marked by johnson to test	
++		//reg = <0x39>;
++		//adi,addr-cec = <0x3c>;	
++	// end of marked
++	
++		reg = <0x39>;
++
++                  adi,addr-cec = <0x3c>;                                                              
++                adi,dsi-channel = <1>; 				
++		adi,dsi-lanes = <4>;
++		pinctrl-0 = <&pinctrl_7535>;
++		interrupt-parent = <&gpio3>;
++		interrupts = <16 IRQ_TYPE_LEVEL_LOW>;
++
++		status = "okay";
++		
++		ports {
++			#address-cells = <1>;
++                	#size-cells = <0>;
++
++		port@0 {
++			reg=<0>;
++
++			adv7535_bridge_out: endpoint {
++				remote-endpoint = <&adv7535_panel_in>;
++			};
++		     };
++		};
++	};
++#endif
++
+ };
+ 
+ &i2s1_2ch {
+@@ -679,20 +1254,30 @@
+ 	#sound-dai-cells = <0>;
+ };
+ 
++#if 0
++&i2s2_2ch {
++        status = "okay";
++//	rockchip,bclk-fs = <64>;
++        #sound-dai-cells = <0>;
++};
++#endif
++
+ &io_domains {
+ 	status = "okay";
+ 
+-	vccio1-supply = <&vcc_3v0>;
++	vccio1-supply = <&vcc1v8_soc>;
+ 	vccio2-supply = <&vccio_sd>;
+ 	vccio3-supply = <&vcc_3v0>;
+-	vccio4-supply = <&vcc3v0_pmu>;
+-	vccio5-supply = <&vcc_3v0>;
++	 vccio4-supply = <&vcc1v8_dvp>; /*<&vcc3v0_pmu>;*/
++         vccio5-supply = <&vcc1v8_soc>; /*vcc_3v0*/
++	
+ };
+ 
+ &isp_mmu {
+ 	status = "okay";
+ };
+ 
++
+ &mipi_dphy_rx0 {
+ 	status = "okay";
+ 
+@@ -733,13 +1318,14 @@
+ 	status = "okay";
+ 
+ 	pmuio1-supply = <&vcc3v0_pmu>;
+-	pmuio2-supply = <&vcc3v0_pmu>;
++	pmuio2-supply = <&vcc1v8_soc>; /* <&vcc3v0_pmu>;*/
+ };
+ 
+ &pwm1 {
+ 	status = "okay";
+ };
+ 
++
+ &rk_rga {
+ 	status = "okay";
+ };
+@@ -769,6 +1355,8 @@
+ };
+ 
+ &sdmmc {
++/*	clock-frequency = <37500000>;
++	max-frequency = <37500000>;*/
+ 	bus-width = <4>;
+ 	cap-mmc-highspeed;
+ 	cap-sd-highspeed;
+@@ -781,35 +1369,61 @@
+ 	sd-uhs-sdr50;
+ 	sd-uhs-sdr104;
+ 	vqmmc-supply = <&vccio_sd>;
+-	vmmc-supply = <&vcc_sd>;
++	vmmc-supply = <&vcc_sd_pwr>;
+ 	status = "okay";
+ };
+ 
++&emmc {
++        bus-width = <8>;
++        cap-mmc-highspeed;
++        mmc-hs200-1_8v;
++        supports-emmc;
++        disable-wp;
++        non-removable;
++        num-slots = <1>;
++        status = "okay";
++};
++
++
+ &sdio {
+-	bus-width = <4>;
++/*	bus-width = <4>;
+ 	cap-sd-highspeed;
+ 	supports-sdio;
+ 	ignore-pm-notify;
+ 	keep-power-in-suspend;
+ 	non-removable;
+ 	mmc-pwrseq = <&sdio_pwrseq>;
+-	sd-uhs-sdr104;
+-	status = "okay";
++	sd-uhs-sdr104;*/
++	status = "disabled";
+ };
+ 
+ &tsadc {
+-	pinctrl-names = "gpio", "otpout";
++	pinctrl-names = "init", "default";
+ 	pinctrl-0 = <&tsadc_otp_gpio>;
+ 	pinctrl-1 = <&tsadc_otp_out>;
+ 	status = "okay";
+ };
+ 
++/*change to uart0 debug*/
++&uart0 {
++        pinctrl-names = "default";
++        pinctrl-0 = <&uart0_xfer /*&uart0_cts &uart0_rts*/>;
++        status = "okay";
++};
++
+ &uart1 {
+ 	pinctrl-names = "default";
+-	pinctrl-0 = <&uart1_xfer &uart1_cts>;
++	pinctrl-0 = <&uart1_xfer /*&uart1_cts &uart1_rts*/>;
+ 	status = "okay";
+ };
+ 
++/*uart2 debug change to uart2m1*/
++&uart2 {
++        pinctrl-names = "default";
++        pinctrl-0 = <&uart2m1_xfer>;
++        status = "disabled";
++};
++
+ &u2phy {
+ 	status = "okay";
+ 
+@@ -855,11 +1469,11 @@
+ };
+ 
+ &pinctrl {
+-	headphone {
++	/*headphone {
+ 		hp_det: hp-det {
+ 			rockchip,pins = <2 RK_PB0 RK_FUNC_GPIO &pcfg_pull_down>;
+ 		};
+-	};
++	};*/
+ 
+ 	pmic {
+ 		pmic_int: pmic_int {
+@@ -883,11 +1497,76 @@
+ 		};
+ 	};
+ 
+-	sdio-pwrseq {
++	can {
++		can_int: can_int {
++			rockchip,pins =
++                                <0 RK_PC1 RK_FUNC_GPIO &pcfg_pull_up>;
++                };
++
++	};
++  	eth_phy {
++		eth_phy_pwr: eth_phy_pwr {
++                        rockchip,pins =
++                                <2 RK_PB0 RK_FUNC_GPIO &pcfg_pull_none>;
++                };
++
++        };
++
++	sdmmc_pwr  {
++                sdmmc_pwr: sdmmc_pwr {
++                        rockchip,pins = <0 RK_PA2 RK_FUNC_GPIO &pcfg_output_high>;
++                };
++        };
++
++	ov13850 {
++
++		 cam_rst: cam_rst {
++                        rockchip,pins =
++                                <3 RK_PC3 RK_FUNC_GPIO &pcfg_pull_up>;
++                };
++
++		 cam_pwr: cam_pwr {
++                        rockchip,pins =
++                                <3 RK_PC1 RK_FUNC_GPIO &pcfg_pull_up>;
++                };
++
++
++	};
++
++	i2c_gpio {
++		sx1509_int: sx1509_int{
++			rockchip,pins =
++			 <3 RK_PC2 RK_FUNC_GPIO &pcfg_pull_up>;
++		};
++	};
++
++	lcd_vdd_gpio {
++                lcd_vdd_gpio_en: lcd_vdd_gpio_en {
++                        rockchip,pins =
++                         <3 RK_PA4 RK_FUNC_GPIO &pcfg_pull_up>;
++                };
++        };
++
++
++	px30_lanxus_gpioset{
++		lanxus_gpioset: lanxus-gpioset {
++			rockchip,pins = <3 RK_PA6 RK_FUNC_GPIO &pcfg_output_high>;
++		};
++	};
++
++
++	adv7535-int {
++                pinctrl_7535: pinctrl-7535 {
++                        rockchip,pins = <3 RK_PC0 RK_FUNC_GPIO &pcfg_pull_up>;
++                };
++        };
++
++
++	/*sdio-pwrseq {
+ 		wifi_enable_h: wifi-enable-h {
+ 			rockchip,pins = <0 RK_PA2 RK_FUNC_GPIO &pcfg_pull_none>;
+ 		};
+-	};
++	};*/
+ };
+ 
+ /* DON'T PUT ANYTHING BELOW HERE.  PUT IT ABOVE PINCTRL */
+diff --git a/arch/arm64/boot/dts/rockchip/px30-evb-ddr3-v10.dtsi b/arch/arm64/boot/dts/rockchip/px30-evb-ddr3-v10.dtsi
+index f1ff3ff..55444b8 100644
+--- a/arch/arm64/boot/dts/rockchip/px30-evb-ddr3-v10.dtsi
++++ b/arch/arm64/boot/dts/rockchip/px30-evb-ddr3-v10.dtsi
+@@ -576,13 +576,13 @@
+ 				};
+ 			};
+ 
+-			vcc5v0_host: SWITCH_REG2 {
++			vcc5v0_host: SWITCH_REG1 {
+ 				regulator-always-on;
+ 				regulator-boot-on;
+ 				regulator-name = "vcc5v0_host";
+ 			};
+ 
+-			vcc3v3_lcd: SWITCH_REG1 {
++			vcc3v3_lcd: SWITCH_REG2 {
+ 				regulator-boot-on;
+ 				regulator-name = "vcc3v3_lcd";
+ 			};
+diff --git a/arch/arm64/boot/dts/rockchip/rk3326-linux.dtsi b/arch/arm64/boot/dts/rockchip/rk3326-linux.dtsi
+index 3672ce7..9fbb720 100644
+--- a/arch/arm64/boot/dts/rockchip/rk3326-linux.dtsi
++++ b/arch/arm64/boot/dts/rockchip/rk3326-linux.dtsi
+@@ -44,7 +44,9 @@
+ 	compatible = "rockchip,linux", "rockchip,rk3326";
+ 
+ 	chosen {
+-		bootargs = "earlycon=uart8250,mmio32,0xff160000 swiotlb=1 console=ttyFIQ0 rw root=PARTUUID=614e0000-0000 rootwait";
++ 		//bootargs = "earlycon=uart8250,mmio32,0xff160000 swiotlb=1 console=ttyFIQ0 rw root=PARTUUID=614e0000-0000 rootwait";
++		bootargs = "earlycon=uart8250,mmio32,0xff160000 swiotlb=1 console=ttyFIQ0 rw root=/dev/mmcblk1p4 rootwait";
++	/*	 bootargs = "console=tty1 rw root=PARTUUID=614e0000-0000 rootwait";*/
+ 	};
+ 
+ 	fiq-debugger {
+@@ -53,10 +55,10 @@
+ 		rockchip,wake-irq = <0>;
+ 		/* If enable uart uses irq instead of fiq */
+ 		rockchip,irq-mode-enable = <0>;
+-		rockchip,baudrate = <1500000>;  /* Only 115200 and 1500000 */
++		rockchip,baudrate = <115200>;  /* Only 115200 and 1500000 */
+ 		interrupts = <GIC_SPI 127 IRQ_TYPE_LEVEL_LOW>;
+ 		pinctrl-names = "default";
+-		pinctrl-0 = <&uart2m0_xfer>;
++		pinctrl-0 = <&uart2m1_xfer>;/*change to uart2m1*/
+ 		status = "okay";
+ 	};
+ 
+diff --git a/arch/arm64/configs/adlink-px30_config b/arch/arm64/configs/adlink-px30_config
+new file mode 100644
+index 0000000..091482f
+--- /dev/null
++++ b/arch/arm64/configs/adlink-px30_config
+@@ -0,0 +1,4410 @@
++#
++# Automatically generated file; DO NOT EDIT.
++# Linux/arm64 4.4.185 Kernel Configuration
++#
++CONFIG_ARM64=y
++CONFIG_64BIT=y
++CONFIG_ARCH_PHYS_ADDR_T_64BIT=y
++CONFIG_MMU=y
++CONFIG_ARCH_MMAP_RND_BITS_MIN=18
++CONFIG_ARCH_MMAP_RND_BITS_MAX=24
++CONFIG_ARCH_MMAP_RND_COMPAT_BITS_MIN=11
++CONFIG_ARCH_MMAP_RND_COMPAT_BITS_MAX=16
++CONFIG_ARM64_PAGE_SHIFT=12
++CONFIG_ARM64_CONT_SHIFT=4
++CONFIG_NO_IOPORT_MAP=y
++CONFIG_STACKTRACE_SUPPORT=y
++CONFIG_ILLEGAL_POINTER_VALUE=0xdead000000000000
++CONFIG_LOCKDEP_SUPPORT=y
++CONFIG_TRACE_IRQFLAGS_SUPPORT=y
++CONFIG_RWSEM_XCHGADD_ALGORITHM=y
++CONFIG_GENERIC_BUG=y
++CONFIG_GENERIC_BUG_RELATIVE_POINTERS=y
++CONFIG_GENERIC_HWEIGHT=y
++CONFIG_GENERIC_CSUM=y
++CONFIG_GENERIC_CALIBRATE_DELAY=y
++CONFIG_ZONE_DMA=y
++CONFIG_HAVE_GENERIC_RCU_GUP=y
++CONFIG_ARCH_DMA_ADDR_T_64BIT=y
++CONFIG_NEED_DMA_MAP_STATE=y
++CONFIG_NEED_SG_DMA_LENGTH=y
++CONFIG_SMP=y
++CONFIG_SWIOTLB=y
++CONFIG_IOMMU_HELPER=y
++CONFIG_KERNEL_MODE_NEON=y
++CONFIG_FIX_EARLYCON_MEM=y
++CONFIG_PGTABLE_LEVELS=3
++CONFIG_DEFCONFIG_LIST="/lib/modules/$UNAME_RELEASE/.config"
++CONFIG_IRQ_WORK=y
++CONFIG_BUILDTIME_EXTABLE_SORT=y
++CONFIG_THREAD_INFO_IN_TASK=y
++
++#
++# General setup
++#
++CONFIG_INIT_ENV_ARG_LIMIT=32
++CONFIG_CROSS_COMPILE=""
++# CONFIG_COMPILE_TEST is not set
++CONFIG_LOCALVERSION="-rockchip-standard"
++CONFIG_LOCALVERSION_AUTO=y
++CONFIG_DEFAULT_HOSTNAME="localhost"
++CONFIG_SWAP=y
++CONFIG_SYSVIPC=y
++CONFIG_SYSVIPC_SYSCTL=y
++# CONFIG_POSIX_MQUEUE is not set
++CONFIG_CROSS_MEMORY_ATTACH=y
++CONFIG_FHANDLE=y
++CONFIG_USELIB=y
++# CONFIG_AUDIT is not set
++CONFIG_HAVE_ARCH_AUDITSYSCALL=y
++
++#
++# IRQ subsystem
++#
++CONFIG_GENERIC_IRQ_PROBE=y
++CONFIG_GENERIC_IRQ_SHOW=y
++CONFIG_GENERIC_IRQ_SHOW_LEVEL=y
++CONFIG_GENERIC_IRQ_MIGRATION=y
++CONFIG_HARDIRQS_SW_RESEND=y
++CONFIG_GENERIC_IRQ_CHIP=y
++CONFIG_IRQ_DOMAIN=y
++CONFIG_IRQ_DOMAIN_HIERARCHY=y
++CONFIG_HANDLE_DOMAIN_IRQ=y
++# CONFIG_IRQ_DOMAIN_DEBUG is not set
++CONFIG_IRQ_FORCED_THREADING=y
++CONFIG_SPARSE_IRQ=y
++CONFIG_GENERIC_TIME_VSYSCALL=y
++CONFIG_GENERIC_CLOCKEVENTS=y
++CONFIG_ARCH_HAS_TICK_BROADCAST=y
++CONFIG_GENERIC_CLOCKEVENTS_BROADCAST=y
++
++#
++# Timers subsystem
++#
++CONFIG_TICK_ONESHOT=y
++CONFIG_NO_HZ_COMMON=y
++# CONFIG_HZ_PERIODIC is not set
++CONFIG_NO_HZ_IDLE=y
++# CONFIG_NO_HZ_FULL is not set
++CONFIG_NO_HZ=y
++CONFIG_HIGH_RES_TIMERS=y
++
++#
++# CPU/Task time and stats accounting
++#
++CONFIG_TICK_CPU_ACCOUNTING=y
++# CONFIG_VIRT_CPU_ACCOUNTING_GEN is not set
++# CONFIG_IRQ_TIME_ACCOUNTING is not set
++# CONFIG_SCHED_WALT is not set
++# CONFIG_BSD_PROCESS_ACCT is not set
++# CONFIG_TASKSTATS is not set
++
++#
++# RCU Subsystem
++#
++CONFIG_TREE_RCU=y
++# CONFIG_RCU_EXPERT is not set
++CONFIG_SRCU=y
++# CONFIG_TASKS_RCU is not set
++CONFIG_RCU_STALL_COMMON=y
++# CONFIG_TREE_RCU_TRACE is not set
++# CONFIG_RCU_EXPEDITE_BOOT is not set
++# CONFIG_BUILD_BIN2C is not set
++# CONFIG_IKCONFIG is not set
++CONFIG_LOG_BUF_SHIFT=18
++CONFIG_LOG_CPU_MAX_BUF_SHIFT=12
++CONFIG_GENERIC_SCHED_CLOCK=y
++CONFIG_CGROUPS=y
++# CONFIG_CGROUP_DEBUG is not set
++CONFIG_CGROUP_FREEZER=y
++# CONFIG_CGROUP_PIDS is not set
++CONFIG_CGROUP_DEVICE=y
++CONFIG_CPUSETS=y
++CONFIG_PROC_PID_CPUSET=y
++CONFIG_CGROUP_CPUACCT=y
++# CONFIG_MEMCG is not set
++# CONFIG_CGROUP_PERF is not set
++CONFIG_CGROUP_SCHED=y
++CONFIG_FAIR_GROUP_SCHED=y
++CONFIG_CFS_BANDWIDTH=y
++# CONFIG_RT_GROUP_SCHED is not set
++# CONFIG_BLK_CGROUP is not set
++# CONFIG_CHECKPOINT_RESTORE is not set
++CONFIG_NAMESPACES=y
++CONFIG_UTS_NS=y
++CONFIG_IPC_NS=y
++CONFIG_USER_NS=y
++CONFIG_PID_NS=y
++CONFIG_NET_NS=y
++# CONFIG_SCHED_AUTOGROUP is not set
++# CONFIG_SCHED_TUNE is not set
++CONFIG_DEFAULT_USE_ENERGY_AWARE=y
++# CONFIG_SYSFS_DEPRECATED is not set
++CONFIG_RELAY=y
++CONFIG_BLK_DEV_INITRD=y
++CONFIG_INITRAMFS_SOURCE=""
++CONFIG_RD_GZIP=y
++CONFIG_RD_BZIP2=y
++CONFIG_RD_LZMA=y
++CONFIG_RD_XZ=y
++CONFIG_RD_LZO=y
++CONFIG_RD_LZ4=y
++# CONFIG_INITRD_ASYNC is not set
++# CONFIG_CC_OPTIMIZE_FOR_PERFORMANCE is not set
++CONFIG_CC_OPTIMIZE_FOR_SIZE=y
++CONFIG_SYSCTL=y
++CONFIG_ANON_INODES=y
++CONFIG_HAVE_UID16=y
++CONFIG_SYSCTL_EXCEPTION_TRACE=y
++CONFIG_BPF=y
++CONFIG_EXPERT=y
++CONFIG_UID16=y
++CONFIG_MULTIUSER=y
++# CONFIG_SGETMASK_SYSCALL is not set
++CONFIG_SYSFS_SYSCALL=y
++# CONFIG_SYSCTL_SYSCALL is not set
++CONFIG_KALLSYMS=y
++# CONFIG_KALLSYMS_ALL is not set
++CONFIG_PRINTK=y
++CONFIG_BUG=y
++CONFIG_ELF_CORE=y
++CONFIG_BASE_FULL=y
++CONFIG_FUTEX=y
++CONFIG_EPOLL=y
++CONFIG_SIGNALFD=y
++CONFIG_TIMERFD=y
++CONFIG_EVENTFD=y
++# CONFIG_BPF_SYSCALL is not set
++CONFIG_SHMEM=y
++CONFIG_AIO=y
++CONFIG_ADVISE_SYSCALLS=y
++# CONFIG_USERFAULTFD is not set
++CONFIG_MEMBARRIER=y
++CONFIG_EMBEDDED=y
++CONFIG_HAVE_PERF_EVENTS=y
++CONFIG_PERF_USE_VMALLOC=y
++
++#
++# Kernel Performance Events And Counters
++#
++CONFIG_PERF_EVENTS=y
++# CONFIG_DEBUG_PERF_USE_VMALLOC is not set
++CONFIG_VM_EVENT_COUNTERS=y
++CONFIG_SLUB_DEBUG=y
++# CONFIG_COMPAT_BRK is not set
++# CONFIG_SLAB is not set
++CONFIG_SLUB=y
++# CONFIG_SLOB is not set
++CONFIG_SLUB_CPU_PARTIAL=y
++# CONFIG_SYSTEM_DATA_VERIFICATION is not set
++CONFIG_PROFILING=y
++CONFIG_TRACEPOINTS=y
++# CONFIG_KPROBES is not set
++# CONFIG_JUMP_LABEL is not set
++# CONFIG_UPROBES is not set
++# CONFIG_HAVE_64BIT_ALIGNED_ACCESS is not set
++CONFIG_HAVE_EFFICIENT_UNALIGNED_ACCESS=y
++CONFIG_HAVE_KPROBES=y
++CONFIG_HAVE_KRETPROBES=y
++CONFIG_HAVE_ARCH_TRACEHOOK=y
++CONFIG_HAVE_DMA_ATTRS=y
++CONFIG_HAVE_DMA_CONTIGUOUS=y
++CONFIG_GENERIC_SMP_IDLE_THREAD=y
++CONFIG_GENERIC_IDLE_POLL_SETUP=y
++CONFIG_HAVE_REGS_AND_STACK_ACCESS_API=y
++CONFIG_HAVE_CLK=y
++CONFIG_HAVE_DMA_API_DEBUG=y
++CONFIG_HAVE_HW_BREAKPOINT=y
++CONFIG_HAVE_PERF_REGS=y
++CONFIG_HAVE_PERF_USER_STACK_DUMP=y
++CONFIG_HAVE_ARCH_JUMP_LABEL=y
++CONFIG_HAVE_RCU_TABLE_FREE=y
++CONFIG_HAVE_ALIGNED_STRUCT_PAGE=y
++CONFIG_HAVE_CMPXCHG_LOCAL=y
++CONFIG_HAVE_CMPXCHG_DOUBLE=y
++CONFIG_ARCH_WANT_COMPAT_IPC_PARSE_VERSION=y
++CONFIG_HAVE_ARCH_SECCOMP_FILTER=y
++CONFIG_SECCOMP_FILTER=y
++CONFIG_HAVE_CC_STACKPROTECTOR=y
++# CONFIG_CC_STACKPROTECTOR is not set
++CONFIG_CC_STACKPROTECTOR_NONE=y
++# CONFIG_CC_STACKPROTECTOR_REGULAR is not set
++# CONFIG_CC_STACKPROTECTOR_STRONG is not set
++CONFIG_HAVE_CONTEXT_TRACKING=y
++CONFIG_HAVE_VIRT_CPU_ACCOUNTING_GEN=y
++CONFIG_HAVE_IRQ_TIME_ACCOUNTING=y
++CONFIG_HAVE_ARCH_TRANSPARENT_HUGEPAGE=y
++CONFIG_HAVE_ARCH_HUGE_VMAP=y
++CONFIG_MODULES_USE_ELF_RELA=y
++CONFIG_ARCH_HAS_ELF_RANDOMIZE=y
++CONFIG_HAVE_ARCH_MMAP_RND_BITS=y
++CONFIG_ARCH_MMAP_RND_BITS=18
++CONFIG_HAVE_ARCH_MMAP_RND_COMPAT_BITS=y
++CONFIG_ARCH_MMAP_RND_COMPAT_BITS=11
++CONFIG_CLONE_BACKWARDS=y
++CONFIG_OLD_SIGSUSPEND3=y
++CONFIG_COMPAT_OLD_SIGACTION=y
++
++#
++# GCOV-based kernel profiling
++#
++# CONFIG_GCOV_KERNEL is not set
++CONFIG_ARCH_HAS_GCOV_PROFILE_ALL=y
++CONFIG_HAVE_GENERIC_DMA_COHERENT=y
++CONFIG_SLABINFO=y
++CONFIG_RT_MUTEXES=y
++CONFIG_BASE_SMALL=0
++CONFIG_MODULES=y
++CONFIG_MODULE_FORCE_LOAD=y
++CONFIG_MODULE_UNLOAD=y
++CONFIG_MODULE_FORCE_UNLOAD=y
++# CONFIG_MODVERSIONS is not set
++# CONFIG_MODULE_SRCVERSION_ALL is not set
++# CONFIG_MODULE_SIG is not set
++# CONFIG_MODULE_COMPRESS is not set
++CONFIG_MODULES_TREE_LOOKUP=y
++CONFIG_BLOCK=y
++CONFIG_BLK_DEV_BSG=y
++# CONFIG_BLK_DEV_BSGLIB is not set
++# CONFIG_BLK_DEV_INTEGRITY is not set
++# CONFIG_BLK_CMDLINE_PARSER is not set
++
++#
++# Partition Types
++#
++CONFIG_PARTITION_ADVANCED=y
++# CONFIG_ACORN_PARTITION is not set
++# CONFIG_AIX_PARTITION is not set
++# CONFIG_OSF_PARTITION is not set
++# CONFIG_AMIGA_PARTITION is not set
++# CONFIG_ATARI_PARTITION is not set
++# CONFIG_MAC_PARTITION is not set
++CONFIG_MSDOS_PARTITION=y
++# CONFIG_BSD_DISKLABEL is not set
++# CONFIG_MINIX_SUBPARTITION is not set
++# CONFIG_SOLARIS_X86_PARTITION is not set
++# CONFIG_UNIXWARE_DISKLABEL is not set
++# CONFIG_LDM_PARTITION is not set
++# CONFIG_SGI_PARTITION is not set
++# CONFIG_ULTRIX_PARTITION is not set
++# CONFIG_SUN_PARTITION is not set
++# CONFIG_KARMA_PARTITION is not set
++CONFIG_EFI_PARTITION=y
++# CONFIG_SYSV68_PARTITION is not set
++CONFIG_RK_PARTITION=y
++# CONFIG_CMDLINE_PARTITION is not set
++CONFIG_BLOCK_COMPAT=y
++
++#
++# IO Schedulers
++#
++CONFIG_IOSCHED_NOOP=y
++CONFIG_IOSCHED_DEADLINE=y
++CONFIG_IOSCHED_CFQ=y
++# CONFIG_DEFAULT_DEADLINE is not set
++CONFIG_DEFAULT_CFQ=y
++# CONFIG_DEFAULT_NOOP is not set
++CONFIG_DEFAULT_IOSCHED="cfq"
++CONFIG_ASN1=y
++CONFIG_UNINLINE_SPIN_UNLOCK=y
++CONFIG_ARCH_SUPPORTS_ATOMIC_RMW=y
++CONFIG_MUTEX_SPIN_ON_OWNER=y
++CONFIG_RWSEM_SPIN_ON_OWNER=y
++CONFIG_LOCK_SPIN_ON_OWNER=y
++CONFIG_FREEZER=y
++
++#
++# Platform selection
++#
++# CONFIG_ARCH_BCM_IPROC is not set
++# CONFIG_ARCH_BERLIN is not set
++# CONFIG_ARCH_EXYNOS7 is not set
++# CONFIG_ARCH_LAYERSCAPE is not set
++# CONFIG_ARCH_HISI is not set
++# CONFIG_ARCH_MEDIATEK is not set
++# CONFIG_ARCH_QCOM is not set
++CONFIG_ARCH_ROCKCHIP=y
++# CONFIG_ARCH_SEATTLE is not set
++# CONFIG_ARCH_STRATIX10 is not set
++# CONFIG_ARCH_TEGRA is not set
++# CONFIG_ARCH_SPRD is not set
++# CONFIG_ARCH_THUNDER is not set
++# CONFIG_ARCH_VEXPRESS is not set
++# CONFIG_ARCH_XGENE is not set
++# CONFIG_ARCH_ZYNQMP is not set
++
++#
++# Bus support
++#
++# CONFIG_PCI is not set
++# CONFIG_PCI_DOMAINS is not set
++# CONFIG_PCI_DOMAINS_GENERIC is not set
++# CONFIG_PCI_SYSCALL is not set
++
++#
++# Kernel Features
++#
++
++#
++# ARM errata workarounds via the alternatives framework
++#
++# CONFIG_ARM64_ERRATUM_826319 is not set
++# CONFIG_ARM64_ERRATUM_827319 is not set
++# CONFIG_ARM64_ERRATUM_824069 is not set
++# CONFIG_ARM64_ERRATUM_819472 is not set
++# CONFIG_ARM64_ERRATUM_832075 is not set
++CONFIG_ARM64_ERRATUM_845719=y
++CONFIG_ARM64_ERRATUM_843419=y
++# CONFIG_ARM64_ERRATUM_1024718 is not set
++# CONFIG_CAVIUM_ERRATUM_22375 is not set
++# CONFIG_CAVIUM_ERRATUM_23154 is not set
++CONFIG_CAVIUM_ERRATUM_27456=y
++CONFIG_ARM64_4K_PAGES=y
++# CONFIG_ARM64_16K_PAGES is not set
++# CONFIG_ARM64_64K_PAGES is not set
++CONFIG_ARM64_VA_BITS_39=y
++# CONFIG_ARM64_VA_BITS_48 is not set
++CONFIG_ARM64_VA_BITS=39
++# CONFIG_CPU_BIG_ENDIAN is not set
++CONFIG_SCHED_MC=y
++# CONFIG_SCHED_SMT is not set
++CONFIG_NR_CPUS=8
++CONFIG_HOTPLUG_CPU=y
++# CONFIG_PREEMPT_NONE is not set
++CONFIG_PREEMPT_VOLUNTARY=y
++# CONFIG_PREEMPT is not set
++# CONFIG_HZ_100 is not set
++# CONFIG_HZ_250 is not set
++# CONFIG_HZ_300 is not set
++CONFIG_HZ_1000=y
++CONFIG_HZ=1000
++CONFIG_SCHED_HRTICK=y
++CONFIG_ARCH_SUPPORTS_DEBUG_PAGEALLOC=y
++CONFIG_ARCH_HAS_HOLES_MEMORYMODEL=y
++CONFIG_ARCH_SPARSEMEM_ENABLE=y
++CONFIG_ARCH_SPARSEMEM_DEFAULT=y
++CONFIG_ARCH_SELECT_MEMORY_MODEL=y
++CONFIG_HAVE_ARCH_PFN_VALID=y
++CONFIG_HW_PERF_EVENTS=y
++CONFIG_SYS_SUPPORTS_HUGETLBFS=y
++CONFIG_ARCH_WANT_HUGE_PMD_SHARE=y
++CONFIG_ARCH_HAS_CACHE_LINE_SIZE=y
++CONFIG_SELECT_MEMORY_MODEL=y
++CONFIG_SPARSEMEM_MANUAL=y
++CONFIG_SPARSEMEM=y
++CONFIG_HAVE_MEMORY_PRESENT=y
++CONFIG_SPARSEMEM_EXTREME=y
++CONFIG_SPARSEMEM_VMEMMAP_ENABLE=y
++CONFIG_SPARSEMEM_VMEMMAP=y
++CONFIG_HAVE_MEMBLOCK=y
++CONFIG_NO_BOOTMEM=y
++# CONFIG_HAVE_BOOTMEM_INFO_NODE is not set
++CONFIG_SPLIT_PTLOCK_CPUS=4
++# CONFIG_COMPACTION is not set
++CONFIG_PHYS_ADDR_T_64BIT=y
++CONFIG_ZONE_DMA_FLAG=1
++CONFIG_BOUNCE=y
++# CONFIG_KSM is not set
++CONFIG_DEFAULT_MMAP_MIN_ADDR=32768
++# CONFIG_TRANSPARENT_HUGEPAGE is not set
++# CONFIG_CLEANCACHE is not set
++# CONFIG_FRONTSWAP is not set
++# CONFIG_CMA is not set
++# CONFIG_ZPOOL is not set
++# CONFIG_ZBUD is not set
++CONFIG_ZSMALLOC=y
++# CONFIG_PGTABLE_MAPPING is not set
++# CONFIG_ZSMALLOC_STAT is not set
++CONFIG_GENERIC_EARLY_IOREMAP=y
++# CONFIG_IDLE_PAGE_TRACKING is not set
++CONFIG_FRAME_VECTOR=y
++CONFIG_SECCOMP=y
++# CONFIG_KEXEC is not set
++# CONFIG_CRASH_DUMP is not set
++# CONFIG_XEN is not set
++CONFIG_FORCE_MAX_ZONEORDER=11
++CONFIG_UNMAP_KERNEL_AT_EL0=y
++CONFIG_ARMV8_DEPRECATED=y
++CONFIG_SWP_EMULATION=y
++CONFIG_CP15_BARRIER_EMULATION=y
++CONFIG_SETEND_EMULATION=y
++# CONFIG_ARM64_SW_TTBR0_PAN is not set
++
++#
++# ARMv8.1 architectural features
++#
++CONFIG_ARM64_HW_AFDBM=y
++CONFIG_ARM64_PAN=y
++# CONFIG_ARM64_LSE_ATOMICS is not set
++CONFIG_ARM64_UAO=y
++CONFIG_ARM64_MODULE_CMODEL_LARGE=y
++# CONFIG_RANDOMIZE_BASE is not set
++
++#
++# Boot options
++#
++CONFIG_CMDLINE=""
++# CONFIG_EFI is not set
++# CONFIG_BUILD_ARM64_APPENDED_DTB_IMAGE is not set
++
++#
++# Userspace binary formats
++#
++CONFIG_BINFMT_ELF=y
++CONFIG_COMPAT_BINFMT_ELF=y
++CONFIG_CORE_DUMP_DEFAULT_ELF_HEADERS=y
++CONFIG_BINFMT_SCRIPT=y
++# CONFIG_HAVE_AOUT is not set
++# CONFIG_BINFMT_MISC is not set
++CONFIG_COREDUMP=y
++CONFIG_COMPAT=y
++CONFIG_SYSVIPC_COMPAT=y
++CONFIG_KEYS_COMPAT=y
++
++#
++# Power management options
++#
++CONFIG_SUSPEND=y
++CONFIG_SUSPEND_FREEZER=y
++# CONFIG_SUSPEND_SKIP_SYNC is not set
++CONFIG_HAS_WAKELOCK=y
++CONFIG_WAKELOCK=y
++# CONFIG_HIBERNATION is not set
++CONFIG_PM_SLEEP=y
++CONFIG_PM_SLEEP_SMP=y
++# CONFIG_PM_AUTOSLEEP is not set
++# CONFIG_PM_WAKELOCKS is not set
++CONFIG_PM=y
++CONFIG_PM_DEBUG=y
++CONFIG_PM_ADVANCED_DEBUG=y
++# CONFIG_PM_TEST_SUSPEND is not set
++CONFIG_PM_SLEEP_DEBUG=y
++CONFIG_PM_OPP=y
++CONFIG_PM_CLK=y
++CONFIG_PM_GENERIC_DOMAINS=y
++CONFIG_WQ_POWER_EFFICIENT_DEFAULT=y
++CONFIG_PM_GENERIC_DOMAINS_SLEEP=y
++CONFIG_PM_GENERIC_DOMAINS_OF=y
++CONFIG_CPU_PM=y
++CONFIG_ARCH_HIBERNATION_POSSIBLE=y
++CONFIG_ARCH_SUSPEND_POSSIBLE=y
++
++#
++# CPU Power Management
++#
++
++#
++# CPU Idle
++#
++CONFIG_CPU_IDLE=y
++CONFIG_CPU_IDLE_GOV_LADDER=y
++CONFIG_CPU_IDLE_GOV_MENU=y
++CONFIG_DT_IDLE_STATES=y
++
++#
++# ARM CPU Idle Drivers
++#
++CONFIG_ARM_CPUIDLE=y
++# CONFIG_ARCH_NEEDS_CPU_IDLE_COUPLED is not set
++
++#
++# CPU Frequency scaling
++#
++CONFIG_CPU_FREQ=y
++CONFIG_CPU_FREQ_GOV_COMMON=y
++CONFIG_CPU_FREQ_STAT=y
++# CONFIG_CPU_FREQ_STAT_DETAILS is not set
++CONFIG_CPU_FREQ_TIMES=y
++# CONFIG_CPU_FREQ_DEFAULT_GOV_PERFORMANCE is not set
++# CONFIG_CPU_FREQ_DEFAULT_GOV_POWERSAVE is not set
++# CONFIG_CPU_FREQ_DEFAULT_GOV_USERSPACE is not set
++# CONFIG_CPU_FREQ_DEFAULT_GOV_ONDEMAND is not set
++# CONFIG_CPU_FREQ_DEFAULT_GOV_CONSERVATIVE is not set
++CONFIG_CPU_FREQ_DEFAULT_GOV_INTERACTIVE=y
++# CONFIG_CPU_FREQ_DEFAULT_GOV_SCHEDUTIL is not set
++CONFIG_CPU_FREQ_GOV_PERFORMANCE=y
++CONFIG_CPU_FREQ_GOV_POWERSAVE=y
++CONFIG_CPU_FREQ_GOV_USERSPACE=y
++CONFIG_CPU_FREQ_GOV_ONDEMAND=y
++CONFIG_CPU_FREQ_GOV_INTERACTIVE=y
++CONFIG_CPU_FREQ_GOV_CONSERVATIVE=y
++# CONFIG_CPU_FREQ_GOV_SCHEDUTIL is not set
++
++#
++# CPU frequency scaling drivers
++#
++CONFIG_CPUFREQ_DT=y
++# CONFIG_ARM_BIG_LITTLE_CPUFREQ is not set
++# CONFIG_ARM_KIRKWOOD_CPUFREQ is not set
++CONFIG_ARM_ROCKCHIP_CPUFREQ=y
++CONFIG_NET=y
++CONFIG_COMPAT_NETLINK_MESSAGES=y
++
++#
++# Networking options
++#
++CONFIG_PACKET=y
++# CONFIG_PACKET_DIAG is not set
++CONFIG_UNIX=y
++# CONFIG_UNIX_DIAG is not set
++CONFIG_XFRM=y
++CONFIG_XFRM_ALGO=y
++CONFIG_XFRM_USER=y
++# CONFIG_XFRM_SUB_POLICY is not set
++# CONFIG_XFRM_MIGRATE is not set
++# CONFIG_XFRM_STATISTICS is not set
++CONFIG_NET_KEY=y
++# CONFIG_NET_KEY_MIGRATE is not set
++CONFIG_INET=y
++CONFIG_IP_MULTICAST=y
++CONFIG_IP_ADVANCED_ROUTER=y
++# CONFIG_IP_FIB_TRIE_STATS is not set
++# CONFIG_IP_MULTIPLE_TABLES is not set
++# CONFIG_IP_ROUTE_MULTIPATH is not set
++# CONFIG_IP_ROUTE_VERBOSE is not set
++# CONFIG_IP_PNP is not set
++# CONFIG_NET_IPIP is not set
++# CONFIG_NET_IPGRE_DEMUX is not set
++# CONFIG_NET_IP_TUNNEL is not set
++CONFIG_IP_MROUTE=y
++# CONFIG_IP_MROUTE_MULTIPLE_TABLES is not set
++# CONFIG_IP_PIMSM_V1 is not set
++# CONFIG_IP_PIMSM_V2 is not set
++CONFIG_SYN_COOKIES=y
++# CONFIG_NET_UDP_TUNNEL is not set
++# CONFIG_NET_FOU is not set
++# CONFIG_INET_AH is not set
++# CONFIG_INET_ESP is not set
++# CONFIG_INET_IPCOMP is not set
++# CONFIG_INET_XFRM_TUNNEL is not set
++# CONFIG_INET_TUNNEL is not set
++# CONFIG_INET_XFRM_MODE_TRANSPORT is not set
++# CONFIG_INET_XFRM_MODE_TUNNEL is not set
++# CONFIG_INET_XFRM_MODE_BEET is not set
++# CONFIG_INET_LRO is not set
++# CONFIG_INET_DIAG is not set
++# CONFIG_TCP_CONG_ADVANCED is not set
++CONFIG_TCP_CONG_CUBIC=y
++CONFIG_DEFAULT_TCP_CONG="cubic"
++# CONFIG_TCP_MD5SIG is not set
++CONFIG_IPV6=y
++# CONFIG_IPV6_ROUTER_PREF is not set
++# CONFIG_IPV6_OPTIMISTIC_DAD is not set
++# CONFIG_INET6_AH is not set
++# CONFIG_INET6_ESP is not set
++# CONFIG_INET6_IPCOMP is not set
++# CONFIG_IPV6_MIP6 is not set
++# CONFIG_IPV6_ILA is not set
++# CONFIG_INET6_XFRM_TUNNEL is not set
++# CONFIG_INET6_TUNNEL is not set
++# CONFIG_INET6_XFRM_MODE_TRANSPORT is not set
++# CONFIG_INET6_XFRM_MODE_TUNNEL is not set
++# CONFIG_INET6_XFRM_MODE_BEET is not set
++# CONFIG_INET6_XFRM_MODE_ROUTEOPTIMIZATION is not set
++# CONFIG_IPV6_SIT is not set
++# CONFIG_IPV6_TUNNEL is not set
++# CONFIG_IPV6_GRE is not set
++# CONFIG_IPV6_MULTIPLE_TABLES is not set
++# CONFIG_IPV6_MROUTE is not set
++# CONFIG_ANDROID_PARANOID_NETWORK is not set
++# CONFIG_NETWORK_SECMARK is not set
++CONFIG_NET_PTP_CLASSIFY=y
++# CONFIG_NETWORK_PHY_TIMESTAMPING is not set
++# CONFIG_NETFILTER is not set
++# CONFIG_IP_DCCP is not set
++# CONFIG_IP_SCTP is not set
++# CONFIG_RDS is not set
++# CONFIG_TIPC is not set
++# CONFIG_ATM is not set
++# CONFIG_L2TP is not set
++# CONFIG_BRIDGE is not set
++CONFIG_HAVE_NET_DSA=y
++# CONFIG_NET_DSA is not set
++# CONFIG_VLAN_8021Q is not set
++# CONFIG_DECNET is not set
++# CONFIG_LLC2 is not set
++# CONFIG_IPX is not set
++# CONFIG_ATALK is not set
++# CONFIG_X25 is not set
++# CONFIG_LAPB is not set
++# CONFIG_PHONET is not set
++# CONFIG_6LOWPAN is not set
++# CONFIG_IEEE802154 is not set
++# CONFIG_NET_SCHED is not set
++# CONFIG_DCB is not set
++CONFIG_DNS_RESOLVER=y
++# CONFIG_BATMAN_ADV is not set
++# CONFIG_OPENVSWITCH is not set
++# CONFIG_VSOCKETS is not set
++# CONFIG_NETLINK_DIAG is not set
++# CONFIG_MPLS is not set
++# CONFIG_HSR is not set
++# CONFIG_NET_SWITCHDEV is not set
++# CONFIG_NET_L3_MASTER_DEV is not set
++CONFIG_RPS=y
++CONFIG_RFS_ACCEL=y
++CONFIG_XPS=y
++# CONFIG_CGROUP_NET_PRIO is not set
++# CONFIG_CGROUP_NET_CLASSID is not set
++CONFIG_NET_RX_BUSY_POLL=y
++CONFIG_BQL=y
++# CONFIG_BPF_JIT is not set
++CONFIG_NET_FLOW_LIMIT=y
++
++#
++# Network testing
++#
++# CONFIG_NET_PKTGEN is not set
++# CONFIG_NET_DROP_MONITOR is not set
++# CONFIG_HAMRADIO is not set
++CONFIG_CAN=y
++CONFIG_CAN_RAW=y
++CONFIG_CAN_BCM=y
++CONFIG_CAN_GW=y
++
++#
++# CAN Device Drivers
++#
++# CONFIG_CAN_VCAN is not set
++# CONFIG_CAN_SLCAN is not set
++CONFIG_CAN_DEV=y
++CONFIG_CAN_CALC_BITTIMING=y
++# CONFIG_CAN_LEDS is not set
++# CONFIG_CAN_GRCAN is not set
++# CONFIG_CAN_XILINXCAN is not set
++# CONFIG_CAN_SJA1000 is not set
++# CONFIG_CAN_C_CAN is not set
++# CONFIG_CAN_M_CAN is not set
++# CONFIG_CAN_CC770 is not set
++
++#
++# CAN SPI interfaces
++#
++# CONFIG_CAN_MCP251X is not set
++CONFIG_CAN_MCP25XXFD=m
++
++#
++# CAN USB interfaces
++#
++# CONFIG_CAN_EMS_USB is not set
++# CONFIG_CAN_ESD_USB2 is not set
++# CONFIG_CAN_GS_USB is not set
++# CONFIG_CAN_KVASER_USB is not set
++# CONFIG_CAN_PEAK_USB is not set
++# CONFIG_CAN_8DEV_USB is not set
++# CONFIG_CAN_SOFTING is not set
++# CONFIG_CAN_DEBUG_DEVICES is not set
++# CONFIG_IRDA is not set
++CONFIG_BT=y
++CONFIG_BT_BREDR=y
++CONFIG_BT_RFCOMM=y
++# CONFIG_BT_RFCOMM_TTY is not set
++# CONFIG_BT_BNEP is not set
++CONFIG_BT_HIDP=y
++CONFIG_BT_HS=y
++CONFIG_BT_LE=y
++# CONFIG_BT_SELFTEST is not set
++CONFIG_BT_DEBUGFS=y
++
++#
++# Bluetooth device drivers
++#
++CONFIG_BT_INTEL=y
++CONFIG_BT_BCM=y
++CONFIG_BT_RTL=y
++# CONFIG_BT_RTKBTUSB is not set
++CONFIG_BT_HCIBTUSB=y
++CONFIG_BT_HCIBTUSB_BCM=y
++CONFIG_BT_HCIBTUSB_RTL=y
++# CONFIG_BT_HCIBTSDIO is not set
++CONFIG_BT_HCIUART=y
++CONFIG_BT_HCIUART_H4=y
++# CONFIG_BT_HCIUART_BCSP is not set
++CONFIG_BT_HCIUART_ATH3K=y
++CONFIG_BT_HCIUART_LL=y
++# CONFIG_BT_HCIUART_3WIRE is not set
++# CONFIG_BT_HCIUART_INTEL is not set
++# CONFIG_BT_HCIUART_BCM is not set
++# CONFIG_BT_HCIUART_QCA is not set
++# CONFIG_BT_HCIBCM203X is not set
++# CONFIG_BT_HCIBPA10X is not set
++CONFIG_BT_HCIBFUSB=y
++CONFIG_BT_HCIVHCI=y
++CONFIG_BT_MRVL=y
++CONFIG_BT_MRVL_SDIO=y
++# CONFIG_BT_ATH3K is not set
++# CONFIG_AF_RXRPC is not set
++CONFIG_WIRELESS=y
++CONFIG_WIRELESS_EXT=y
++CONFIG_WEXT_CORE=y
++CONFIG_WEXT_PROC=y
++CONFIG_WEXT_PRIV=y
++CONFIG_CFG80211=y
++CONFIG_NL80211_TESTMODE=y
++# CONFIG_CFG80211_DEVELOPER_WARNINGS is not set
++# CONFIG_CFG80211_REG_DEBUG is not set
++# CONFIG_CFG80211_CERTIFICATION_ONUS is not set
++CONFIG_CFG80211_DEFAULT_PS=y
++CONFIG_CFG80211_DEBUGFS=y
++# CONFIG_CFG80211_INTERNAL_REGDB is not set
++CONFIG_CFG80211_CRDA_SUPPORT=y
++CONFIG_CFG80211_WEXT=y
++# CONFIG_LIB80211 is not set
++CONFIG_MAC80211=y
++CONFIG_MAC80211_HAS_RC=y
++CONFIG_MAC80211_RC_MINSTREL=y
++CONFIG_MAC80211_RC_MINSTREL_HT=y
++# CONFIG_MAC80211_RC_MINSTREL_VHT is not set
++CONFIG_MAC80211_RC_DEFAULT_MINSTREL=y
++CONFIG_MAC80211_RC_DEFAULT="minstrel_ht"
++# CONFIG_MAC80211_MESH is not set
++CONFIG_MAC80211_LEDS=y
++CONFIG_MAC80211_DEBUGFS=y
++# CONFIG_MAC80211_MESSAGE_TRACING is not set
++CONFIG_MAC80211_DEBUG_MENU=y
++# CONFIG_MAC80211_NOINLINE is not set
++CONFIG_MAC80211_VERBOSE_DEBUG=y
++# CONFIG_MAC80211_MLME_DEBUG is not set
++# CONFIG_MAC80211_STA_DEBUG is not set
++# CONFIG_MAC80211_HT_DEBUG is not set
++# CONFIG_MAC80211_OCB_DEBUG is not set
++# CONFIG_MAC80211_IBSS_DEBUG is not set
++# CONFIG_MAC80211_PS_DEBUG is not set
++# CONFIG_MAC80211_TDLS_DEBUG is not set
++# CONFIG_MAC80211_DEBUG_COUNTERS is not set
++CONFIG_MAC80211_STA_HASH_MAX_SIZE=0
++# CONFIG_WIMAX is not set
++CONFIG_RFKILL=y
++CONFIG_RFKILL_PM=y
++CONFIG_RFKILL_LEDS=y
++# CONFIG_RFKILL_INPUT is not set
++# CONFIG_RFKILL_REGULATOR is not set
++# CONFIG_RFKILL_GPIO is not set
++# CONFIG_NET_9P is not set
++# CONFIG_CAIF is not set
++# CONFIG_CEPH_LIB is not set
++# CONFIG_NFC is not set
++# CONFIG_LWTUNNEL is not set
++# CONFIG_DST_CACHE is not set
++CONFIG_HAVE_BPF_JIT=y
++CONFIG_HAVE_EBPF_JIT=y
++
++#
++# Device Drivers
++#
++CONFIG_ARM_AMBA=y
++# CONFIG_TEGRA_AHB is not set
++
++#
++# Generic Driver Options
++#
++CONFIG_UEVENT_HELPER=y
++CONFIG_UEVENT_HELPER_PATH=""
++CONFIG_DEVTMPFS=y
++CONFIG_DEVTMPFS_MOUNT=y
++CONFIG_STANDALONE=y
++CONFIG_PREVENT_FIRMWARE_BUILD=y
++CONFIG_FW_LOADER=y
++CONFIG_FIRMWARE_IN_KERNEL=y
++CONFIG_EXTRA_FIRMWARE=""
++# CONFIG_FW_LOADER_USER_HELPER_FALLBACK is not set
++CONFIG_WANT_DEV_COREDUMP=y
++CONFIG_ALLOW_DEV_COREDUMP=y
++CONFIG_DEV_COREDUMP=y
++# CONFIG_DEBUG_DRIVER is not set
++CONFIG_DEBUG_DEVRES=y
++# CONFIG_SYS_HYPERVISOR is not set
++# CONFIG_GENERIC_CPU_DEVICES is not set
++CONFIG_GENERIC_CPU_AUTOPROBE=y
++CONFIG_REGMAP=y
++CONFIG_REGMAP_I2C=y
++CONFIG_REGMAP_SPI=y
++CONFIG_REGMAP_MMIO=y
++CONFIG_REGMAP_IRQ=y
++CONFIG_DMA_SHARED_BUFFER=y
++# CONFIG_FENCE_TRACE is not set
++
++#
++# Bus devices
++#
++# CONFIG_ARM_CCI400_PMU is not set
++# CONFIG_ARM_CCI500_PMU is not set
++# CONFIG_ARM_CCN is not set
++# CONFIG_VEXPRESS_CONFIG is not set
++CONFIG_CONNECTOR=y
++CONFIG_PROC_EVENTS=y
++# CONFIG_MTD is not set
++CONFIG_DTC=y
++CONFIG_OF=y
++# CONFIG_OF_UNITTEST is not set
++CONFIG_OF_FLATTREE=y
++CONFIG_OF_EARLY_FLATTREE=y
++CONFIG_OF_ADDRESS=y
++CONFIG_OF_IRQ=y
++CONFIG_OF_NET=y
++CONFIG_OF_MDIO=y
++CONFIG_OF_RESERVED_MEM=y
++# CONFIG_OF_OVERLAY is not set
++# CONFIG_PARPORT is not set
++CONFIG_BLK_DEV=y
++# CONFIG_BLK_DEV_NULL_BLK is not set
++CONFIG_ZRAM=y
++# CONFIG_ZRAM_WRITEBACK is not set
++# CONFIG_ZRAM_MEMORY_TRACKING is not set
++# CONFIG_BLK_DEV_COW_COMMON is not set
++CONFIG_BLK_DEV_LOOP=y
++CONFIG_BLK_DEV_LOOP_MIN_COUNT=8
++# CONFIG_BLK_DEV_CRYPTOLOOP is not set
++# CONFIG_BLK_DEV_DRBD is not set
++# CONFIG_BLK_DEV_NBD is not set
++CONFIG_BLK_DEV_RAM=y
++CONFIG_BLK_DEV_RAM_COUNT=1
++CONFIG_BLK_DEV_RAM_SIZE=4096
++# CONFIG_CDROM_PKTCDVD is not set
++# CONFIG_ATA_OVER_ETH is not set
++# CONFIG_BLK_DEV_RBD is not set
++
++#
++# Misc devices
++#
++# CONFIG_ROCKCHIP_SCR is not set
++# CONFIG_SENSORS_LIS3LV02D is not set
++# CONFIG_AD525X_DPOT is not set
++# CONFIG_DUMMY_IRQ is not set
++# CONFIG_ICS932S401 is not set
++# CONFIG_ENCLOSURE_SERVICES is not set
++# CONFIG_APDS9802ALS is not set
++# CONFIG_ISL29003 is not set
++# CONFIG_ISL29020 is not set
++# CONFIG_SENSORS_TSL2550 is not set
++# CONFIG_SENSORS_BH1780 is not set
++# CONFIG_SENSORS_BH1770 is not set
++# CONFIG_SENSORS_APDS990X is not set
++# CONFIG_HMC6352 is not set
++# CONFIG_DS1682 is not set
++# CONFIG_TI_DAC7512 is not set
++# CONFIG_BMP085_I2C is not set
++# CONFIG_BMP085_SPI is not set
++# CONFIG_USB_SWITCH_FSA9480 is not set
++# CONFIG_LATTICE_ECP3_CONFIG is not set
++# CONFIG_SRAM is not set
++# CONFIG_MEMORY_STATE_TIME is not set
++# CONFIG_USB_CAM_GPIO is not set
++# CONFIG_GPIO_DET is not set
++# CONFIG_C2PORT is not set
++
++#
++# EEPROM support
++#
++# CONFIG_EEPROM_AT24 is not set
++# CONFIG_EEPROM_AT25 is not set
++# CONFIG_EEPROM_LEGACY is not set
++# CONFIG_EEPROM_MAX6875 is not set
++# CONFIG_EEPROM_93CX6 is not set
++# CONFIG_EEPROM_93XX46 is not set
++
++#
++# Texas Instruments shared transport line discipline
++#
++# CONFIG_TI_ST is not set
++# CONFIG_SENSORS_LIS3_SPI is not set
++# CONFIG_SENSORS_LIS3_I2C is not set
++
++#
++# Altera FPGA firmware download module
++#
++# CONFIG_ALTERA_STAPL is not set
++
++#
++# Intel MIC Bus Driver
++#
++
++#
++# SCIF Bus Driver
++#
++
++#
++# Intel MIC Host Driver
++#
++
++#
++# Intel MIC Card Driver
++#
++
++#
++# SCIF Driver
++#
++
++#
++# Intel MIC Coprocessor State Management (COSM) Drivers
++#
++# CONFIG_ECHO is not set
++# CONFIG_CXL_BASE is not set
++# CONFIG_CXL_KERNEL_API is not set
++# CONFIG_CXL_EEH is not set
++
++#
++# SCSI device support
++#
++CONFIG_SCSI_MOD=y
++# CONFIG_RAID_ATTRS is not set
++CONFIG_SCSI=y
++CONFIG_SCSI_DMA=y
++# CONFIG_SCSI_NETLINK is not set
++# CONFIG_SCSI_MQ_DEFAULT is not set
++CONFIG_SCSI_PROC_FS=y
++
++#
++# SCSI support type (disk, tape, CD-ROM)
++#
++CONFIG_BLK_DEV_SD=y
++# CONFIG_CHR_DEV_ST is not set
++# CONFIG_CHR_DEV_OSST is not set
++CONFIG_BLK_DEV_SR=y
++# CONFIG_BLK_DEV_SR_VENDOR is not set
++# CONFIG_CHR_DEV_SG is not set
++# CONFIG_CHR_DEV_SCH is not set
++# CONFIG_SCSI_CONSTANTS is not set
++# CONFIG_SCSI_LOGGING is not set
++CONFIG_SCSI_SCAN_ASYNC=y
++
++#
++# SCSI Transports
++#
++CONFIG_SCSI_SPI_ATTRS=y
++# CONFIG_SCSI_FC_ATTRS is not set
++# CONFIG_SCSI_ISCSI_ATTRS is not set
++# CONFIG_SCSI_SAS_ATTRS is not set
++# CONFIG_SCSI_SAS_LIBSAS is not set
++# CONFIG_SCSI_SRP_ATTRS is not set
++CONFIG_SCSI_LOWLEVEL=y
++# CONFIG_ISCSI_TCP is not set
++# CONFIG_ISCSI_BOOT_SYSFS is not set
++# CONFIG_SCSI_UFSHCD is not set
++# CONFIG_SCSI_DEBUG is not set
++# CONFIG_SCSI_LOWLEVEL_PCMCIA is not set
++# CONFIG_SCSI_DH is not set
++# CONFIG_SCSI_OSD_INITIATOR is not set
++CONFIG_HAVE_PATA_PLATFORM=y
++# CONFIG_ATA is not set
++# CONFIG_MD is not set
++# CONFIG_TARGET_CORE is not set
++CONFIG_NETDEVICES=y
++CONFIG_MII=y
++CONFIG_NET_CORE=y
++# CONFIG_BONDING is not set
++# CONFIG_DUMMY is not set
++# CONFIG_EQUALIZER is not set
++# CONFIG_NET_TEAM is not set
++# CONFIG_MACVLAN is not set
++# CONFIG_IPVLAN is not set
++# CONFIG_VXLAN is not set
++# CONFIG_NETCONSOLE is not set
++# CONFIG_NETPOLL is not set
++# CONFIG_NET_POLL_CONTROLLER is not set
++# CONFIG_TUN is not set
++# CONFIG_TUN_VNET_CROSS_LE is not set
++# CONFIG_VETH is not set
++# CONFIG_NLMON is not set
++
++#
++# CAIF transport drivers
++#
++
++#
++# Distributed Switch Architecture drivers
++#
++# CONFIG_NET_DSA_MV88E6XXX is not set
++# CONFIG_NET_DSA_MV88E6XXX_NEED_PPU is not set
++CONFIG_ETHERNET=y
++# CONFIG_ALTERA_TSE is not set
++# CONFIG_NET_VENDOR_AMD is not set
++# CONFIG_NET_VENDOR_ARC is not set
++# CONFIG_NET_VENDOR_AURORA is not set
++# CONFIG_NET_CADENCE is not set
++# CONFIG_NET_VENDOR_BROADCOM is not set
++# CONFIG_DNET is not set
++# CONFIG_NET_VENDOR_EZCHIP is not set
++# CONFIG_NET_VENDOR_HISILICON is not set
++# CONFIG_NET_VENDOR_INTEL is not set
++# CONFIG_NET_VENDOR_MARVELL is not set
++# CONFIG_NET_VENDOR_MICREL is not set
++# CONFIG_NET_VENDOR_MICROCHIP is not set
++# CONFIG_NET_VENDOR_NATSEMI is not set
++# CONFIG_ETHOC is not set
++# CONFIG_NET_VENDOR_QUALCOMM is not set
++# CONFIG_NET_VENDOR_RENESAS is not set
++# CONFIG_NET_VENDOR_ROCKER is not set
++# CONFIG_NET_VENDOR_SAMSUNG is not set
++# CONFIG_NET_VENDOR_SEEQ is not set
++# CONFIG_NET_VENDOR_SMSC is not set
++CONFIG_NET_VENDOR_SMSC9514=y
++CONFIG_SMSC9500=m
++CONFIG_SMSCUSBNET=m
++CONFIG_NET_VENDOR_STMICRO=y
++CONFIG_STMMAC_ETH=y
++CONFIG_STMMAC_PLATFORM=y
++# CONFIG_DWMAC_GENERIC is not set
++# CONFIG_DWMAC_IPQ806X is not set
++# CONFIG_DWMAC_LPC18XX is not set
++# CONFIG_DWMAC_MESON is not set
++CONFIG_DWMAC_ROCKCHIP=y
++# CONFIG_DWMAC_SOCFPGA is not set
++# CONFIG_DWMAC_STI is not set
++# CONFIG_DWMAC_SUNXI is not set
++# CONFIG_NET_VENDOR_SYNOPSYS is not set
++# CONFIG_NET_VENDOR_VIA is not set
++# CONFIG_NET_VENDOR_WIZNET is not set
++CONFIG_PHYLIB=y
++
++#
++# MII PHY device drivers
++#
++# CONFIG_AQUANTIA_PHY is not set
++# CONFIG_AT803X_PHY is not set
++# CONFIG_AMD_PHY is not set
++# CONFIG_MARVELL_PHY is not set
++# CONFIG_DAVICOM_PHY is not set
++# CONFIG_QSEMI_PHY is not set
++# CONFIG_LXT_PHY is not set
++# CONFIG_CICADA_PHY is not set
++# CONFIG_VITESSE_PHY is not set
++# CONFIG_TERANETICS_PHY is not set
++CONFIG_ROCKCHIP_PHY=y
++# CONFIG_SMSC_PHY is not set
++# CONFIG_BROADCOM_PHY is not set
++# CONFIG_BCM7XXX_PHY is not set
++# CONFIG_BCM87XX_PHY is not set
++# CONFIG_ICPLUS_PHY is not set
++# CONFIG_REALTEK_PHY is not set
++# CONFIG_NATIONAL_PHY is not set
++# CONFIG_STE10XP is not set
++# CONFIG_LSI_ET1011C_PHY is not set
++# CONFIG_MICREL_PHY is not set
++# CONFIG_DP83848_PHY is not set
++# CONFIG_DP83867_PHY is not set
++# CONFIG_MICROCHIP_PHY is not set
++# CONFIG_FIXED_PHY is not set
++# CONFIG_MDIO_BITBANG is not set
++# CONFIG_MDIO_OCTEON is not set
++# CONFIG_MDIO_BUS_MUX_GPIO is not set
++# CONFIG_MDIO_BUS_MUX_MMIOREG is not set
++# CONFIG_MDIO_BCM_UNIMAC is not set
++# CONFIG_MICREL_KS8995MA is not set
++# CONFIG_PPP is not set
++# CONFIG_SLIP is not set
++CONFIG_USB_NET_DRIVERS=y
++# CONFIG_USB_CATC is not set
++# CONFIG_USB_KAWETH is not set
++# CONFIG_USB_PEGASUS is not set
++CONFIG_USB_RTL8150=y
++CONFIG_USB_RTL8152=y
++# CONFIG_USB_LAN78XX is not set
++CONFIG_USB_USBNET=y
++CONFIG_USB_NET_AX8817X=y
++CONFIG_USB_NET_AX88179_178A=y
++CONFIG_USB_NET_CDCETHER=y
++# CONFIG_USB_NET_CDC_EEM is not set
++CONFIG_USB_NET_CDC_NCM=y
++# CONFIG_USB_NET_HUAWEI_CDC_NCM is not set
++CONFIG_USB_NET_CDC_MBIM=y
++# CONFIG_USB_NET_DM9601 is not set
++# CONFIG_USB_NET_SR9700 is not set
++# CONFIG_USB_NET_SR9800 is not set
++# CONFIG_USB_NET_SMSC75XX is not set
++CONFIG_USB_NET_SMSC95XX=y
++# CONFIG_USB_NET_GL620A is not set
++# CONFIG_USB_NET_NET1080 is not set
++# CONFIG_USB_NET_PLUSB is not set
++# CONFIG_USB_NET_MCS7830 is not set
++CONFIG_USB_NET_RNDIS_HOST=y
++# CONFIG_USB_NET_CDC_SUBSET is not set
++# CONFIG_USB_NET_ZAURUS is not set
++# CONFIG_USB_NET_CX82310_ETH is not set
++# CONFIG_USB_NET_KALMIA is not set
++# CONFIG_USB_NET_QMI_WWAN is not set
++# CONFIG_USB_HSO is not set
++# CONFIG_USB_NET_INT51X1 is not set
++# CONFIG_USB_IPHETH is not set
++# CONFIG_USB_SIERRA_NET is not set
++# CONFIG_USB_VL600 is not set
++# CONFIG_USB_NET_CH9200 is not set
++CONFIG_WLAN=y
++CONFIG_LIBERTAS_THINFIRM=y
++# CONFIG_LIBERTAS_THINFIRM_DEBUG is not set
++# CONFIG_LIBERTAS_THINFIRM_USB is not set
++# CONFIG_AT76C50X_USB is not set
++# CONFIG_USB_ZD1201 is not set
++CONFIG_USB_NET_RNDIS_WLAN=y
++# CONFIG_RTL8187 is not set
++# CONFIG_MAC80211_HWSIM is not set
++# CONFIG_VIRT_WIFI is not set
++# CONFIG_ATH_CARDS is not set
++# CONFIG_B43 is not set
++# CONFIG_B43LEGACY is not set
++# CONFIG_BRCMSMAC is not set
++# CONFIG_BRCMFMAC is not set
++# CONFIG_HOSTAP is not set
++# CONFIG_LIBERTAS is not set
++# CONFIG_P54_COMMON is not set
++# CONFIG_RT2X00 is not set
++# CONFIG_WL_MEDIATEK is not set
++CONFIG_RTL_CARDS=y
++# CONFIG_RTL8192CU is not set
++# CONFIG_RTL8XXXU is not set
++CONFIG_WL_ROCKCHIP=y
++CONFIG_WIFI_BUILD_MODULE=y
++# CONFIG_WIFI_LOAD_DRIVER_WHEN_KERNEL_BOOTUP is not set
++# CONFIG_WIFI_GENERATE_RANDOM_MAC_ADDR is not set
++CONFIG_AP6XXX=m
++# CONFIG_CYW_BCMDHD is not set
++CONFIG_RTL_WIRELESS_SOLUTION=y
++CONFIG_RTL8188EU=m
++# CONFIG_RTL8188FU is not set
++# CONFIG_RTL8189ES is not set
++# CONFIG_RTL8189FS is not set
++# CONFIG_RTL8723BS is not set
++# CONFIG_RTL8723BU is not set
++# CONFIG_RTL8723CS is not set
++# CONFIG_RTL8723DS is not set
++# CONFIG_MVL88W8977 is not set
++
++#
++# SouthSV 6XXX WLAN support
++#
++# CONFIG_SSV6051 is not set
++# CONFIG_WL_TI is not set
++# CONFIG_ZD1211RW is not set
++CONFIG_MWIFIEX=y
++CONFIG_MWIFIEX_SDIO=y
++# CONFIG_MWIFIEX_USB is not set
++# CONFIG_CW1200 is not set
++# CONFIG_RSI_91X is not set
++
++#
++# Enable WiMAX (Networking options) to see the WiMAX drivers
++#
++# CONFIG_WAN is not set
++# CONFIG_ISDN is not set
++# CONFIG_NVM is not set
++
++#
++# Input device support
++#
++CONFIG_INPUT=y
++CONFIG_INPUT_LEDS=y
++CONFIG_INPUT_FF_MEMLESS=y
++CONFIG_INPUT_POLLDEV=y
++# CONFIG_INPUT_SPARSEKMAP is not set
++CONFIG_INPUT_MATRIXKMAP=y
++
++#
++# Userland interfaces
++#
++# CONFIG_INPUT_MOUSEDEV is not set
++# CONFIG_INPUT_JOYDEV is not set
++CONFIG_INPUT_EVDEV=y
++# CONFIG_INPUT_EVBUG is not set
++# CONFIG_INPUT_KEYRESET is not set
++# CONFIG_INPUT_KEYCOMBO is not set
++
++#
++# Input Device Drivers
++#
++CONFIG_INPUT_KEYBOARD=y
++CONFIG_KEYBOARD_ADC=y
++# CONFIG_KEYBOARD_ADP5588 is not set
++# CONFIG_KEYBOARD_ADP5589 is not set
++# CONFIG_KEYBOARD_ATKBD is not set
++# CONFIG_KEYBOARD_QT1070 is not set
++# CONFIG_KEYBOARD_QT2160 is not set
++# CONFIG_KEYBOARD_LKKBD is not set
++CONFIG_KEYBOARD_GPIO=y
++CONFIG_KEYBOARD_GPIO_POLLED=y
++# CONFIG_KEYBOARD_TCA6416 is not set
++# CONFIG_KEYBOARD_TCA8418 is not set
++# CONFIG_KEYBOARD_MATRIX is not set
++# CONFIG_KEYBOARD_LM8323 is not set
++# CONFIG_KEYBOARD_LM8333 is not set
++# CONFIG_KEYBOARD_MAX7359 is not set
++# CONFIG_KEYBOARD_MCS is not set
++# CONFIG_KEYBOARD_MPR121 is not set
++# CONFIG_KEYBOARD_NEWTON is not set
++# CONFIG_KEYBOARD_OPENCORES is not set
++# CONFIG_KEYBOARD_SAMSUNG is not set
++# CONFIG_KEYBOARD_STOWAWAY is not set
++# CONFIG_KEYBOARD_SUNKBD is not set
++# CONFIG_KEYBOARD_OMAP4 is not set
++CONFIG_KEYBOARD_ROCKCHIP=y
++# CONFIG_KEYBOARD_XTKBD is not set
++# CONFIG_KEYBOARD_CAP11XX is not set
++# CONFIG_KEYBOARD_BCM is not set
++CONFIG_INPUT_MOUSE=y
++# CONFIG_MOUSE_PS2 is not set
++# CONFIG_MOUSE_SERIAL is not set
++# CONFIG_MOUSE_APPLETOUCH is not set
++# CONFIG_MOUSE_BCM5974 is not set
++CONFIG_MOUSE_CYAPA=y
++CONFIG_MOUSE_ELAN_I2C=y
++CONFIG_MOUSE_ELAN_I2C_I2C=y
++# CONFIG_MOUSE_ELAN_I2C_SMBUS is not set
++# CONFIG_MOUSE_VSXXXAA is not set
++# CONFIG_MOUSE_GPIO is not set
++# CONFIG_MOUSE_SYNAPTICS_I2C is not set
++# CONFIG_MOUSE_SYNAPTICS_USB is not set
++# CONFIG_INPUT_JOYSTICK is not set
++# CONFIG_INPUT_TABLET is not set
++CONFIG_INPUT_TOUCHSCREEN=y
++CONFIG_TOUCHSCREEN_PROPERTIES=y
++# CONFIG_TOUCHSCREEN_ADS7846 is not set
++# CONFIG_TOUCHSCREEN_AD7877 is not set
++# CONFIG_TOUCHSCREEN_AD7879 is not set
++# CONFIG_TOUCHSCREEN_AR1021_I2C is not set
++CONFIG_TOUCHSCREEN_ATMEL_MXT=y
++# CONFIG_TOUCHSCREEN_AUO_PIXCIR is not set
++# CONFIG_TOUCHSCREEN_BU21013 is not set
++# CONFIG_TOUCHSCREEN_CHIPONE_ICN8318 is not set
++# CONFIG_TOUCHSCREEN_CY8C40XX is not set
++# CONFIG_TOUCHSCREEN_CY8CTMG110 is not set
++# CONFIG_TOUCHSCREEN_CYTTSP_CORE is not set
++# CONFIG_TOUCHSCREEN_CYTTSP4_CORE is not set
++# CONFIG_TOUCHSCREEN_DYNAPRO is not set
++# CONFIG_TOUCHSCREEN_HAMPSHIRE is not set
++# CONFIG_TOUCHSCREEN_EETI is not set
++# CONFIG_TOUCHSCREEN_EGALAX is not set
++# CONFIG_TOUCHSCREEN_FT6236 is not set
++# CONFIG_TOUCHSCREEN_FUJITSU is not set
++# CONFIG_TOUCHSCREEN_GOODIX is not set
++# CONFIG_TOUCHSCREEN_GSLX680A is not set
++# CONFIG_TOUCHSCREEN_GSLX680_D708 is not set
++# CONFIG_TOUCHSCREEN_GSLX680_PAD is not set
++CONFIG_TOUCHSCREEN_GSLX680_VR=y
++# CONFIG_TOUCHSCREEN_GSLX680_FIREFLY is not set
++CONFIG_TOUCHSCREEN_GSL3673=y
++# CONFIG_TOUCHSCREEN_GSL3673_800X1280 is not set
++CONFIG_TOUCHSCREEN_GT9XX=y
++# CONFIG_TOUCHSCREEN_ILI210X is not set
++# CONFIG_TOUCHSCREEN_GUNZE is not set
++CONFIG_TOUCHSCREEN_ELAN=y
++# CONFIG_TOUCHSCREEN_ELO is not set
++# CONFIG_TOUCHSCREEN_WACOM_W8001 is not set
++# CONFIG_TOUCHSCREEN_WACOM_I2C is not set
++# CONFIG_TOUCHSCREEN_MAX11801 is not set
++# CONFIG_TOUCHSCREEN_MCS5000 is not set
++# CONFIG_TOUCHSCREEN_MMS114 is not set
++# CONFIG_TOUCHSCREEN_MTOUCH is not set
++# CONFIG_TOUCHSCREEN_IMX6UL_TSC is not set
++# CONFIG_TOUCHSCREEN_INEXIO is not set
++# CONFIG_TOUCHSCREEN_MK712 is not set
++# CONFIG_TOUCHSCREEN_PENMOUNT is not set
++# CONFIG_TOUCHSCREEN_EDT_FT5X06 is not set
++# CONFIG_TOUCHSCREEN_TOUCHRIGHT is not set
++# CONFIG_TOUCHSCREEN_TOUCHWIN is not set
++# CONFIG_TOUCHSCREEN_PIXCIR is not set
++# CONFIG_TOUCHSCREEN_WDT87XX_I2C is not set
++CONFIG_TOUCHSCREEN_USB_COMPOSITE=y
++CONFIG_TOUCHSCREEN_USB_EGALAX=y
++CONFIG_TOUCHSCREEN_USB_PANJIT=y
++CONFIG_TOUCHSCREEN_USB_3M=y
++CONFIG_TOUCHSCREEN_USB_ITM=y
++CONFIG_TOUCHSCREEN_USB_ETURBO=y
++CONFIG_TOUCHSCREEN_USB_GUNZE=y
++CONFIG_TOUCHSCREEN_USB_DMC_TSC10=y
++CONFIG_TOUCHSCREEN_USB_IRTOUCH=y
++CONFIG_TOUCHSCREEN_USB_IDEALTEK=y
++CONFIG_TOUCHSCREEN_USB_GENERAL_TOUCH=y
++CONFIG_TOUCHSCREEN_USB_GOTOP=y
++CONFIG_TOUCHSCREEN_USB_JASTEC=y
++CONFIG_TOUCHSCREEN_USB_ELO=y
++CONFIG_TOUCHSCREEN_USB_E2I=y
++CONFIG_TOUCHSCREEN_USB_ZYTRONIC=y
++CONFIG_TOUCHSCREEN_USB_ETT_TC45USB=y
++CONFIG_TOUCHSCREEN_USB_NEXIO=y
++CONFIG_TOUCHSCREEN_USB_EASYTOUCH=y
++# CONFIG_TOUCHSCREEN_TOUCHIT213 is not set
++# CONFIG_TOUCHSCREEN_TSC_SERIO is not set
++# CONFIG_TOUCHSCREEN_TSC2004 is not set
++# CONFIG_TOUCHSCREEN_TSC2005 is not set
++# CONFIG_TOUCHSCREEN_TSC2007 is not set
++# CONFIG_TOUCHSCREEN_ST1232 is not set
++# CONFIG_TOUCHSCREEN_SUR40 is not set
++# CONFIG_TOUCHSCREEN_SX8654 is not set
++# CONFIG_TOUCHSCREEN_TPS6507X is not set
++# CONFIG_TOUCHSCREEN_ZFORCE is not set
++# CONFIG_TOUCHSCREEN_ROHM_BU21023 is not set
++# CONFIG_TOUCHSCREEN_VTL_CT36X is not set
++CONFIG_TOUCHSCREEN_GT1X=y
++CONFIG_ROCKCHIP_REMOTECTL=y
++CONFIG_ROCKCHIP_REMOTECTL_PWM=y
++
++#
++# handle all sensors
++#
++# CONFIG_SENSOR_DEVICE is not set
++CONFIG_INPUT_MISC=y
++# CONFIG_INPUT_AD714X is not set
++# CONFIG_INPUT_BMA150 is not set
++# CONFIG_INPUT_E3X0_BUTTON is not set
++# CONFIG_INPUT_MMA8450 is not set
++# CONFIG_INPUT_MPU3050 is not set
++# CONFIG_INPUT_GP2A is not set
++# CONFIG_INPUT_GPIO_BEEPER is not set
++# CONFIG_INPUT_GPIO_TILT_POLLED is not set
++# CONFIG_INPUT_ATI_REMOTE2 is not set
++# CONFIG_INPUT_KEYCHORD is not set
++# CONFIG_INPUT_KEYSPAN_REMOTE is not set
++# CONFIG_INPUT_KXTJ9 is not set
++# CONFIG_INPUT_POWERMATE is not set
++# CONFIG_INPUT_YEALINK is not set
++# CONFIG_INPUT_CM109 is not set
++# CONFIG_INPUT_REGULATOR_HAPTIC is not set
++CONFIG_INPUT_RK8XX_PWRKEY=y
++CONFIG_INPUT_UINPUT=y
++CONFIG_INPUT_GPIO=y
++# CONFIG_INPUT_PCF8574 is not set
++# CONFIG_INPUT_PWM_BEEPER is not set
++# CONFIG_INPUT_GPIO_ROTARY_ENCODER is not set
++# CONFIG_INPUT_ADXL34X is not set
++# CONFIG_INPUT_IMS_PCU is not set
++# CONFIG_INPUT_CMA3000 is not set
++# CONFIG_INPUT_SOC_BUTTON_ARRAY is not set
++# CONFIG_INPUT_DRV260X_HAPTICS is not set
++# CONFIG_INPUT_DRV2665_HAPTICS is not set
++# CONFIG_INPUT_DRV2667_HAPTICS is not set
++
++#
++# Hardware I/O ports
++#
++# CONFIG_SERIO is not set
++# CONFIG_GAMEPORT is not set
++
++#
++# Character devices
++#
++CONFIG_TTY=y
++CONFIG_VT=y
++CONFIG_CONSOLE_TRANSLATIONS=y
++CONFIG_VT_CONSOLE=y
++CONFIG_VT_CONSOLE_SLEEP=y
++CONFIG_HW_CONSOLE=y
++CONFIG_VT_HW_CONSOLE_BINDING=y
++CONFIG_UNIX98_PTYS=y
++CONFIG_DEVPTS_MULTIPLE_INSTANCES=y
++# CONFIG_LEGACY_PTYS is not set
++# CONFIG_SERIAL_NONSTANDARD is not set
++# CONFIG_N_GSM is not set
++# CONFIG_TRACE_SINK is not set
++CONFIG_LDISC_AUTOLOAD=y
++CONFIG_DEVMEM=y
++# CONFIG_DEVKMEM is not set
++
++#
++# Serial drivers
++#
++CONFIG_SERIAL_EARLYCON=y
++CONFIG_SERIAL_8250=y
++CONFIG_SERIAL_8250_DEPRECATED_OPTIONS=y
++CONFIG_SERIAL_8250_CONSOLE=y
++CONFIG_SERIAL_8250_DMA=y
++CONFIG_SERIAL_8250_NR_UARTS=5
++CONFIG_SERIAL_8250_RUNTIME_UARTS=5
++# CONFIG_SERIAL_8250_EXTENDED is not set
++CONFIG_SERIAL_8250_FSL=y
++CONFIG_SERIAL_8250_DW=y
++# CONFIG_SERIAL_8250_RT288X is not set
++# CONFIG_SERIAL_8250_INGENIC is not set
++
++#
++# Non-8250 serial port support
++#
++# CONFIG_SERIAL_AMBA_PL010 is not set
++# CONFIG_SERIAL_AMBA_PL011 is not set
++# CONFIG_SERIAL_EARLYCON_ARM_SEMIHOST is not set
++# CONFIG_SERIAL_MAX3100 is not set
++# CONFIG_SERIAL_MAX310X is not set
++# CONFIG_SERIAL_UARTLITE is not set
++CONFIG_SERIAL_CORE=y
++CONFIG_SERIAL_CORE_CONSOLE=y
++CONFIG_SERIAL_OF_PLATFORM=y
++# CONFIG_SERIAL_SCCNXP is not set
++# CONFIG_SERIAL_SC16IS7XX is not set
++# CONFIG_SERIAL_ALTERA_JTAGUART is not set
++# CONFIG_SERIAL_ALTERA_UART is not set
++# CONFIG_SERIAL_IFX6X60 is not set
++# CONFIG_SERIAL_XILINX_PS_UART is not set
++# CONFIG_SERIAL_ARC is not set
++# CONFIG_SERIAL_FSL_LPUART is not set
++# CONFIG_SERIAL_CONEXANT_DIGICOLOR is not set
++# CONFIG_TTY_PRINTK is not set
++# CONFIG_HVC_DCC is not set
++# CONFIG_IPMI_HANDLER is not set
++CONFIG_HW_RANDOM=y
++# CONFIG_HW_RANDOM_TIMERIOMEM is not set
++CONFIG_HW_RANDOM_TPM=y
++CONFIG_HW_RANDOM_ROCKCHIP=y
++
++#
++# PCMCIA character devices
++#
++# CONFIG_RAW_DRIVER is not set
++CONFIG_TCG_TPM=y
++# CONFIG_TCG_TIS_I2C_ATMEL is not set
++CONFIG_TCG_TIS_I2C_INFINEON=y
++# CONFIG_TCG_TIS_I2C_NUVOTON is not set
++# CONFIG_TCG_TIS_ST33ZP24 is not set
++# CONFIG_XILLYBUS is not set
++
++#
++# I2C support
++#
++CONFIG_I2C=y
++CONFIG_I2C_BOARDINFO=y
++CONFIG_I2C_COMPAT=y
++CONFIG_I2C_CHARDEV=y
++CONFIG_I2C_MUX=y
++
++#
++# Multiplexer I2C Chip support
++#
++# CONFIG_I2C_ARB_GPIO_CHALLENGE is not set
++# CONFIG_I2C_MUX_GPIO is not set
++# CONFIG_I2C_MUX_PCA9541 is not set
++# CONFIG_I2C_MUX_PCA954x is not set
++# CONFIG_I2C_MUX_PINCTRL is not set
++# CONFIG_I2C_MUX_REG is not set
++CONFIG_I2C_HELPER_AUTO=y
++CONFIG_I2C_ALGOBIT=y
++
++#
++# I2C Hardware Bus support
++#
++
++#
++# I2C system bus drivers (mostly embedded / system-on-chip)
++#
++# CONFIG_I2C_CADENCE is not set
++# CONFIG_I2C_CBUS_GPIO is not set
++# CONFIG_I2C_DESIGNWARE_PLATFORM is not set
++# CONFIG_I2C_EMEV2 is not set
++# CONFIG_I2C_GPIO is not set
++# CONFIG_I2C_NOMADIK is not set
++# CONFIG_I2C_OCORES is not set
++# CONFIG_I2C_PCA_PLATFORM is not set
++# CONFIG_I2C_PXA_PCI is not set
++CONFIG_I2C_RK3X=y
++# CONFIG_I2C_SIMTEC is not set
++# CONFIG_I2C_XILINX is not set
++
++#
++# External I2C/SMBus adapter drivers
++#
++# CONFIG_I2C_DIOLAN_U2C is not set
++# CONFIG_I2C_PARPORT_LIGHT is not set
++# CONFIG_I2C_ROBOTFUZZ_OSIF is not set
++# CONFIG_I2C_TAOS_EVM is not set
++# CONFIG_I2C_TINY_USB is not set
++
++#
++# Other I2C/SMBus bus drivers
++#
++# CONFIG_I2C_STUB is not set
++# CONFIG_I2C_SLAVE is not set
++# CONFIG_I2C_DEBUG_CORE is not set
++# CONFIG_I2C_DEBUG_ALGO is not set
++# CONFIG_I2C_DEBUG_BUS is not set
++CONFIG_SPI=y
++# CONFIG_SPI_DEBUG is not set
++CONFIG_SPI_MASTER=y
++
++#
++# SPI Master Controller Drivers
++#
++# CONFIG_SPI_ALTERA is not set
++CONFIG_SPI_BITBANG=y
++# CONFIG_SPI_CADENCE is not set
++# CONFIG_SPI_GPIO is not set
++# CONFIG_SPI_FSL_SPI is not set
++# CONFIG_SPI_OC_TINY is not set
++# CONFIG_SPI_PL022 is not set
++# CONFIG_SPI_PXA2XX_PCI is not set
++CONFIG_SPI_ROCKCHIP=y
++# CONFIG_SPI_SC18IS602 is not set
++# CONFIG_SPI_XCOMM is not set
++# CONFIG_SPI_XILINX is not set
++# CONFIG_SPI_ZYNQMP_GQSPI is not set
++# CONFIG_SPI_DESIGNWARE is not set
++
++#
++# SPI Protocol Masters
++#
++CONFIG_SPI_SPIDEV=y
++# CONFIG_SPI_TLE62X0 is not set
++# CONFIG_SPMI is not set
++# CONFIG_HSI is not set
++
++#
++# PPS support
++#
++CONFIG_PPS=y
++# CONFIG_PPS_DEBUG is not set
++
++#
++# PPS clients support
++#
++# CONFIG_PPS_CLIENT_KTIMER is not set
++# CONFIG_PPS_CLIENT_LDISC is not set
++# CONFIG_PPS_CLIENT_GPIO is not set
++
++#
++# PPS generators support
++#
++
++#
++# PTP clock support
++#
++CONFIG_PTP_1588_CLOCK=y
++
++#
++# Enable PHYLIB and NETWORK_PHY_TIMESTAMPING to see the additional clocks.
++#
++CONFIG_PINCTRL=y
++
++#
++# Pin controllers
++#
++CONFIG_PINMUX=y
++CONFIG_PINCONF=y
++CONFIG_GENERIC_PINCONF=y
++# CONFIG_DEBUG_PINCTRL is not set
++# CONFIG_PINCTRL_AMD is not set
++CONFIG_PINCTRL_ROCKCHIP=y
++# CONFIG_PINCTRL_SINGLE is not set
++CONFIG_PINCTRL_RK805=y
++CONFIG_ARCH_WANT_OPTIONAL_GPIOLIB=y
++CONFIG_ARCH_REQUIRE_GPIOLIB=y
++CONFIG_GPIOLIB=y
++CONFIG_GPIO_DEVRES=y
++CONFIG_OF_GPIO=y
++CONFIG_DEBUG_GPIO=y
++CONFIG_GPIO_SYSFS=y
++CONFIG_GPIO_GENERIC=y
++
++#
++# Memory mapped GPIO drivers
++#
++# CONFIG_GPIO_74XX_MMIO is not set
++# CONFIG_GPIO_ALTERA is not set
++# CONFIG_GPIO_DWAPB is not set
++CONFIG_GPIO_GENERIC_PLATFORM=y
++# CONFIG_GPIO_GRGPIO is not set
++# CONFIG_GPIO_PL061 is not set
++# CONFIG_GPIO_SYSCON is not set
++# CONFIG_GPIO_XGENE is not set
++# CONFIG_GPIO_XILINX is not set
++# CONFIG_GPIO_ZX is not set
++
++#
++# I2C GPIO expanders
++#
++# CONFIG_GPIO_ADP5588 is not set
++# CONFIG_GPIO_ADNP is not set
++# CONFIG_GPIO_MAX7300 is not set
++# CONFIG_GPIO_MAX732X is not set
++# CONFIG_GPIO_PCA953X is not set
++# CONFIG_GPIO_PCF857X is not set
++# CONFIG_GPIO_SX150X is not set
++
++#
++# MFD GPIO expanders
++#
++CONFIG_GPIO_RK8XX=y
++
++#
++# SPI GPIO expanders
++#
++# CONFIG_GPIO_74X164 is not set
++# CONFIG_GPIO_MAX7301 is not set
++# CONFIG_GPIO_MC33880 is not set
++
++#
++# SPI or I2C GPIO expanders
++#
++# CONFIG_GPIO_MCP23S08 is not set
++
++#
++# USB GPIO expanders
++#
++# CONFIG_W1 is not set
++CONFIG_POWER_SUPPLY=y
++# CONFIG_POWER_SUPPLY_DEBUG is not set
++# CONFIG_PDA_POWER is not set
++# CONFIG_GENERIC_ADC_BATTERY is not set
++# CONFIG_TEST_POWER is not set
++# CONFIG_BATTERY_DS2780 is not set
++# CONFIG_BATTERY_DS2781 is not set
++# CONFIG_BATTERY_DS2782 is not set
++# CONFIG_BATTERY_SBS is not set
++# CONFIG_BATTERY_BQ27XXX is not set
++# CONFIG_BATTERY_MAX17040 is not set
++# CONFIG_BATTERY_MAX17042 is not set
++# CONFIG_CHARGER_MAX8903 is not set
++# CONFIG_CHARGER_LP8727 is not set
++CONFIG_CHARGER_GPIO=y
++# CONFIG_CHARGER_MANAGER is not set
++# CONFIG_CHARGER_BQ2415X is not set
++# CONFIG_CHARGER_BQ24190 is not set
++# CONFIG_CHARGER_BQ24257 is not set
++# CONFIG_CHARGER_BQ24735 is not set
++# CONFIG_CHARGER_BQ25700 is not set
++# CONFIG_CHARGER_BQ25890 is not set
++# CONFIG_CHARGER_SMB347 is not set
++# CONFIG_CHARGER_SY6982C is not set
++# CONFIG_CHARGER_UNIVERSAL is not set
++# CONFIG_BATTERY_GAUGE_LTC2941 is not set
++# CONFIG_BATTERY_EC is not set
++# CONFIG_BATTERY_CW2015 is not set
++# CONFIG_BATTERY_RK816 is not set
++CONFIG_BATTERY_RK817=y
++CONFIG_CHARGER_RK817=y
++# CONFIG_BATTERY_RK818 is not set
++# CONFIG_CHARGER_RK818 is not set
++# CONFIG_CHARGER_RT9455 is not set
++CONFIG_POWER_RESET=y
++CONFIG_POWER_RESET_GPIO=y
++CONFIG_POWER_RESET_GPIO_RESTART=y
++# CONFIG_POWER_RESET_LTC2952 is not set
++# CONFIG_POWER_RESET_RESTART is not set
++# CONFIG_POWER_RESET_XGENE is not set
++# CONFIG_POWER_RESET_SYSCON is not set
++# CONFIG_POWER_RESET_SYSCON_POWEROFF is not set
++CONFIG_REBOOT_MODE=y
++CONFIG_SYSCON_REBOOT_MODE=y
++CONFIG_POWER_AVS=y
++CONFIG_ROCKCHIP_IODOMAIN=y
++CONFIG_HWMON=y
++# CONFIG_HWMON_VID is not set
++# CONFIG_HWMON_DEBUG_CHIP is not set
++
++#
++# Native drivers
++#
++# CONFIG_SENSORS_AD7314 is not set
++# CONFIG_SENSORS_AD7414 is not set
++# CONFIG_SENSORS_AD7418 is not set
++# CONFIG_SENSORS_ADM1021 is not set
++# CONFIG_SENSORS_ADM1025 is not set
++# CONFIG_SENSORS_ADM1026 is not set
++# CONFIG_SENSORS_ADM1029 is not set
++# CONFIG_SENSORS_ADM1031 is not set
++# CONFIG_SENSORS_ADM9240 is not set
++# CONFIG_SENSORS_ADT7310 is not set
++# CONFIG_SENSORS_ADT7410 is not set
++# CONFIG_SENSORS_ADT7411 is not set
++# CONFIG_SENSORS_ADT7462 is not set
++# CONFIG_SENSORS_ADT7470 is not set
++# CONFIG_SENSORS_ADT7475 is not set
++# CONFIG_SENSORS_ASC7621 is not set
++# CONFIG_SENSORS_ATXP1 is not set
++# CONFIG_SENSORS_DS620 is not set
++# CONFIG_SENSORS_DS1621 is not set
++# CONFIG_SENSORS_F71805F is not set
++# CONFIG_SENSORS_F71882FG is not set
++# CONFIG_SENSORS_F75375S is not set
++# CONFIG_SENSORS_GL518SM is not set
++# CONFIG_SENSORS_GL520SM is not set
++# CONFIG_SENSORS_G760A is not set
++# CONFIG_SENSORS_G762 is not set
++# CONFIG_SENSORS_GPIO_FAN is not set
++# CONFIG_SENSORS_HIH6130 is not set
++# CONFIG_SENSORS_IIO_HWMON is not set
++# CONFIG_SENSORS_IT87 is not set
++# CONFIG_SENSORS_JC42 is not set
++# CONFIG_SENSORS_POWR1220 is not set
++# CONFIG_SENSORS_LINEAGE is not set
++# CONFIG_SENSORS_LTC2945 is not set
++# CONFIG_SENSORS_LTC4151 is not set
++# CONFIG_SENSORS_LTC4215 is not set
++# CONFIG_SENSORS_LTC4222 is not set
++# CONFIG_SENSORS_LTC4245 is not set
++# CONFIG_SENSORS_LTC4260 is not set
++# CONFIG_SENSORS_LTC4261 is not set
++# CONFIG_SENSORS_MAX1111 is not set
++# CONFIG_SENSORS_MAX16065 is not set
++# CONFIG_SENSORS_MAX1619 is not set
++# CONFIG_SENSORS_MAX1668 is not set
++# CONFIG_SENSORS_MAX197 is not set
++# CONFIG_SENSORS_MAX6639 is not set
++# CONFIG_SENSORS_MAX6642 is not set
++# CONFIG_SENSORS_MAX6650 is not set
++# CONFIG_SENSORS_MAX6697 is not set
++# CONFIG_SENSORS_MAX31790 is not set
++# CONFIG_SENSORS_HTU21 is not set
++# CONFIG_SENSORS_MCP3021 is not set
++# CONFIG_SENSORS_ADCXX is not set
++# CONFIG_SENSORS_LM63 is not set
++# CONFIG_SENSORS_LM70 is not set
++# CONFIG_SENSORS_LM73 is not set
++# CONFIG_SENSORS_LM75 is not set
++# CONFIG_SENSORS_LM77 is not set
++# CONFIG_SENSORS_LM78 is not set
++# CONFIG_SENSORS_LM80 is not set
++# CONFIG_SENSORS_LM83 is not set
++# CONFIG_SENSORS_LM85 is not set
++# CONFIG_SENSORS_LM87 is not set
++# CONFIG_SENSORS_LM90 is not set
++# CONFIG_SENSORS_LM92 is not set
++# CONFIG_SENSORS_LM93 is not set
++# CONFIG_SENSORS_LM95234 is not set
++# CONFIG_SENSORS_LM95241 is not set
++# CONFIG_SENSORS_LM95245 is not set
++# CONFIG_SENSORS_PC87360 is not set
++# CONFIG_SENSORS_PC87427 is not set
++# CONFIG_SENSORS_NTC_THERMISTOR is not set
++# CONFIG_SENSORS_NCT6683 is not set
++# CONFIG_SENSORS_NCT6775 is not set
++# CONFIG_SENSORS_NCT7802 is not set
++# CONFIG_SENSORS_NCT7904 is not set
++# CONFIG_SENSORS_PCF8591 is not set
++# CONFIG_PMBUS is not set
++# CONFIG_SENSORS_PWM_FAN is not set
++# CONFIG_SENSORS_SHT15 is not set
++# CONFIG_SENSORS_SHT21 is not set
++# CONFIG_SENSORS_SHTC1 is not set
++# CONFIG_SENSORS_DME1737 is not set
++# CONFIG_SENSORS_EMC1403 is not set
++# CONFIG_SENSORS_EMC2103 is not set
++# CONFIG_SENSORS_EMC6W201 is not set
++# CONFIG_SENSORS_SMSC47M1 is not set
++# CONFIG_SENSORS_SMSC47M192 is not set
++# CONFIG_SENSORS_SMSC47B397 is not set
++# CONFIG_SENSORS_SCH56XX_COMMON is not set
++# CONFIG_SENSORS_SCH5627 is not set
++# CONFIG_SENSORS_SCH5636 is not set
++# CONFIG_SENSORS_SMM665 is not set
++# CONFIG_SENSORS_ADC128D818 is not set
++CONFIG_SENSORS_ADS1015=y
++# CONFIG_SENSORS_ADS7828 is not set
++# CONFIG_SENSORS_ADS7871 is not set
++# CONFIG_SENSORS_AMC6821 is not set
++# CONFIG_SENSORS_INA209 is not set
++# CONFIG_SENSORS_INA2XX is not set
++# CONFIG_SENSORS_TC74 is not set
++# CONFIG_SENSORS_THMC50 is not set
++# CONFIG_SENSORS_TMP102 is not set
++# CONFIG_SENSORS_TMP103 is not set
++# CONFIG_SENSORS_TMP401 is not set
++# CONFIG_SENSORS_TMP421 is not set
++# CONFIG_SENSORS_VT1211 is not set
++# CONFIG_SENSORS_W83781D is not set
++# CONFIG_SENSORS_W83791D is not set
++# CONFIG_SENSORS_W83792D is not set
++# CONFIG_SENSORS_W83793 is not set
++# CONFIG_SENSORS_W83795 is not set
++# CONFIG_SENSORS_W83L785TS is not set
++# CONFIG_SENSORS_W83L786NG is not set
++# CONFIG_SENSORS_W83627HF is not set
++# CONFIG_SENSORS_W83627EHF is not set
++CONFIG_THERMAL=y
++CONFIG_THERMAL_HWMON=y
++CONFIG_THERMAL_OF=y
++CONFIG_THERMAL_WRITABLE_TRIPS=y
++# CONFIG_THERMAL_DEFAULT_GOV_STEP_WISE is not set
++# CONFIG_THERMAL_DEFAULT_GOV_FAIR_SHARE is not set
++# CONFIG_THERMAL_DEFAULT_GOV_USER_SPACE is not set
++CONFIG_THERMAL_DEFAULT_GOV_POWER_ALLOCATOR=y
++CONFIG_THERMAL_GOV_FAIR_SHARE=y
++CONFIG_THERMAL_GOV_STEP_WISE=y
++# CONFIG_THERMAL_GOV_BANG_BANG is not set
++# CONFIG_THERMAL_GOV_USER_SPACE is not set
++CONFIG_THERMAL_GOV_POWER_ALLOCATOR=y
++CONFIG_CPU_THERMAL=y
++# CONFIG_CLOCK_THERMAL is not set
++CONFIG_DEVFREQ_THERMAL=y
++# CONFIG_THERMAL_EMULATION is not set
++# CONFIG_IMX_THERMAL is not set
++CONFIG_ROCKCHIP_THERMAL=y
++# CONFIG_RK_VIRTUAL_THERMAL is not set
++# CONFIG_RK3368_THERMAL is not set
++CONFIG_WATCHDOG=y
++# CONFIG_WATCHDOG_CORE is not set
++# CONFIG_WATCHDOG_NOWAYOUT is not set
++
++#
++# Watchdog Device Drivers
++#
++# CONFIG_SOFT_WATCHDOG is not set
++# CONFIG_GPIO_WATCHDOG is not set
++# CONFIG_XILINX_WATCHDOG is not set
++# CONFIG_ARM_SP805_WATCHDOG is not set
++# CONFIG_CADENCE_WATCHDOG is not set
++CONFIG_DW_WATCHDOG=y
++# CONFIG_MAX63XX_WATCHDOG is not set
++# CONFIG_BCM7038_WDT is not set
++# CONFIG_MEN_A21_WDT is not set
++
++#
++# USB-based Watchdog Cards
++#
++# CONFIG_USBPCWATCHDOG is not set
++CONFIG_SSB_POSSIBLE=y
++
++#
++# Sonics Silicon Backplane
++#
++# CONFIG_SSB is not set
++CONFIG_BCMA_POSSIBLE=y
++
++#
++# Broadcom specific AMBA
++#
++# CONFIG_BCMA is not set
++
++#
++# Multifunction device drivers
++#
++CONFIG_MFD_CORE=y
++# CONFIG_MFD_AS3711 is not set
++# CONFIG_MFD_AS3722 is not set
++# CONFIG_PMIC_ADP5520 is not set
++# CONFIG_MFD_AAT2870_CORE is not set
++# CONFIG_MFD_ATMEL_FLEXCOM is not set
++# CONFIG_MFD_ATMEL_HLCDC is not set
++# CONFIG_MFD_BCM590XX is not set
++# CONFIG_MFD_AXP20X is not set
++# CONFIG_MFD_CROS_EC is not set
++# CONFIG_PMIC_DA903X is not set
++# CONFIG_MFD_DA9052_SPI is not set
++# CONFIG_MFD_DA9052_I2C is not set
++# CONFIG_MFD_DA9055 is not set
++# CONFIG_MFD_DA9062 is not set
++# CONFIG_MFD_DA9063 is not set
++# CONFIG_MFD_DA9150 is not set
++# CONFIG_MFD_DLN2 is not set
++# CONFIG_MFD_MC13XXX_SPI is not set
++# CONFIG_MFD_MC13XXX_I2C is not set
++# CONFIG_MFD_HI6421_PMIC is not set
++# CONFIG_HTC_PASIC3 is not set
++# CONFIG_HTC_I2CPLD is not set
++# CONFIG_INTEL_SOC_PMIC is not set
++# CONFIG_MFD_KEMPLD is not set
++# CONFIG_MFD_88PM800 is not set
++# CONFIG_MFD_88PM805 is not set
++# CONFIG_MFD_88PM860X is not set
++# CONFIG_MFD_MAX14577 is not set
++# CONFIG_MFD_MAX77686 is not set
++# CONFIG_MFD_MAX77693 is not set
++# CONFIG_MFD_MAX77843 is not set
++# CONFIG_MFD_MAX8907 is not set
++# CONFIG_MFD_MAX8925 is not set
++# CONFIG_MFD_MAX8997 is not set
++# CONFIG_MFD_MAX8998 is not set
++# CONFIG_MFD_MT6397 is not set
++# CONFIG_MFD_MENF21BMC is not set
++# CONFIG_EZX_PCAP is not set
++# CONFIG_MFD_VIPERBOARD is not set
++# CONFIG_MFD_RETU is not set
++# CONFIG_MFD_PCF50633 is not set
++# CONFIG_MFD_RT5033 is not set
++# CONFIG_MFD_RTSX_USB is not set
++# CONFIG_MFD_RC5T583 is not set
++# CONFIG_MFD_RK618 is not set
++CONFIG_MFD_RK808=y
++# CONFIG_MFD_RN5T618 is not set
++# CONFIG_MFD_SEC_CORE is not set
++# CONFIG_MFD_SI476X_CORE is not set
++# CONFIG_MFD_SM501 is not set
++# CONFIG_MFD_SKY81452 is not set
++# CONFIG_MFD_SMSC is not set
++# CONFIG_ABX500_CORE is not set
++# CONFIG_MFD_STMPE is not set
++CONFIG_MFD_SYSCON=y
++# CONFIG_MFD_TI_AM335X_TSCADC is not set
++# CONFIG_MFD_LP3943 is not set
++# CONFIG_MFD_LP8788 is not set
++# CONFIG_MFD_PALMAS is not set
++# CONFIG_TPS6105X is not set
++# CONFIG_TPS65010 is not set
++# CONFIG_TPS6507X is not set
++# CONFIG_MFD_TPS65090 is not set
++# CONFIG_MFD_TPS65217 is not set
++# CONFIG_MFD_TPS65218 is not set
++# CONFIG_MFD_TPS6586X is not set
++# CONFIG_MFD_TPS65910 is not set
++# CONFIG_MFD_TPS65912 is not set
++# CONFIG_MFD_TPS65912_I2C is not set
++# CONFIG_MFD_TPS65912_SPI is not set
++# CONFIG_MFD_TPS80031 is not set
++# CONFIG_TWL4030_CORE is not set
++# CONFIG_TWL6040_CORE is not set
++# CONFIG_MFD_WL1273_CORE is not set
++# CONFIG_MFD_LM3533 is not set
++# CONFIG_MFD_TC3589X is not set
++# CONFIG_MFD_TMIO is not set
++# CONFIG_MFD_ARIZONA_I2C is not set
++# CONFIG_MFD_ARIZONA_SPI is not set
++# CONFIG_MFD_WM8400 is not set
++# CONFIG_MFD_WM831X_I2C is not set
++# CONFIG_MFD_WM831X_SPI is not set
++# CONFIG_MFD_RK1000 is not set
++# CONFIG_MFD_WM8350_I2C is not set
++# CONFIG_MFD_WM8994 is not set
++CONFIG_FUSB_30X=y
++CONFIG_REGULATOR=y
++CONFIG_REGULATOR_DEBUG=y
++CONFIG_REGULATOR_FIXED_VOLTAGE=y
++# CONFIG_REGULATOR_VIRTUAL_CONSUMER is not set
++# CONFIG_REGULATOR_USERSPACE_CONSUMER is not set
++# CONFIG_REGULATOR_ACT8865 is not set
++# CONFIG_REGULATOR_AD5398 is not set
++# CONFIG_REGULATOR_ANATOP is not set
++# CONFIG_REGULATOR_DA9210 is not set
++# CONFIG_REGULATOR_DA9211 is not set
++CONFIG_REGULATOR_FAN53555=y
++CONFIG_REGULATOR_GPIO=y
++# CONFIG_REGULATOR_ISL9305 is not set
++# CONFIG_REGULATOR_ISL6271A is not set
++# CONFIG_REGULATOR_LP3971 is not set
++# CONFIG_REGULATOR_LP3972 is not set
++# CONFIG_REGULATOR_LP872X is not set
++# CONFIG_REGULATOR_LP8752 is not set
++# CONFIG_REGULATOR_LP8755 is not set
++# CONFIG_REGULATOR_LTC3589 is not set
++# CONFIG_REGULATOR_MAX1586 is not set
++# CONFIG_REGULATOR_MAX8649 is not set
++# CONFIG_REGULATOR_MAX8660 is not set
++# CONFIG_REGULATOR_MAX8952 is not set
++# CONFIG_REGULATOR_MAX8973 is not set
++# CONFIG_REGULATOR_MP8865 is not set
++# CONFIG_REGULATOR_MT6311 is not set
++# CONFIG_REGULATOR_PFUZE100 is not set
++CONFIG_REGULATOR_PWM=y
++CONFIG_REGULATOR_RK808=y
++CONFIG_REGULATOR_RK818=y
++# CONFIG_REGULATOR_SYR82X is not set
++# CONFIG_REGULATOR_TPS51632 is not set
++# CONFIG_REGULATOR_TPS549B22 is not set
++# CONFIG_REGULATOR_TPS62360 is not set
++# CONFIG_REGULATOR_TPS65023 is not set
++# CONFIG_REGULATOR_TPS6507X is not set
++# CONFIG_REGULATOR_TPS65132 is not set
++# CONFIG_REGULATOR_TPS6524X is not set
++# CONFIG_REGULATOR_XZ3216 is not set
++CONFIG_MEDIA_SUPPORT=y
++
++#
++# Multimedia core support
++#
++CONFIG_MEDIA_CAMERA_SUPPORT=y
++# CONFIG_MEDIA_ANALOG_TV_SUPPORT is not set
++# CONFIG_MEDIA_DIGITAL_TV_SUPPORT is not set
++# CONFIG_MEDIA_RADIO_SUPPORT is not set
++# CONFIG_MEDIA_SDR_SUPPORT is not set
++CONFIG_MEDIA_RC_SUPPORT=y
++# CONFIG_MEDIA_CEC_SUPPORT is not set
++CONFIG_MEDIA_CONTROLLER=y
++CONFIG_VIDEO_DEV=y
++CONFIG_VIDEO_V4L2_SUBDEV_API=y
++CONFIG_VIDEO_V4L2=y
++# CONFIG_VIDEO_ADV_DEBUG is not set
++# CONFIG_VIDEO_FIXED_MINOR_RANGES is not set
++CONFIG_V4L2_MEM2MEM_DEV=y
++CONFIG_V4L2_FWNODE=y
++CONFIG_VIDEOBUF_GEN=y
++CONFIG_VIDEOBUF2_CORE=y
++CONFIG_VIDEOBUF2_MEMOPS=y
++CONFIG_VIDEOBUF2_DMA_CONTIG=y
++CONFIG_VIDEOBUF2_VMALLOC=y
++CONFIG_VIDEOBUF2_DMA_SG=y
++# CONFIG_TTPCI_EEPROM is not set
++
++#
++# Media drivers
++#
++CONFIG_RC_CORE=y
++CONFIG_RC_MAP=y
++# CONFIG_LIRC is not set
++CONFIG_RC_DECODERS=y
++CONFIG_IR_NEC_DECODER=y
++# CONFIG_IR_RC5_DECODER is not set
++# CONFIG_IR_RC6_DECODER is not set
++# CONFIG_IR_JVC_DECODER is not set
++# CONFIG_IR_SONY_DECODER is not set
++# CONFIG_IR_SANYO_DECODER is not set
++# CONFIG_IR_SHARP_DECODER is not set
++# CONFIG_IR_MCE_KBD_DECODER is not set
++# CONFIG_IR_XMP_DECODER is not set
++# CONFIG_IR_IMON_DECODER is not set
++# CONFIG_RC_DEVICES is not set
++CONFIG_MEDIA_USB_SUPPORT=y
++
++#
++# Webcam devices
++#
++CONFIG_USB_VIDEO_CLASS=y
++# CONFIG_USB_VIDEO_CLASS_INPUT_EVDEV is not set
++# CONFIG_USB_GSPCA is not set
++# CONFIG_USB_PWC is not set
++# CONFIG_VIDEO_CPIA2 is not set
++# CONFIG_USB_ZR364XX is not set
++# CONFIG_USB_STKWEBCAM is not set
++# CONFIG_USB_S2255 is not set
++# CONFIG_VIDEO_USBTV is not set
++# CONFIG_NPU_USB_ACM is not set
++
++#
++# Webcam, TV (analog/digital) USB devices
++#
++# CONFIG_VIDEO_EM28XX is not set
++CONFIG_V4L_PLATFORM_DRIVERS=y
++CONFIG_SOC_CAMERA=y
++# CONFIG_SOC_CAMERA_PLATFORM is not set
++# CONFIG_VIDEO_XILINX is not set
++# CONFIG_VIDEO_RK_CIF_ISP10 is not set
++# CONFIG_VIDEO_ROCKCHIP_CIF is not set
++CONFIG_VIDEO_ROCKCHIP_ISP1=y
++CONFIG_V4L_MEM2MEM_DRIVERS=y
++# CONFIG_VIDEO_MEM2MEM_DEINTERLACE is not set
++# CONFIG_VIDEO_SH_VEU is not set
++CONFIG_VIDEO_ROCKCHIP_RGA=y
++# CONFIG_VIDEO_ROCKCHIP_VPU is not set
++# CONFIG_V4L_TEST_DRIVERS is not set
++# CONFIG_ROCKCHIP_TSP is not set
++
++#
++# Supported MMC/SDIO adapters
++#
++# CONFIG_CYPRESS_FIRMWARE is not set
++
++#
++# Media ancillary drivers (tuners, sensors, i2c, spi, frontends)
++#
++# CONFIG_MEDIA_SUBDRV_AUTOSELECT is not set
++# CONFIG_VIDEO_IR_I2C is not set
++
++#
++# I2C Encoders, decoders, sensors and other helper chips
++#
++
++#
++# Audio decoders, processors and mixers
++#
++# CONFIG_VIDEO_TVAUDIO is not set
++# CONFIG_VIDEO_TDA7432 is not set
++# CONFIG_VIDEO_TDA9840 is not set
++# CONFIG_VIDEO_TEA6415C is not set
++# CONFIG_VIDEO_TEA6420 is not set
++# CONFIG_VIDEO_MSP3400 is not set
++# CONFIG_VIDEO_CS5345 is not set
++# CONFIG_VIDEO_CS53L32A is not set
++# CONFIG_VIDEO_TLV320AIC23B is not set
++# CONFIG_VIDEO_UDA1342 is not set
++# CONFIG_VIDEO_WM8775 is not set
++# CONFIG_VIDEO_WM8739 is not set
++# CONFIG_VIDEO_VP27SMPX is not set
++# CONFIG_VIDEO_SONY_BTF_MPX is not set
++
++#
++# RDS decoders
++#
++# CONFIG_VIDEO_SAA6588 is not set
++
++#
++# Video decoders
++#
++# CONFIG_VIDEO_ADV7180 is not set
++# CONFIG_VIDEO_ADV7181D is not set
++# CONFIG_VIDEO_ADV7183 is not set
++# CONFIG_VIDEO_ADV7604 is not set
++# CONFIG_VIDEO_ADV7842 is not set
++# CONFIG_VIDEO_BT819 is not set
++# CONFIG_VIDEO_BT856 is not set
++# CONFIG_VIDEO_BT866 is not set
++# CONFIG_VIDEO_KS0127 is not set
++# CONFIG_VIDEO_ML86V7667 is not set
++# CONFIG_VIDEO_SAA7110 is not set
++# CONFIG_VIDEO_SAA711X is not set
++# CONFIG_VIDEO_TC35874X is not set
++# CONFIG_VIDEO_TVP514X is not set
++# CONFIG_VIDEO_TVP5150 is not set
++# CONFIG_VIDEO_TVP7002 is not set
++# CONFIG_VIDEO_TW2804 is not set
++# CONFIG_VIDEO_TW9903 is not set
++# CONFIG_VIDEO_TW9906 is not set
++# CONFIG_VIDEO_VPX3220 is not set
++
++#
++# Video and audio decoders
++#
++# CONFIG_VIDEO_SAA717X is not set
++# CONFIG_VIDEO_CX25840 is not set
++
++#
++# Video encoders
++#
++# CONFIG_VIDEO_SAA7127 is not set
++# CONFIG_VIDEO_SAA7185 is not set
++# CONFIG_VIDEO_ADV7170 is not set
++# CONFIG_VIDEO_ADV7175 is not set
++# CONFIG_VIDEO_ADV7343 is not set
++# CONFIG_VIDEO_ADV7393 is not set
++# CONFIG_VIDEO_ADV7511 is not set
++# CONFIG_VIDEO_AD9389B is not set
++# CONFIG_VIDEO_AK881X is not set
++# CONFIG_VIDEO_THS8200 is not set
++
++#
++# Camera sensor devices
++#
++# CONFIG_VIDEO_IMX219 is not set
++# CONFIG_VIDEO_IMX258 is not set
++# CONFIG_VIDEO_IMX317 is not set
++# CONFIG_VIDEO_IMX323 is not set
++# CONFIG_VIDEO_IMX327 is not set
++# CONFIG_VIDEO_VIRT_CAMERA is not set
++# CONFIG_VIDEO_OV2659 is not set
++# CONFIG_VIDEO_OV2680 is not set
++# CONFIG_VIDEO_OV2685 is not set
++# CONFIG_VIDEO_OV2718 is not set
++# CONFIG_VIDEO_OV2735 is not set
++# CONFIG_VIDEO_OV4689 is not set
++# CONFIG_VIDEO_OV5647 is not set
++# CONFIG_VIDEO_OV5648 is not set
++CONFIG_VIDEO_OV5695=y
++# CONFIG_VIDEO_OV7251 is not set
++# CONFIG_VIDEO_OV7640 is not set
++# CONFIG_VIDEO_OV7670 is not set
++# CONFIG_VIDEO_OV7725 is not set
++# CONFIG_VIDEO_OV7750 is not set
++# CONFIG_VIDEO_OV8858 is not set
++# CONFIG_VIDEO_OV9281 is not set
++# CONFIG_VIDEO_OV9650 is not set
++# CONFIG_VIDEO_OV13850 is not set
++# CONFIG_VIDEO_VS6624 is not set
++# CONFIG_VIDEO_MT9M032 is not set
++# CONFIG_VIDEO_MT9P031 is not set
++# CONFIG_VIDEO_MT9T001 is not set
++# CONFIG_VIDEO_MT9V011 is not set
++# CONFIG_VIDEO_MT9V032 is not set
++# CONFIG_VIDEO_AR0230 is not set
++# CONFIG_VIDEO_SR030PC30 is not set
++# CONFIG_VIDEO_NOON010PC30 is not set
++# CONFIG_VIDEO_M5MOLS is not set
++# CONFIG_VIDEO_S5K6AA is not set
++# CONFIG_VIDEO_S5K6A3 is not set
++# CONFIG_VIDEO_S5K4ECGX is not set
++# CONFIG_VIDEO_S5K5BAF is not set
++# CONFIG_VIDEO_SMIAPP is not set
++# CONFIG_VIDEO_S5C73M3 is not set
++# CONFIG_VIDEO_GC2155 is not set
++# CONFIG_VIDEO_GC0312 is not set
++# CONFIG_VIDEO_GC2145 is not set
++CONFIG_VIDEO_GC2355=y
++# CONFIG_VIDEO_GC2385 is not set
++# CONFIG_VIDEO_GC5025 is not set
++# CONFIG_VIDEO_GC8034 is not set
++CONFIG_VIDEO_SC031GS=y
++# CONFIG_VIDEO_SC132GS is not set
++# CONFIG_VIDEO_GC0329 is not set
++# CONFIG_VIDEO_GC2035 is not set
++# CONFIG_VIDEO_BF3925 is not set
++# CONFIG_VIDEO_JX_H65 is not set
++CONFIG_VIDEO_PREISP_DUMMY_SENSOR=y
++
++#
++# Flash devices
++#
++# CONFIG_VIDEO_ADP1653 is not set
++# CONFIG_VIDEO_AS3645A is not set
++# CONFIG_VIDEO_LM3560 is not set
++# CONFIG_VIDEO_LM3646 is not set
++# CONFIG_VIDEO_SGM3784 is not set
++
++#
++# Video improvement chips
++#
++# CONFIG_VIDEO_UPD64031A is not set
++# CONFIG_VIDEO_UPD64083 is not set
++
++#
++# Camera lens devices
++#
++# CONFIG_VIDEO_VM149C is not set
++# CONFIG_VIDEO_DW9714 is not set
++# CONFIG_VIDEO_FP5510 is not set
++
++#
++# Audio/Video compression chips
++#
++# CONFIG_VIDEO_SAA6752HS is not set
++
++#
++# Miscellaneous helper chips
++#
++# CONFIG_VIDEO_THS7303 is not set
++# CONFIG_VIDEO_M52790 is not set
++# CONFIG_VIDEO_NVP6324 is not set
++
++#
++# Sensors used on soc_camera driver
++#
++
++#
++# soc_camera sensor drivers
++#
++# CONFIG_SOC_CAMERA_IMX074 is not set
++# CONFIG_SOC_CAMERA_MT9M001 is not set
++# CONFIG_SOC_CAMERA_MT9M111 is not set
++# CONFIG_SOC_CAMERA_MT9T031 is not set
++# CONFIG_SOC_CAMERA_MT9T112 is not set
++# CONFIG_SOC_CAMERA_MT9V022 is not set
++# CONFIG_SOC_CAMERA_OV2640 is not set
++# CONFIG_SOC_CAMERA_OV5642 is not set
++# CONFIG_SOC_CAMERA_OV6650 is not set
++# CONFIG_SOC_CAMERA_OV772X is not set
++# CONFIG_SOC_CAMERA_OV9640 is not set
++# CONFIG_SOC_CAMERA_OV9740 is not set
++# CONFIG_SOC_CAMERA_RJ54N1 is not set
++# CONFIG_SOC_CAMERA_TW9910 is not set
++
++#
++# SPI helper chips
++#
++# CONFIG_VIDEO_GS1662 is not set
++CONFIG_VIDEO_ROCKCHIP_PREISP=y
++
++#
++# Customise DVB Frontends
++#
++# CONFIG_DVB_AU8522_V4L is not set
++# CONFIG_DVB_TUNER_DIB0070 is not set
++# CONFIG_DVB_TUNER_DIB0090 is not set
++
++#
++# Tools to develop new frontends
++#
++# CONFIG_DVB_DUMMY_FE is not set
++# CONFIG_CAMSYS_DRV is not set
++# CONFIG_ROCK_CHIP_SOC_CAMERA is not set
++
++#
++# Graphics support
++#
++CONFIG_DRM=y
++CONFIG_DRM_IGNORE_IOTCL_PERMIT=y
++CONFIG_DRM_MIPI_DSI=y
++CONFIG_DRM_KMS_HELPER=y
++CONFIG_DRM_KMS_FB_HELPER=y
++CONFIG_DRM_FBDEV_EMULATION=y
++CONFIG_DRM_LOAD_EDID_FIRMWARE=y
++# CONFIG_DRM_DP_CEC is not set
++# CONFIG_DRM_SCDC_HELPER is not set
++CONFIG_DRM_DMA_SYNC=y
++
++#
++# I2C encoder or helper chips
++#
++# CONFIG_DRM_I2C_ADV7511 is not set
++# CONFIG_DRM_I2C_CH7006 is not set
++# CONFIG_DRM_I2C_SIL164 is not set
++# CONFIG_DRM_I2C_NXP_TDA998X is not set
++# CONFIG_DRM_VGEM is not set
++CONFIG_DRM_ROCKCHIP=y
++# CONFIG_ROCKCHIP_DRM_DEBUG is not set
++# CONFIG_ROCKCHIP_DW_HDMI is not set
++CONFIG_ROCKCHIP_DW_MIPI_DSI=y
++# CONFIG_ROCKCHIP_MIPI_CSI_TX is not set
++CONFIG_ROCKCHIP_ANALOGIX_DP=y
++# CONFIG_ROCKCHIP_INNO_HDMI is not set
++CONFIG_ROCKCHIP_LVDS=y
++CONFIG_ROCKCHIP_DRM_TVE=y
++# CONFIG_ROCKCHIP_RGB is not set
++# CONFIG_ROCKCHIP_DRM_BACKLIGHT is not set
++# CONFIG_ROCKCHIP_RK3066_HDMI is not set
++# CONFIG_DRM_UDL is not set
++CONFIG_DRM_PANEL=y
++
++#
++# Display Panels
++#
++CONFIG_DRM_PANEL_SIMPLE=y
++# CONFIG_DRM_PANEL_SAMSUNG_LD9040 is not set
++# CONFIG_DRM_PANEL_LG_LG4573 is not set
++# CONFIG_DRM_PANEL_SAMSUNG_S6E8AA0 is not set
++# CONFIG_DRM_PANEL_SHARP_LQ101R1SX01 is not set
++CONFIG_DRM_BRIDGE=y
++
++#
++# Display Interface Bridges
++#
++# CONFIG_DRM_NXP_PTN3460 is not set
++# CONFIG_DRM_PARADE_PS8622 is not set
++# CONFIG_DRM_RK1000 is not set
++# CONFIG_DRM_DUMB_VGA_DAC is not set
++# CONFIG_DRM_LONTIUM_LT8912 is not set
++CONFIG_DRM_LONTIUM_LT9611_I2C=y
++# CONFIG_DRM_CHIPONE_ICN6211 is not set
++CONFIG_DRM_ANALOGIX_DP=y
++# CONFIG_DRM_ANALOGIX_ANX78XX is not set
++# CONFIG_DRM_ANALOGIX_ANX6345 is not set
++# CONFIG_POWERVR_ROGUE_M is not set
++# CONFIG_MALI400 is not set
++CONFIG_MALI_MIDGARD_FOR_ANDROID=y
++# CONFIG_MALI_MIDGARD_FOR_LINUX is not set
++# CONFIG_MALI_MIDGARD is not set
++# CONFIG_MALI_CORESTACK is not set
++CONFIG_MALI_PWRSOFT_765=y
++# CONFIG_MALI_KUTF is not set
++# CONFIG_MALI_BIFROST_FOR_ANDROID is not set
++CONFIG_MALI_BIFROST_FOR_LINUX=y
++CONFIG_MALI_BIFROST=y
++# CONFIG_MALI_BIFROST_GATOR_SUPPORT is not set
++# CONFIG_MALI_BIFROST_ENABLE_TRACE is not set
++CONFIG_MALI_BIFROST_DEVFREQ=y
++# CONFIG_MALI_BIFROST_DMA_FENCE is not set
++CONFIG_MALI_PLATFORM_NAME="rk"
++CONFIG_MALI_BIFROST_EXPERT=y
++# CONFIG_MALI_BIFROST_PRFCNT_SET_SECONDARY is not set
++CONFIG_MALI_BIFROST_DEBUG=y
++# CONFIG_MALI_BIFROST_NO_MALI is not set
++# CONFIG_MALI_BIFROST_TRACE_TIMELINE is not set
++# CONFIG_MALI_BIFROST_SYSTEM_TRACE is not set
++# CONFIG_MALI_JOB_DUMP is not set
++# CONFIG_MALI_2MB_ALLOC is not set
++
++#
++# Frame buffer Devices
++#
++CONFIG_FB=y
++# CONFIG_FIRMWARE_EDID is not set
++CONFIG_FB_CMDLINE=y
++# CONFIG_FB_DDC is not set
++# CONFIG_FB_BOOT_VESA_SUPPORT is not set
++CONFIG_FB_CFB_FILLRECT=y
++CONFIG_FB_CFB_COPYAREA=y
++CONFIG_FB_CFB_IMAGEBLIT=y
++# CONFIG_FB_CFB_REV_PIXELS_IN_BYTE is not set
++CONFIG_FB_SYS_FILLRECT=y
++CONFIG_FB_SYS_COPYAREA=y
++CONFIG_FB_SYS_IMAGEBLIT=y
++# CONFIG_FB_FOREIGN_ENDIAN is not set
++CONFIG_FB_SYS_FOPS=y
++# CONFIG_FB_SVGALIB is not set
++# CONFIG_FB_MACMODES is not set
++# CONFIG_FB_BACKLIGHT is not set
++# CONFIG_FB_MODE_HELPERS is not set
++# CONFIG_FB_TILEBLITTING is not set
++
++#
++# Frame buffer hardware drivers
++#
++# CONFIG_FB_ARMCLCD is not set
++# CONFIG_FB_UVESA is not set
++# CONFIG_FB_OPENCORES is not set
++# CONFIG_FB_S1D13XXX is not set
++# CONFIG_FB_SMSCUFX is not set
++# CONFIG_FB_UDL is not set
++# CONFIG_FB_IBM_GXT4500 is not set
++# CONFIG_FB_VIRTUAL is not set
++# CONFIG_FB_METRONOME is not set
++# CONFIG_FB_BROADSHEET is not set
++# CONFIG_FB_AUO_K190X is not set
++# CONFIG_FB_SIMPLE is not set
++# CONFIG_FB_SSD1307 is not set
++CONFIG_BACKLIGHT_LCD_SUPPORT=y
++# CONFIG_LCD_CLASS_DEVICE is not set
++CONFIG_BACKLIGHT_CLASS_DEVICE=y
++CONFIG_BACKLIGHT_GENERIC=y
++CONFIG_BACKLIGHT_PWM=y
++# CONFIG_BACKLIGHT_PM8941_WLED is not set
++# CONFIG_BACKLIGHT_ADP8860 is not set
++# CONFIG_BACKLIGHT_ADP8870 is not set
++# CONFIG_BACKLIGHT_LM3630A is not set
++# CONFIG_BACKLIGHT_LM3639 is not set
++# CONFIG_BACKLIGHT_LP855X is not set
++# CONFIG_BACKLIGHT_GPIO is not set
++# CONFIG_BACKLIGHT_LV5207LP is not set
++# CONFIG_BACKLIGHT_BD6107 is not set
++
++#
++# Rockchip Misc Video driver
++#
++# CONFIG_FB_ROCKCHIP is not set
++# CONFIG_LCDC_RK3368 is not set
++CONFIG_LCD_GENERAL=y
++# CONFIG_LCD_MIPI is not set
++# CONFIG_RK_TRSM is not set
++# CONFIG_RK_HDMI is not set
++
++#
++# RGA
++#
++# CONFIG_ROCKCHIP_RGA is not set
++
++#
++# RGA2
++#
++# CONFIG_ROCKCHIP_RGA2 is not set
++
++#
++# VCODEC
++#
++CONFIG_RK_VCODEC=y
++
++#
++# IEP
++#
++# CONFIG_IEP is not set
++# CONFIG_IEP_MMU is not set
++
++#
++# DP
++#
++
++#
++# ROCKCHIP_MPP
++#
++CONFIG_ROCKCHIP_MPP_SERVICE=y
++CONFIG_ROCKCHIP_MPP_DEVICE=y
++# CONFIG_VGASTATE is not set
++CONFIG_VIDEOMODE_HELPERS=y
++CONFIG_HDMI=y
++
++#
++# Console display driver support
++#
++CONFIG_DUMMY_CONSOLE=y
++CONFIG_DUMMY_CONSOLE_COLUMNS=80
++CONFIG_DUMMY_CONSOLE_ROWS=25
++# CONFIG_FRAMEBUFFER_CONSOLE is not set
++# CONFIG_LOGO is not set
++CONFIG_SOUND=y
++# CONFIG_SOUND_OSS_CORE is not set
++CONFIG_SND=y
++CONFIG_SND_TIMER=y
++CONFIG_SND_PCM=y
++CONFIG_SND_DMAENGINE_PCM=y
++CONFIG_SND_HWDEP=y
++CONFIG_SND_RAWMIDI=y
++CONFIG_SND_JACK=y
++CONFIG_SND_SEQUENCER=y
++CONFIG_SND_SEQ_DUMMY=y
++# CONFIG_SND_MIXER_OSS is not set
++# CONFIG_SND_PCM_OSS is not set
++CONFIG_SND_PCM_TIMER=y
++# CONFIG_SND_SEQUENCER_OSS is not set
++CONFIG_SND_HRTIMER=y
++CONFIG_SND_SEQ_HRTIMER_DEFAULT=y
++CONFIG_SND_DYNAMIC_MINORS=y
++CONFIG_SND_MAX_CARDS=32
++# CONFIG_SND_SUPPORT_OLD_API is not set
++CONFIG_SND_PROC_FS=y
++CONFIG_SND_VERBOSE_PROCFS=y
++# CONFIG_SND_VERBOSE_PRINTK is not set
++# CONFIG_SND_DEBUG is not set
++CONFIG_SND_RAWMIDI_SEQ=y
++# CONFIG_SND_OPL3_LIB_SEQ is not set
++# CONFIG_SND_OPL4_LIB_SEQ is not set
++# CONFIG_SND_SBAWE_SEQ is not set
++# CONFIG_SND_EMU10K1_SEQ is not set
++CONFIG_SND_DRIVERS=y
++# CONFIG_SND_DUMMY is not set
++# CONFIG_SND_ALOOP is not set
++# CONFIG_SND_VIRMIDI is not set
++# CONFIG_SND_MTPAV is not set
++# CONFIG_SND_SERIAL_U16550 is not set
++# CONFIG_SND_MPU401 is not set
++
++#
++# HD-Audio
++#
++CONFIG_SND_HDA_PREALLOC_SIZE=64
++# CONFIG_SND_SPI is not set
++CONFIG_SND_USB=y
++CONFIG_SND_USB_AUDIO=y
++# CONFIG_SND_USB_UA101 is not set
++# CONFIG_SND_USB_CAIAQ is not set
++# CONFIG_SND_USB_6FIRE is not set
++# CONFIG_SND_USB_HIFACE is not set
++# CONFIG_SND_BCD2000 is not set
++# CONFIG_SND_USB_POD is not set
++# CONFIG_SND_USB_PODHD is not set
++# CONFIG_SND_USB_TONEPORT is not set
++# CONFIG_SND_USB_VARIAX is not set
++CONFIG_SND_SOC=y
++CONFIG_SND_SOC_GENERIC_DMAENGINE_PCM=y
++# CONFIG_SND_ATMEL_SOC is not set
++# CONFIG_SND_DESIGNWARE_I2S is not set
++
++#
++# SoC Audio for Freescale CPUs
++#
++
++#
++# Common SoC Audio options for Freescale CPUs:
++#
++# CONFIG_SND_SOC_FSL_ASRC is not set
++# CONFIG_SND_SOC_FSL_SAI is not set
++# CONFIG_SND_SOC_FSL_SSI is not set
++# CONFIG_SND_SOC_FSL_SPDIF is not set
++# CONFIG_SND_SOC_FSL_ESAI is not set
++# CONFIG_SND_SOC_IMX_AUDMUX is not set
++CONFIG_SND_SOC_ROCKCHIP=y
++# CONFIG_SND_SOC_ROCKCHIP_FORCE_SRAM is not set
++CONFIG_SND_SOC_ROCKCHIP_I2S=y
++# CONFIG_SND_SOC_ROCKCHIP_I2S_TDM is not set
++# CONFIG_SND_SOC_ROCKCHIP_MULTI_DAIS is not set
++# CONFIG_SND_SOC_ROCKCHIP_PDM is not set
++# CONFIG_SND_SOC_ROCKCHIP_SPDIF is not set
++# CONFIG_SND_SOC_ROCKCHIP_SPDIFRX is not set
++# CONFIG_SND_SOC_ROCKCHIP_VAD is not set
++# CONFIG_SND_SOC_ROCKCHIP_DA7219 is not set
++# CONFIG_SND_SOC_ROCKCHIP_HDMI_ANALOG is not set
++# CONFIG_SND_SOC_ROCKCHIP_MAX98090 is not set
++# CONFIG_SND_SOC_ROCKCHIP_MULTICODECS is not set
++# CONFIG_SND_SOC_ROCKCHIP_RT5645 is not set
++# CONFIG_SND_SOC_ROCKCHIP_RT5651_TC358749 is not set
++# CONFIG_SND_SOC_ROCKCHIP_CDNDP is not set
++
++#
++# Allwinner SoC Audio support
++#
++# CONFIG_SND_SUN4I_CODEC is not set
++# CONFIG_SND_SOC_XTFPGA_I2S is not set
++CONFIG_SND_SOC_I2C_AND_SPI=y
++
++#
++# CODEC drivers
++#
++# CONFIG_SND_SOC_AC97_CODEC is not set
++# CONFIG_SND_SOC_ADAU1701 is not set
++# CONFIG_SND_SOC_AK4104 is not set
++# CONFIG_SND_SOC_AK4554 is not set
++# CONFIG_SND_SOC_AK4613 is not set
++# CONFIG_SND_SOC_AK4642 is not set
++# CONFIG_SND_SOC_AK5386 is not set
++# CONFIG_SND_SOC_ALC5623 is not set
++# CONFIG_SND_SOC_CS35L32 is not set
++# CONFIG_SND_SOC_CS42L51_I2C is not set
++# CONFIG_SND_SOC_CS42L52 is not set
++# CONFIG_SND_SOC_CS42L56 is not set
++# CONFIG_SND_SOC_CS42L73 is not set
++# CONFIG_SND_SOC_CS4265 is not set
++# CONFIG_SND_SOC_CS4270 is not set
++# CONFIG_SND_SOC_CS4271_I2C is not set
++# CONFIG_SND_SOC_CS4271_SPI is not set
++# CONFIG_SND_SOC_CS42XX8_I2C is not set
++# CONFIG_SND_SOC_CS4349 is not set
++# CONFIG_SND_SOC_CX2072X is not set
++# CONFIG_SND_SOC_CX20810 is not set
++# CONFIG_SND_SOC_DUMMY_CODEC is not set
++# CONFIG_SND_SOC_BT_SCO is not set
++# CONFIG_SND_SOC_ES8316 is not set
++# CONFIG_SND_SOC_ES8323 is not set
++# CONFIG_SND_SOC_ES8328 is not set
++# CONFIG_SND_SOC_ES8328_I2C is not set
++# CONFIG_SND_SOC_ES8396 is not set
++# CONFIG_SND_SOC_GTM601 is not set
++# CONFIG_SND_SOC_GVA_CODEC is not set
++# CONFIG_SND_SOC_FM1288 is not set
++# CONFIG_SND_SOC_PCM1681 is not set
++# CONFIG_SND_SOC_PCM1792A is not set
++# CONFIG_SND_SOC_PCM512x_I2C is not set
++# CONFIG_SND_SOC_PCM512x_SPI is not set
++# CONFIG_SND_SOC_RK312X is not set
++# CONFIG_SND_SOC_RK3228 is not set
++# CONFIG_SND_SOC_RK3308 is not set
++# CONFIG_SND_SOC_RK3328 is not set
++CONFIG_SND_SOC_RK817=y
++CONFIG_SND_SOC_RL6231=y
++# CONFIG_SND_SOC_RT5616 is not set
++# CONFIG_SND_SOC_RT5631 is not set
++CONFIG_SND_SOC_RT5640=y
++# CONFIG_SND_SOC_RT5651 is not set
++# CONFIG_SND_SOC_RT5677_SPI is not set
++# CONFIG_SND_SOC_SGTL5000 is not set
++# CONFIG_SND_SOC_SIRF_AUDIO_CODEC is not set
++# CONFIG_SND_SOC_SPDIF is not set
++# CONFIG_SND_SOC_SSM2602_SPI is not set
++# CONFIG_SND_SOC_SSM2602_I2C is not set
++# CONFIG_SND_SOC_SSM4567 is not set
++# CONFIG_SND_SOC_STA32X is not set
++# CONFIG_SND_SOC_STA350 is not set
++# CONFIG_SND_SOC_STI_SAS is not set
++# CONFIG_SND_SOC_TAS2552 is not set
++# CONFIG_SND_SOC_TAS5086 is not set
++# CONFIG_SND_SOC_TAS571X is not set
++# CONFIG_SND_SOC_TC358749X is not set
++# CONFIG_SND_SOC_TFA9879 is not set
++# CONFIG_SND_SOC_TLV320AIC23_I2C is not set
++# CONFIG_SND_SOC_TLV320AIC23_SPI is not set
++# CONFIG_SND_SOC_TLV320AIC31XX is not set
++# CONFIG_SND_SOC_TLV320AIC3X is not set
++# CONFIG_SND_SOC_TS3A227E is not set
++# CONFIG_SND_SOC_WM8510 is not set
++# CONFIG_SND_SOC_WM8523 is not set
++# CONFIG_SND_SOC_WM8580 is not set
++# CONFIG_SND_SOC_WM8711 is not set
++# CONFIG_SND_SOC_WM8728 is not set
++# CONFIG_SND_SOC_WM8731 is not set
++# CONFIG_SND_SOC_WM8737 is not set
++# CONFIG_SND_SOC_WM8741 is not set
++# CONFIG_SND_SOC_WM8750 is not set
++# CONFIG_SND_SOC_WM8753 is not set
++# CONFIG_SND_SOC_WM8770 is not set
++# CONFIG_SND_SOC_WM8776 is not set
++# CONFIG_SND_SOC_WM8804_I2C is not set
++# CONFIG_SND_SOC_WM8804_SPI is not set
++# CONFIG_SND_SOC_WM8903 is not set
++# CONFIG_SND_SOC_WM8962 is not set
++# CONFIG_SND_SOC_WM8978 is not set
++# CONFIG_SND_SOC_TPA6130A2 is not set
++CONFIG_SND_SIMPLE_CARD=y
++# CONFIG_SOUND_PRIME is not set
++
++#
++# HID support
++#
++CONFIG_HID=y
++CONFIG_HID_BATTERY_STRENGTH=y
++CONFIG_HIDRAW=y
++CONFIG_UHID=y
++CONFIG_HID_GENERIC=y
++
++#
++# Special HID drivers
++#
++# CONFIG_HID_A4TECH is not set
++# CONFIG_HID_ACRUX is not set
++# CONFIG_HID_APPLE is not set
++# CONFIG_HID_APPLEIR is not set
++# CONFIG_HID_AUREAL is not set
++# CONFIG_HID_BELKIN is not set
++# CONFIG_HID_BETOP_FF is not set
++# CONFIG_HID_CHERRY is not set
++# CONFIG_HID_CHICONY is not set
++# CONFIG_HID_CORSAIR is not set
++# CONFIG_HID_PRODIKEYS is not set
++# CONFIG_HID_CP2112 is not set
++# CONFIG_HID_CYPRESS is not set
++# CONFIG_HID_DRAGONRISE is not set
++# CONFIG_HID_EMS_FF is not set
++# CONFIG_HID_ELECOM is not set
++# CONFIG_HID_ELO is not set
++# CONFIG_HID_EZKEY is not set
++# CONFIG_HID_GEMBIRD is not set
++# CONFIG_HID_GFRM is not set
++# CONFIG_HID_HOLTEK is not set
++# CONFIG_HID_GT683R is not set
++# CONFIG_HID_KEYTOUCH is not set
++# CONFIG_HID_KYE is not set
++# CONFIG_HID_UCLOGIC is not set
++# CONFIG_HID_WALTOP is not set
++# CONFIG_HID_GYRATION is not set
++# CONFIG_HID_ICADE is not set
++# CONFIG_HID_TWINHAN is not set
++CONFIG_HID_KENSINGTON=y
++# CONFIG_HID_LCPOWER is not set
++# CONFIG_HID_LENOVO is not set
++# CONFIG_HID_LOGITECH is not set
++# CONFIG_HID_MAGICMOUSE is not set
++# CONFIG_HID_MICROSOFT is not set
++# CONFIG_HID_MONTEREY is not set
++CONFIG_HID_MULTITOUCH=y
++# CONFIG_HID_NTRIG is not set
++# CONFIG_HID_ORTEK is not set
++# CONFIG_HID_PANTHERLORD is not set
++# CONFIG_HID_PENMOUNT is not set
++# CONFIG_HID_PETALYNX is not set
++# CONFIG_HID_PICOLCD is not set
++# CONFIG_HID_PLANTRONICS is not set
++# CONFIG_HID_PRIMAX is not set
++# CONFIG_HID_ROCCAT is not set
++# CONFIG_HID_SAITEK is not set
++# CONFIG_HID_SAMSUNG is not set
++# CONFIG_HID_SONY is not set
++# CONFIG_HID_SPEEDLINK is not set
++# CONFIG_HID_STEELSERIES is not set
++# CONFIG_HID_SUNPLUS is not set
++# CONFIG_HID_RMI is not set
++# CONFIG_HID_GREENASIA is not set
++# CONFIG_HID_SMARTJOYPLUS is not set
++# CONFIG_HID_TIVO is not set
++# CONFIG_HID_TOPSEED is not set
++# CONFIG_HID_THINGM is not set
++# CONFIG_HID_THRUSTMASTER is not set
++# CONFIG_HID_WACOM is not set
++# CONFIG_HID_WIIMOTE is not set
++# CONFIG_HID_XINMO is not set
++# CONFIG_HID_ZEROPLUS is not set
++# CONFIG_HID_ZYDACRON is not set
++# CONFIG_HID_SENSOR_HUB is not set
++# CONFIG_HID_RKVR is not set
++# CONFIG_HID_ALPS is not set
++
++#
++# USB HID support
++#
++CONFIG_USB_HID=y
++# CONFIG_HID_PID is not set
++CONFIG_USB_HIDDEV=y
++
++#
++# I2C HID support
++#
++CONFIG_I2C_HID=y
++CONFIG_USB_OHCI_LITTLE_ENDIAN=y
++CONFIG_USB_SUPPORT=y
++CONFIG_USB_COMMON=y
++CONFIG_USB_ARCH_HAS_HCD=y
++CONFIG_USB=y
++CONFIG_USB_ANNOUNCE_NEW_DEVICES=y
++
++#
++# Miscellaneous USB options
++#
++# CONFIG_USB_DEFAULT_PERSIST is not set
++# CONFIG_USB_DYNAMIC_MINORS is not set
++CONFIG_USB_OTG=y
++# CONFIG_USB_OTG_WHITELIST is not set
++# CONFIG_USB_OTG_BLACKLIST_HUB is not set
++# CONFIG_USB_OTG_FSM is not set
++# CONFIG_USB_ULPI_BUS is not set
++CONFIG_USB_MON=y
++# CONFIG_USB_WUSB_CBAF is not set
++
++#
++# USB Host Controller Drivers
++#
++# CONFIG_USB_C67X00_HCD is not set
++# CONFIG_USB_XHCI_HCD is not set
++CONFIG_USB_EHCI_HCD=y
++CONFIG_USB_EHCI_ROOT_HUB_TT=y
++CONFIG_USB_EHCI_TT_NEWSCHED=y
++CONFIG_USB_EHCI_HCD_PLATFORM=y
++# CONFIG_USB_OXU210HP_HCD is not set
++# CONFIG_USB_ISP116X_HCD is not set
++# CONFIG_USB_ISP1362_HCD is not set
++# CONFIG_USB_FOTG210_HCD is not set
++# CONFIG_USB_MAX3421_HCD is not set
++CONFIG_USB_OHCI_HCD=y
++CONFIG_USB_OHCI_HCD_PLATFORM=y
++# CONFIG_USB_SL811_HCD is not set
++# CONFIG_USB_R8A66597_HCD is not set
++# CONFIG_USB_HCD_TEST_MODE is not set
++
++#
++# USB Device Class drivers
++#
++CONFIG_USB_ACM=y
++# CONFIG_USB_PRINTER is not set
++CONFIG_USB_WDM=y
++# CONFIG_USB_TMC is not set
++
++#
++# NOTE: USB_STORAGE depends on SCSI but BLK_DEV_SD may
++#
++
++#
++# also be needed; see USB_STORAGE Help for more info
++#
++CONFIG_USB_STORAGE=y
++# CONFIG_USB_STORAGE_DEBUG is not set
++# CONFIG_USB_STORAGE_REALTEK is not set
++# CONFIG_USB_STORAGE_DATAFAB is not set
++# CONFIG_USB_STORAGE_FREECOM is not set
++# CONFIG_USB_STORAGE_ISD200 is not set
++# CONFIG_USB_STORAGE_USBAT is not set
++# CONFIG_USB_STORAGE_SDDR09 is not set
++# CONFIG_USB_STORAGE_SDDR55 is not set
++# CONFIG_USB_STORAGE_JUMPSHOT is not set
++# CONFIG_USB_STORAGE_ALAUDA is not set
++# CONFIG_USB_STORAGE_ONETOUCH is not set
++# CONFIG_USB_STORAGE_KARMA is not set
++# CONFIG_USB_STORAGE_CYPRESS_ATACB is not set
++# CONFIG_USB_STORAGE_ENE_UB6250 is not set
++CONFIG_USB_UAS=y
++
++#
++# USB Imaging devices
++#
++# CONFIG_USB_MDC800 is not set
++# CONFIG_USB_MICROTEK is not set
++# CONFIG_USBIP_CORE is not set
++# CONFIG_USB_MUSB_HDRC is not set
++# CONFIG_USB_DWC3 is not set
++CONFIG_USB_DWC2=y
++# CONFIG_USB_DWC2_HOST is not set
++
++#
++# Gadget/Dual-role mode requires USB Gadget support to be enabled
++#
++# CONFIG_USB_DWC2_PERIPHERAL is not set
++CONFIG_USB_DWC2_DUAL_ROLE=y
++# CONFIG_USB_DWC2_DEBUG is not set
++# CONFIG_USB_DWC2_TRACK_MISSED_SOFS is not set
++# CONFIG_USB_CHIPIDEA is not set
++# CONFIG_USB_ISP1760 is not set
++
++#
++# USB port drivers
++#
++CONFIG_USB_SERIAL=y
++# CONFIG_USB_SERIAL_CONSOLE is not set
++CONFIG_USB_SERIAL_GENERIC=y
++# CONFIG_USB_SERIAL_SIMPLE is not set
++# CONFIG_USB_SERIAL_AIRCABLE is not set
++# CONFIG_USB_SERIAL_ARK3116 is not set
++# CONFIG_USB_SERIAL_BELKIN is not set
++# CONFIG_USB_SERIAL_CH341 is not set
++# CONFIG_USB_SERIAL_WHITEHEAT is not set
++# CONFIG_USB_SERIAL_DIGI_ACCELEPORT is not set
++CONFIG_USB_SERIAL_CP210X=y
++# CONFIG_USB_SERIAL_CYPRESS_M8 is not set
++# CONFIG_USB_SERIAL_EMPEG is not set
++CONFIG_USB_SERIAL_FTDI_SIO=y
++# CONFIG_USB_SERIAL_VISOR is not set
++# CONFIG_USB_SERIAL_IPAQ is not set
++# CONFIG_USB_SERIAL_IR is not set
++# CONFIG_USB_SERIAL_EDGEPORT is not set
++# CONFIG_USB_SERIAL_EDGEPORT_TI is not set
++# CONFIG_USB_SERIAL_F81232 is not set
++# CONFIG_USB_SERIAL_GARMIN is not set
++# CONFIG_USB_SERIAL_IPW is not set
++# CONFIG_USB_SERIAL_IUU is not set
++# CONFIG_USB_SERIAL_KEYSPAN_PDA is not set
++CONFIG_USB_SERIAL_KEYSPAN=y
++# CONFIG_USB_SERIAL_KEYSPAN_MPR is not set
++# CONFIG_USB_SERIAL_KEYSPAN_USA28 is not set
++# CONFIG_USB_SERIAL_KEYSPAN_USA28X is not set
++# CONFIG_USB_SERIAL_KEYSPAN_USA28XA is not set
++# CONFIG_USB_SERIAL_KEYSPAN_USA28XB is not set
++# CONFIG_USB_SERIAL_KEYSPAN_USA19 is not set
++# CONFIG_USB_SERIAL_KEYSPAN_USA18X is not set
++# CONFIG_USB_SERIAL_KEYSPAN_USA19W is not set
++# CONFIG_USB_SERIAL_KEYSPAN_USA19QW is not set
++# CONFIG_USB_SERIAL_KEYSPAN_USA19QI is not set
++# CONFIG_USB_SERIAL_KEYSPAN_USA49W is not set
++# CONFIG_USB_SERIAL_KEYSPAN_USA49WLC is not set
++# CONFIG_USB_SERIAL_KLSI is not set
++# CONFIG_USB_SERIAL_KOBIL_SCT is not set
++# CONFIG_USB_SERIAL_MCT_U232 is not set
++# CONFIG_USB_SERIAL_METRO is not set
++# CONFIG_USB_SERIAL_MOS7720 is not set
++# CONFIG_USB_SERIAL_MOS7840 is not set
++# CONFIG_USB_SERIAL_MXUPORT is not set
++# CONFIG_USB_SERIAL_NAVMAN is not set
++CONFIG_USB_SERIAL_PL2303=y
++CONFIG_USB_SERIAL_OTI6858=y
++# CONFIG_USB_SERIAL_QCAUX is not set
++CONFIG_USB_SERIAL_QUALCOMM=y
++# CONFIG_USB_SERIAL_SPCP8X5 is not set
++# CONFIG_USB_SERIAL_SAFE is not set
++CONFIG_USB_SERIAL_SIERRAWIRELESS=y
++# CONFIG_USB_SERIAL_SYMBOL is not set
++# CONFIG_USB_SERIAL_TI is not set
++# CONFIG_USB_SERIAL_CYBERJACK is not set
++# CONFIG_USB_SERIAL_XIRCOM is not set
++CONFIG_USB_SERIAL_WWAN=y
++CONFIG_USB_SERIAL_OPTION=y
++# CONFIG_USB_SERIAL_OMNINET is not set
++# CONFIG_USB_SERIAL_OPTICON is not set
++# CONFIG_USB_SERIAL_XSENS_MT is not set
++# CONFIG_USB_SERIAL_WISHBONE is not set
++# CONFIG_USB_SERIAL_SSU100 is not set
++# CONFIG_USB_SERIAL_QT2 is not set
++# CONFIG_USB_SERIAL_DEBUG is not set
++
++#
++# USB Miscellaneous drivers
++#
++# CONFIG_USB_EMI62 is not set
++# CONFIG_USB_EMI26 is not set
++# CONFIG_USB_ADUTUX is not set
++# CONFIG_USB_SEVSEG is not set
++# CONFIG_USB_RIO500 is not set
++# CONFIG_USB_LEGOTOWER is not set
++# CONFIG_USB_LCD is not set
++# CONFIG_USB_LED is not set
++# CONFIG_USB_CYPRESS_CY7C63 is not set
++# CONFIG_USB_CYTHERM is not set
++# CONFIG_USB_IDMOUSE is not set
++# CONFIG_USB_FTDI_ELAN is not set
++# CONFIG_USB_APPLEDISPLAY is not set
++# CONFIG_USB_SISUSBVGA is not set
++# CONFIG_USB_LD is not set
++# CONFIG_USB_TRANCEVIBRATOR is not set
++# CONFIG_USB_IOWARRIOR is not set
++# CONFIG_USB_TEST is not set
++# CONFIG_USB_EHSET_TEST_FIXTURE is not set
++# CONFIG_USB_ISIGHTFW is not set
++# CONFIG_USB_YUREX is not set
++CONFIG_USB_EZUSB_FX2=y
++# CONFIG_USB_HSIC_USB3503 is not set
++# CONFIG_USB_LINK_LAYER_TEST is not set
++# CONFIG_USB_CHAOSKEY is not set
++
++#
++# USB Physical Layer drivers
++#
++# CONFIG_USB_PHY is not set
++# CONFIG_USB_OTG_WAKELOCK is not set
++# CONFIG_NOP_USB_XCEIV is not set
++# CONFIG_USB_GPIO_VBUS is not set
++# CONFIG_USB_ISP1301 is not set
++# CONFIG_USB_ULPI is not set
++CONFIG_USB_GADGET=y
++# CONFIG_USB_GADGET_DEBUG is not set
++CONFIG_USB_GADGET_DEBUG_FILES=y
++# CONFIG_USB_GADGET_DEBUG_FS is not set
++CONFIG_USB_GADGET_VBUS_DRAW=500
++CONFIG_USB_GADGET_STORAGE_NUM_BUFFERS=2
++
++#
++# USB Peripheral Controller
++#
++# CONFIG_USB_FOTG210_UDC is not set
++# CONFIG_USB_GR_UDC is not set
++# CONFIG_USB_R8A66597 is not set
++# CONFIG_USB_PXA27X is not set
++# CONFIG_USB_MV_UDC is not set
++# CONFIG_USB_MV_U3D is not set
++# CONFIG_USB_M66592 is not set
++# CONFIG_USB_BDC_UDC is not set
++# CONFIG_USB_NET2272 is not set
++# CONFIG_USB_GADGET_XILINX is not set
++# CONFIG_USB_DUMMY_HCD is not set
++CONFIG_USB_LIBCOMPOSITE=y
++CONFIG_USB_F_ACM=y
++CONFIG_USB_U_SERIAL=y
++CONFIG_USB_F_SERIAL=y
++CONFIG_USB_F_OBEX=y
++# CONFIG_USB_CONFIGFS is not set
++# CONFIG_USB_ZERO is not set
++# CONFIG_USB_AUDIO is not set
++# CONFIG_USB_ETH is not set
++# CONFIG_USB_G_NCM is not set
++# CONFIG_USB_GADGETFS is not set
++# CONFIG_USB_FUNCTIONFS is not set
++# CONFIG_USB_MASS_STORAGE is not set
++CONFIG_USB_G_SERIAL=y
++# CONFIG_USB_MIDI_GADGET is not set
++# CONFIG_USB_G_PRINTER is not set
++# CONFIG_USB_CDC_COMPOSITE is not set
++# CONFIG_USB_G_ACM_MS is not set
++# CONFIG_USB_G_MULTI is not set
++# CONFIG_USB_G_HID is not set
++# CONFIG_USB_G_DBGP is not set
++# CONFIG_USB_G_WEBCAM is not set
++
++#
++# ROCKCHIP USB Support
++#
++# CONFIG_USB20_HOST is not set
++# CONFIG_USB20_OTG is not set
++# CONFIG_USB_LED_TRIG is not set
++# CONFIG_UWB is not set
++CONFIG_MMC=y
++# CONFIG_MMC_DEBUG is not set
++# CONFIG_MMC_EMBEDDED_SDIO is not set
++# CONFIG_MMC_PARANOID_SD_INIT is not set
++
++#
++# MMC/SD/SDIO Card Drivers
++#
++CONFIG_MMC_BLOCK=y
++CONFIG_MMC_BLOCK_MINORS=32
++CONFIG_MMC_BLOCK_BOUNCE=y
++# CONFIG_SDIO_UART is not set
++CONFIG_MMC_TEST=y
++# CONFIG_MMC_SIMULATE_MAX_SPEED is not set
++
++#
++# MMC/SD/SDIO Host Controller Drivers
++#
++# CONFIG_MMC_ARMMMCI is not set
++# CONFIG_MMC_SDHCI is not set
++# CONFIG_MMC_SPI is not set
++CONFIG_MMC_DW=y
++CONFIG_MMC_DW_PLTFM=y
++# CONFIG_MMC_DW_EXYNOS is not set
++# CONFIG_MMC_DW_K3 is not set
++CONFIG_MMC_DW_ROCKCHIP=y
++# CONFIG_MMC_VUB300 is not set
++# CONFIG_MMC_USHC is not set
++# CONFIG_MMC_USDHI6ROL0 is not set
++# CONFIG_MMC_MTK is not set
++# CONFIG_MEMSTICK is not set
++CONFIG_NEW_LEDS=y
++CONFIG_LEDS_CLASS=y
++# CONFIG_LEDS_CLASS_FLASH is not set
++
++#
++# LED drivers
++#
++# CONFIG_LEDS_BCM6328 is not set
++# CONFIG_LEDS_BCM6358 is not set
++# CONFIG_LEDS_LM3530 is not set
++# CONFIG_LEDS_LM3642 is not set
++# CONFIG_LEDS_PCA9532 is not set
++CONFIG_LEDS_GPIO=y
++# CONFIG_LEDS_LP3944 is not set
++# CONFIG_LEDS_LP5521 is not set
++# CONFIG_LEDS_LP5523 is not set
++# CONFIG_LEDS_LP5562 is not set
++# CONFIG_LEDS_LP8501 is not set
++# CONFIG_LEDS_LP8860 is not set
++# CONFIG_LEDS_PCA955X is not set
++# CONFIG_LEDS_PCA963X is not set
++# CONFIG_LEDS_DAC124S085 is not set
++# CONFIG_LEDS_PWM is not set
++# CONFIG_LEDS_REGULATOR is not set
++# CONFIG_LEDS_BD2802 is not set
++# CONFIG_LEDS_LT3593 is not set
++# CONFIG_LEDS_TCA6507 is not set
++# CONFIG_LEDS_TLC591XX is not set
++# CONFIG_LEDS_LM355x is not set
++CONFIG_LEDS_IS31FL32XX=y
++
++#
++# LED driver for blink(1) USB RGB LED is under Special HID drivers (HID_THINGM)
++#
++# CONFIG_LEDS_BLINKM is not set
++# CONFIG_LEDS_SYSCON is not set
++
++#
++# LED Triggers
++#
++CONFIG_LEDS_TRIGGERS=y
++# CONFIG_LEDS_TRIGGER_TIMER is not set
++# CONFIG_LEDS_TRIGGER_ONESHOT is not set
++# CONFIG_LEDS_TRIGGER_HEARTBEAT is not set
++# CONFIG_LEDS_TRIGGER_BACKLIGHT is not set
++# CONFIG_LEDS_TRIGGER_CPU is not set
++# CONFIG_LEDS_TRIGGER_GPIO is not set
++# CONFIG_LEDS_TRIGGER_DEFAULT_ON is not set
++
++#
++# iptables trigger is under Netfilter config (LED target)
++#
++# CONFIG_LEDS_TRIGGER_TRANSIENT is not set
++# CONFIG_LEDS_TRIGGER_CAMERA is not set
++# CONFIG_SWITCH is not set
++# CONFIG_ACCESSIBILITY is not set
++CONFIG_EDAC_SUPPORT=y
++# CONFIG_EDAC is not set
++CONFIG_RTC_LIB=y
++CONFIG_RTC_CLASS=y
++CONFIG_RTC_HCTOSYS=y
++CONFIG_RTC_HCTOSYS_DEVICE="rtc0"
++CONFIG_RTC_SYSTOHC=y
++CONFIG_RTC_SYSTOHC_DEVICE="rtc0"
++# CONFIG_RTC_DEBUG is not set
++
++#
++# RTC interfaces
++#
++CONFIG_RTC_INTF_SYSFS=y
++CONFIG_RTC_INTF_PROC=y
++CONFIG_RTC_INTF_DEV=y
++# CONFIG_RTC_INTF_DEV_UIE_EMUL is not set
++# CONFIG_RTC_DRV_TEST is not set
++
++#
++# I2C RTC drivers
++#
++# CONFIG_RTC_DRV_ABB5ZES3 is not set
++# CONFIG_RTC_DRV_ABX80X is not set
++# CONFIG_RTC_DRV_DS1307 is not set
++# CONFIG_RTC_DRV_DS1374 is not set
++# CONFIG_RTC_DRV_DS1672 is not set
++# CONFIG_RTC_DRV_DS3232 is not set
++# CONFIG_RTC_DRV_FAKE is not set
++# CONFIG_RTC_DRV_HYM8563 is not set
++# CONFIG_RTC_DRV_MAX6900 is not set
++CONFIG_RTC_DRV_RK808=y
++# CONFIG_RTC_DRV_RK_TIMER is not set
++# CONFIG_RTC_DRV_RS5C372 is not set
++# CONFIG_RTC_DRV_ISL1208 is not set
++# CONFIG_RTC_DRV_ISL12022 is not set
++# CONFIG_RTC_DRV_ISL12057 is not set
++# CONFIG_RTC_DRV_X1205 is not set
++# CONFIG_RTC_DRV_PCF2127 is not set
++# CONFIG_RTC_DRV_PCF8523 is not set
++# CONFIG_RTC_DRV_PCF8563 is not set
++# CONFIG_RTC_DRV_PCF85063 is not set
++# CONFIG_RTC_DRV_PCF8583 is not set
++# CONFIG_RTC_DRV_M41T80 is not set
++# CONFIG_RTC_DRV_BQ32K is not set
++# CONFIG_RTC_DRV_S35390A is not set
++# CONFIG_RTC_DRV_FM3130 is not set
++# CONFIG_RTC_DRV_RX8581 is not set
++# CONFIG_RTC_DRV_RX8025 is not set
++# CONFIG_RTC_DRV_EM3027 is not set
++# CONFIG_RTC_DRV_RV3029C2 is not set
++# CONFIG_RTC_DRV_RV8803 is not set
++
++#
++# SPI RTC drivers
++#
++# CONFIG_RTC_DRV_M41T93 is not set
++# CONFIG_RTC_DRV_M41T94 is not set
++# CONFIG_RTC_DRV_DS1305 is not set
++# CONFIG_RTC_DRV_DS1343 is not set
++# CONFIG_RTC_DRV_DS1347 is not set
++# CONFIG_RTC_DRV_DS1390 is not set
++# CONFIG_RTC_DRV_MAX6902 is not set
++# CONFIG_RTC_DRV_R9701 is not set
++# CONFIG_RTC_DRV_RS5C348 is not set
++# CONFIG_RTC_DRV_DS3234 is not set
++# CONFIG_RTC_DRV_PCF2123 is not set
++# CONFIG_RTC_DRV_RX4581 is not set
++# CONFIG_RTC_DRV_MCP795 is not set
++
++#
++# Platform RTC drivers
++#
++# CONFIG_RTC_DRV_DS1286 is not set
++# CONFIG_RTC_DRV_DS1511 is not set
++# CONFIG_RTC_DRV_DS1553 is not set
++# CONFIG_RTC_DRV_DS1685_FAMILY is not set
++# CONFIG_RTC_DRV_DS1742 is not set
++# CONFIG_RTC_DRV_DS2404 is not set
++# CONFIG_RTC_DRV_STK17TA8 is not set
++# CONFIG_RTC_DRV_M48T86 is not set
++# CONFIG_RTC_DRV_M48T35 is not set
++# CONFIG_RTC_DRV_M48T59 is not set
++# CONFIG_RTC_DRV_MSM6242 is not set
++# CONFIG_RTC_DRV_BQ4802 is not set
++# CONFIG_RTC_DRV_RP5C01 is not set
++# CONFIG_RTC_DRV_V3020 is not set
++# CONFIG_RTC_DRV_ZYNQMP is not set
++
++#
++# on-CPU RTC drivers
++#
++# CONFIG_RTC_DRV_PL030 is not set
++# CONFIG_RTC_DRV_PL031 is not set
++# CONFIG_RTC_DRV_SNVS is not set
++
++#
++# HID Sensor RTC drivers
++#
++# CONFIG_RTC_DRV_HID_SENSOR_TIME is not set
++CONFIG_DMADEVICES=y
++# CONFIG_DMADEVICES_DEBUG is not set
++
++#
++# DMA Devices
++#
++CONFIG_DMA_ENGINE=y
++CONFIG_DMA_OF=y
++# CONFIG_AMBA_PL08X is not set
++# CONFIG_FSL_EDMA is not set
++# CONFIG_INTEL_IDMA64 is not set
++CONFIG_PL330_DMA=y
++# CONFIG_DW_DMAC is not set
++
++#
++# DMA Clients
++#
++# CONFIG_ASYNC_TX_DMA is not set
++# CONFIG_DMATEST is not set
++# CONFIG_AUXDISPLAY is not set
++# CONFIG_UIO is not set
++# CONFIG_VFIO is not set
++# CONFIG_VIRT_DRIVERS is not set
++
++#
++# Virtio drivers
++#
++# CONFIG_VIRTIO_MMIO is not set
++
++#
++# Microsoft Hyper-V guest support
++#
++CONFIG_STAGING=y
++# CONFIG_PRISM2_USB is not set
++# CONFIG_COMEDI is not set
++# CONFIG_RTLLIB is not set
++# CONFIG_R8712U is not set
++# CONFIG_R8188EU is not set
++# CONFIG_R8723AU is not set
++# CONFIG_VT6656 is not set
++
++#
++# IIO staging drivers
++#
++
++#
++# Accelerometers
++#
++# CONFIG_ADIS16201 is not set
++# CONFIG_ADIS16203 is not set
++# CONFIG_ADIS16204 is not set
++# CONFIG_ADIS16209 is not set
++# CONFIG_ADIS16220 is not set
++# CONFIG_ADIS16240 is not set
++# CONFIG_LIS3L02DQ is not set
++# CONFIG_SCA3000 is not set
++
++#
++# Analog to digital converters
++#
++# CONFIG_AD7606 is not set
++# CONFIG_AD7780 is not set
++# CONFIG_AD7816 is not set
++# CONFIG_AD7192 is not set
++# CONFIG_AD7280 is not set
++
++#
++# Analog digital bi-direction converters
++#
++# CONFIG_ADT7316 is not set
++
++#
++# Capacitance to digital converters
++#
++# CONFIG_AD7150 is not set
++# CONFIG_AD7152 is not set
++# CONFIG_AD7746 is not set
++
++#
++# Direct Digital Synthesis
++#
++# CONFIG_AD9832 is not set
++# CONFIG_AD9834 is not set
++
++#
++# Digital gyroscope sensors
++#
++# CONFIG_ADIS16060 is not set
++
++#
++# Network Analyzer, Impedance Converters
++#
++# CONFIG_AD5933 is not set
++# CONFIG_INV_MPU_IIO is not set
++
++#
++# Light sensors
++#
++CONFIG_SENSORS_ISL29018=y
++# CONFIG_SENSORS_ISL29028 is not set
++CONFIG_TSL2583=y
++# CONFIG_TSL2x7x is not set
++
++#
++# Magnetometer sensors
++#
++# CONFIG_SENSORS_HMC5843_I2C is not set
++# CONFIG_SENSORS_HMC5843_SPI is not set
++
++#
++# Active energy metering IC
++#
++# CONFIG_ADE7753 is not set
++# CONFIG_ADE7754 is not set
++# CONFIG_ADE7758 is not set
++# CONFIG_ADE7759 is not set
++# CONFIG_ADE7854 is not set
++
++#
++# Resolver to digital converters
++#
++# CONFIG_AD2S90 is not set
++# CONFIG_AD2S1200 is not set
++# CONFIG_AD2S1210 is not set
++
++#
++# Triggers - standalone
++#
++# CONFIG_IIO_PERIODIC_RTC_TRIGGER is not set
++# CONFIG_IIO_SIMPLE_DUMMY is not set
++
++#
++# Speakup console speech
++#
++# CONFIG_SPEAKUP is not set
++# CONFIG_TOUCHSCREEN_SYNAPTICS_I2C_RMI4 is not set
++# CONFIG_STAGING_MEDIA is not set
++
++#
++# Android
++#
++# CONFIG_ASHMEM is not set
++# CONFIG_ANDROID_TIMED_OUTPUT is not set
++# CONFIG_ANDROID_LOW_MEMORY_KILLER is not set
++# CONFIG_SYNC is not set
++# CONFIG_ION is not set
++CONFIG_FIQ_DEBUGGER=y
++CONFIG_FIQ_DEBUGGER_NO_SLEEP=y
++# CONFIG_FIQ_DEBUGGER_WAKEUP_IRQ_ALWAYS_ON is not set
++CONFIG_FIQ_DEBUGGER_CONSOLE=y
++CONFIG_FIQ_DEBUGGER_CONSOLE_DEFAULT_ENABLE=y
++# CONFIG_FIQ_DEBUGGER_TRUST_ZONE is not set
++# CONFIG_FIQ_DEBUGGER_UART_OVERLAY is not set
++# CONFIG_FIQ_WATCHDOG is not set
++# CONFIG_RK_CONSOLE_THREAD is not set
++# CONFIG_STAGING_BOARD is not set
++# CONFIG_WIMAX_GDM72XX is not set
++# CONFIG_LTE_GDM724X is not set
++# CONFIG_LUSTRE_FS is not set
++# CONFIG_DGAP is not set
++# CONFIG_GS_FPGABOOT is not set
++# CONFIG_COMMON_CLK_XLNX_CLKWZRD is not set
++# CONFIG_FB_TFT is not set
++# CONFIG_FSL_MC_BUS is not set
++# CONFIG_WILC1000_DRIVER is not set
++# CONFIG_MOST is not set
++# CONFIG_POWERVR_ROGUE_N is not set
++# CONFIG_GOLDFISH is not set
++# CONFIG_CHROME_PLATFORMS is not set
++CONFIG_CLKDEV_LOOKUP=y
++CONFIG_HAVE_CLK_PREPARE=y
++CONFIG_COMMON_CLK=y
++
++#
++# Common Clock Framework
++#
++# CONFIG_COMMON_CLK_VERSATILE is not set
++CONFIG_COMMON_CLK_RK808=y
++# CONFIG_COMMON_CLK_SI5351 is not set
++# CONFIG_COMMON_CLK_SI514 is not set
++# CONFIG_COMMON_CLK_SI570 is not set
++# CONFIG_COMMON_CLK_CDCE925 is not set
++# CONFIG_CLK_QORIQ is not set
++# CONFIG_COMMON_CLK_XGENE is not set
++# CONFIG_COMMON_CLK_PWM is not set
++# CONFIG_COMMON_CLK_PXA is not set
++# CONFIG_COMMON_CLK_CDCE706 is not set
++
++#
++# Hardware Spinlock drivers
++#
++# CONFIG_HWSPINLOCK_ROCKCHIP is not set
++
++#
++# Clock Source drivers
++#
++CONFIG_CLKSRC_OF=y
++CONFIG_CLKSRC_PROBE=y
++CONFIG_ROCKCHIP_TIMER=y
++CONFIG_ARM_ARCH_TIMER=y
++CONFIG_ARM_ARCH_TIMER_EVTSTREAM=y
++# CONFIG_ARM_ARCH_TIMER_VCT_ACCESS is not set
++# CONFIG_ARM_TIMER_SP804 is not set
++# CONFIG_ATMEL_PIT is not set
++# CONFIG_SH_TIMER_CMT is not set
++# CONFIG_SH_TIMER_MTU2 is not set
++# CONFIG_SH_TIMER_TMU is not set
++# CONFIG_EM_TIMER_STI is not set
++# CONFIG_MAILBOX is not set
++CONFIG_IOMMU_API=y
++CONFIG_IOMMU_SUPPORT=y
++
++#
++# Generic IOMMU Pagetable Support
++#
++# CONFIG_IOMMU_IO_PGTABLE_LPAE is not set
++CONFIG_IOMMU_IOVA=y
++CONFIG_OF_IOMMU=y
++CONFIG_IOMMU_DMA=y
++CONFIG_ROCKCHIP_IOMMU=y
++# CONFIG_RK_IOMMU is not set
++# CONFIG_ARM_SMMU is not set
++
++#
++# Remoteproc drivers
++#
++# CONFIG_STE_MODEM_RPROC is not set
++
++#
++# Rpmsg drivers
++#
++
++#
++# SOC (System On Chip) specific Drivers
++#
++
++#
++# Rockchip CPU selection
++#
++CONFIG_CPU_PX30=y
++# CONFIG_CPU_RK1808 is not set
++# CONFIG_CPU_RK3308 is not set
++CONFIG_CPU_RK3328=y
++# CONFIG_CPU_RK3366 is not set
++CONFIG_CPU_RK3368=y
++CONFIG_CPU_RK3399=y
++CONFIG_ANDROID_VERSION=0x07010000
++CONFIG_ROCKCHIP_CPUINFO=y
++# CONFIG_ROCKCHIP_DEVICEINFO is not set
++CONFIG_ROCKCHIP_IPA=y
++CONFIG_ROCKCHIP_OPP=y
++# CONFIG_ROCKCHIP_PM_TEST is not set
++CONFIG_ROCKCHIP_GRF=y
++CONFIG_ROCKCHIP_PM_DOMAINS=y
++CONFIG_ROCKCHIP_PVTM=y
++CONFIG_ROCKCHIP_SUSPEND_MODE=y
++CONFIG_ROCKCHIP_SYSTEM_MONITOR=y
++# CONFIG_ROCKCHIP_VENDOR_STORAGE_UPDATE_LOADER is not set
++# CONFIG_SUNXI_SRAM is not set
++# CONFIG_SOC_TI is not set
++CONFIG_PM_DEVFREQ=y
++
++#
++# DEVFREQ Governors
++#
++CONFIG_DEVFREQ_GOV_SIMPLE_ONDEMAND=y
++CONFIG_DEVFREQ_GOV_PERFORMANCE=y
++CONFIG_DEVFREQ_GOV_POWERSAVE=y
++CONFIG_DEVFREQ_GOV_USERSPACE=y
++
++#
++# DEVFREQ Drivers
++#
++# CONFIG_ARM_ROCKCHIP_BUS_DEVFREQ is not set
++CONFIG_ARM_ROCKCHIP_DMC_DEVFREQ=y
++CONFIG_PM_DEVFREQ_EVENT=y
++CONFIG_DEVFREQ_EVENT_ROCKCHIP_DFI=y
++# CONFIG_DEVFREQ_EVENT_ROCKCHIP_NOCP is not set
++CONFIG_EXTCON=y
++
++#
++# Extcon Device Drivers
++#
++# CONFIG_EXTCON_ADC_JACK is not set
++# CONFIG_EXTCON_GPIO is not set
++# CONFIG_EXTCON_RT8973A is not set
++# CONFIG_EXTCON_SM5502 is not set
++# CONFIG_EXTCON_USB_GPIO is not set
++CONFIG_MEMORY=y
++# CONFIG_ARM_PL172_MPMC is not set
++CONFIG_IIO=y
++CONFIG_IIO_BUFFER=y
++# CONFIG_IIO_BUFFER_CB is not set
++CONFIG_IIO_KFIFO_BUF=y
++CONFIG_IIO_TRIGGER=y
++CONFIG_IIO_CONSUMERS_PER_TRIGGER=2
++
++#
++# Accelerometers
++#
++# CONFIG_BMA180 is not set
++# CONFIG_BMC150_ACCEL is not set
++# CONFIG_IIO_ST_ACCEL_3AXIS is not set
++# CONFIG_KXSD9 is not set
++# CONFIG_KXCJK1013 is not set
++# CONFIG_MMA8452 is not set
++# CONFIG_MMA9551 is not set
++# CONFIG_MMA9553 is not set
++# CONFIG_MXC4005 is not set
++# CONFIG_STK8312 is not set
++# CONFIG_STK8BA50 is not set
++
++#
++# Analog to digital converters
++#
++# CONFIG_AD7266 is not set
++# CONFIG_AD7291 is not set
++# CONFIG_AD7298 is not set
++# CONFIG_AD7476 is not set
++# CONFIG_AD7791 is not set
++# CONFIG_AD7793 is not set
++# CONFIG_AD7887 is not set
++# CONFIG_AD7923 is not set
++# CONFIG_AD799X is not set
++# CONFIG_CC10001_ADC is not set
++# CONFIG_GPIO_MUXADC is not set
++# CONFIG_HI8435 is not set
++# CONFIG_MAX1027 is not set
++# CONFIG_MAX1363 is not set
++# CONFIG_MCP320X is not set
++# CONFIG_MCP3422 is not set
++# CONFIG_NAU7802 is not set
++CONFIG_ROCKCHIP_SARADC=y
++# CONFIG_TI_ADC081C is not set
++# CONFIG_TI_ADC128S052 is not set
++# CONFIG_VF610_ADC is not set
++
++#
++# Amplifiers
++#
++# CONFIG_AD8366 is not set
++
++#
++# Chemical Sensors
++#
++# CONFIG_VZ89X is not set
++
++#
++# Hid Sensor IIO Common
++#
++
++#
++# SSP Sensor Common
++#
++# CONFIG_IIO_SSP_SENSORHUB is not set
++
++#
++# Digital to analog converters
++#
++# CONFIG_AD5064 is not set
++# CONFIG_AD5360 is not set
++# CONFIG_AD5380 is not set
++# CONFIG_AD5421 is not set
++# CONFIG_AD5446 is not set
++# CONFIG_AD5449 is not set
++# CONFIG_AD5504 is not set
++# CONFIG_AD5624R_SPI is not set
++# CONFIG_AD5686 is not set
++# CONFIG_AD5755 is not set
++# CONFIG_AD5764 is not set
++# CONFIG_AD5791 is not set
++# CONFIG_AD7303 is not set
++# CONFIG_M62332 is not set
++# CONFIG_MAX517 is not set
++# CONFIG_MAX5821 is not set
++# CONFIG_MCP4725 is not set
++# CONFIG_MCP4922 is not set
++
++#
++# Frequency Synthesizers DDS/PLL
++#
++
++#
++# Clock Generator/Distribution
++#
++# CONFIG_AD9523 is not set
++
++#
++# Phase-Locked Loop (PLL) frequency synthesizers
++#
++# CONFIG_ADF4350 is not set
++
++#
++# Digital gyroscope sensors
++#
++# CONFIG_ADIS16080 is not set
++# CONFIG_ADIS16130 is not set
++# CONFIG_ADIS16136 is not set
++# CONFIG_ADIS16260 is not set
++# CONFIG_ADXRS450 is not set
++# CONFIG_BMG160 is not set
++# CONFIG_IIO_ST_GYRO_3AXIS is not set
++# CONFIG_ITG3200 is not set
++
++#
++# Humidity sensors
++#
++# CONFIG_DHT11 is not set
++# CONFIG_HDC100X is not set
++# CONFIG_HTU21 is not set
++# CONFIG_SI7005 is not set
++# CONFIG_SI7020 is not set
++
++#
++# Inertial measurement units
++#
++# CONFIG_ADIS16400 is not set
++# CONFIG_ADIS16480 is not set
++# CONFIG_KMX61 is not set
++# CONFIG_INV_MPU6050_IIO is not set
++
++#
++# Light sensors
++#
++# CONFIG_ADJD_S311 is not set
++# CONFIG_AL3320A is not set
++# CONFIG_APDS9300 is not set
++# CONFIG_APDS9960 is not set
++# CONFIG_BH1750 is not set
++# CONFIG_CM32181 is not set
++# CONFIG_CM3232 is not set
++# CONFIG_CM3323 is not set
++# CONFIG_CM36651 is not set
++# CONFIG_GP2AP020A00F is not set
++# CONFIG_ISL29125 is not set
++# CONFIG_JSA1212 is not set
++# CONFIG_RPR0521 is not set
++# CONFIG_LTR501 is not set
++# CONFIG_OPT3001 is not set
++# CONFIG_PA12203001 is not set
++# CONFIG_STK3310 is not set
++# CONFIG_TCS3414 is not set
++# CONFIG_TCS3472 is not set
++CONFIG_SENSORS_TSL2563=y
++# CONFIG_TSL4531 is not set
++# CONFIG_US5182D is not set
++# CONFIG_VCNL4000 is not set
++# CONFIG_VL6180 is not set
++
++#
++# Magnetometer sensors
++#
++# CONFIG_AK8975 is not set
++# CONFIG_AK09911 is not set
++# CONFIG_BMC150_MAGN is not set
++# CONFIG_MAG3110 is not set
++# CONFIG_MMC35240 is not set
++# CONFIG_IIO_ST_MAGN_3AXIS is not set
++
++#
++# Inclinometer sensors
++#
++
++#
++# Triggers - standalone
++#
++# CONFIG_IIO_INTERRUPT_TRIGGER is not set
++CONFIG_IIO_SYSFS_TRIGGER=y
++
++#
++# Digital potentiometers
++#
++# CONFIG_MCP4531 is not set
++
++#
++# Pressure sensors
++#
++# CONFIG_BMP280 is not set
++# CONFIG_MPL115 is not set
++# CONFIG_MPL3115 is not set
++# CONFIG_MS5611 is not set
++# CONFIG_MS5637 is not set
++# CONFIG_IIO_ST_PRESS is not set
++# CONFIG_T5403 is not set
++
++#
++# Lightning sensors
++#
++# CONFIG_AS3935 is not set
++
++#
++# Proximity sensors
++#
++# CONFIG_LIDAR_LITE_V2 is not set
++# CONFIG_SRF04 is not set
++# CONFIG_SX9500 is not set
++
++#
++# Temperature sensors
++#
++# CONFIG_MLX90614 is not set
++# CONFIG_TMP006 is not set
++# CONFIG_TSYS01 is not set
++# CONFIG_TSYS02D is not set
++CONFIG_PWM=y
++CONFIG_PWM_SYSFS=y
++# CONFIG_PWM_FSL_FTM is not set
++# CONFIG_PWM_GPIO is not set
++# CONFIG_PWM_PCA9685 is not set
++CONFIG_PWM_ROCKCHIP=y
++# CONFIG_PWM_ROCKCHIP_I2S is not set
++CONFIG_IRQCHIP=y
++CONFIG_ARM_GIC=y
++CONFIG_ARM_GIC_V3=y
++CONFIG_PARTITION_PERCPU=y
++# CONFIG_IPACK_BUS is not set
++CONFIG_ARCH_HAS_RESET_CONTROLLER=y
++CONFIG_RESET_CONTROLLER=y
++# CONFIG_FMC is not set
++
++#
++# PHY Subsystem
++#
++CONFIG_GENERIC_PHY=y
++# CONFIG_PHY_PXA_28NM_HSIC is not set
++# CONFIG_PHY_PXA_28NM_USB2 is not set
++# CONFIG_BCM_KONA_USB2_PHY is not set
++# CONFIG_PHY_SAMSUNG_USB2 is not set
++# CONFIG_PHY_XGENE is not set
++# CONFIG_PHY_ROCKCHIP_USB is not set
++# CONFIG_PHY_ROCKCHIP_INNO_COMBPHY is not set
++CONFIG_PHY_ROCKCHIP_INNO_USB2=y
++# CONFIG_PHY_ROCKCHIP_INNO_USB3 is not set
++# CONFIG_PHY_ROCKCHIP_EMMC is not set
++# CONFIG_PHY_ROCKCHIP_DP is not set
++CONFIG_PHY_ROCKCHIP_MIPI_RX=y
++# CONFIG_PHY_ROCKCHIP_INNO_MIPI_DPHY is not set
++# CONFIG_PHY_ROCKCHIP_INNO_HDMI_PHY is not set
++# CONFIG_PHY_ROCKCHIP_INNO_VIDEO_PHY is not set
++CONFIG_PHY_ROCKCHIP_INNO_VIDEO_COMBO_PHY=y
++# CONFIG_PHY_ROCKCHIP_TYPEC is not set
++# CONFIG_PHY_ROCKCHIP_PCIE is not set
++# CONFIG_POWERCAP is not set
++# CONFIG_MCB is not set
++
++#
++# Performance monitor support
++#
++CONFIG_ARM_PMU=y
++CONFIG_RAS=y
++
++#
++# Android
++#
++CONFIG_ANDROID=y
++# CONFIG_ANDROID_BINDER_IPC is not set
++# CONFIG_LIBNVDIMM is not set
++CONFIG_NVMEM=y
++# CONFIG_ROCKCHIP_EFUSE is not set
++CONFIG_ROCKCHIP_OTP=y
++# CONFIG_STM is not set
++# CONFIG_INTEL_TH is not set
++
++#
++# FPGA Configuration Support
++#
++# CONFIG_FPGA is not set
++# CONFIG_TEE is not set
++# CONFIG_RK_FLASH is not set
++# CONFIG_RK_NAND is not set
++
++#
++# Headset device support
++#
++# CONFIG_RK_HEADSET is not set
++
++#
++# Firmware Drivers
++#
++CONFIG_ARM_PSCI_FW=y
++# CONFIG_FIRMWARE_MEMMAP is not set
++CONFIG_HAVE_ARM_SMCCC=y
++CONFIG_ROCKCHIP_SIP=y
++
++#
++# File systems
++#
++CONFIG_DCACHE_WORD_ACCESS=y
++# CONFIG_EXT2_FS is not set
++# CONFIG_EXT3_FS is not set
++CONFIG_EXT4_FS=y
++CONFIG_EXT4_USE_FOR_EXT2=y
++CONFIG_EXT4_FS_POSIX_ACL=y
++CONFIG_EXT4_FS_SECURITY=y
++# CONFIG_EXT4_ENCRYPTION is not set
++# CONFIG_EXT4_DEBUG is not set
++CONFIG_JBD2=y
++# CONFIG_JBD2_DEBUG is not set
++CONFIG_FS_MBCACHE=y
++# CONFIG_REISERFS_FS is not set
++# CONFIG_JFS_FS is not set
++CONFIG_XFS_FS=y
++# CONFIG_XFS_QUOTA is not set
++# CONFIG_XFS_POSIX_ACL is not set
++# CONFIG_XFS_RT is not set
++# CONFIG_XFS_WARN is not set
++# CONFIG_XFS_DEBUG is not set
++# CONFIG_GFS2_FS is not set
++# CONFIG_OCFS2_FS is not set
++# CONFIG_BTRFS_FS is not set
++# CONFIG_NILFS2_FS is not set
++# CONFIG_F2FS_FS is not set
++# CONFIG_FS_DAX is not set
++CONFIG_FS_POSIX_ACL=y
++CONFIG_EXPORTFS=y
++CONFIG_FILE_LOCKING=y
++# CONFIG_FS_ENCRYPTION is not set
++CONFIG_FSNOTIFY=y
++# CONFIG_DNOTIFY is not set
++CONFIG_INOTIFY_USER=y
++# CONFIG_FANOTIFY is not set
++# CONFIG_QUOTA is not set
++# CONFIG_QUOTACTL is not set
++# CONFIG_AUTOFS4_FS is not set
++CONFIG_FUSE_FS=y
++# CONFIG_CUSE is not set
++# CONFIG_OVERLAY_FS is not set
++
++#
++# Caches
++#
++# CONFIG_FSCACHE is not set
++
++#
++# CD-ROM/DVD Filesystems
++#
++CONFIG_ISO9660_FS=y
++CONFIG_JOLIET=y
++CONFIG_ZISOFS=y
++# CONFIG_UDF_FS is not set
++
++#
++# DOS/FAT/NT Filesystems
++#
++CONFIG_FAT_FS=y
++# CONFIG_MSDOS_FS is not set
++CONFIG_VFAT_FS=y
++CONFIG_FAT_DEFAULT_CODEPAGE=936
++CONFIG_FAT_DEFAULT_IOCHARSET="utf8"
++# CONFIG_NTFS_FS is not set
++
++#
++# Pseudo filesystems
++#
++CONFIG_PROC_FS=y
++# CONFIG_PROC_KCORE is not set
++CONFIG_PROC_SYSCTL=y
++CONFIG_PROC_PAGE_MONITOR=y
++# CONFIG_PROC_CHILDREN is not set
++CONFIG_PROC_UID=y
++CONFIG_KERNFS=y
++CONFIG_SYSFS=y
++CONFIG_TMPFS=y
++CONFIG_TMPFS_POSIX_ACL=y
++CONFIG_TMPFS_XATTR=y
++# CONFIG_HUGETLBFS is not set
++# CONFIG_HUGETLB_PAGE is not set
++CONFIG_CONFIGFS_FS=y
++CONFIG_MISC_FILESYSTEMS=y
++# CONFIG_ADFS_FS is not set
++# CONFIG_AFFS_FS is not set
++# CONFIG_ECRYPT_FS is not set
++# CONFIG_SDCARD_FS is not set
++# CONFIG_HFS_FS is not set
++# CONFIG_HFSPLUS_FS is not set
++# CONFIG_BEFS_FS is not set
++# CONFIG_BFS_FS is not set
++# CONFIG_EFS_FS is not set
++# CONFIG_LOGFS is not set
++# CONFIG_CRAMFS is not set
++CONFIG_SQUASHFS=y
++CONFIG_SQUASHFS_DECOMP_SINGLE=y
++# CONFIG_SQUASHFS_DECOMP_MULTI is not set
++# CONFIG_SQUASHFS_DECOMP_MULTI_PERCPU is not set
++# CONFIG_SQUASHFS_XATTR is not set
++CONFIG_SQUASHFS_ZLIB=y
++# CONFIG_SQUASHFS_LZ4 is not set
++# CONFIG_SQUASHFS_LZO is not set
++# CONFIG_SQUASHFS_XZ is not set
++# CONFIG_SQUASHFS_ZSTD is not set
++# CONFIG_SQUASHFS_4K_DEVBLK_SIZE is not set
++# CONFIG_SQUASHFS_EMBEDDED is not set
++CONFIG_SQUASHFS_FRAGMENT_CACHE_SIZE=3
++# CONFIG_VXFS_FS is not set
++# CONFIG_MINIX_FS is not set
++# CONFIG_OMFS_FS is not set
++# CONFIG_HPFS_FS is not set
++# CONFIG_QNX4FS_FS is not set
++# CONFIG_QNX6FS_FS is not set
++# CONFIG_ROMFS_FS is not set
++# CONFIG_PSTORE is not set
++# CONFIG_SYSV_FS is not set
++# CONFIG_UFS_FS is not set
++CONFIG_NETWORK_FILESYSTEMS=y
++CONFIG_NFS_FS=y
++CONFIG_NFS_V2=y
++CONFIG_NFS_V3=y
++CONFIG_NFS_V3_ACL=y
++CONFIG_NFS_V4=y
++CONFIG_NFS_SWAP=y
++# CONFIG_NFS_V4_1 is not set
++# CONFIG_NFS_USE_LEGACY_DNS is not set
++CONFIG_NFS_USE_KERNEL_DNS=y
++# CONFIG_NFSD is not set
++CONFIG_GRACE_PERIOD=y
++CONFIG_LOCKD=y
++CONFIG_LOCKD_V4=y
++CONFIG_NFS_ACL_SUPPORT=y
++CONFIG_NFS_COMMON=y
++CONFIG_SUNRPC=y
++CONFIG_SUNRPC_GSS=y
++CONFIG_SUNRPC_SWAP=y
++# CONFIG_SUNRPC_DEBUG is not set
++# CONFIG_CEPH_FS is not set
++# CONFIG_CIFS is not set
++# CONFIG_NCP_FS is not set
++# CONFIG_CODA_FS is not set
++# CONFIG_AFS_FS is not set
++CONFIG_NLS=y
++CONFIG_NLS_DEFAULT="utf8"
++CONFIG_NLS_CODEPAGE_437=y
++# CONFIG_NLS_CODEPAGE_737 is not set
++# CONFIG_NLS_CODEPAGE_775 is not set
++# CONFIG_NLS_CODEPAGE_850 is not set
++# CONFIG_NLS_CODEPAGE_852 is not set
++# CONFIG_NLS_CODEPAGE_855 is not set
++# CONFIG_NLS_CODEPAGE_857 is not set
++# CONFIG_NLS_CODEPAGE_860 is not set
++# CONFIG_NLS_CODEPAGE_861 is not set
++# CONFIG_NLS_CODEPAGE_862 is not set
++# CONFIG_NLS_CODEPAGE_863 is not set
++# CONFIG_NLS_CODEPAGE_864 is not set
++# CONFIG_NLS_CODEPAGE_865 is not set
++# CONFIG_NLS_CODEPAGE_866 is not set
++# CONFIG_NLS_CODEPAGE_869 is not set
++CONFIG_NLS_CODEPAGE_936=y
++# CONFIG_NLS_CODEPAGE_950 is not set
++# CONFIG_NLS_CODEPAGE_932 is not set
++# CONFIG_NLS_CODEPAGE_949 is not set
++# CONFIG_NLS_CODEPAGE_874 is not set
++# CONFIG_NLS_ISO8859_8 is not set
++# CONFIG_NLS_CODEPAGE_1250 is not set
++# CONFIG_NLS_CODEPAGE_1251 is not set
++CONFIG_NLS_ASCII=y
++CONFIG_NLS_ISO8859_1=y
++# CONFIG_NLS_ISO8859_2 is not set
++# CONFIG_NLS_ISO8859_3 is not set
++# CONFIG_NLS_ISO8859_4 is not set
++# CONFIG_NLS_ISO8859_5 is not set
++# CONFIG_NLS_ISO8859_6 is not set
++# CONFIG_NLS_ISO8859_7 is not set
++# CONFIG_NLS_ISO8859_9 is not set
++# CONFIG_NLS_ISO8859_13 is not set
++# CONFIG_NLS_ISO8859_14 is not set
++# CONFIG_NLS_ISO8859_15 is not set
++# CONFIG_NLS_KOI8_R is not set
++# CONFIG_NLS_KOI8_U is not set
++# CONFIG_NLS_MAC_ROMAN is not set
++# CONFIG_NLS_MAC_CELTIC is not set
++# CONFIG_NLS_MAC_CENTEURO is not set
++# CONFIG_NLS_MAC_CROATIAN is not set
++# CONFIG_NLS_MAC_CYRILLIC is not set
++# CONFIG_NLS_MAC_GAELIC is not set
++# CONFIG_NLS_MAC_GREEK is not set
++# CONFIG_NLS_MAC_ICELAND is not set
++# CONFIG_NLS_MAC_INUIT is not set
++# CONFIG_NLS_MAC_ROMANIAN is not set
++# CONFIG_NLS_MAC_TURKISH is not set
++CONFIG_NLS_UTF8=y
++# CONFIG_DLM is not set
++# CONFIG_VIRTUALIZATION is not set
++
++#
++# Kernel hacking
++#
++
++#
++# printk and dmesg options
++#
++CONFIG_PRINTK_TIME=y
++# CONFIG_PRINTK_PROCESS is not set
++CONFIG_MESSAGE_LOGLEVEL_DEFAULT=4
++# CONFIG_BOOT_PRINTK_DELAY is not set
++CONFIG_DYNAMIC_DEBUG=y
++
++#
++# Compile-time checks and compiler options
++#
++CONFIG_DEBUG_INFO=y
++# CONFIG_DEBUG_INFO_REDUCED is not set
++# CONFIG_DEBUG_INFO_SPLIT is not set
++# CONFIG_DEBUG_INFO_DWARF4 is not set
++# CONFIG_GDB_SCRIPTS is not set
++CONFIG_ENABLE_WARN_DEPRECATED=y
++CONFIG_ENABLE_MUST_CHECK=y
++CONFIG_FRAME_WARN=2048
++# CONFIG_STRIP_ASM_SYMS is not set
++# CONFIG_READABLE_ASM is not set
++# CONFIG_UNUSED_SYMBOLS is not set
++# CONFIG_PAGE_OWNER is not set
++CONFIG_DEBUG_FS=y
++# CONFIG_HEADERS_CHECK is not set
++# CONFIG_DEBUG_SECTION_MISMATCH is not set
++CONFIG_SECTION_MISMATCH_WARN_ONLY=y
++CONFIG_ARCH_WANT_FRAME_POINTERS=y
++CONFIG_FRAME_POINTER=y
++# CONFIG_DEBUG_FORCE_WEAK_PER_CPU is not set
++CONFIG_MAGIC_SYSRQ=y
++CONFIG_MAGIC_SYSRQ_DEFAULT_ENABLE=0
++CONFIG_DEBUG_KERNEL=y
++
++#
++# Memory Debugging
++#
++# CONFIG_PAGE_EXTENSION is not set
++# CONFIG_DEBUG_PAGEALLOC is not set
++# CONFIG_DEBUG_OBJECTS is not set
++# CONFIG_SLUB_DEBUG_ON is not set
++# CONFIG_SLUB_STATS is not set
++CONFIG_HAVE_DEBUG_KMEMLEAK=y
++# CONFIG_DEBUG_KMEMLEAK is not set
++# CONFIG_DEBUG_STACK_USAGE is not set
++# CONFIG_DEBUG_VM is not set
++# CONFIG_DEBUG_MEMORY_INIT is not set
++# CONFIG_DEBUG_PER_CPU_MAPS is not set
++CONFIG_HAVE_ARCH_KASAN=y
++# CONFIG_KASAN is not set
++# CONFIG_DEBUG_SHIRQ is not set
++
++#
++# Debug Lockups and Hangs
++#
++CONFIG_LOCKUP_DETECTOR=y
++CONFIG_HARDLOCKUP_DETECTOR_OTHER_CPU=y
++CONFIG_HARDLOCKUP_DETECTOR=y
++# CONFIG_BOOTPARAM_HARDLOCKUP_PANIC is not set
++CONFIG_BOOTPARAM_HARDLOCKUP_PANIC_VALUE=0
++CONFIG_BOOTPARAM_SOFTLOCKUP_PANIC=y
++CONFIG_BOOTPARAM_SOFTLOCKUP_PANIC_VALUE=1
++CONFIG_DETECT_HUNG_TASK=y
++CONFIG_DEFAULT_HUNG_TASK_TIMEOUT=120
++CONFIG_BOOTPARAM_HUNG_TASK_PANIC=y
++CONFIG_BOOTPARAM_HUNG_TASK_PANIC_VALUE=1
++# CONFIG_PANIC_ON_OOPS is not set
++CONFIG_PANIC_ON_OOPS_VALUE=0
++CONFIG_PANIC_TIMEOUT=0
++CONFIG_SCHED_DEBUG=y
++CONFIG_SCHED_INFO=y
++# CONFIG_PANIC_ON_RT_THROTTLING is not set
++CONFIG_SCHEDSTATS=y
++# CONFIG_SCHED_STACK_END_CHECK is not set
++# CONFIG_DEBUG_TIMEKEEPING is not set
++CONFIG_TIMER_STATS=y
++
++#
++# Lock Debugging (spinlocks, mutexes, etc...)
++#
++# CONFIG_DEBUG_RT_MUTEXES is not set
++CONFIG_DEBUG_SPINLOCK=y
++# CONFIG_DEBUG_MUTEXES is not set
++# CONFIG_DEBUG_WW_MUTEX_SLOWPATH is not set
++# CONFIG_DEBUG_LOCK_ALLOC is not set
++# CONFIG_PROVE_LOCKING is not set
++# CONFIG_LOCK_STAT is not set
++# CONFIG_DEBUG_ATOMIC_SLEEP is not set
++# CONFIG_DEBUG_LOCKING_API_SELFTESTS is not set
++# CONFIG_LOCK_TORTURE_TEST is not set
++CONFIG_STACKTRACE=y
++# CONFIG_DEBUG_KOBJECT is not set
++CONFIG_HAVE_DEBUG_BUGVERBOSE=y
++CONFIG_DEBUG_BUGVERBOSE=y
++# CONFIG_DEBUG_LIST is not set
++# CONFIG_DEBUG_PI_LIST is not set
++# CONFIG_DEBUG_SG is not set
++# CONFIG_DEBUG_NOTIFIERS is not set
++CONFIG_DEBUG_CREDENTIALS=y
++
++#
++# RCU Debugging
++#
++# CONFIG_PROVE_RCU is not set
++# CONFIG_SPARSE_RCU_POINTER is not set
++# CONFIG_TORTURE_TEST is not set
++# CONFIG_RCU_TORTURE_TEST is not set
++CONFIG_RCU_CPU_STALL_TIMEOUT=60
++# CONFIG_RCU_TRACE is not set
++# CONFIG_RCU_EQS_DEBUG is not set
++# CONFIG_DEBUG_BLOCK_EXT_DEVT is not set
++# CONFIG_NOTIFIER_ERROR_INJECTION is not set
++# CONFIG_FAULT_INJECTION is not set
++CONFIG_NOP_TRACER=y
++CONFIG_HAVE_FUNCTION_TRACER=y
++CONFIG_HAVE_FUNCTION_GRAPH_TRACER=y
++CONFIG_HAVE_DYNAMIC_FTRACE=y
++CONFIG_HAVE_FTRACE_MCOUNT_RECORD=y
++CONFIG_HAVE_SYSCALL_TRACEPOINTS=y
++CONFIG_HAVE_C_RECORDMCOUNT=y
++CONFIG_TRACE_CLOCK=y
++CONFIG_RING_BUFFER=y
++CONFIG_EVENT_TRACING=y
++CONFIG_GPU_TRACEPOINTS=y
++CONFIG_CONTEXT_SWITCH_TRACER=y
++CONFIG_TRACING=y
++CONFIG_GENERIC_TRACER=y
++CONFIG_TRACING_SUPPORT=y
++CONFIG_FTRACE=y
++CONFIG_FUNCTION_TRACER=y
++CONFIG_FUNCTION_GRAPH_TRACER=y
++# CONFIG_PREEMPTIRQ_EVENTS is not set
++# CONFIG_IRQSOFF_TRACER is not set
++# CONFIG_SCHED_TRACER is not set
++# CONFIG_FTRACE_SYSCALLS is not set
++# CONFIG_TRACER_SNAPSHOT is not set
++CONFIG_BRANCH_PROFILE_NONE=y
++# CONFIG_PROFILE_ANNOTATED_BRANCHES is not set
++# CONFIG_PROFILE_ALL_BRANCHES is not set
++# CONFIG_STACK_TRACER is not set
++CONFIG_BLK_DEV_IO_TRACE=y
++# CONFIG_PROBE_EVENTS is not set
++CONFIG_DYNAMIC_FTRACE=y
++# CONFIG_FUNCTION_PROFILER is not set
++CONFIG_FTRACE_MCOUNT_RECORD=y
++# CONFIG_FTRACE_STARTUP_TEST is not set
++# CONFIG_TRACEPOINT_BENCHMARK is not set
++# CONFIG_RING_BUFFER_BENCHMARK is not set
++# CONFIG_RING_BUFFER_STARTUP_TEST is not set
++# CONFIG_TRACE_ENUM_MAP_FILE is not set
++CONFIG_TRACING_EVENTS_GPIO=y
++
++#
++# Runtime Testing
++#
++CONFIG_LKDTM=y
++# CONFIG_TEST_LIST_SORT is not set
++# CONFIG_BACKTRACE_SELF_TEST is not set
++# CONFIG_RBTREE_TEST is not set
++# CONFIG_INTERVAL_TREE_TEST is not set
++# CONFIG_PERCPU_TEST is not set
++# CONFIG_ATOMIC64_SELFTEST is not set
++# CONFIG_TEST_HEXDUMP is not set
++# CONFIG_TEST_STRING_HELPERS is not set
++# CONFIG_TEST_KSTRTOX is not set
++# CONFIG_TEST_PRINTF is not set
++# CONFIG_TEST_RHASHTABLE is not set
++# CONFIG_DMA_API_DEBUG is not set
++# CONFIG_TEST_LKM is not set
++# CONFIG_TEST_USER_COPY is not set
++# CONFIG_TEST_BPF is not set
++# CONFIG_TEST_FIRMWARE is not set
++# CONFIG_TEST_UDELAY is not set
++# CONFIG_MEMTEST is not set
++# CONFIG_TEST_STATIC_KEYS is not set
++# CONFIG_BUG_ON_DATA_CORRUPTION is not set
++# CONFIG_SAMPLES is not set
++CONFIG_HAVE_ARCH_KGDB=y
++# CONFIG_KGDB is not set
++# CONFIG_ARM64_PTDUMP is not set
++CONFIG_STRICT_DEVMEM=y
++# CONFIG_PID_IN_CONTEXTIDR is not set
++# CONFIG_ARM64_RANDOMIZE_TEXT_OFFSET is not set
++CONFIG_DEBUG_SET_MODULE_RONX=y
++CONFIG_DEBUG_RODATA=y
++# CONFIG_DEBUG_ALIGN_RODATA is not set
++# CONFIG_CORESIGHT is not set
++
++#
++# Security options
++#
++CONFIG_KEYS=y
++# CONFIG_PERSISTENT_KEYRINGS is not set
++# CONFIG_BIG_KEYS is not set
++# CONFIG_TRUSTED_KEYS is not set
++# CONFIG_ENCRYPTED_KEYS is not set
++# CONFIG_SECURITY_DMESG_RESTRICT is not set
++# CONFIG_SECURITY_PERF_EVENTS_RESTRICT is not set
++# CONFIG_SECURITY is not set
++CONFIG_SECURITYFS=y
++CONFIG_HAVE_HARDENED_USERCOPY_ALLOCATOR=y
++CONFIG_HAVE_ARCH_HARDENED_USERCOPY=y
++# CONFIG_HARDENED_USERCOPY is not set
++# CONFIG_TEE_SUPPORT is not set
++CONFIG_DEFAULT_SECURITY_DAC=y
++CONFIG_DEFAULT_SECURITY=""
++CONFIG_CRYPTO=y
++
++#
++# Crypto core or helper
++#
++CONFIG_CRYPTO_ALGAPI=y
++CONFIG_CRYPTO_ALGAPI2=y
++CONFIG_CRYPTO_AEAD=y
++CONFIG_CRYPTO_AEAD2=y
++CONFIG_CRYPTO_BLKCIPHER=y
++CONFIG_CRYPTO_BLKCIPHER2=y
++CONFIG_CRYPTO_HASH=y
++CONFIG_CRYPTO_HASH2=y
++CONFIG_CRYPTO_RNG=y
++CONFIG_CRYPTO_RNG2=y
++CONFIG_CRYPTO_RNG_DEFAULT=y
++CONFIG_CRYPTO_PCOMP2=y
++CONFIG_CRYPTO_AKCIPHER2=y
++CONFIG_CRYPTO_AKCIPHER=y
++# CONFIG_CRYPTO_RSA is not set
++CONFIG_CRYPTO_MANAGER=y
++CONFIG_CRYPTO_MANAGER2=y
++# CONFIG_CRYPTO_USER is not set
++CONFIG_CRYPTO_MANAGER_DISABLE_TESTS=y
++CONFIG_CRYPTO_GF128MUL=y
++CONFIG_CRYPTO_NULL=y
++CONFIG_CRYPTO_NULL2=y
++# CONFIG_CRYPTO_PCRYPT is not set
++CONFIG_CRYPTO_WORKQUEUE=y
++CONFIG_CRYPTO_CRYPTD=y
++# CONFIG_CRYPTO_MCRYPTD is not set
++# CONFIG_CRYPTO_AUTHENC is not set
++# CONFIG_CRYPTO_TEST is not set
++CONFIG_CRYPTO_ABLK_HELPER=y
++
++#
++# Authenticated Encryption with Associated Data
++#
++CONFIG_CRYPTO_CCM=y
++CONFIG_CRYPTO_GCM=y
++# CONFIG_CRYPTO_CHACHA20POLY1305 is not set
++CONFIG_CRYPTO_SEQIV=y
++# CONFIG_CRYPTO_ECHAINIV is not set
++
++#
++# Block modes
++#
++# CONFIG_CRYPTO_CBC is not set
++# CONFIG_CRYPTO_HEH is not set
++CONFIG_CRYPTO_CTR=y
++# CONFIG_CRYPTO_CTS is not set
++CONFIG_CRYPTO_ECB=y
++# CONFIG_CRYPTO_LRW is not set
++# CONFIG_CRYPTO_PCBC is not set
++# CONFIG_CRYPTO_XTS is not set
++# CONFIG_CRYPTO_KEYWRAP is not set
++
++#
++# Hash modes
++#
++CONFIG_CRYPTO_CMAC=y
++CONFIG_CRYPTO_HMAC=y
++# CONFIG_CRYPTO_XCBC is not set
++# CONFIG_CRYPTO_VMAC is not set
++
++#
++# Digest
++#
++CONFIG_CRYPTO_CRC32C=y
++# CONFIG_CRYPTO_CRC32 is not set
++CONFIG_CRYPTO_CRCT10DIF=y
++CONFIG_CRYPTO_GHASH=y
++# CONFIG_CRYPTO_POLY1305 is not set
++# CONFIG_CRYPTO_MD4 is not set
++CONFIG_CRYPTO_MD5=y
++# CONFIG_CRYPTO_MICHAEL_MIC is not set
++# CONFIG_CRYPTO_RMD128 is not set
++# CONFIG_CRYPTO_RMD160 is not set
++# CONFIG_CRYPTO_RMD256 is not set
++# CONFIG_CRYPTO_RMD320 is not set
++CONFIG_CRYPTO_SHA1=y
++CONFIG_CRYPTO_SHA256=y
++CONFIG_CRYPTO_SHA512=y
++# CONFIG_CRYPTO_TGR192 is not set
++# CONFIG_CRYPTO_WP512 is not set
++
++#
++# Ciphers
++#
++CONFIG_CRYPTO_AES=y
++# CONFIG_CRYPTO_ANUBIS is not set
++CONFIG_CRYPTO_ARC4=y
++# CONFIG_CRYPTO_BLOWFISH is not set
++# CONFIG_CRYPTO_CAMELLIA is not set
++# CONFIG_CRYPTO_CAST5 is not set
++# CONFIG_CRYPTO_CAST6 is not set
++# CONFIG_CRYPTO_DES is not set
++# CONFIG_CRYPTO_FCRYPT is not set
++# CONFIG_CRYPTO_KHAZAD is not set
++# CONFIG_CRYPTO_SALSA20 is not set
++# CONFIG_CRYPTO_CHACHA20 is not set
++# CONFIG_CRYPTO_SEED is not set
++# CONFIG_CRYPTO_SERPENT is not set
++# CONFIG_CRYPTO_TEA is not set
++CONFIG_CRYPTO_TWOFISH=y
++CONFIG_CRYPTO_TWOFISH_COMMON=y
++
++#
++# Compression
++#
++# CONFIG_CRYPTO_DEFLATE is not set
++# CONFIG_CRYPTO_ZLIB is not set
++CONFIG_CRYPTO_LZO=y
++# CONFIG_CRYPTO_842 is not set
++# CONFIG_CRYPTO_LZ4 is not set
++# CONFIG_CRYPTO_LZ4HC is not set
++# CONFIG_CRYPTO_ZSTD is not set
++
++#
++# Random Number Generation
++#
++CONFIG_CRYPTO_ANSI_CPRNG=y
++CONFIG_CRYPTO_DRBG_MENU=y
++CONFIG_CRYPTO_DRBG_HMAC=y
++# CONFIG_CRYPTO_DRBG_HASH is not set
++# CONFIG_CRYPTO_DRBG_CTR is not set
++CONFIG_CRYPTO_DRBG=y
++CONFIG_CRYPTO_JITTERENTROPY=y
++CONFIG_CRYPTO_USER_API=y
++CONFIG_CRYPTO_USER_API_HASH=y
++CONFIG_CRYPTO_USER_API_SKCIPHER=y
++# CONFIG_CRYPTO_USER_API_RNG is not set
++# CONFIG_CRYPTO_USER_API_AEAD is not set
++CONFIG_CRYPTO_HASH_INFO=y
++CONFIG_CRYPTO_HW=y
++# CONFIG_CRYPTO_DEV_CCP is not set
++# CONFIG_CRYPTO_DEV_ROCKCHIP_V1 is not set
++# CONFIG_CRYPTO_DEV_ROCKCHIP_V2 is not set
++CONFIG_ASYMMETRIC_KEY_TYPE=y
++CONFIG_ASYMMETRIC_PUBLIC_KEY_SUBTYPE=y
++CONFIG_PUBLIC_KEY_ALGO_RSA=y
++CONFIG_X509_CERTIFICATE_PARSER=y
++CONFIG_PKCS7_MESSAGE_PARSER=y
++# CONFIG_PKCS7_TEST_KEY is not set
++# CONFIG_SIGNED_PE_FILE_VERIFICATION is not set
++
++#
++# Certificates for signature checking
++#
++CONFIG_SYSTEM_TRUSTED_KEYRING=y
++CONFIG_SYSTEM_TRUSTED_KEYS=""
++CONFIG_ARM64_CRYPTO=y
++CONFIG_CRYPTO_SHA1_ARM64_CE=y
++CONFIG_CRYPTO_SHA2_ARM64_CE=y
++CONFIG_CRYPTO_GHASH_ARM64_CE=y
++# CONFIG_CRYPTO_POLY_HASH_ARM64_CE is not set
++CONFIG_CRYPTO_AES_ARM64_CE=y
++CONFIG_CRYPTO_AES_ARM64_CE_CCM=y
++CONFIG_CRYPTO_AES_ARM64_CE_BLK=y
++# CONFIG_CRYPTO_AES_ARM64_NEON_BLK is not set
++# CONFIG_CRYPTO_CRC32_ARM64 is not set
++CONFIG_BINARY_PRINTF=y
++
++#
++# Library routines
++#
++CONFIG_BITREVERSE=y
++CONFIG_HAVE_ARCH_BITREVERSE=y
++CONFIG_RATIONAL=y
++CONFIG_GENERIC_STRNCPY_FROM_USER=y
++CONFIG_GENERIC_STRNLEN_USER=y
++CONFIG_GENERIC_NET_UTILS=y
++CONFIG_GENERIC_PCI_IOMAP=y
++CONFIG_GENERIC_IO=y
++CONFIG_ARCH_USE_CMPXCHG_LOCKREF=y
++CONFIG_CRC_CCITT=y
++CONFIG_CRC16=y
++CONFIG_CRC_T10DIF=y
++CONFIG_CRC_ITU_T=y
++CONFIG_CRC32=y
++# CONFIG_CRC32_SELFTEST is not set
++CONFIG_CRC32_SLICEBY8=y
++# CONFIG_CRC32_SLICEBY4 is not set
++# CONFIG_CRC32_SARWATE is not set
++# CONFIG_CRC32_BIT is not set
++CONFIG_CRC7=y
++CONFIG_LIBCRC32C=y
++# CONFIG_CRC8 is not set
++CONFIG_AUDIT_ARCH_COMPAT_GENERIC=y
++# CONFIG_RANDOM32_SELFTEST is not set
++CONFIG_ZLIB_INFLATE=y
++CONFIG_LZO_COMPRESS=y
++CONFIG_LZO_DECOMPRESS=y
++CONFIG_LZ4_DECOMPRESS=y
++CONFIG_XZ_DEC=y
++# CONFIG_XZ_DEC_X86 is not set
++# CONFIG_XZ_DEC_POWERPC is not set
++# CONFIG_XZ_DEC_IA64 is not set
++CONFIG_XZ_DEC_ARM=y
++CONFIG_XZ_DEC_ARMTHUMB=y
++# CONFIG_XZ_DEC_SPARC is not set
++CONFIG_XZ_DEC_BCJ=y
++# CONFIG_XZ_DEC_TEST is not set
++CONFIG_DECOMPRESS_GZIP=y
++CONFIG_DECOMPRESS_BZIP2=y
++CONFIG_DECOMPRESS_LZMA=y
++CONFIG_DECOMPRESS_XZ=y
++CONFIG_DECOMPRESS_LZO=y
++CONFIG_DECOMPRESS_LZ4=y
++CONFIG_GENERIC_ALLOCATOR=y
++CONFIG_ASSOCIATIVE_ARRAY=y
++CONFIG_HAS_IOMEM=y
++CONFIG_HAS_DMA=y
++CONFIG_CPU_RMAP=y
++CONFIG_DQL=y
++CONFIG_NLATTR=y
++CONFIG_ARCH_HAS_ATOMIC64_DEC_IF_POSITIVE=y
++CONFIG_CLZ_TAB=y
++# CONFIG_CORDIC is not set
++# CONFIG_DDR is not set
++CONFIG_MPILIB=y
++CONFIG_LIBFDT=y
++CONFIG_OID_REGISTRY=y
++# CONFIG_SG_SPLIT is not set
++CONFIG_ARCH_HAS_SG_CHAIN=y
+-- 
+2.7.4
+
+
diff --git a/layers/meta-balena-nanopc-t4/recipes-kernel/linux/files/4.4.185/0002-Added-ethernet-driver-support-for-LEC-PX30-A2.patch b/layers/meta-balena-nanopc-t4/recipes-kernel/linux/files/4.4.185/0002-Added-ethernet-driver-support-for-LEC-PX30-A2.patch
new file mode 100644
index 000000000..e8f221db4
--- /dev/null
+++ b/layers/meta-balena-nanopc-t4/recipes-kernel/linux/files/4.4.185/0002-Added-ethernet-driver-support-for-LEC-PX30-A2.patch
@@ -0,0 +1,9584 @@
+From 67ca8500e5934cd7dfd1f837b3f38631aba8a67b Mon Sep 17 00:00:00 2001
+From: Katha Ashok <katha.ashok@adlinktech.com>
+Date: Tue, 5 Nov 2019 11:33:29 +0530
+Subject: [PATCH 2/2] Added ethernet driver support for LEC-PX30 A2
+
+---
+ drivers/net/ethernet/Kconfig               |    1 +
+ drivers/net/ethernet/Makefile              |    1 +
+ drivers/net/ethernet/smsc9514/Kconfig      |   25 +
+ drivers/net/ethernet/smsc9514/Makefile     |    9 +
+ drivers/net/ethernet/smsc9514/ioctl_9500.h |  160 +
+ drivers/net/ethernet/smsc9514/smsc9500.c   | 5918 ++++++++++++++++++++++++++++
+ drivers/net/ethernet/smsc9514/smsc9500.h   |  859 ++++
+ drivers/net/ethernet/smsc9514/smscusbnet.c | 2157 ++++++++++
+ drivers/net/ethernet/smsc9514/smscusbnet.h |  328 ++
+ drivers/net/ethernet/smsc9514/version.h    |    6 +
+ include/linux/usb.h                        |    2 +
+ 11 files changed, 9466 insertions(+)
+ create mode 100644 drivers/net/ethernet/smsc9514/Kconfig
+ create mode 100755 drivers/net/ethernet/smsc9514/Makefile
+ create mode 100755 drivers/net/ethernet/smsc9514/ioctl_9500.h
+ create mode 100755 drivers/net/ethernet/smsc9514/smsc9500.c
+ create mode 100755 drivers/net/ethernet/smsc9514/smsc9500.h
+ create mode 100755 drivers/net/ethernet/smsc9514/smscusbnet.c
+ create mode 100755 drivers/net/ethernet/smsc9514/smscusbnet.h
+ create mode 100755 drivers/net/ethernet/smsc9514/version.h
+
+diff --git a/drivers/net/ethernet/Kconfig b/drivers/net/ethernet/Kconfig
+index 31c5e47..b417916 100644
+--- a/drivers/net/ethernet/Kconfig
++++ b/drivers/net/ethernet/Kconfig
+@@ -165,6 +165,7 @@ source "drivers/net/ethernet/sis/Kconfig"
+ source "drivers/net/ethernet/sfc/Kconfig"
+ source "drivers/net/ethernet/sgi/Kconfig"
+ source "drivers/net/ethernet/smsc/Kconfig"
++source "drivers/net/ethernet/smsc9514/Kconfig"
+ source "drivers/net/ethernet/stmicro/Kconfig"
+ source "drivers/net/ethernet/sun/Kconfig"
+ source "drivers/net/ethernet/synopsys/Kconfig"
+diff --git a/drivers/net/ethernet/Makefile b/drivers/net/ethernet/Makefile
+index 071f84e..60701cd 100644
+--- a/drivers/net/ethernet/Makefile
++++ b/drivers/net/ethernet/Makefile
+@@ -75,6 +75,7 @@ obj-$(CONFIG_NET_VENDOR_SIS) += sis/
+ obj-$(CONFIG_SFC) += sfc/
+ obj-$(CONFIG_NET_VENDOR_SGI) += sgi/
+ obj-$(CONFIG_NET_VENDOR_SMSC) += smsc/
++obj-$(CONFIG_NET_VENDOR_SMSC9514) += smsc9514/
+ obj-$(CONFIG_NET_VENDOR_STMICRO) += stmicro/
+ obj-$(CONFIG_NET_VENDOR_SUN) += sun/
+ obj-$(CONFIG_NET_VENDOR_SYNOPSYS) += synopsys/
+diff --git a/drivers/net/ethernet/smsc9514/Kconfig b/drivers/net/ethernet/smsc9514/Kconfig
+new file mode 100644
+index 0000000..2d8b513
+--- /dev/null
++++ b/drivers/net/ethernet/smsc9514/Kconfig
+@@ -0,0 +1,25 @@
++#
++# SMSC95XX USB to Ethernet controller device configuration
++#
++
++menuconfig NET_VENDOR_SMSC9514
++       tristate 'LAN 9514 driver configuration'
++       help
++         This enables SMSC95XX USB to Ethernet controller board specific character
++         devices.
++
++if NET_VENDOR_SMSC9514
++
++config SMSC9500
++       tristate "SMSC 9500 module"
++       help
++          This driver is required for smsc9500 module.
++
++config SMSCUSBNET
++       tristate "SMSCUSBNET module"
++       help
++          This driver is required for smsc usb net module.
++
++endif # NET_VENDOR_SMSC9514
++
++
+diff --git a/drivers/net/ethernet/smsc9514/Makefile b/drivers/net/ethernet/smsc9514/Makefile
+new file mode 100755
+index 0000000..80e9fb5
+--- /dev/null
++++ b/drivers/net/ethernet/smsc9514/Makefile
+@@ -0,0 +1,9 @@
++obj-$(CONFIG_SMSC9500) += smsc9500.o
++obj-$(CONFIG_SMSCUSBNET) += smscusbnet.o
++
++
++
++
++
++
++
+diff --git a/drivers/net/ethernet/smsc9514/ioctl_9500.h b/drivers/net/ethernet/smsc9514/ioctl_9500.h
+new file mode 100755
+index 0000000..9b293c4
+--- /dev/null
++++ b/drivers/net/ethernet/smsc9514/ioctl_9500.h
+@@ -0,0 +1,160 @@
++#ifndef IOCTL_9500_H_
++#define IOCTL_9500_H_
++
++/***************************************************************************
++ *
++ * Copyright (C) 2008-2009  SMSC
++ *
++ * This program is free software; you can redistribute it and/or
++ * modify it under the terms of the GNU General Public License
++ * as published by the Free Software Foundation; either version 2
++ * of the License, or (at your option) any later version.
++ *
++ * This program is distributed in the hope that it will be useful,
++ * but WITHOUT ANY WARRANTY; without even the implied warranty of
++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
++ * GNU General Public License for more details.
++ *
++ * You should have received a copy of the GNU General Public License
++ * along with this program; if not, write to the Free Software
++ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
++ *
++ ***************************************************************************
++ * File: ioctl_500.h
++ */
++
++#define SMSC9500_DRIVER_SIGNATURE	(0x82745BACUL+DRIVER_VERSION)
++#define SMSC9500_APP_SIGNATURE		(0x987BEF28UL+DRIVER_VERSION)
++
++#define SMSC9500_IOCTL			(SIOCDEVPRIVATE + 0xB)
++#define MAX_EEPROM_SIZE 		512
++
++enum {
++	COMMAND_BASE = 0x974FB832UL,
++	COMMAND_GET_SIGNATURE,
++	COMMAND_LAN_GET_REG,
++	COMMAND_LAN_SET_REG,
++	COMMAND_MAC_GET_REG,
++	COMMAND_MAC_SET_REG,
++	COMMAND_PHY_GET_REG,
++	COMMAND_PHY_SET_REG,
++	COMMAND_DUMP_LAN_REGS,
++	COMMAND_DUMP_MAC_REGS,
++	COMMAND_DUMP_PHY_REGS,
++	COMMAND_DUMP_EEPROM,
++	COMMAND_GET_MAC_ADDRESS,
++	COMMAND_SET_MAC_ADDRESS,
++	COMMAND_LOAD_MAC_ADDRESS,
++	COMMAND_SAVE_MAC_ADDRESS,
++	COMMAND_SET_DEBUG_MODE,
++	COMMAND_SET_POWER_MODE,
++	COMMAND_GET_POWER_MODE,
++	COMMAND_SET_LINK_MODE,
++	COMMAND_GET_LINK_MODE,
++	COMMAND_SET_LINK_STATUS,
++	COMMAND_GET_LINK_STATUS,
++	COMMAND_GET_CONFIGURATION,
++	COMMAND_DUMP_TEMP,
++	COMMAND_READ_BYTE,
++	COMMAND_READ_WORD,
++	COMMAND_READ_DWORD,
++	COMMAND_WRITE_BYTE,
++	COMMAND_WRITE_WORD,
++	COMMAND_WRITE_DWORD,
++	COMMAND_CHECK_LINK,
++	COMMAND_GET_ERRORS,
++	COMMAND_SET_EEPROM,
++	COMMAND_GET_EEPROM,
++	COMMAND_WRITE_EEPROM_FROM_FILE,
++	COMMAND_WRITE_EEPROM_TO_FILE,
++	COMMAND_VERIFY_EEPROM_WITH_FILE,
++
++	/*The following codes are intended for cmd9500 only
++	They are not intended to have any use in the driver */
++
++	COMMAND_RUN_SERVER,
++	COMMAND_RUN_TUNER,
++	COMMAND_GET_FLOW_PARAMS,
++	COMMAND_SET_FLOW_PARAMS,
++	COMMAND_SET_AMDIX_STS,
++	COMMAND_GET_AMDIX_STS,
++	COMMAND_SET_EEPROM_BUFFER
++};
++
++enum {
++	LAN_REG_ID_REV,
++	LAN_REG_FPGA_REV,
++	LAN_REG_INT_STS,
++	LAN_REG_RX_CFG,
++	LAN_REG_TX_CFG,
++	LAN_REG_HW_CFG,
++	LAN_REG_RX_FIFO_INF,
++	LAN_REG_TX_FIFO_INF,
++	LAN_REG_PMT_CTRL,
++	LAN_REG_LED_GPIO_CFG,
++	LAN_REG_GPIO_CFG,
++	LAN_REG_AFC_CFG,
++	LAN_REG_E2P_CMD,
++	LAN_REG_E2P_DATA,
++	LAN_REG_BURST_CAP,
++	LAN_REG_STRAP_DBG,
++	LAN_REG_DP_SEL,
++	LAN_REG_DP_CMD,
++	LAN_REG_DP_ADDR,
++	LAN_REG_DP_DATA0,
++	LAN_REG_DP_DATA1,
++	LAN_REG_GPIO_WAKE,
++	LAN_REG_INT_EP_CTL,
++	LAN_REG_BULK_IN_DLY,
++	MAX_LAN_REG_NUM
++};
++
++enum {
++	MAC_REG_MAC_CR,
++	MAC_REG_ADDRH,
++	MAC_REG_ADDRL,
++	MAC_REG_HASHH,
++	MAC_REG_HASHL,
++	MAC_REG_MII_ADDR,
++	MAC_REG_MII_DATA,
++	MAC_REG_FLOW,
++	MAC_REG_VLAN1,
++	MAC_REG_VLAN2,
++	MAC_REG_WUFF,
++	MAC_REG_WUCSR,
++	MAC_REG_COE_CR,
++	MAX_MAC_REG_NUM
++};
++
++enum {
++	PHY_REG_BCR,
++	PHY_REG_BSR,
++	PHY_REG_ID1,
++	PHY_REG_ID2,
++	PHY_REG_ANEG_ADV,
++	PHY_REG_ANEG_LPA,
++	PHY_REG_ANEG_ER,
++	PHY_REG_SILICON_REV,
++	PHY_REG_MODE_CTRL_STS,
++	PHY_REG_SPECIAL_MODES,
++	PHY_REG_TSTCNTL,
++	PHY_REG_TSTREAD1,
++	PHY_REG_TSTREAD2,
++	PHY_REG_TSTWRITE,
++	PHY_REG_SPECIAL_CTRL_STS,
++	PHY_REG_SITC,
++	PHY_REG_INT_SRC,
++	PHY_REG_INT_MASK,
++	PHY_REG_SPECIAL,
++	MAX_PHY_REG_NUM
++};
++
++typedef struct _SMSC9500_IOCTL_DATA {
++	unsigned long dwSignature;
++	unsigned long dwCommand;
++	unsigned long Data[526];
++	char Strng1[30];
++	char Strng2[10];
++} SMSC9500_IOCTL_DATA, *PSMSC9500_IOCTL_DATA;
++
++#endif /*IOCTL_9500_H_*/
+diff --git a/drivers/net/ethernet/smsc9514/smsc9500.c b/drivers/net/ethernet/smsc9514/smsc9500.c
+new file mode 100755
+index 0000000..3e17b83
+--- /dev/null
++++ b/drivers/net/ethernet/smsc9514/smsc9500.c
+@@ -0,0 +1,5918 @@
++ /*
++ * Copyright (C) 2007-2008  SMSC
++ *
++ * This program is free software; you can redistribute it and/or
++ * modify it under the terms of the GNU General Public License
++ * as published by the Free Software Foundation; either version 2
++ * of the License, or (at your option) any later version.
++ *
++ * This program is distributed in the hope that it will be useful,
++ * but WITHOUT ANY WARRANTY; without even the implied warranty of
++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
++ * GNU General Public License for more details.
++ *
++ * You should have received a copy of the GNU General Public License
++ * along with this program; if not, write to the Free Software
++ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
++ *
++ ***************************************************************************
++ * File: smsc9500.c
++ ***************************************************************************/
++
++#ifndef __KERNEL__
++#define __KERNEL__
++#endif
++
++#include <linux/version.h>
++#include <linux/module.h>
++#include <linux/moduleparam.h>
++#include <linux/module.h>
++#include <linux/kmod.h>
++#include <linux/sched.h>
++#include <linux/init.h>
++#include <linux/netdevice.h>
++#include <linux/etherdevice.h>
++#include <linux/ethtool.h>
++#include <linux/workqueue.h>
++#include <linux/mii.h>
++#include <linux/usb.h>
++#include <linux/crc32.h>
++#include <linux/ioport.h>
++#include <asm/io.h>
++#include <linux/mm.h>
++#include "version.h"
++#include "smscusbnet.h"
++#include "smsc9500.h"
++#include "ioctl_9500.h"
++
++//#define PME_EEPROMLESS
++
++#ifndef bool
++#define bool int
++#endif
++
++#define CHECK_RETURN_STATUS(A)		\
++	{                               \
++	    if((A) < 0)			\
++	    {                           \
++		SMSC_WARNING("Failure in %s(), line: %d\n", __FUNCTION__,__LINE__); \
++		goto DONE;              \
++	    }                           \
++	}
++
++unsigned int debug_mode = DBG_WARNING | DBG_LINK_CHANGE;
++module_param(debug_mode, uint, 0);
++MODULE_PARM_DESC(debug_mode,"bit 0 enables trace points, bit 1 enables warning points, bit 2 enables eth gpios, bit 3 enables gen gpios");
++
++u32 link_mode=0x7fUL;
++module_param(link_mode, uint, 0);
++MODULE_PARM_DESC(link_mode,"Set Link speed and Duplex, 1=10HD,2=10FD,4=100HD,8=100FD,default=0x7F");
++
++u32 auto_mdix=0x2U;//0x3U
++module_param(auto_mdix, uint, 0);
++MODULE_PARM_DESC(auto_mdix,"Set Auto-MDIX state, 0=StraightCable,1=CrossOver,2=Enable AMDIX,3=controlled by Strap");
++
++u32 mac_addr_hi16=0xFFFFFFFFUL;
++module_param(mac_addr_hi16, uint, 0);
++MODULE_PARM_DESC(mac_addr_hi16,"Specifies the high 16 bits of the mac address");
++
++u32 mac_addr_lo32=0xFFFFFFFFUL;
++module_param(mac_addr_lo32, uint, 0);
++MODULE_PARM_DESC(mac_addr_lo32,"Specifies the low 32 bits of the mac address");
++
++u32 phy_addr=0xFFFFFFFFUL;
++module_param(phy_addr, uint, 0);
++MODULE_PARM_DESC(phy_addr,"phy_addr, only valid if it is external phy set by strap; 0-31=external phy with specified address, else autodetect external phy addr");
++
++bool tx_Csum=FALSE;
++module_param(tx_Csum,bool, 0);
++MODULE_PARM_DESC(tx_Csum,"Enable Tx Hardware Checksum Offload");
++
++bool rx_Csum=FALSE;
++module_param(rx_Csum,bool, 0);
++MODULE_PARM_DESC(tx_Csum,"Enable Rx Hardware Checksum Offload");
++
++u32 bulkin_delay=DEFAULT_BULK_IN_DELAY;
++module_param(bulkin_delay,uint, 0);
++MODULE_PARM_DESC(bulkin_delay,"16 bit value in units of 16ns to delay UTX sending data");
++
++bool LinkActLedCfg=TRUE;
++module_param(LinkActLedCfg,bool, 0);
++MODULE_PARM_DESC(LinkActLedCfg,"Enables separate Link and Activity LEDs in LAN9500A");
++
++u32 LinkLedOnGpio=11;
++module_param(LinkLedOnGpio, uint, 0);
++MODULE_PARM_DESC(LinkLedOnGpio,"Enable separate Link and Activity LEDs in LAN9500 and specifies gpio port for link status");
++
++u32 LinkLedBufType=0;
++module_param(LinkLedBufType, uint, 0);
++MODULE_PARM_DESC(LinkLedBufType,"Specifies gpio buffer type for link led");
++
++u32 LinkLedPolarity = 0;
++module_param(LinkLedPolarity, uint, 0);
++MODULE_PARM_DESC(LinkLedPolarity,"Specifies active level on gpio port");
++
++/*
++ linkdownsuspend = 0----> Disabled
++ linkdownsuspend = 1----> Enabled, wake up on auto-negotiation complete, device is in suspend0.
++ linkdownsuspend = 2----> Enabled, wake up on energy detection, device is in suspend1.
++*/
++static uint linkdownsuspend=0;
++module_param(linkdownsuspend, uint, 0);
++MODULE_PARM_DESC(linkdownsuspend,"Suspend device when link is down");
++
++static u32 dynamicsuspend=0;
++module_param(dynamicsuspend,uint, 0);
++MODULE_PARM_DESC(dynamicsuspend,"Enable dynamic autosuspend mode");
++
++static u32 netdetach=0;
++module_param(netdetach,uint, 0);
++MODULE_PARM_DESC(netdetach,"Enable net detach mode, for LAN9500A only");
++
++u32 EDPDConfig=EDPD_CFG_DEFAULT;
++module_param(EDPDConfig, uint, 0);
++MODULE_PARM_DESC(EDPDConfig,"Set EDPD Config");
++
++u32 tx_skb_clone=TRUE;
++module_param(tx_skb_clone, uint, 0);
++MODULE_PARM_DESC(tx_skb_clone,"Set tx_skb_clone");
++
++u32 EnableEEE=0;
++module_param(EnableEEE, uint, 0);
++MODULE_PARM_DESC(EnableEEE,"Enable EEE");
++
++/*
++ MdioDisable: 
++ bit 0: when set disables all internal access to phy
++ bit 1: when set disables IOCTL access to phy
++ when MdioDisable is set the auto-neg need to be disabled.
++ for 100FD, set link_mode=0x08UL;
++*/
++u32 MdioDisable=0;
++module_param(MdioDisable, uint, 0);
++MODULE_PARM_DESC(MdioDisable,"MDIO Access control");
++
++/* MdioDefaultLinkStatus: (applicable only when MdioDisable bit 0 is set) 
++   bit 0: When set report link down after initilization
++	  When clear (default) report link up after initialization
++*/
++u32 MdioDefaultLinkStatus=1;
++module_param(MdioDefaultLinkStatus, uint, 0);
++MODULE_PARM_DESC(MdioDefaultLinkStatus,"Default link status reporting when MdioDisable bit 0 is set");
++
++static int smsc9500_reset(struct usbnet *dev);
++static int smsc9500_get_stats(struct usbnet *dev, char *data);
++static int smsc9500_private_ioctl(PADAPTER_DATA privateData, struct usbnet *dev, PSMSC9500_IOCTL_DATA ioctlData);
++static int smsc9500_device_recovery(struct usbnet *dev);
++static int SetGpo(struct usbnet * dev,  u32 Gpo, u32 State);
++static int Smsc9500_suspend (struct usb_interface *intf, pm_message_t state);
++static int Smsc9500SystemSuspend (struct usb_interface *intf, pm_message_t state);
++static int Smsc9500AutoSuspend (struct usb_interface *intf, pm_message_t state);
++static int Smsc9500SystemResume(struct usb_interface *intf);
++static u16 CalculateCrc16(const BYTE * bpData,const u32 dwLen, const BOOLEAN fBitReverse);
++static int SetLinkDownWakeupEvents(struct usbnet *dev, int wakeUpMode);
++static int ResetLinkDownWakeupEvents(struct usbnet *dev);
++static int Smsc9500AutoResume(struct usb_interface *intf);
++static int EnablePHYWakeupInterrupt(struct usbnet *dev, u32 interrupt);
++static int DisablePHYWakeupInterrupt(struct usbnet *dev, u32 interrupt);
++static int smsc9500_eth_mac_addr(struct net_device *netdev, void *p);
++static int smsc9500_eth_phy_boost(struct usbnet *dev, int mode);
++#ifdef PME_EEPROMLESS
++static int EepromLessPMESetting(struct usbnet *dev);
++#endif
++
++static u32 LanRegMap[MAX_LAN_REG_NUM];
++static u32 MacRegMap[MAX_MAC_REG_NUM];
++static u32 PhyRegMap[MAX_PHY_REG_NUM];
++
++enum{
++    SMSC9500_FAIL = -1,
++    SMSC9500_SUCCESS = 0
++};
++
++static int smsc9500_read_reg(struct usbnet *dev,   u32 index, u32 *data)
++{
++	int ret = 0;
++	u32 *buf = NULL;
++	u16 retry_count = 0;
++
++	BUG_ON(!dev);
++
++	/* The heap buffer should be used for usb_control_msg, because the stack might not be DMA-mappable
++	   Control message is very slow so it really isn't big deal to dynamically allocate the data
++	*/
++	buf = kmalloc (sizeof(u32), GFP_KERNEL | GFP_DMA);
++	if(buf == NULL) {
++		return SMSC9500_FAIL;
++	}
++
++	do {
++		if (dev->disconnected) {
++			ret = -1;
++			break;
++		}
++			
++		ret = usb_control_msg(
++			dev->udev,
++			usb_rcvctrlpipe(dev->udev, 0),
++			USB_VENDOR_REQUEST_READ_REGISTER,
++			USB_DIR_IN | USB_TYPE_VENDOR | USB_RECIP_DEVICE,
++			00,
++			index,
++			(void*)buf,
++			sizeof(u32),
++			USB_CTRL_GET_TIMEOUT);
++	} while((ret < 0) && (retry_count++ < 3));
++
++	if (ret < 0) {
++		SMSC_WARNING("Failed to read register index 0x%08x\n", index);
++	} else {
++		le32_to_cpus(buf);
++		*data = *buf;
++	}
++	kfree(buf);
++	return ret;
++}
++
++static int smsc9500_write_reg(struct usbnet *dev,  u32 index, u32 data)
++{
++	int ret = 0;
++	u32* buf = NULL;
++	u16 retry_count = 0;
++
++	BUG_ON(!dev);
++
++	/* The heap buffer should be used for usb_control_msg, because the stack might not be DMA-mappable
++	   Control message is very slow so it really isn't big deal to dynamically allocate the data
++	*/
++	buf = kmalloc (sizeof(u32), GFP_KERNEL | GFP_DMA);
++	if(buf == NULL) {
++		return SMSC9500_FAIL;
++	}
++	*buf = data;
++
++	cpu_to_le32s(buf);
++
++	do{
++		if (dev->disconnected) {
++			ret = -1;
++			break;
++		}
++		ret = usb_control_msg(
++			dev->udev,
++			usb_sndctrlpipe(dev->udev, 0),
++			USB_VENDOR_REQUEST_WRITE_REGISTER,
++			USB_DIR_OUT | USB_TYPE_VENDOR | USB_RECIP_DEVICE,
++			00,
++			index,
++			buf,
++			sizeof(u32),
++			USB_CTRL_SET_TIMEOUT);
++	} while((ret < 0) && (retry_count++ < 3));
++
++	if (ret < 0) {
++		SMSC_WARNING("Failed to write register index 0x%08x\n", index);
++	}
++	kfree(buf);
++	return ret;
++}
++
++static int smsc9500_set_feature(struct usbnet *dev,  u32 feature)
++{
++	BUG_ON(!dev);
++
++	cpu_to_le32s((u32*)&feature);
++
++	return usb_control_msg(
++		dev->udev,
++		usb_sndctrlpipe(dev->udev, 0),
++		USB_REQ_SET_FEATURE,
++		USB_RECIP_DEVICE,
++		feature,
++		0,
++		NULL,
++		0,
++		USB_CTRL_SET_TIMEOUT);
++}
++
++static int smsc9500_clear_feature(struct usbnet *dev,  u32 feature)
++{
++	BUG_ON(!dev);
++
++	cpu_to_le32s((u32*)&feature);
++
++	return usb_control_msg(
++		dev->udev,
++		usb_sndctrlpipe(dev->udev, 0),
++		USB_REQ_CLEAR_FEATURE,
++		USB_RECIP_DEVICE,
++		feature,
++		0,
++		NULL,
++		0,
++		USB_CTRL_SET_TIMEOUT);
++}
++
++static int smsc9500_read_phy(struct usbnet *dev,  u32 Register, u32 *pValue32)
++{
++	int ret = SMSC9500_FAIL;
++	PADAPTER_DATA adapterData = (PADAPTER_DATA)(dev->data[0]);
++	u32 dwValue,dwAddr;
++	int Count;
++
++	BUG_ON(!dev);
++
++	if (MdioDisable & MDIO_DISABLE_INTERNAL_ACCESS) {
++		SMSC_WARNING ("smsc9500_read_phy: Phy (mdio) access disabled\n");
++		return ret;
++	}
++
++	if (down_interruptible(&adapterData->phy_mutex)) {
++		return -EINTR;
++	}
++
++	/* confirm MII not busy */
++	CHECK_RETURN_STATUS(smsc9500_read_reg(dev, MII_ADDR, &dwValue));
++
++	if ((dwValue & MII_BUSY_) != 0UL){
++		SMSC_WARNING("MII is busy in smsc9500_read_phy\n");
++		goto DONE;
++	}
++
++	/* set the address, index & direction (read from PHY) */
++	dwAddr = ((adapterData->dwPhyAddress & 0x1FUL) << 11) | ((Register & 0x1FUL) << 6)| MII_READ_ | MII_BUSY_;
++	CHECK_RETURN_STATUS(smsc9500_write_reg(dev, MII_ADDR, dwAddr));
++
++	/* Loop until the read is completed w/timeout */
++	for(Count = 1; Count < 100; Count++) {
++		CHECK_RETURN_STATUS(smsc9500_read_reg(dev, MII_ADDR, &dwValue));
++		if (!(dwValue & MII_BUSY_))
++			break;
++		udelay(1);
++	}
++
++	if (Count < 100) {
++		ret = smsc9500_read_reg(dev, MII_DATA, pValue32);
++	} else {
++		SMSC_WARNING("Timed out reading MII register %08X\n",Register & 0x1f);
++	}
++DONE:
++	up(&adapterData->phy_mutex);
++	return ret;
++} 
++
++static int smsc9500_read_phy_address(struct usbnet *dev,  u32 dwPhyAddress, u32 Register, u32 *pValue32)
++{
++	int ret = SMSC9500_FAIL;
++	PADAPTER_DATA adapterData = (PADAPTER_DATA)(dev->data[0]);
++	u32 dwValue,dwAddr;
++	int Count;
++
++	BUG_ON(!dev);
++
++	if (down_interruptible(&adapterData->phy_mutex)) {
++		return -EINTR;
++	}
++
++	/* confirm MII not busy */
++	CHECK_RETURN_STATUS(smsc9500_read_reg(dev, MII_ADDR, &dwValue));
++
++	if ((dwValue & MII_BUSY_) != 0UL) {
++		SMSC_WARNING("MII is busy in smsc9500_read_phy\n");
++		goto DONE;
++	}
++
++	/* set the address, index & direction (read from PHY) */
++	dwAddr = ((dwPhyAddress & 0x1FUL) << 11) | ((Register & 0x1FUL) << 6)| MII_READ_ | MII_BUSY_;
++	CHECK_RETURN_STATUS(smsc9500_write_reg(dev, MII_ADDR, dwAddr));
++
++	/* Loop until the read is completed w/timeout */
++	for(Count = 1; Count < 100; Count++) {
++		CHECK_RETURN_STATUS(smsc9500_read_reg(dev, MII_ADDR, &dwValue));
++		if (!(dwValue & MII_BUSY_))
++			break;
++		udelay(1);
++	}
++
++	if (Count < 100) {
++		ret = smsc9500_read_reg(dev, MII_DATA, pValue32);
++	} else {
++		SMSC_WARNING ("Timed out reading MII register %08X\n",Register & 0x1f);
++	}
++DONE:
++	up(&adapterData->phy_mutex);
++	return ret;
++}
++
++static int smsc9500_write_phy(struct usbnet *dev, u32 Register, u32 pValue32)
++{
++	int Count;
++	u32 dwValue,dwAddr;
++	int ret = SMSC9500_FAIL;
++	PADAPTER_DATA adapterData = (PADAPTER_DATA)(dev->data[0]);
++
++	BUG_ON(!dev);
++
++	if (MdioDisable & MDIO_DISABLE_INTERNAL_ACCESS) {
++		SMSC_WARNING ("smsc9500_write_phy: Phy (mdio) access disabled\n");
++		return ret;
++	}
++
++	if (down_interruptible(&adapterData->phy_mutex)) {
++		return -EINTR;
++	}
++
++	if (Register == 0) {
++		if (((LOWORD(pValue32))&0x1200)==0x1200) {
++			adapterData->wLastADVatRestart = adapterData->wLastADV;
++		}
++	}
++	if (Register == 4) {
++		adapterData->wLastADV = LOWORD(pValue32);
++	}
++
++	/* confirm MII not busy */
++	CHECK_RETURN_STATUS(smsc9500_read_reg(dev, MII_ADDR, &dwValue));
++
++	if ((dwValue & MII_BUSY_) != 0UL) {
++		SMSC_WARNING ("MII is busy in smsc9500_read_phy\n");
++		goto DONE;
++	}
++
++	CHECK_RETURN_STATUS(smsc9500_write_reg(dev, MII_DATA, pValue32));
++
++	/* set the address, index & direction (read from PHY) */
++	dwAddr = ((adapterData->dwPhyAddress & 0x1FUL) << 11) | ((Register & 0x1FUL) << 6)| MII_WRITE_ | MII_BUSY_;
++	CHECK_RETURN_STATUS(smsc9500_write_reg(dev, MII_ADDR, dwAddr));
++
++	/* Loop until the read is completed w/timeout */
++	for(Count = 1; Count < 100; Count++) {
++		CHECK_RETURN_STATUS(smsc9500_read_reg(dev, MII_ADDR, &dwValue));
++		if(!(dwValue & MII_BUSY_))
++			break;
++		udelay(1);
++	}
++
++	if (Count < 100) {
++		ret = 0;
++	} else {
++		SMSC_WARNING("Timed out writing MII register %08X\n",Register & 0x1f);
++	}
++DONE:
++	up(&adapterData->phy_mutex);
++	return ret;
++}
++
++static int smsc9500_write_phy_address(struct usbnet *dev, u32 dwPhyAddress, u32 Register, u32 pValue32)
++{
++	int Count;
++	u32 dwValue,dwAddr;
++	int ret = SMSC9500_FAIL;
++	PADAPTER_DATA adapterData = (PADAPTER_DATA)(dev->data[0]);
++
++	BUG_ON(!dev);
++
++	if (down_interruptible(&adapterData->phy_mutex)) {
++		return -EINTR;
++	}
++
++	if (Register == 0){
++		if (((LOWORD(pValue32)) & 0x1200) == 0x1200) {
++			adapterData->wLastADVatRestart = adapterData->wLastADV;
++		}
++	}
++	if (Register == 4) {
++		adapterData->wLastADV = LOWORD(pValue32);
++	}
++
++	/* confirm MII not busy */
++	CHECK_RETURN_STATUS(smsc9500_read_reg(dev, MII_ADDR, &dwValue));
++
++	if ((dwValue & MII_BUSY_) != 0UL) {
++		SMSC_WARNING ("MII is busy in smsc9500_read_phy\n");
++		goto DONE;
++	}
++
++	CHECK_RETURN_STATUS(smsc9500_write_reg(dev, MII_DATA, pValue32));
++
++	/* set the address, index & direction (read from PHY) */
++	dwAddr = ((dwPhyAddress & 0x1FUL) << 11) | ((Register & 0x1FUL) << 6)| MII_WRITE_ | MII_BUSY_;
++	CHECK_RETURN_STATUS(smsc9500_write_reg(dev, MII_ADDR, dwAddr));
++
++	/* Loop until the read is completed w/timeout */
++	for(Count = 1; Count <100; Count++) {
++		CHECK_RETURN_STATUS(smsc9500_read_reg(dev, MII_ADDR, &dwValue));
++		if (!(dwValue & MII_BUSY_))
++			break;
++		udelay(1);
++	}
++
++	if (Count < 100) {
++		ret = 0;
++	} else {
++		SMSC_WARNING("Timed out writing MII register %08X\n",Register & 0x1f);
++	}
++DONE:
++	up(&adapterData->phy_mutex);
++	return ret;
++}
++
++static int smsc9500_eeprom_IsBusy(struct usbnet *dev)
++{
++	int Count, retVal = 0;
++	u32 dwValue;
++
++	BUG_ON(!dev);
++
++	for(Count = 0; Count < 1000; Count++) {
++		if(smsc9500_read_reg(dev, E2P_CMD, &dwValue) < 0) {
++			return SMSC9500_FAIL;
++		}
++		if (!(dwValue & E2P_CMD_BUSY_) || (dwValue & E2P_CMD_TIMEOUT_)) {
++			break;
++		}
++		udelay(60);
++	}
++
++	if ((dwValue & E2P_CMD_TIMEOUT_) || (dwValue & E2P_CMD_BUSY_)) {
++		SMSC_WARNING("EEPROM read operation timeout");
++		retVal = SMSC9500_FAIL;
++	}
++
++	return retVal;
++}
++
++/* Read EEPROM data
++ */
++static int smsc9500_read_eeprom(struct usbnet *dev,  u32 dwOffset, u32 dwLength,  BYTE* pbValue)
++{
++	int i, ret = SMSC9500_FAIL;
++	u32 dwValue,dwAddr;
++	PADAPTER_DATA adapterData = (PADAPTER_DATA)(dev->data[0]);
++
++	BUG_ON(!dev);
++	BUG_ON(!pbValue);
++
++	if(down_interruptible(&adapterData->eeprom_mutex)) {
++		return -EINTR;
++	}
++
++	/* confirm eeprom not busy */
++	CHECK_RETURN_STATUS(smsc9500_eeprom_IsBusy(dev));
++
++	dwAddr = dwOffset;
++	for(i = 0; i < dwLength; i++) {
++		/* Isuue command */
++		dwValue = E2P_CMD_BUSY_ | E2P_CMD_READ_ | (dwAddr & E2P_CMD_ADDR_);
++		CHECK_RETURN_STATUS(smsc9500_write_reg(dev, E2P_CMD, dwValue));
++		CHECK_RETURN_STATUS(smsc9500_eeprom_IsBusy(dev));
++
++		/* Read data when ready */
++		CHECK_RETURN_STATUS(smsc9500_read_reg(dev, E2P_DATA, &dwValue));
++
++		pbValue[i] = dwValue & 0xFF;
++		dwAddr++;
++	}
++	ret = SMSC9500_SUCCESS;
++DONE:
++	up(&adapterData->eeprom_mutex);
++	return ret;
++
++}
++
++static int smsc9500_do_write_eeprom(struct usbnet *dev,  u32 dwOffset, u32 dwLength,  BYTE* pbValue)
++{
++	int i, ret = SMSC9500_FAIL;
++	u32 dwValue,dwAddr;
++	PADAPTER_DATA adapterData = (PADAPTER_DATA)(dev->data[0]);
++
++	BUG_ON(!dev);
++	BUG_ON(!pbValue);
++
++	if (down_interruptible(&adapterData->eeprom_mutex)) {
++		return -EINTR;
++	}
++
++	/* confirm eeprom not busy */
++	CHECK_RETURN_STATUS(smsc9500_eeprom_IsBusy(dev));
++
++	/* Iuuse write/erase enable command */
++	dwValue = E2P_CMD_BUSY_ | E2P_CMD_EWEN_;
++	CHECK_RETURN_STATUS(smsc9500_write_reg(dev, E2P_CMD, dwValue));
++	CHECK_RETURN_STATUS(smsc9500_eeprom_IsBusy(dev));
++
++	dwAddr = dwOffset;
++	for(i = 0; i < dwLength; i++) {
++		/* Fill data register */
++		dwValue = pbValue[i];
++		CHECK_RETURN_STATUS(smsc9500_write_reg(dev, E2P_DATA, dwValue));
++
++		/* Send "write"  command */
++		dwValue = E2P_CMD_BUSY_ | E2P_CMD_WRITE_ | (dwAddr & E2P_CMD_ADDR_);
++		CHECK_RETURN_STATUS(smsc9500_write_reg(dev, E2P_CMD, dwValue));
++		CHECK_RETURN_STATUS(smsc9500_eeprom_IsBusy(dev));
++		dwAddr++;
++	}
++	ret = SMSC9500_SUCCESS;
++DONE:
++	up(&adapterData->eeprom_mutex);
++	return ret;
++
++} 
++
++static int smsc9500_write_eeprom(struct usbnet *dev,  u32 dwOffset, u32 dwLength,  BYTE* pbValue)
++{
++	u32 dwValue;
++	int i, retries = 10;
++	
++	for (i = 0; i < retries; i++) {
++		if (smsc9500_do_write_eeprom(dev, dwOffset, dwLength, pbValue) == SMSC9500_SUCCESS)
++			return SMSC9500_SUCCESS;
++	}
++	mdelay(100);
++	if ((smsc9500_eeprom_IsBusy(dev) != 0) && (smsc9500_read_reg(dev,ID_REV, &dwValue)== 0))
++		set_bit (EVENT_DEV_RECOVERY, &dev->flags);
++	return SMSC9500_FAIL;
++}
++
++static int IsDataPortReady(struct usbnet *dev) 
++{
++	u32 dwValue;
++	int count = 0;
++	int ret = FALSE;
++
++	/* confirm data port is not busy */
++	for(count=0; count<100; count++){
++		CHECK_RETURN_STATUS(smsc9500_read_reg(dev, DP_SEL, &dwValue));
++		if (dwValue & DP_SEL_DPRDY) {
++			ret = TRUE;
++			break;
++		}
++		udelay(40);
++	}
++
++	if (ret == FALSE) {
++		SMSC_WARNING("Data port is busy ");
++	}
++DONE:
++	return ret;
++}
++
++/** Read data from internal RAM
++ */
++static int ReadDataPort(struct usbnet *dev, int ramSel, u32 startAddr, u32 length, u32 *valLow, u32 *valHigh)
++{
++	int i;
++	u32 dwValue;
++	int ret = SMSC9500_FAIL;
++	PADAPTER_DATA adapterData;
++
++	BUG_ON(!dev);
++	adapterData = (PADAPTER_DATA)(dev->data[0]);
++	BUG_ON(!adapterData);
++
++	if (down_interruptible(&adapterData->internal_ram_mutex)) {
++		return -EINTR;
++	}
++
++	/* confirm data port not busy */
++	if (!IsDataPortReady(dev))
++		goto DONE;
++
++	CHECK_RETURN_STATUS(smsc9500_read_reg(dev, DP_SEL, &dwValue));
++	dwValue &= ~DP_SEL_RSEL;
++	switch(ramSel) {
++		case RAMSEL_FCT:
++			dwValue |= DP_SEL_RSEL_FCT; break;
++		case RAMSEL_EEPROM:
++			dwValue |= DP_SEL_RSEL_EEPROM; break;
++		case RAMSEL_TXTLI:
++			dwValue |= DP_SEL_RSEL_TXTLI; break;
++		case RAMSEL_RXTLI:
++			dwValue |= DP_SEL_RSEL_RXTLI; break;
++	}
++	dwValue |= DP_SEL_TESTEN;
++	CHECK_RETURN_STATUS(smsc9500_write_reg(dev, DP_SEL, dwValue));
++
++	for(i = 0; i < length; i++) {
++		/* Set device ram address */
++		CHECK_RETURN_STATUS(smsc9500_write_reg(dev, DP_ADDR, startAddr + i));
++		/* Enable reading */
++		CHECK_RETURN_STATUS(smsc9500_write_reg(dev, DP_CMD, DP_CMD_READ));
++
++		if(!IsDataPortReady(dev))
++			goto DONE;
++
++		CHECK_RETURN_STATUS(smsc9500_read_reg(dev, DP_DATA0, valLow + i));
++		if (valHigh) {
++			CHECK_RETURN_STATUS(smsc9500_read_reg(dev, DP_DATA1, valHigh + i));
++		}
++	}
++
++	ret = SMSC9500_SUCCESS;
++DONE:
++	smsc9500_read_reg(dev, DP_SEL, &dwValue);
++	dwValue &= ~DP_SEL_TESTEN;
++	smsc9500_write_reg(dev, DP_SEL, dwValue);
++
++	up(&adapterData->internal_ram_mutex);
++	return ret;
++}
++
++/**
++ * smsc9500_is_zero_ether_addr - Determine if give Ethernet address is all zeros.
++ * @addr: Pointer to a six-byte array containing the Ethernet address
++ *
++ * Return true if the address is all zeroes.
++ */
++static int smsc9500_is_zero_ether_addr(const u8 *addr)
++{
++	return !(addr[0] | addr[1] | addr[2] | addr[3] | addr[4] | addr[5]);
++}
++
++/**
++ * smsc9500_is_multicast_ether_addr - Determine if the Ethernet address is a multicast.
++ * @addr: Pointer to a six-byte array containing the Ethernet address
++ *
++ * Return true if the address is a multicast address.
++ * By definition the broadcast address is also a multicast address.
++ */
++static int smsc9500_is_multicast_ether_addr(const u8 *addr)
++{
++	return (0x01 & addr[0]);
++}
++
++/**
++ * smsc9500_is_valid_ether_addr - Determine if the given Ethernet address is valid
++ * @addr: Pointer to a six-byte array containing the Ethernet address
++ *
++ * Check that the Ethernet address (MAC) is not 00:00:00:00:00:00, is not
++ * a multicast address, and is not FF:FF:FF:FF:FF:FF.
++ *
++ * Return true if the address is valid.
++ */
++
++static int smsc9500_is_valid_ether_addr(const u8 *addr)
++{
++	/* FF:FF:FF:FF:FF:FF is a multicast address so we don't need to
++	 * explicitly check for it here. */
++	return !smsc9500_is_multicast_ether_addr(addr) && !smsc9500_is_zero_ether_addr(addr);
++}
++
++static void smsc9500_status(struct usbnet *dev, struct urb *urb)
++{
++	int hasFrame;
++	struct smsc9500_int_data *event;
++
++	BUG_ON(!dev);
++	BUG_ON(!urb);
++
++	SMSC_TRACE(DBG_INTR, "smsc9500_status");
++
++	if (urb->actual_length < 4) {
++		SMSC_WARNING("urb->actual_length = %d", urb->actual_length);
++		return;
++	}
++	event = urb->transfer_buffer;
++
++	le32_to_cpus((u32*)&event->IntEndPoint);
++
++	SMSC_TRACE(DBG_INTR, "event->IntEndPoint = 0x%08x", event->IntEndPoint);
++	hasFrame = event->IntEndPoint &INT_END_RXFIFO_HAS_FRAME_;
++
++	if (hasFrame) {
++		dev->StopSummitUrb=0;
++		tasklet_schedule (&dev->bh);
++	}
++}
++
++
++static int smsc9500_get_stats(struct usbnet *dev, char *data)
++{
++	void* buf;
++	int ret = 0;
++	u16 retry_count = 0;
++	u16 RxStatSize = 0;
++	u16 TxStatSize = 0;
++
++	BUG_ON(!dev);
++	BUG_ON(!data);
++
++	SMSC_TRACE(DBG_RX, "smsc9500_get_stats");
++
++	buf = kmalloc (sizeof(SMSC9500_RX_STATS) + sizeof(SMSC9500_TX_STATS), GFP_KERNEL | GFP_DMA);
++	if (buf == NULL) {
++		return SMSC9500_FAIL;
++	}
++
++	if (dev->chipDependFeatures[FEATURE_EEE]) {
++		RxStatSize = sizeof(SMSC9500_RX_STATS);	
++		TxStatSize = sizeof(SMSC9500_TX_STATS);	
++	}else{
++		/* 20h for RX statistics. 28h for TX statistics */
++		RxStatSize = sizeof(SMSC9500_RX_STATS) - 8;	
++		TxStatSize = sizeof(SMSC9500_TX_STATS) - 8;	
++	}
++
++	do {
++		ret = usb_control_msg(
++			dev->udev,
++			usb_rcvctrlpipe(dev->udev, 0),
++			USB_VENDOR_REQUEST_GET_STATS,
++			USB_DIR_IN | USB_TYPE_VENDOR | USB_RECIP_DEVICE,
++			00,
++			0,
++			buf,
++			RxStatSize,
++			USB_CTRL_SET_TIMEOUT);
++	} while((ret < 0) && (retry_count++ < 3));
++
++	if (ret < 0) {
++		SMSC_WARNING("Failed to get Rx status\n");
++		goto Done;
++	}
++
++	retry_count = 0;
++
++	 do {
++		ret = usb_control_msg(
++			dev->udev,
++			usb_rcvctrlpipe(dev->udev, 0),
++			USB_VENDOR_REQUEST_GET_STATS,
++			USB_DIR_IN | USB_TYPE_VENDOR | USB_RECIP_DEVICE,
++			00,
++			1,
++			buf+sizeof(SMSC9500_RX_STATS),
++			TxStatSize,
++			USB_CTRL_SET_TIMEOUT);
++	} while((ret < 0) && (retry_count++ < 3));
++
++	if (ret < 0) {
++		SMSC_WARNING("Failed to get Tx status\n");
++	} else {
++		memcpy(data,  buf, (sizeof(SMSC9500_TX_STATS)+sizeof(SMSC9500_RX_STATS)));
++	}
++Done:
++	kfree(buf);
++	return ret;
++}
++
++void UpdateStatCounters(struct usbnet *dev,  char * pStats)
++{
++	int i = 0;
++	u32 * pValue32 = (u32 *)pStats;
++    	pSMSC9500_RX_STATS   pRxStats;
++    	pSMSC9500_TX_STATS   pTxStats;
++	PADAPTER_DATA pAdapter = (PADAPTER_DATA)(dev->data[0]);
++    
++	for (i = 0; i < ((sizeof(SMSC9500_RX_STATS) + sizeof(SMSC9500_RX_STATS)) / 4); i++) {
++   		le32_to_cpus((u32*)&pValue32[i]);
++		if ((i != 0)|| (i != 8) || (i != 9) || (i != 10) || (i != 20) || (i != 21))
++			pValue32[i] &= 0xFFFFF; //This counter has 20 bits.
++   	}
++
++	pRxStats = (pSMSC9500_RX_STATS) pStats;
++	pTxStats = (pSMSC9500_TX_STATS) (pStats + sizeof(SMSC9500_RX_STATS));
++	
++	if (dev->chipDependFeatures[FEATURE_NEWSTATIS_CNT]) {
++		// Good Tx (32Bit Counter)       
++		if (pTxStats->TxGoodFrames >= pAdapter->tx_statistics.TxGoodFrames)
++		    pAdapter->TxGoodFrames += (u64)(pTxStats->TxGoodFrames - pAdapter->tx_statistics.TxGoodFrames);
++		else
++		    pAdapter->TxGoodFrames += (u64)(pTxStats->TxGoodFrames + (0xFFFFFFFFUL - pAdapter->tx_statistics.TxGoodFrames) + 1UL);
++
++		pAdapter->tx_statistics.TxGoodFrames = pTxStats->TxGoodFrames;
++
++		// Tx Excess Collisions (20Bit Counter)       
++		if (pTxStats->TxExcessiveCollisionErrors >= pAdapter->tx_statistics.TxExcessiveCollisionErrors)
++		    pAdapter->TxExcessiveCollisionErrors += (pTxStats->TxExcessiveCollisionErrors - pAdapter->tx_statistics.TxExcessiveCollisionErrors);
++		else
++		    pAdapter->TxExcessiveCollisionErrors += (pTxStats->TxExcessiveCollisionErrors + (0xFFFFFUL - pAdapter->tx_statistics.TxExcessiveCollisionErrors) + 1UL);
++
++		pAdapter->tx_statistics.TxExcessiveCollisionErrors = pTxStats->TxExcessiveCollisionErrors;
++
++		// Tx Late Collisions (20Bit Counter)        
++		if (pTxStats->TxLateCollisionErrors >= pAdapter->tx_statistics.TxLateCollisionErrors)
++			pAdapter->TxLateCollisionErrors += (pTxStats->TxLateCollisionErrors - pAdapter->tx_statistics.TxLateCollisionErrors);
++		else
++		    pAdapter->TxLateCollisionErrors += (pTxStats->TxLateCollisionErrors + (0xFFFFFUL - pAdapter->tx_statistics.TxLateCollisionErrors) + 1UL);
++
++		pAdapter->tx_statistics.TxLateCollisionErrors = pTxStats->TxLateCollisionErrors;
++
++		// Tx Underrun (20Bit Counter)       
++		if (pTxStats->TxBufferUnderrunErrors >= pAdapter->tx_statistics.TxBufferUnderrunErrors)
++			pAdapter->TxBufferUnderrunErrors += (pTxStats->TxBufferUnderrunErrors - pAdapter->tx_statistics.TxBufferUnderrunErrors);
++		else
++			pAdapter->TxBufferUnderrunErrors += (pTxStats->TxBufferUnderrunErrors + (0xFFFFFUL - pAdapter->tx_statistics.TxBufferUnderrunErrors) + 1UL);
++
++		pAdapter->tx_statistics.TxBufferUnderrunErrors = pTxStats->TxBufferUnderrunErrors;
++
++		// Tx Carrier Errors (20Bit Counter)        
++		if (pTxStats->TxCarrierErrors >= pAdapter->tx_statistics.TxCarrierErrors)
++			pAdapter->TxCarrierErrors += (pTxStats->TxCarrierErrors - pAdapter->tx_statistics.TxCarrierErrors);
++		else
++			pAdapter->TxCarrierErrors += (pTxStats->TxCarrierErrors + (0xFFFFFUL - pAdapter->tx_statistics.TxCarrierErrors) + 1UL);
++
++		pAdapter->tx_statistics.TxCarrierErrors = pTxStats->TxCarrierErrors;
++
++		// Tx Single Collision (20Bit Counter)       
++		if (pTxStats->TxSingleCollisions >= pAdapter->tx_statistics.TxSingleCollisions)
++			pAdapter->TxSingleCollisions += (pTxStats->TxSingleCollisions - pAdapter->tx_statistics.TxSingleCollisions);
++		else
++			pAdapter->TxSingleCollisions += (pTxStats->TxSingleCollisions + (0xFFFFFUL - pAdapter->tx_statistics.TxSingleCollisions) + 1UL);
++
++		pAdapter->tx_statistics.TxSingleCollisions = pTxStats->TxSingleCollisions;
++
++		// Tx Multiple Collision (20Bit Counter)        
++		if (pTxStats->TxMultipleCollisions >= pAdapter->tx_statistics.TxMultipleCollisions)
++			pAdapter->TxMultipleCollisions += (pTxStats->TxMultipleCollisions - pAdapter->tx_statistics.TxMultipleCollisions);
++		else
++			pAdapter->TxMultipleCollisions += (pTxStats->TxMultipleCollisions + (0xFFFFFUL - pAdapter->tx_statistics.TxMultipleCollisions) + 1UL);
++
++		pAdapter->tx_statistics.TxMultipleCollisions = pTxStats->TxMultipleCollisions;
++
++		// Tx Excessive Deferral (20Bit Counter)       
++		if (pTxStats->TxExcessiveDeferralErrors >= pAdapter->tx_statistics.TxExcessiveDeferralErrors)
++			pAdapter->TxExcessiveDeferralErrors += (pTxStats->TxExcessiveDeferralErrors - pAdapter->tx_statistics.TxExcessiveDeferralErrors);
++		else
++			pAdapter->TxExcessiveDeferralErrors += (pTxStats->TxExcessiveDeferralErrors + (0xFFFFFUL - pAdapter->tx_statistics.TxExcessiveDeferralErrors) + 1UL);
++
++		pAdapter->tx_statistics.TxExcessiveDeferralErrors = pTxStats->TxExcessiveDeferralErrors;
++
++		// Tx Pause (20Bit Counter)       
++		if (pTxStats->TxPauseFrames >= pAdapter->tx_statistics.TxPauseFrames)
++			pAdapter->TxPauseFrames += (pTxStats->TxPauseFrames - pAdapter->tx_statistics.TxPauseFrames);
++		else
++			pAdapter->TxPauseFrames += (pTxStats->TxPauseFrames + (0xFFFFFUL - pAdapter->tx_statistics.TxPauseFrames) + 1UL);
++
++		pAdapter->tx_statistics.TxPauseFrames = pTxStats->TxPauseFrames;
++
++		// Tx Bad (20Bit Counter)       
++		if (pTxStats->TxBadFrames >= pAdapter->tx_statistics.TxBadFrames)
++			pAdapter->TxBadFrames += (pTxStats->TxBadFrames - pAdapter->tx_statistics.TxBadFrames);
++		else
++			pAdapter->TxBadFrames += (pTxStats->TxBadFrames + (0xFFFFFUL - pAdapter->tx_statistics.TxBadFrames) + 1UL);
++
++		pAdapter->tx_statistics.TxPauseFrames = pTxStats->TxPauseFrames;
++
++		// Good Rx (32Bit Counter)       
++		if (pRxStats->RxGoodFrames >= pAdapter->rx_statistics.RxGoodFrames)
++			pAdapter->RxGoodFrames += (u64)(pRxStats->RxGoodFrames - pAdapter->rx_statistics.RxGoodFrames);
++		else
++			pAdapter->RxGoodFrames += (u64)(pRxStats->RxGoodFrames + (0xFFFFFFFFUL - pAdapter->rx_statistics.RxGoodFrames) + 1UL);
++
++		pAdapter->rx_statistics.RxGoodFrames = pRxStats->RxGoodFrames;
++
++		// Rx Crc (20Bit Counter)        
++		if (pRxStats->RxCrcErrors >= pAdapter->rx_statistics.RxCrcErrors)  
++			pAdapter->RxCrcErrors += (pRxStats->RxCrcErrors - pAdapter->rx_statistics.RxCrcErrors);
++		else
++			pAdapter->RxCrcErrors += (pRxStats->RxCrcErrors + (0xFFFFFUL - pAdapter->rx_statistics.RxCrcErrors) + 1UL);
++
++		pAdapter->rx_statistics.RxCrcErrors = pRxStats->RxCrcErrors;
++
++		// Rx Alignment (20Bit Counter)        
++		if (pRxStats->RxAlignmentErrors >= pAdapter->rx_statistics.RxAlignmentErrors)
++			pAdapter->RxAlignmentErrors += (pRxStats->RxAlignmentErrors - pAdapter->rx_statistics.RxAlignmentErrors);
++		else
++			pAdapter->RxAlignmentErrors += (pRxStats->RxAlignmentErrors + (0xFFFFFUL - pAdapter->rx_statistics.RxAlignmentErrors) + 1UL);
++
++		pAdapter->rx_statistics.RxAlignmentErrors = pRxStats->RxAlignmentErrors;
++
++		// Rx Resources (20Bit Counter)     
++		if (pRxStats->RxFifoDroppedFrames >= pAdapter->rx_statistics.RxFifoDroppedFrames)
++			pAdapter->RxFifoDroppedFrames += (pRxStats->RxFifoDroppedFrames - pAdapter->rx_statistics.RxFifoDroppedFrames);
++		else
++			pAdapter->RxFifoDroppedFrames += (pRxStats->RxFifoDroppedFrames + (0xFFFFFUL - pAdapter->rx_statistics.RxFifoDroppedFrames) + 1UL);
++
++		pAdapter->rx_statistics.RxFifoDroppedFrames = pRxStats->RxFifoDroppedFrames;
++
++		// Rx Runts (20Bit Counter)       
++		if (pRxStats->RxRuntFrameErrors >= pAdapter->rx_statistics.RxRuntFrameErrors)
++			pAdapter->RxRuntFrameErrors += (pRxStats->RxRuntFrameErrors - pAdapter->rx_statistics.RxRuntFrameErrors);
++		else
++			pAdapter->RxRuntFrameErrors += (pRxStats->RxRuntFrameErrors + (0xFFFFFUL - pAdapter->rx_statistics.RxRuntFrameErrors) + 1UL);
++
++		pAdapter->rx_statistics.RxRuntFrameErrors = pRxStats->RxRuntFrameErrors;
++
++		// Rx TooLong (20Bit Counter)       
++		if (pRxStats->RxFrameTooLongError >= pAdapter->rx_statistics.RxFrameTooLongError)
++			pAdapter->RxFrameTooLongError += (pRxStats->RxFrameTooLongError - pAdapter->rx_statistics.RxFrameTooLongError);
++		else
++			pAdapter->RxFrameTooLongError += (pRxStats->RxFrameTooLongError + (0xFFFFFUL - pAdapter->rx_statistics.RxFrameTooLongError) + 1UL);
++
++		pAdapter->rx_statistics.RxFrameTooLongError = pRxStats->RxFrameTooLongError;
++
++		// Rx Late Collisions (20Bit Counter)
++		if (pRxStats->RxLaterCollisionError >= pAdapter->rx_statistics.RxLaterCollisionError)
++			pAdapter->RxLaterCollisionError += (pRxStats->RxLaterCollisionError - pAdapter->rx_statistics.RxLaterCollisionError);
++		else
++			pAdapter->RxLaterCollisionError += (pRxStats->RxLaterCollisionError + (0xFFFFFUL - pAdapter->rx_statistics.RxLaterCollisionError) + 1UL);
++
++		pAdapter->rx_statistics.RxLaterCollisionError = pRxStats->RxLaterCollisionError;
++
++		// Rx Bad (20Bit Counter)
++		if (pRxStats->RxBadFrames >= pAdapter->rx_statistics.RxBadFrames)
++			pAdapter->RxBadFrames += (pRxStats->RxBadFrames - pAdapter->rx_statistics.RxBadFrames);
++		else
++			pAdapter->RxBadFrames += (pRxStats->RxBadFrames + (0xFFFFFUL - pAdapter->rx_statistics.RxBadFrames) + 1UL);
++
++		pAdapter->rx_statistics.RxBadFrames = pRxStats->RxBadFrames;
++
++		if (dev->chipDependFeatures[FEATURE_EEE]) {
++			// EEE Tx LPI Transitions (32 bit)
++			if (pTxStats->EeeTxLpiTransitions >= pAdapter->tx_statistics.EeeTxLpiTransitions) {
++			    pAdapter->EeeTxLpiTransitions +=
++				(u64)(pTxStats->EeeTxLpiTransitions - pAdapter->tx_statistics.EeeTxLpiTransitions);
++			} else {
++			    pAdapter->EeeTxLpiTransitions +=
++				(u64)(pTxStats->EeeTxLpiTransitions + (0xFFFFFFFFUL - pAdapter->tx_statistics.EeeTxLpiTransitions) + 1UL);
++			}
++
++			// EEE Tx LPI Time (32 bit)
++			if (pTxStats->EeeTxLpiTime >= pAdapter->tx_statistics.EeeTxLpiTime) {
++			    pAdapter->EeeTxLpiTime +=
++				(u64)(pTxStats->EeeTxLpiTime - pAdapter->tx_statistics.EeeTxLpiTime);
++			} else {
++			    pAdapter->EeeTxLpiTime +=
++				(u64)(pTxStats->EeeTxLpiTime + (0xFFFFFFFFUL - pAdapter->tx_statistics.EeeTxLpiTime) + 1UL);
++			}
++
++			//EEE Rx LPI Transitions (32 bit)
++			if (pRxStats->EeeRxLpiTransitions >= pAdapter->rx_statistics.EeeRxLpiTransitions) {
++			    pAdapter->EeeRxLpiTransitions +=
++				(u64)(pRxStats->EeeRxLpiTransitions - pAdapter->rx_statistics.EeeRxLpiTransitions);
++			} else {
++			    pAdapter->EeeRxLpiTransitions +=
++				(u64)(pRxStats->EeeRxLpiTransitions + (0xFFFFFFFFUL - pAdapter->rx_statistics.EeeRxLpiTransitions) + 1UL);
++			}
++
++			//EEE Rx LPI Time (32 bit)
++			if (pRxStats->EeeRxLpiTime >= pAdapter->rx_statistics.EeeRxLpiTime) {
++			    pAdapter->EeeRxLpiTime += (u64)(pRxStats->EeeRxLpiTime - pAdapter->rx_statistics.EeeRxLpiTime);
++			} else {
++			    pAdapter->EeeRxLpiTime +=
++				(u64)(pRxStats->EeeRxLpiTime + (0xFFFFFFFFUL - pAdapter->rx_statistics.EeeRxLpiTime) + 1UL);
++			}
++		}
++	} else {
++		// Good Tx (32Bit Counter)
++		pAdapter->TxGoodFrames += (u64)pTxStats->TxGoodFrames;
++
++		// Tx Excess Collisions (20Bit Counter)
++		pAdapter->TxExcessiveCollisionErrors += pTxStats->TxExcessiveCollisionErrors;
++
++		// Tx Late Collisions (20Bit Counter)
++		pAdapter->TxLateCollisionErrors += pTxStats->TxLateCollisionErrors;
++
++		// Tx Underrun (20Bit Counter)
++		pAdapter->TxBufferUnderrunErrors += pTxStats->TxBufferUnderrunErrors;
++
++		// Tx Carrier Errors (20Bit Counter)
++		pAdapter->TxCarrierErrors += pTxStats->TxCarrierErrors;
++
++		// Tx Single Collision (20Bit Counter)
++		pAdapter->TxSingleCollisions += pTxStats->TxSingleCollisions;
++
++		// Tx Multiple Collision (20Bit Counter)
++		pAdapter->TxMultipleCollisions += pTxStats->TxMultipleCollisions;
++
++		// Tx Excessive Deferral (20Bit Counter)
++		pAdapter->TxExcessiveDeferralErrors += pTxStats->TxExcessiveDeferralErrors;
++
++		// Tx Pause (20Bit Counter)
++		pAdapter->TxPauseFrames += pTxStats->TxPauseFrames;
++
++		// Tx Bad (20Bit Counter)
++		pAdapter->TxBadFrames += pTxStats->TxBadFrames;
++
++		// Good Rx (32Bit Counter)
++		pAdapter->RxGoodFrames += (u64)pRxStats->RxGoodFrames;
++
++		// Rx Crc (20Bit Counter)
++		pAdapter->RxCrcErrors += pRxStats->RxCrcErrors;
++
++		// Rx Alignment (20Bit Counter)
++		pAdapter->RxAlignmentErrors += pRxStats->RxAlignmentErrors;
++
++		// Rx Resources (20Bit Counter)
++		pAdapter->RxFifoDroppedFrames += pRxStats->RxFifoDroppedFrames;
++
++		// Rx Runts (20Bit Counter)
++		pAdapter->RxRuntFrameErrors += pRxStats->RxRuntFrameErrors;
++
++		// Rx TooLong (20Bit Counter)
++		pAdapter->RxFrameTooLongError += pRxStats->RxFrameTooLongError;
++
++		// Rx Late Collisions (20Bit Counter)
++		pAdapter->RxLaterCollisionError += pRxStats->RxLaterCollisionError;
++
++		// Rx Bad (20Bit Counter)
++		pAdapter->RxBadFrames += pRxStats->RxBadFrames;
++	}
++}
++
++
++static void smsc9500_async_cmd_callback(struct urb *urb, struct pt_regs *regs)
++{
++	struct USB_CONTEXT *usb_context = (struct USB_CONTEXT *)urb->context;
++
++	if (urb->status < 0)
++		SMSC_WARNING("smsc9500_async_cmd_callback() failed with %d\n",urb->status);
++
++	complete((struct completion *)&usb_context->notify);
++
++	kfree(&usb_context->req);
++	usb_free_urb(urb);
++}
++
++static int
++smsc9500_read_reg_async(struct usbnet *dev,   u32 index, void *data, int wait)
++{
++	int status;
++	u32 size = 4;
++	struct urb *urb;
++	int ret = ASYNC_RW_SUCCESS;
++	struct USB_CONTEXT *usb_context;
++#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,11))
++	int expire;
++#endif
++
++	BUG_ON(!dev);
++	BUG_ON(!data);
++
++	if ((urb = usb_alloc_urb(0, GFP_ATOMIC)) == NULL) {
++		SMSC_WARNING("Error allocating URB in write_cmd_async!");
++		return ASYNC_RW_FAIL;
++	}
++
++	if ((usb_context = kmalloc(sizeof(struct USB_CONTEXT), GFP_ATOMIC)) == NULL) {
++		SMSC_WARNING("Failed to allocate memory for control request");
++		usb_free_urb(urb);
++		return ASYNC_RW_FAIL;
++	}
++
++	usb_context->req.bRequestType = USB_DIR_IN | USB_TYPE_VENDOR | USB_RECIP_DEVICE;
++	usb_context->req.bRequest = USB_VENDOR_REQUEST_READ_REGISTER;
++	usb_context->req.wValue = 00;
++	usb_context->req.wIndex = cpu_to_le32(index);
++	usb_context->req.wLength = cpu_to_le32(size);
++	init_completion(&usb_context->notify);
++
++	usb_fill_control_urb(urb, dev->udev,
++			     usb_rcvctrlpipe(dev->udev, 0),
++			     (void *)&usb_context->req, data, size,
++			     (usb_complete_t)smsc9500_async_cmd_callback, (void*)usb_context);
++
++	if ((status = usb_submit_urb(urb, GFP_ATOMIC)) < 0) {
++		SMSC_WARNING( "Error submitting the control message: status=%d", status);
++		kfree(usb_context);
++		usb_free_urb(urb);
++		return ASYNC_RW_FAIL;
++	}
++
++	if (wait) {
++	/* wait_for_completion_timeout only implemented in 2.6.11 and higher kernel version */
++#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,11))
++	    expire = msecs_to_jiffies(USB_CTRL_SET_TIMEOUT);
++	    if (!wait_for_completion_timeout(&usb_context->notify, expire)) {
++	  		ret = ASYNC_RW_TIMEOUT;
++	  		SMSC_TRACE(DBG_WARNING, "urb timeout");
++	  		kfree(usb_context);
++			usb_free_urb(urb);
++			return ASYNC_RW_FAIL;
++	    }
++#endif
++	}
++	return ret;
++}
++
++#if (LINUX_VERSION_CODE < KERNEL_VERSION(2,6,22))
++extern void *page_address(struct page *);
++static void CalculateTxChecksumOffset( struct sk_buff *skb, int *csum_start_offset)
++{
++	int i;
++	u32 offset;
++	unsigned int skbFragCnt;
++
++	skbFragCnt = skb_shinfo(skb)->nr_frags + 1;
++
++	/* Initialize csum offset locations as if it was single frag */
++#if (LINUX_VERSION_CODE < KERNEL_VERSION(2,6,22))
++	SMSC_ASSERT(skb->h.raw);
++#else
++	/* Should never happen for a CHECKSUM_HW packet */
++	SMSC_ASSERT(skb->transport_header);
++#endif
++
++#if (LINUX_VERSION_CODE < KERNEL_VERSION(2,6,22))
++	*csum_start_offset = skb->h.raw - skb->data;
++#else
++	*csum_start_offset = (unsigned long)skb->transport_header - (unsigned long)skb->data;
++#endif
++
++	offset = (skbFragCnt == 1) ? skb->len : (skb->len - skb->data_len);
++
++	/* Process all fragments */
++	for(i = 0; i < (skbFragCnt-1); i++) {
++		skb_frag_t *frag = &skb_shinfo(skb)->frags[i];
++		unsigned char *frag_addr = (unsigned char *) page_address(frag->page) + frag->page_offset;
++
++		/* Find if transport header start belongs to this fragment
++		and if so calculate offset from start of packet */
++#if (LINUX_VERSION_CODE < KERNEL_VERSION(2,6,22))
++		if((frag_addr <= skb->h.raw) && ((frag_addr + frag->size) >=skb->h.raw)) {
++			*csum_start_offset = offset + ((u32)skb->h.raw) - ((u32)frag_addr);
++		}
++#else
++		if((frag_addr <= (unsigned char *)((unsigned long)skb->transport_header)) &&
++			((frag_addr + frag->size) >= (unsigned char *)((unsigned long)skb->transport_header))) {
++			*csum_start_offset = offset + ((unsigned long)skb->transport_header) - ((unsigned long)frag_addr);
++		}
++#endif
++
++		SMSC_ASSERT((offset + frag->size) <= skb->len);
++
++		offset += frag->size;
++	}
++
++}
++#endif
++
++static void Tx_StopQueue(
++	struct usbnet *dev,u32 dwSource)
++{
++	unsigned long intFlags = 0;
++	PADAPTER_DATA adapterData = (PADAPTER_DATA)(dev->data[0]);
++
++	spin_lock_irqsave(&(adapterData->TxQueueLock), intFlags);
++	if(adapterData->dwTxQueueDisableMask == 0) {
++		netif_stop_queue(dev->net);
++	}
++	adapterData->dwTxQueueDisableMask |= dwSource;
++	spin_unlock_irqrestore(&(adapterData->TxQueueLock), intFlags);
++}
++
++static void Tx_WakeQueue(
++	struct usbnet *dev,u32 dwSource)
++{
++	unsigned long intFlags = 0;
++	PADAPTER_DATA adapterData = (PADAPTER_DATA)(dev->data[0]);
++
++	spin_lock_irqsave(&(adapterData->TxQueueLock), intFlags);
++	adapterData->dwTxQueueDisableMask&=(~dwSource);
++	if(adapterData->dwTxQueueDisableMask == 0) {
++		netif_wake_queue(dev->net);
++	}
++	spin_unlock_irqrestore(&(adapterData->TxQueueLock), intFlags);
++}
++
++
++int NICStartRxPath(struct usbnet *dev)
++{ 
++	u32 Value32;
++	int Status = -1;   
++
++	/* Enable the receiver at the Mac */
++	CHECK_RETURN_STATUS(smsc9500_read_reg(dev, MAC_CR, &Value32));
++	Value32 |= MAC_CR_RXEN_;
++	CHECK_RETURN_STATUS(smsc9500_write_reg(dev, MAC_CR, Value32));
++	Status = 0;
++DONE:
++	return (Status);
++}
++
++
++
++int NICStopRxPath(struct usbnet *dev)
++{ 
++	int Status = -1;
++	u32 Value32, dwValue, Count = 0;
++
++	/* Clr the Rx Stop bit if not already */
++	dwValue = INT_STS_RX_STOP_;
++	CHECK_RETURN_STATUS(smsc9500_write_reg(dev, INT_STS, dwValue));
++
++	/* Disable the receiver at the Mac */
++	CHECK_RETURN_STATUS(smsc9500_read_reg(dev, MAC_CR, &Value32));
++	Value32 &= (~MAC_CR_RXEN_);
++	CHECK_RETURN_STATUS(smsc9500_write_reg(dev, MAC_CR, Value32));
++
++
++	// The Rx Stop bit should assert as soon as the packet "in flight" makes 
++	// it into the Mac, worst case is 10 Mbps HD. This will be ~2ms tops
++	// Assuming one register read per (micro)frame the case of high speed USB 
++	// - 125us register read cycle time - is the worse and would need up to 
++	// 16 reads. Let's just round up to 20.
++	do {
++		CHECK_RETURN_STATUS(smsc9500_read_reg(dev, INT_STS, &Value32));
++		// Let it try to do the 20 reads even if the reg reads are failing
++		// If the previous write did go thru at least this way we have a better 
++		// chance of making sure the receiver did stop.
++	} while ((++Count<20) && ((Value32 & INT_STS_RX_STOP_) == 0));
++
++DONE:
++	return (Status);
++}
++
++int NICStopAndFlushRxPath(struct usbnet *dev)
++{ 
++	int Status = -1;
++	u32 Value32, dwValue;
++
++	Status = NICStopRxPath(dev);
++
++	dwValue = RX_FIFO_FLUSH_;
++	CHECK_RETURN_STATUS(smsc9500_write_reg(dev, RX_CFG, dwValue));
++
++	/* Should self clear way before the read */
++	CHECK_RETURN_STATUS(smsc9500_read_reg(dev, RX_CFG, &Value32));
++
++	if (Value32 & RX_FIFO_FLUSH_) {
++		// Flush did not self clear!
++		Status = -1;
++	} else {
++		Status = 0;
++	}
++DONE:
++	return (Status);
++}
++
++
++/* Returns hash bit number for given MAC address
++example:
++	01 00 5E 00 00 01 -> returns bit number 31
++*/
++static u32 Rx_Hash(BYTE addr[6])
++{
++	int i;
++	u32 result = 0;
++	u32 crc = 0xFFFFFFFFUL;
++	u32 poly = 0xEDB88320UL;
++	for(i = 0; i < 6; i++) {
++		int bit;
++		u32 data = ((u32)addr[i]);
++		for(bit=0;bit<8;bit++) {
++			u32 p = (crc^((u32)data))&1UL;
++			crc >>= 1;
++			if(p != 0) crc ^= poly;
++			data >>= 1;
++		}
++	}
++	result=((crc&0x01UL)<<5)|
++		((crc&0x02UL)<<3)|
++		((crc&0x04UL)<<1)|
++		((crc&0x08UL)>>1)|
++		((crc&0x10UL)>>3)|
++		((crc&0x20UL)>>5);
++	return result;
++}
++
++static int smsc9500_rx_setmulticastlist(struct usbnet *dev)
++{
++	u32 ret = SMSC9500_FAIL;
++	u32 local_MACCR, dwHashHi,dwHashLo;
++
++	PADAPTER_DATA adapterData = (PADAPTER_DATA)(dev->data[0]);
++
++	if ((dev->suspendFlag) || (dev->netDetachDone)) {
++		return 0;
++	}
++
++	if (down_interruptible(&adapterData->RxFilterLock)) {
++		return -EINTR;
++	}
++
++	SMSC_TRACE(DBG_MCAST, "smsc9500_set_multicast");
++
++    	if (dev->net->flags & IFF_PROMISC) {
++		SMSC_TRACE(DBG_MCAST, "Promiscuous Mode Enabled");
++		adapterData->set_bits_mask = MAC_CR_PRMS_;
++		adapterData->clear_bits_mask = (MAC_CR_MCPAS_ | MAC_CR_HPFILT_);
++
++		adapterData->HashHi = 0UL;
++		adapterData->HashLo = 0UL;
++		goto PREPARE;
++	}
++
++	if (dev->net->flags & IFF_ALLMULTI) {
++		SMSC_TRACE(DBG_MCAST, "Receive all Multicast Enabled");
++		adapterData->set_bits_mask = MAC_CR_MCPAS_;
++		adapterData->clear_bits_mask = (MAC_CR_PRMS_ | MAC_CR_HPFILT_);
++
++		adapterData->HashHi = 0UL;
++		adapterData->HashLo = 0UL;
++		goto PREPARE;
++	}
++
++
++#if (LINUX_VERSION_CODE < KERNEL_VERSION(2,6,35))
++	if (dev->net->mc_count > 0) {
++		u32 dwHashH = 0;
++		u32 dwHashL = 0;
++		u32 dwCount = 0;
++		struct dev_mc_list *mc_list = dev->net->mc_list;
++
++		adapterData->set_bits_mask = MAC_CR_HPFILT_;
++		adapterData->clear_bits_mask = (MAC_CR_PRMS_ | MAC_CR_MCPAS_);
++
++		while (mc_list != NULL) {
++			dwCount++;
++			if((mc_list->dmi_addrlen) == 6) {
++				u32 dwMask = 0x01UL;
++				u32 dwBitNum = Rx_Hash(mc_list->dmi_addr);
++
++				dwMask <<= (dwBitNum&0x1FUL);
++				if (dwBitNum & 0x20UL) {
++					dwHashH |= dwMask;
++				} else {
++					dwHashL |= dwMask;
++				}
++			} else {
++				SMSC_WARNING("dmi_addrlen!=6");
++			}
++			mc_list = mc_list->next;
++		}
++		if (dwCount != ((u32)(dev->net->mc_count))) {
++			SMSC_WARNING("dwCount != dev->net->mc_count");
++		}
++		SMSC_TRACE(DBG_MCAST, "Multicast: HASHH = 0x%08X,HASHL = 0x%08X", dwHashH, dwHashL);
++		adapterData->HashHi = dwHashH;
++		adapterData->HashLo = dwHashL;
++	}
++#else
++	if( netdev_mc_count(dev->net)>0) {
++		u32 dwHashH = 0;
++		u32 dwHashL = 0;
++		u32 dwCount = 0;
++		struct netdev_hw_addr *ha;
++
++		adapterData->set_bits_mask = MAC_CR_HPFILT_;
++		adapterData->clear_bits_mask = (MAC_CR_PRMS_ | MAC_CR_MCPAS_);
++
++		netdev_for_each_mc_addr(ha, dev->net) {
++			u32 dwMask = 0x01UL;
++			u32 dwBitNum = Rx_Hash(ha->addr);
++			dwCount++;
++
++			dwMask <<= (dwBitNum&0x1FUL);
++			if(dwBitNum & 0x20UL) {
++				dwHashH |= dwMask;
++			} else {
++				dwHashL |= dwMask;
++			}
++		}
++		if (dwCount != ((u32)netdev_mc_count(dev->net))) {
++			SMSC_WARNING("dwCount != netdev_mc_count(dev->net)");
++		}
++		SMSC_TRACE(DBG_MCAST, "Multicast: HASHH = 0x%08X,HASHL = 0x%08X", dwHashH, dwHashL);
++		adapterData->HashHi = dwHashH;
++		adapterData->HashLo = dwHashL;
++	}
++#endif
++	else {
++		adapterData->set_bits_mask = 0L;
++		adapterData->clear_bits_mask = (MAC_CR_PRMS_ | MAC_CR_MCPAS_ | MAC_CR_HPFILT_);
++
++		SMSC_TRACE(DBG_MCAST, "Receive own packets only");
++		adapterData->HashHi = 0UL;
++		adapterData->HashLo = 0UL;
++	}
++
++
++PREPARE:
++	up(&adapterData->RxFilterLock);
++
++	dwHashHi = adapterData->HashHi;
++	dwHashLo = adapterData->HashLo;
++	CHECK_RETURN_STATUS(smsc9500_write_reg(dev, HASHH, dwHashHi));
++	CHECK_RETURN_STATUS(smsc9500_write_reg(dev, HASHL, dwHashLo));
++	CHECK_RETURN_STATUS(smsc9500_read_reg(dev, MAC_CR, &local_MACCR));
++
++	local_MACCR |= adapterData->set_bits_mask;
++	local_MACCR &= ~(adapterData->clear_bits_mask);
++
++	CHECK_RETURN_STATUS(smsc9500_write_reg(dev, MAC_CR, local_MACCR));
++
++	SMSC_TRACE(DBG_MCAST, "smsc9500_set_multicast");
++	ret = 0;
++DONE:
++	return ret;
++}
++
++static void smsc9500_set_multicast(struct net_device *netdev)
++{
++	struct usbnet *dev = netdev_priv(netdev);
++	smscusbnet_defer_myevent(dev, EVENT_SET_MULTICAST);
++}
++
++static int Phy_GetLinkMode(struct usbnet *dev)
++{
++	u16 wRegBcr = 0;
++	int ret = SMSC9500_FAIL;
++	u16 wRegBSR, wRegLPA, WSpeedIndication;
++	u32 dwTemp, dwValue, result = LINK_OFF;
++	PADAPTER_DATA adapterData = (PADAPTER_DATA)(dev->data[0]);
++
++	SMSC_TRACE(DBG_LINK, "Phy_GetLinkMode");
++
++	/* if mdio access disable return the initialized link speed */
++	if (MdioDisable & MDIO_DISABLE_INTERNAL_ACCESS) {
++		if (adapterData->DefaultLinkStatus & MDIO_DEFAULT_LINK_INIT_MASK) {
++			result = link_mode & (LINK_SPEED_10HD | LINK_SPEED_10FD | LINK_SPEED_100HD | LINK_SPEED_100FD);
++			adapterData->dwLinkSpeed = adapterData->dwLinkSettings = result;
++		} else {
++			adapterData->dwLinkSpeed = adapterData->dwLinkSettings = LINK_OFF;
++		}
++		return 0;
++	}
++
++	/* Read PHY_BSR twice: link status bit is LL */
++	CHECK_RETURN_STATUS(smsc9500_read_phy(dev, PHY_BSR, &dwTemp));
++	CHECK_RETURN_STATUS(smsc9500_read_phy(dev, PHY_BSR, &dwTemp));
++
++	wRegBSR = LOWORD(dwTemp);
++
++	adapterData->dwLinkSettings = LINK_OFF;
++
++	if (wRegBSR&PHY_BSR_LINK_STATUS_) {
++		CHECK_RETURN_STATUS(smsc9500_read_phy(dev, PHY_BCR, &dwValue));
++		wRegBcr = LOWORD(dwValue);
++
++		if (wRegBcr & PHY_BCR_AUTO_NEG_ENABLE_) {
++			u32 linkSettings = LINK_AUTO_NEGOTIATE;
++			u16 wRegADV = adapterData->wLastADVatRestart;
++			CHECK_RETURN_STATUS(smsc9500_read_phy(dev, PHY_ANEG_LPA, &dwTemp));
++			wRegLPA = LOWORD(dwTemp);
++
++			if (wRegADV & PHY_ANEG_ADV_ASYMP_) {
++				linkSettings |= LINK_ASYMMETRIC_PAUSE;
++			}
++			if (wRegADV & PHY_ANEG_ADV_SYMP_) {
++				linkSettings |= LINK_SYMMETRIC_PAUSE;
++			}
++			if (wRegADV & PHY_ANEG_LPA_100FDX_) {
++				linkSettings |= LINK_SPEED_100FD;
++			}
++			if (wRegADV & PHY_ANEG_LPA_100HDX_) {
++				linkSettings |= LINK_SPEED_100HD;
++			}
++			if (wRegADV & PHY_ANEG_LPA_10FDX_) {
++				linkSettings |= LINK_SPEED_10FD;
++			}
++			if (wRegADV & PHY_ANEG_LPA_10HDX_) {
++				linkSettings |= LINK_SPEED_10HD;
++			}
++			adapterData->dwLinkSettings = linkSettings;
++
++			wRegLPA &= wRegADV;
++			if(wRegLPA & PHY_ANEG_LPA_100FDX_) {
++				result = LINK_SPEED_100FD;
++			} else if(wRegLPA & PHY_ANEG_LPA_100HDX_) {
++				result = LINK_SPEED_100HD;
++			} else if(wRegLPA & PHY_ANEG_LPA_10FDX_) {
++				result = LINK_SPEED_10FD;
++			} else if(wRegLPA & PHY_ANEG_LPA_10HDX_) {
++				result = LINK_SPEED_10HD;
++			}
++			if (result == LINK_OFF) {
++				CHECK_RETURN_STATUS(smsc9500_read_phy(dev, PHY_SPECIAL, &dwTemp));
++				WSpeedIndication = LOWORD(dwTemp);
++				if ((WSpeedIndication & PHY_SPECIAL_SPD_)== PHY_SPECIAL_SPD_10HALF_) {
++					result = LINK_SPEED_10HD;
++				} else if ((WSpeedIndication & PHY_SPECIAL_SPD_)== PHY_SPECIAL_SPD_10FULL_) {
++					result = LINK_SPEED_10FD;
++				} else if ((WSpeedIndication & PHY_SPECIAL_SPD_)== PHY_SPECIAL_SPD_100HALF_) {
++					result = LINK_SPEED_100HD;
++				} else if ((WSpeedIndication & PHY_SPECIAL_SPD_)== PHY_SPECIAL_SPD_100FULL_) {
++					result = LINK_SPEED_100FD;
++				} 
++			}
++		} else {
++			if (wRegBcr & PHY_BCR_SPEED_SELECT_) {
++				if (wRegBcr & PHY_BCR_DUPLEX_MODE_) {
++					adapterData->dwLinkSettings = result = LINK_SPEED_100FD;
++				} else {
++					adapterData->dwLinkSettings = result = LINK_SPEED_100HD;
++				}
++			} else {
++				if(wRegBcr & PHY_BCR_DUPLEX_MODE_) {
++					adapterData->dwLinkSettings = result = LINK_SPEED_10FD;
++				} else {
++					adapterData->dwLinkSettings = result = LINK_SPEED_10HD;
++				}
++			}
++		}
++	}
++	adapterData->dwLinkSpeed = result;
++	ret = 0;
++DONE:
++	return ret;
++}
++
++static int Phy_UpdateLinkMode(struct usbnet *dev)
++{
++	u32 dwTemp,dwValue;
++	int ret = SMSC9500_FAIL;
++	PADAPTER_DATA adapterData = (PADAPTER_DATA)(dev->data[0]);
++	u32 dwOldLinkSpeed = adapterData->dwLinkSpeed;
++
++	SMSC_TRACE(DBG_LINK, "Phy_UpdateLinkMode");
++
++	Phy_GetLinkMode(dev);
++
++	if (dwOldLinkSpeed != (adapterData->dwLinkSpeed)) {
++		if (adapterData->dwLinkSpeed != LINK_OFF) {
++			u32 dwRegVal=0;
++
++			/* Ethernet output boost */
++			smsc9500_eth_phy_boost(dev, 1);
++
++			switch(adapterData->dwLinkSpeed) {
++				case LINK_SPEED_10HD:
++					SMSC_TRACE(DBG_LINK_CHANGE, "Link is now UP at 10Mbps HD");
++					break;
++				case LINK_SPEED_10FD:
++					SMSC_TRACE(DBG_LINK_CHANGE, "Link is now UP at 10Mbps FD");
++					break;
++				case LINK_SPEED_100HD:
++					SMSC_TRACE(DBG_LINK_CHANGE, "Link is now UP at 100Mbps HD");
++					break;
++				case LINK_SPEED_100FD:
++					SMSC_TRACE(DBG_LINK_CHANGE, "Link is now UP at 100Mbps FD");
++					break;
++				default:
++					SMSC_TRACE(DBG_LINK_CHANGE, "Link is now UP at Unknown Link Speed, dwLinkSpeed=0x%08X",
++						adapterData->dwLinkSpeed);
++					break;
++			}
++
++			CHECK_RETURN_STATUS(smsc9500_read_reg(dev, MAC_CR, &dwRegVal));
++			dwRegVal &= ~(MAC_CR_FDPX_ | MAC_CR_RCVOWN_);
++			switch (adapterData->dwLinkSpeed) {
++				case LINK_SPEED_10HD:
++				case LINK_SPEED_100HD:
++					dwRegVal |= MAC_CR_RCVOWN_;
++					break;
++				case LINK_SPEED_10FD:
++				case LINK_SPEED_100FD:
++					dwRegVal |= MAC_CR_FDPX_;
++					break;
++				default:
++					break;
++			}
++			CHECK_RETURN_STATUS(smsc9500_write_reg(dev, MAC_CR, dwRegVal));
++
++			if (adapterData->dwLinkSettings & LINK_AUTO_NEGOTIATE) {
++				u16 linkPartner = 0;
++				u16 localLink = 0;
++
++				CHECK_RETURN_STATUS(smsc9500_read_phy(dev, PHY_ANEG_ADV, &dwTemp));
++				localLink = LOWORD(dwTemp);
++				CHECK_RETURN_STATUS(smsc9500_read_phy(dev, PHY_ANEG_LPA, &dwTemp));
++				linkPartner = LOWORD(dwTemp);
++				switch(adapterData->dwLinkSpeed) {
++				case LINK_SPEED_10FD:
++				case LINK_SPEED_100FD:
++					if (((localLink&linkPartner) & ((u16)PHY_ANEG_ADV_SYMP_)) != ((u16)0U)) {
++						/* Enable PAUSE receive and transmit */
++						dwTemp = 0xFFFF0002UL;
++						CHECK_RETURN_STATUS(smsc9500_write_reg(dev, FLOW, dwTemp));
++
++						CHECK_RETURN_STATUS(smsc9500_read_reg(dev, AFC_CFG, &dwValue));
++						dwValue = dwValue | 0x0000000FUL;
++						CHECK_RETURN_STATUS(smsc9500_write_reg(dev, AFC_CFG, dwValue));
++
++					} else if(((localLink & ((u16)0x0C00U)) == ((u16)0x0C00U)) &&
++						  ((linkPartner & ((u16)0x0C00U)) == ((u16)0x0800U))) {
++						/* Enable PAUSE receive, disable PAUSE transmit */
++						dwTemp = 0xFFFF0002UL;
++						CHECK_RETURN_STATUS(smsc9500_write_reg(dev, FLOW, dwTemp));
++						CHECK_RETURN_STATUS(smsc9500_read_reg(dev, AFC_CFG, &dwValue));
++						dwValue = dwValue&(~0x0000000FUL);
++						CHECK_RETURN_STATUS(smsc9500_write_reg(dev, AFC_CFG, dwValue));
++
++					} else if(((localLink & ((u16)0x0C00U)) == ((u16)0x0800U)) &&
++						  ((linkPartner & ((u16)0x0C00U)) == ((u16)0x0C00U))) {
++						/* Enable PAUSE transmit, disable PAUSE receive */
++						dwTemp = 0x0UL;
++						CHECK_RETURN_STATUS(smsc9500_write_reg(dev, FLOW, dwTemp));
++						CHECK_RETURN_STATUS(smsc9500_read_reg(dev, AFC_CFG, &dwValue));
++						dwValue = dwValue | 0x0000000FUL;
++						CHECK_RETURN_STATUS(smsc9500_write_reg(dev, AFC_CFG, dwValue));
++
++					} else {
++						/* Disable PAUSE receive and transmit */
++						dwTemp = 0x0UL;
++						CHECK_RETURN_STATUS(smsc9500_write_reg(dev, FLOW, dwTemp));
++						CHECK_RETURN_STATUS(smsc9500_read_reg(dev, AFC_CFG,&dwValue));
++						dwValue = dwValue&(~0x0000000FUL);
++						CHECK_RETURN_STATUS(smsc9500_write_reg(dev, AFC_CFG, dwValue));
++					}
++					break;
++				case LINK_SPEED_10HD:
++				case LINK_SPEED_100HD:
++						dwTemp = 0x0UL;
++						CHECK_RETURN_STATUS(smsc9500_write_reg(dev, FLOW, dwTemp));
++						CHECK_RETURN_STATUS(smsc9500_read_reg(dev, AFC_CFG,&dwValue));
++						dwValue = dwValue | 0x0000000FUL;
++						CHECK_RETURN_STATUS(smsc9500_write_reg(dev, AFC_CFG, dwValue));
++					break;
++				default:
++					break;
++				}
++				SMSC_TRACE(DBG_LINK_CHANGE, "LAN9500: %s,%s,%s,%s,%s,%s",
++					(localLink&PHY_ANEG_ADV_ASYMP_)?"ASYMP":"     ",
++					(localLink&PHY_ANEG_ADV_SYMP_)?"SYMP ":"     ",
++					(localLink&PHY_ANEG_ADV_100F_)?"100FD":"     ",
++					(localLink&PHY_ANEG_ADV_100H_)?"100HD":"     ",
++					(localLink&PHY_ANEG_ADV_10F_)?"10FD ":"     ",
++					(localLink&PHY_ANEG_ADV_10H_)?"10HD ":"     ");
++
++				SMSC_TRACE(DBG_LINK_CHANGE, "Partner: %s,%s,%s,%s,%s,%s",
++					(linkPartner&PHY_ANEG_LPA_ASYMP_)?"ASYMP":"     ",
++					(linkPartner&PHY_ANEG_LPA_SYMP_)?"SYMP ":"     ",
++					(linkPartner&PHY_ANEG_LPA_100FDX_)?"100FD":"     ",
++					(linkPartner&PHY_ANEG_LPA_100HDX_)?"100HD":"     ",
++					(linkPartner&PHY_ANEG_LPA_10FDX_)?"10FD ":"     ",
++					(linkPartner&PHY_ANEG_LPA_10HDX_)?"10HD ":"     ");
++			} else {
++				switch(adapterData->dwLinkSpeed) {
++				case LINK_SPEED_10HD:
++				case LINK_SPEED_100HD:
++					dwTemp = 0x0UL;
++					CHECK_RETURN_STATUS(smsc9500_write_reg(dev, FLOW, dwTemp));
++					CHECK_RETURN_STATUS(smsc9500_read_reg(dev, AFC_CFG, &dwValue));
++					dwValue = dwValue | 0x0000000FUL;
++					CHECK_RETURN_STATUS(smsc9500_write_reg(dev, AFC_CFG, dwValue));
++					break;
++				default:
++					dwTemp = 0x0UL;
++					CHECK_RETURN_STATUS(smsc9500_write_reg(dev, FLOW, dwTemp));
++					CHECK_RETURN_STATUS(smsc9500_read_reg(dev, AFC_CFG, &dwValue));
++					dwValue = dwValue & (~0x0000000FUL);
++					CHECK_RETURN_STATUS(smsc9500_write_reg(dev, AFC_CFG, dwValue));
++					break;
++				}
++			}
++			netif_carrier_on(dev->net);
++			Tx_WakeQueue(dev,0x01);
++			SetGpo(dev, adapterData->LinkLedOnGpio, !adapterData->LinkLedOnGpioPolarity);
++			NICStartRxPath(dev);
++			set_bit(EVENT_LINK_UP, &dev->flags);
++			
++		} else {
++			SMSC_TRACE(DBG_LINK_CHANGE,"Link is now DOWN");
++			Tx_StopQueue(dev,0x01);
++			netif_carrier_off(dev->net);
++			SetGpo(dev, adapterData->LinkLedOnGpio, adapterData->LinkLedOnGpioPolarity);
++			NICStopAndFlushRxPath(dev);
++			CHECK_RETURN_STATUS(smsc9500_write_reg(dev, FLOW, 0));
++			CHECK_RETURN_STATUS(smsc9500_read_reg(dev, AFC_CFG, &dwValue));
++			dwValue = dwValue & (~0x0000000FUL);
++			CHECK_RETURN_STATUS(smsc9500_write_reg(dev, AFC_CFG, dwValue));
++			set_bit(EVENT_LINK_DOWN, &dev->flags);
++		}
++	}
++	ret = 0;
++DONE:
++	return ret;
++}
++
++static int Phy_CheckLink(void * ptr)
++{
++        u32 dwValue;
++	struct usbnet *dev = ptr;
++    	int ret = SMSC9500_FAIL;
++	char statistics[sizeof(SMSC9500_RX_STATS) + sizeof(SMSC9500_TX_STATS)];
++
++        BUG_ON(!dev);
++
++	SMSC_TRACE(DBG_LINK, "Phy_CheckLink");
++
++	if (Phy_UpdateLinkMode(dev) < 0)
++		return ret;
++
++	/* verify whether ethernet boost is set */
++	smsc9500_eth_phy_boost(dev, 0);
++
++	if (dev->suspendFlag & AUTOSUSPEND_DETACH) {
++		if(!netif_carrier_ok(dev->net)) {
++			/* Link is down, detach device*/
++			/* Set wakeup event */
++			SetLinkDownWakeupEvents(dev, WAKEPHY_ENERGY);
++
++			/* Enable net detach */
++			CHECK_RETURN_STATUS(smsc9500_read_reg(dev, HW_CFG, &dwValue));
++			dwValue |= HW_CFG_SMDET_EN;
++			/* Not checking return status here. Failure or
++			success smsc9500_write_reg() return negetive */
++			smsc9500_write_reg(dev,	HW_CFG, dwValue);
++			dev->suspendFlag &= ~AUTOSUSPEND_DETACH;
++			dev->netDetachDone = TRUE;
++			ret = SMSC9500_SUCCESS;
++			goto DONE;
++		}
++	}
++
++	if (smsc9500_get_stats(dev, statistics) > 0){
++		UpdateStatCounters(dev,statistics);
++	}
++
++	if ((!(dev->StopLinkPolling)) && (!timer_pending(&dev->LinkPollingTimer))) {
++		dev->LinkPollingTimer.expires = jiffies+HZ;
++		add_timer(&(dev->LinkPollingTimer));
++	}
++	ret = SMSC9500_SUCCESS;
++DONE:
++	return ret;
++}
++
++
++static int phy_SetLink(struct usbnet *dev, u32 dwLinkRequest)
++{
++	u32 dwValue;
++	u16 wTemp = 0;
++	int ret = SMSC9500_FAIL;
++	PADAPTER_DATA adapterData = (PADAPTER_DATA)(dev->data[0]);
++
++	SMSC_TRACE(DBG_LINK, "phy_SetLink");
++
++	/* If mdio access is disabled return */
++	if (MdioDisable & MDIO_DISABLE_INTERNAL_ACCESS) {
++		return 0;
++	}
++
++	if(dwLinkRequest&LINK_AUTO_NEGOTIATE) {
++
++		CHECK_RETURN_STATUS(smsc9500_read_phy(dev, PHY_ANEG_ADV,&dwValue));
++		wTemp=LOWORD(dwValue);
++		wTemp&=~PHY_ANEG_ADV_PAUSE_;
++		if(dwLinkRequest&LINK_ASYMMETRIC_PAUSE) {
++			wTemp|=PHY_ANEG_ADV_ASYMP_;
++		}
++		if(dwLinkRequest&LINK_SYMMETRIC_PAUSE) {
++			wTemp|=PHY_ANEG_ADV_SYMP_;
++		}
++		wTemp&=~PHY_ANEG_ADV_SPEED_;
++		if(dwLinkRequest&LINK_SPEED_10HD) {
++			wTemp|=PHY_ANEG_ADV_10H_;
++		}
++		if(dwLinkRequest&LINK_SPEED_10FD) {
++			wTemp|=PHY_ANEG_ADV_10F_;
++		}
++
++		if((dwLinkRequest&LINK_SPEED_100HD) && (dev->udev->speed == USB_SPEED_HIGH)) {
++			wTemp|=PHY_ANEG_ADV_100H_;
++		}
++		if((dwLinkRequest&LINK_SPEED_100FD) && (dev->udev->speed == USB_SPEED_HIGH)) {
++			wTemp|=PHY_ANEG_ADV_100F_;
++		}
++
++		dwValue=(u32)(wTemp) &0x0000FFFFUL;
++		CHECK_RETURN_STATUS(smsc9500_write_phy(dev,PHY_ANEG_ADV, dwValue));
++
++		// begin to establish link
++		wTemp=PHY_BCR_AUTO_NEG_ENABLE_|PHY_BCR_RESTART_AUTO_NEG_;
++		dwValue=(u32)(wTemp) &0x0000FFFFUL;
++		CHECK_RETURN_STATUS(smsc9500_write_phy(dev,PHY_BCR, dwValue));
++	} else {
++	
++		/* Automdix fix when force mode */
++		if (adapterData->internalPhy == TRUE) {
++			if ((auto_mdix >= AMDIX_ENABLE) && (dev->chipDependFeatures[FEATURE_MDIX_MODE] == TRUE)) {
++				CHECK_RETURN_STATUS(smsc9500_read_phy(dev, PHY_SILICON_REV, &dwValue));
++				CHECK_RETURN_STATUS(smsc9500_write_phy(dev, PHY_SILICON_REV, dwValue | PHY_SILICON_REV_AMDIX_XTD_));
++			} else {
++				CHECK_RETURN_STATUS(smsc9500_read_phy(dev, PHY_SPECIAL_CTRL_STS, &dwValue));
++				CHECK_RETURN_STATUS(smsc9500_write_phy(dev, PHY_SPECIAL_CTRL_STS, (dwValue & 0x1FFF)|0x8000));
++			}
++		}
++
++		if(dwLinkRequest&(LINK_SPEED_100FD)) {
++			dwLinkRequest=LINK_SPEED_100FD;
++		} else if(dwLinkRequest&(LINK_SPEED_100HD)) {
++			dwLinkRequest=LINK_SPEED_100HD;
++		} else if(dwLinkRequest&(LINK_SPEED_10FD)) {
++			dwLinkRequest=LINK_SPEED_10FD;
++		} else if(dwLinkRequest&(LINK_SPEED_10HD)) {
++			dwLinkRequest=LINK_SPEED_10HD;
++		}
++		if(dwLinkRequest&(LINK_SPEED_10FD|LINK_SPEED_100FD)) {
++			wTemp|=PHY_BCR_DUPLEX_MODE_;
++		}
++		if(dwLinkRequest&(LINK_SPEED_100HD|LINK_SPEED_100FD)) {
++			wTemp|=PHY_BCR_SPEED_SELECT_;
++		}
++		dwValue=(u32)(wTemp) &0x0000FFFFUL;
++		CHECK_RETURN_STATUS(smsc9500_write_phy(dev,PHY_BCR, dwValue));
++	}
++
++	/* Ethernet output boost */
++	smsc9500_eth_phy_boost(dev, 1);
++
++	ret = 0;
++DONE:
++	return ret;
++}
++
++static int Phy_SetAutoMdix( struct usbnet *dev, u16 wAutoMdix)
++{
++	u32 SpecialCtrlSts = 0U;
++	int ret = SMSC9500_FAIL;
++
++	/* If mdio access is disabled return */
++	if (MdioDisable & MDIO_DISABLE_INTERNAL_ACCESS) {
++		return 0;
++	}
++
++	if (wAutoMdix > AMDIX_ENABLE) {
++		SMSC_TRACE(DBG_INIT, "LAN9500 Auto MDIX feature controlled by hardware strap");
++	} else {
++		CHECK_RETURN_STATUS(smsc9500_read_phy(dev, PHY_SPECIAL_CTRL_STS, &SpecialCtrlSts));
++		if (wAutoMdix == AMDIX_DISABLE_CROSSOVER) {
++			SpecialCtrlSts |= (SPECIAL_CTRL_STS_OVRRD_AMDIX_ | SPECIAL_CTRL_STS_AMDIX_STATE_);
++			SpecialCtrlSts &= ~SPECIAL_CTRL_STS_AMDIX_ENABLE_;
++			SMSC_WARNING("LAN9500 Auto MDIX hardware strap was overiden by driver. " 
++				"AutoMdix is disabled, use crossover cable.");
++		} else if (wAutoMdix == AMDIX_DISABLE_STRAIGHT) {
++			SpecialCtrlSts |= SPECIAL_CTRL_STS_OVRRD_AMDIX_;
++			SpecialCtrlSts &= ~(SPECIAL_CTRL_STS_AMDIX_ENABLE_ | SPECIAL_CTRL_STS_AMDIX_STATE_);
++			SMSC_WARNING("LAN9500 Auto MDIX hardware strap was overiden by driver. "
++				"AutoMdix is disabled, use straight cable.");
++		} else {
++			SpecialCtrlSts |= (SPECIAL_CTRL_STS_OVRRD_AMDIX_ | SPECIAL_CTRL_STS_AMDIX_ENABLE_);
++			SMSC_WARNING("LAN9500 Auto MDIX hardware strap was overiden by driver. AutoMdix is enabled");
++		}
++		CHECK_RETURN_STATUS(smsc9500_write_phy(dev, PHY_SPECIAL_CTRL_STS, SpecialCtrlSts));
++	}
++	ret = 0;
++DONE:
++	return ret;
++}
++
++static BOOLEAN Phy_Initialize( struct usbnet *dev, u32 dwPhyAddr, u32 dwLinkRequest)
++{
++	u32 dwPhyBcr;
++	u32 dwLoopCount = 0;
++	u32 phy_id_1, phy_id_2;
++	BOOLEAN result = FALSE, bConfigureAutoMdix = FALSE;
++	u32 dwTemp = 0,dwValue, address, Value32, Temp32;
++	PADAPTER_DATA adapterData = (PADAPTER_DATA)(dev->data[0]);
++
++	SMSC_TRACE(DBG_INIT, "Phy_Initialize");
++
++	SMSC_ASSERT(dwLinkRequest <= 0x7FUL);
++
++	adapterData->internalPhy = TRUE;
++
++	CHECK_RETURN_STATUS(smsc9500_read_reg(dev, HW_CFG, &dwValue));
++	if (dwValue & HW_CFG_PSEL_) {
++		if (dwPhyAddr <= 31) {
++			/* We know the phy address. Use it. */
++			adapterData->dwPhyAddress = dwPhyAddr;
++		} else if ((dwPhyAddr > 31) && (MdioDisable & MDIO_DISABLE_INTERNAL_ACCESS)) {
++			/* When phy access is disabled, phy address do
++			not matter. Assign 0 */
++			adapterData->dwPhyAddress = 0;
++		} else { /* Auto detect PHY */
++			phy_id_1 = 0xFFFFU;
++			phy_id_2 = 0xFFFFU;
++			for (address = 0; address <= 31; address++) {
++				adapterData->dwPhyAddress = address;
++				CHECK_RETURN_STATUS(smsc9500_read_phy(dev, PHY_ID_1, &phy_id_1));
++				CHECK_RETURN_STATUS(smsc9500_read_phy(dev, PHY_ID_2, &phy_id_2));
++				if((phy_id_1 != 0x7FFFU) && (phy_id_1 != 0xFFFFU) && (phy_id_1 != 0x0000U)){
++					SMSC_TRACE(DBG_INIT, "Deteced Phy at address = 0x%02X", address);
++					break;
++				}
++			}
++		}
++		SMSC_TRACE(DBG_INIT, "Using external PHY ");
++		adapterData->internalPhy = FALSE;
++
++	} else { /* Use Internal Phy */
++		SMSC_TRACE(DBG_INIT, "Using internal PHY ");
++		adapterData->dwPhyAddress = 1;
++		bConfigureAutoMdix = TRUE;
++	}
++
++	adapterData->dwLinkSpeed = LINK_INIT;
++	adapterData->dwLinkSettings = LINK_INIT;
++
++	if (!(MdioDisable & MDIO_DISABLE_INTERNAL_ACCESS)) {
++		CHECK_RETURN_STATUS(smsc9500_read_phy(dev, PHY_ID_2, &dwTemp));
++		adapterData->bPhyRev = ((BYTE)(dwTemp & (0x0FUL)));
++		adapterData->bPhyModel = ((BYTE)((dwTemp >> 4) & (0x3FUL)));
++		adapterData->dwPhyId = ((dwTemp & (0xFC00UL)) << 8);
++		CHECK_RETURN_STATUS(smsc9500_read_phy(dev, PHY_ID_1, &dwTemp));
++		adapterData->dwPhyId |= ((dwTemp & (0x0000FFFFUL)) << 2);
++
++		SMSC_TRACE(DBG_INIT, "PhyId: 0x%08X, PhyModel: 0x%02X, PhyRev: 0x%02X",
++			adapterData->dwPhyId, adapterData->bPhyModel, adapterData->bPhyRev);
++
++		/* Reset the PHY */
++		dwPhyBcr = (u32)PHY_BCR_RESET_ ;
++		CHECK_RETURN_STATUS(smsc9500_write_phy(dev,PHY_BCR, dwPhyBcr));
++
++		dwLoopCount = 20;
++		do {
++			mdelay(100);
++			CHECK_RETURN_STATUS(smsc9500_read_phy(dev,PHY_BCR,&dwPhyBcr));
++
++			dwLoopCount--;
++		} while((dwLoopCount>0) && ((u16)dwPhyBcr&PHY_BCR_RESET_));
++
++		if((u16)dwPhyBcr&PHY_BCR_RESET_) {
++			SMSC_WARNING("PHY reset failed to complete");
++			goto DONE;
++		}
++		else {
++			SMSC_TRACE(DBG_INIT, "PHY reset!");
++		}
++
++		if (bConfigureAutoMdix) {
++			Phy_SetAutoMdix(dev, (u16)auto_mdix);
++		}
++
++		phy_SetLink(dev,dwLinkRequest);
++
++		/* set EDPD settings */
++		if ((EDPDConfig != 0) && (adapterData->internalPhy) && 
++			((dev->chipID == PID_LAN9500A) || (dev->chipID == PID_LAN9530) ||
++			(dev->chipID == PID_LAN9730) || (dev->chipID == PID_LAN89530))) {
++			CHECK_RETURN_STATUS(smsc9500_read_phy(dev, PHY_SILICON_REV, &dwTemp));
++			CHECK_RETURN_STATUS(smsc9500_write_phy(dev, PHY_SILICON_REV, 
++				(dwTemp & 0x03FF) | EDPDConfig));
++		}
++		
++		/* Set EEE (for external or internal phy) if enabled and supported */
++		if (((dev->chipID == PID_LAN9730) || (dev->chipID == PID_LAN9530) 
++			|| (dev->chipID == PID_LAN89530)) && (EnableEEE < 2))
++		{
++			CHECK_RETURN_STATUS(smsc9500_read_reg(dev,MAC_CR,&Value32));
++			CHECK_RETURN_STATUS(smsc9500_read_phy(dev, PHY_SILICON_REV, &Temp32));
++			CHECK_RETURN_STATUS(smsc9500_read_phy(dev, PHY_ANEG_ADV, &dwTemp));
++			
++			if (EnableEEE == 0) {	 
++				Value32 &= ~MAC_CR_ENABLE_EEE;    
++				Temp32 &= ~PHY_SILICON_REV_EEE_ENABLE;		   
++				dwTemp &= ~PHY_ANEG_NEXT_PAGE;
++			} else if (EnableEEE == 1) {
++				Value32 |= MAC_CR_ENABLE_EEE;		  
++				Temp32 |= PHY_SILICON_REV_EEE_ENABLE;		
++				dwTemp |= PHY_ANEG_NEXT_PAGE;
++			}
++			CHECK_RETURN_STATUS(smsc9500_write_phy(dev,PHY_ANEG_ADV, dwTemp));
++			CHECK_RETURN_STATUS(smsc9500_write_phy(dev, PHY_SILICON_REV, Temp32));
++			CHECK_RETURN_STATUS(smsc9500_write_reg(dev, MAC_CR, Value32)) ;
++		}
++	}
++
++	result = TRUE;
++DONE:
++	return result;
++}
++
++
++
++static int smsc9500_get_settings(struct net_device *net, struct ethtool_cmd *cmd)
++{
++	struct usbnet *dev = netdev_priv(net);
++	PADAPTER_DATA adapterData = (PADAPTER_DATA)(dev->data[0]);
++	cmd->supported = SUPPORTED_10baseT_Half |
++				SUPPORTED_10baseT_Full |
++				SUPPORTED_100baseT_Half |
++				SUPPORTED_100baseT_Full |
++				SUPPORTED_Autoneg |
++				SUPPORTED_MII;
++	cmd->advertising = ADVERTISED_MII;
++
++	if (adapterData->dwLinkSettings & LINK_SPEED_10HD)
++		cmd->advertising |= ADVERTISED_10baseT_Half;
++	if (adapterData->dwLinkSettings & LINK_SPEED_10FD)
++		cmd->advertising |= ADVERTISED_10baseT_Full;
++	if (adapterData->dwLinkSettings & LINK_SPEED_100HD)
++		cmd->advertising |= ADVERTISED_100baseT_Half;
++	if (adapterData->dwLinkSettings & LINK_SPEED_100FD)
++		cmd->advertising |= ADVERTISED_100baseT_Full;
++	if (adapterData->dwLinkSettings & LINK_AUTO_NEGOTIATE) {
++		cmd->advertising |= ADVERTISED_Autoneg;
++		cmd->autoneg = AUTONEG_ENABLE;
++	} else {
++		cmd->autoneg = AUTONEG_DISABLE;
++	}
++	if (adapterData->dwLinkSpeed & (LINK_SPEED_100HD | LINK_SPEED_100FD)) {
++		cmd->speed = SPEED_100;
++	} else {
++		cmd->speed = SPEED_10;
++	}
++	if (adapterData->dwLinkSpeed & (LINK_SPEED_10FD | LINK_SPEED_100FD)) {
++		cmd->duplex=DUPLEX_FULL;
++	} else {
++		cmd->duplex=DUPLEX_HALF;
++	}
++	cmd->port = PORT_MII;
++	cmd->phy_address = (u8)adapterData->dwPhyAddress;
++	cmd->transceiver = XCVR_INTERNAL;
++	cmd->maxtxpkt = 0;
++	cmd->maxrxpkt = 0;
++
++	return 0;
++}
++
++static int smsc9500_set_settings(struct net_device *net, struct ethtool_cmd *cmd)
++{
++	int result = -EFAULT;
++	u32 linkRequest = 0;
++	struct usbnet *dev = netdev_priv(net);
++	PADAPTER_DATA adapterData = (PADAPTER_DATA)(dev->data[0]);
++
++	if (cmd->autoneg == AUTONEG_ENABLE) {
++		u32 mask = (ADVERTISED_100baseT_Half |
++				ADVERTISED_100baseT_Full |
++				ADVERTISED_10baseT_Half |
++				ADVERTISED_10baseT_Full);
++
++		if (cmd->advertising & ~mask)
++			return -EINVAL;
++		if (cmd->advertising & ADVERTISED_100baseT_Full)
++			linkRequest |= LINK_SPEED_100FD;
++		if (cmd->advertising & ADVERTISED_100baseT_Half)
++			linkRequest |= LINK_SPEED_100HD;
++		if (cmd->advertising & ADVERTISED_10baseT_Full)
++			linkRequest |= LINK_SPEED_10FD;
++		if (cmd->advertising & ADVERTISED_10baseT_Half)
++			linkRequest |= LINK_SPEED_10HD;
++		linkRequest |= LINK_AUTO_NEGOTIATE;
++	} else {
++
++		if (!((cmd->speed == SPEED_10) || (cmd->speed == SPEED_100)))
++			return -EOPNOTSUPP;
++
++		if (cmd->speed == SPEED_100) {
++			if (cmd->duplex == DUPLEX_FULL) {
++				linkRequest |= LINK_SPEED_100FD;
++			} else {
++				linkRequest |= LINK_SPEED_100HD;
++			}
++		} else {
++			if (cmd->duplex == DUPLEX_FULL) {
++				linkRequest |= LINK_SPEED_10FD;
++			} else {
++				linkRequest |= LINK_SPEED_10HD;
++			}
++		}
++	}
++	
++	/* keep the flow control settings */
++	linkRequest |= adapterData->dwLinkSettings  & (LINK_SYMMETRIC_PAUSE | LINK_ASYMMETRIC_PAUSE);
++	adapterData->dwLinkSettings = linkRequest;
++	adapterData->dwSavedLinkSettings = linkRequest;
++
++	if (phy_SetLink(dev, adapterData->dwLinkSettings) == SMSC9500_SUCCESS) {
++		result = 0;
++	}
++
++	return result;
++}
++
++void smsc9500_get_drvinfo (struct net_device *net, struct ethtool_drvinfo *info)
++{
++	struct usbnet *dev = netdev_priv(net);
++	PADAPTER_DATA adapterData = (PADAPTER_DATA)(dev->data[0]);
++
++	strcpy(info->driver, "Smsc9500");
++	memset(&info->version, 0, sizeof(info->version));
++	sprintf(info->version, "%lX.%02lX.%02lX",
++		(DRIVER_VERSION >> 16),(DRIVER_VERSION >> 8) & 0xFF, (DRIVER_VERSION & 0xFFUL));
++	memset(&info->fw_version, 0, sizeof(info->fw_version));
++	sprintf(info->fw_version, "%lu", (adapterData->dwIdRev) & 0xFFFFUL);
++	memset(&info->bus_info, 0, sizeof(info->bus_info));
++/*
++ * kernel 4.x does not have reserved1 in ethtool.h drvinfo.
++ */
++#if (LINUX_VERSION_CODE <= KERNEL_VERSION(3,19,8))
++	memset(&info->reserved1, 0, sizeof(info->reserved1));
++#endif
++	memset(&info->reserved2, 0, sizeof(info->reserved2));
++	info->n_stats = 0;
++	info->testinfo_len = 0;
++	info->eedump_len = 0;
++	info->regdump_len = 0;
++}
++
++
++static int smsc9500_regs_len(struct net_device *dev)
++{
++	/* all smsc9500 registers plus all phy registers */
++	return 0x200 + (32 * sizeof(u32));
++}
++
++
++static void smsc9500_get_regs(struct net_device *net, struct ethtool_regs *regs, void *buf)
++{
++	u32 *data = buf;
++	unsigned int i, j = 0;
++	struct usbnet *dev = netdev_priv(net);
++
++	smsc9500_read_reg(dev, ID_REV,&regs->version);
++	for (i = 0; i < 0x200; i += (sizeof(u32)))
++		 smsc9500_read_reg(dev, i,&data[j++]);
++
++	if (MdioDisable & MDIO_DISABLE_INTERNAL_ACCESS) {
++		SMSC_WARNING("Phy Mdio internal access disabled\n");
++		return;
++	}
++	
++	for (i = 0; i <= 31; i++)
++		 smsc9500_read_phy(dev, i,&data[j++]);
++}
++
++
++int smsc9500_nway_restart(struct usbnet *dev)
++{
++	uint bmcr;
++	int ret = -EINVAL;
++
++	if (MdioDisable & MDIO_DISABLE_INTERNAL_ACCESS) {
++		SMSC_WARNING("Phy Mdio internal access disabled\n");
++		return ret;
++	}
++
++	/* if autoneg is off, it's an error */
++	 smsc9500_read_phy(dev, PHY_BCR, &bmcr);
++
++	if (bmcr & PHY_BCR_AUTO_NEG_ENABLE_) {
++		bmcr |= PHY_BCR_RESTART_AUTO_NEG_;
++		smsc9500_write_phy(dev, PHY_BCR, bmcr);
++		ret = 0;
++	}
++
++	return ret;
++}
++
++int smsc9500_nway_reset(struct net_device *net)
++{
++	struct usbnet *dev = netdev_priv(net);
++
++	return smsc9500_nway_restart(dev);
++}
++
++static u32 smsc9500_get_link (struct net_device *net)
++{
++	u32 wRegBSR;
++	struct usbnet *dev = netdev_priv(net);
++	PADAPTER_DATA adapterData = (PADAPTER_DATA)(dev->data[0]);
++
++	if (MdioDisable & MDIO_DISABLE_INTERNAL_ACCESS) {
++		/* No phy access, report link up */
++		return (adapterData->DefaultLinkStatus & MDIO_DEFAULT_LINK_INIT_MASK);
++	}
++
++	/* read PHY_BSR twice: link status bit is LL */
++	CHECK_RETURN_STATUS(smsc9500_read_phy(dev, PHY_BSR, &wRegBSR));
++	CHECK_RETURN_STATUS(smsc9500_read_phy(dev, PHY_BSR, &wRegBSR));
++        if(!(wRegBSR & PHY_BSR_LINK_STATUS_)) {
++                return 0;
++        } else {
++                return 1;
++        }
++DONE:
++        return 0;
++}
++
++static u32 smsc9500_get_msglevel (struct net_device *net)
++{
++	struct usbnet *dev = netdev_priv(net);
++
++	return dev->msg_enable;
++}
++
++
++static void smsc9500_set_msglevel (struct net_device *net, u32 level)
++{
++	struct usbnet *dev = netdev_priv(net);
++
++	dev->msg_enable = level;
++}
++
++
++static void smsc9500_get_wol(struct net_device *net, struct ethtool_wolinfo *wolinfo)
++{
++	struct usbnet *dev = netdev_priv(net);
++	PADAPTER_DATA adapterData = (PADAPTER_DATA)(dev->data[0]);
++
++	wolinfo->supported = (WAKE_PHY | WAKE_UCAST | WAKE_BCAST | WAKE_MCAST | WAKE_ARP | WAKE_MAGIC);
++	wolinfo->wolopts = adapterData->WolWakeupOpts;
++}
++
++static int smsc9500_set_wol(struct net_device *net, struct ethtool_wolinfo *wolinfo)
++{
++	int result = -EFAULT;
++	struct usbnet *dev = netdev_priv(net);
++	PADAPTER_DATA adapterData = (PADAPTER_DATA)(dev->data[0]);
++
++	adapterData->WolWakeupOpts = wolinfo->wolopts;
++	result = 0;
++
++	return result;
++}
++
++
++static BOOLEAN IsEepromContentValid(struct usbnet *dev)
++{
++	u32 tmp, strapVal, idRev;
++	BOOLEAN validContent = FALSE;
++	PADAPTER_DATA adapterData = (PADAPTER_DATA)(dev->data[0]);
++
++	CHECK_RETURN_STATUS(smsc9500_read_reg(dev, ID_REV, &idRev));
++	idRev = idRev >> 16;	
++
++	if((idRev == PID_LAN9500) || (idRev == PID_LAN9500A)) {
++		CHECK_RETURN_STATUS(smsc9500_read_reg(dev, STRAP_DBG, &strapVal));
++		if (strapVal & EEPROM_DISABLE) {
++			SMSC_WARNING("EEPROM disable strap is set\n");
++			adapterData->eepromContentValid = FALSE;
++			return FALSE;
++		}
++	}
++
++	CHECK_RETURN_STATUS(smsc9500_read_reg(dev, E2P_CMD, &tmp));
++	if (tmp & E2P_CMD_LOADED_) {
++		validContent = TRUE;
++	} else {
++		SMSC_TRACE(DBG_INIT, "EEPROM content not valid, not loaded");
++		validContent = FALSE;
++	}
++DONE:
++	adapterData->eepromContentValid = validContent;	
++	return validContent;
++}
++
++static int smsc9500_eeprom_size(struct usbnet *dev)
++{
++	int size = 0;
++	u32 start, end;
++	u32 tmp, strapVal, idRev;
++	BOOLEAN validContent = FALSE;
++	PADAPTER_DATA adapterData = (PADAPTER_DATA)(dev->data[0]);
++
++	CHECK_RETURN_STATUS(smsc9500_read_reg(dev, ID_REV, &idRev));
++	idRev = idRev >> 16;	
++
++	if((idRev == PID_LAN9500) || (idRev == PID_LAN9500A)) {
++		CHECK_RETURN_STATUS(smsc9500_read_reg(dev, STRAP_DBG, &strapVal));
++		if (strapVal & EEPROM_DISABLE) {
++			SMSC_WARNING("EEPROM disable strap is set\n");
++			size = 0;
++			adapterData->eepromContentValid = FALSE;
++			return size;
++		} else if (!(strapVal & EEPROM_SIZE)) {
++			size = 128;
++			goto CheckValid;
++		} 
++	}
++
++	if(smsc9500_read_eeprom(dev, 0, sizeof(u32), (BYTE*)&start) < 0) {
++		goto DONE;
++	}
++	if(smsc9500_read_eeprom(dev, 256, sizeof(u32), (BYTE*)&end) < 0) {
++		goto DONE;
++	}
++	/* write to 256 the inverse value of start */
++	tmp = ~start;
++	if(smsc9500_write_eeprom(dev, 256, sizeof(u32), (BYTE*)&tmp) < 0) {
++		goto DONE;
++	}
++	/* read the location 0 again */
++	if(smsc9500_read_eeprom(dev, 0, sizeof(u32), (BYTE*)&tmp) < 0) {
++		goto DONE;
++	}
++	if (tmp != start) {
++		/* restore the value of location 0 */
++		if(smsc9500_write_eeprom(dev, 0, sizeof(u32), (BYTE*)&start) < 0) {
++			goto DONE;
++		}
++		/* 256 byte eeprom */
++		size = 256;
++	} else {
++		/* restore the value of location 0 */
++		if(smsc9500_write_eeprom(dev, 256, sizeof(u32), (BYTE*)&end) < 0) {
++			goto DONE;
++		}
++		/* 512 byte eeprom */
++		size = 512;
++	}
++
++CheckValid:
++	CHECK_RETURN_STATUS(smsc9500_read_reg(dev, E2P_CMD, &tmp));
++	if (tmp & E2P_CMD_LOADED_) {
++		validContent = TRUE;
++	} else {
++		validContent = FALSE;
++	}
++DONE:
++	adapterData->eepromContentValid = validContent;	
++	return size;
++
++}
++
++static int smsc9500_get_eeprom_len(struct net_device *net)
++{
++	struct usbnet *dev = netdev_priv(net);
++	PADAPTER_DATA adapterData = (PADAPTER_DATA)(dev->data[0]);
++
++	return adapterData->eepromSize = smsc9500_eeprom_size(dev);
++}
++
++static int smsc9500_get_eeprom(struct net_device *netdev, struct ethtool_eeprom *ee, u8 *data)
++{
++	int result = 0;
++	int len = ee->len;
++	int offset = ee->offset;
++	struct usbnet *dev = netdev_priv(netdev);
++	PADAPTER_DATA adapterData = (PADAPTER_DATA)(dev->data[0]);
++
++	ee->magic = LAN9500_EEPROM_MAGIC;
++
++	adapterData->eepromSize = smsc9500_eeprom_size(dev);
++
++	if (len == 0) {
++		return 0;
++	}
++
++	if (offset + len > adapterData->eepromSize) {
++		SMSC_WARNING("EEPROM address is out of range");
++		result = -EINVAL;
++	} else {
++		if (smsc9500_read_eeprom(dev, offset, len,  data) < 0) {
++			result = -EFAULT;
++		}
++	}
++
++	return result;
++}
++
++static int smsc9500_set_eeprom(struct net_device *netdev, struct ethtool_eeprom *ee, u8 *data)
++{
++	int result = 0;
++	int len = ee->len;
++	int offset = ee->offset;
++	struct usbnet *dev = netdev_priv(netdev);
++	PADAPTER_DATA adapterData = (PADAPTER_DATA)(dev->data[0]);
++
++	adapterData->eepromSize = smsc9500_eeprom_size(dev);
++
++	if (len == 0) {
++		return 0;
++	}
++
++	if (offset + len > adapterData->eepromSize) {
++		SMSC_WARNING("EEPROM address is out of range");
++		result = -EINVAL;
++		return result;
++	}
++
++	if (ee->magic != LAN9500_EEPROM_MAGIC) {
++		SMSC_WARNING("EEPROM: magic value mismatch, writing fail, magic = 0x%x", ee->magic);
++		result = -EFAULT;
++		return result;
++	}
++
++	if (smsc9500_write_eeprom(dev, offset, len,  data) < 0) {
++		result = -EFAULT;
++	}
++
++	return result;
++}
++
++#if (LINUX_VERSION_CODE <= KERNEL_VERSION(3,2,31))
++static u32 smsc9500_ethtool_get_tx_csum(struct net_device *netdev)
++{
++	struct usbnet *dev = netdev_priv(netdev);
++	PADAPTER_DATA adapterData = (PADAPTER_DATA)(dev->data[0]);
++
++	return adapterData->UseTxCsum;
++}
++
++static u32 smsc9500_ethtool_get_rx_csum(struct net_device *netdev)
++{
++	struct usbnet *dev = netdev_priv(netdev);
++	PADAPTER_DATA adapterData = (PADAPTER_DATA)(dev->data[0]);
++
++	return adapterData->UseRxCsum;
++}
++
++/* Enable or disable Tx & Rx checksum offload engines */
++static int smsc9500_set_csums(struct usbnet *dev)
++{
++	u32 read_buf;
++	PADAPTER_DATA adapterData = (PADAPTER_DATA)(dev->data[0]);
++
++	int ret = smsc9500_read_reg(dev, COE_CR, &read_buf);
++	if (ret < 0) {
++		SMSC_WARNING("Failed to read COE_CR: %d\n", ret);
++		return ret;
++	}
++
++	if (adapterData->UseTxCsum)
++		read_buf |= Tx_COE_EN_;
++	else
++		read_buf &= ~Tx_COE_EN_;
++
++	if (adapterData->UseRxCsum)
++		read_buf |= Rx_COE_EN_;
++	else
++		read_buf &= ~Rx_COE_EN_;
++
++	ret = smsc9500_write_reg(dev, COE_CR, read_buf);
++	if (ret < 0) {
++		SMSC_WARNING("Failed to write COE_CR: %d\n", ret);
++		return ret;
++	}
++
++	return 0;
++}
++
++static int smsc9500_ethtool_set_tx_csum(struct net_device *netdev, u32 val)
++{
++	struct usbnet *dev = netdev_priv(netdev);
++	PADAPTER_DATA adapterData = (PADAPTER_DATA)(dev->data[0]);
++
++	adapterData->UseTxCsum = !!val;
++
++	if (adapterData->UseTxCsum)
++		netdev->features |= NETIF_F_HW_CSUM;
++	else
++		netdev->features &= ~NETIF_F_HW_CSUM;
++
++	return smsc9500_set_csums(dev);
++}
++
++
++static int smsc9500_ethtool_set_rx_csum(struct net_device *netdev, u32 val)
++{
++	struct usbnet *dev = netdev_priv(netdev);
++	PADAPTER_DATA adapterData = (PADAPTER_DATA)(dev->data[0]);
++
++	adapterData->UseRxCsum = !!val;
++
++	return smsc9500_set_csums(dev);
++}
++#endif
++
++static void smsc9500_get_ethtool_stats(struct net_device *netdev,struct ethtool_stats *stats, u64 *data)
++{
++	struct usbnet *dev = netdev_priv(netdev);
++	PADAPTER_DATA adapterData = (PADAPTER_DATA)(dev->data[0]);
++	char statistics[sizeof(SMSC9500_RX_STATS) + sizeof(SMSC9500_TX_STATS)];
++	
++	
++	/* Get statistics counters */
++	if (smsc9500_get_stats(dev, statistics) > 0) {
++		UpdateStatCounters(dev,statistics);
++	}
++		
++	data[0] = dev->stats.rx_packets;
++	data[1] = dev->stats.tx_packets;
++	data[2] = dev->stats.rx_bytes;
++	data[3] = dev->stats.tx_bytes;
++	data[4] = dev->stats.rx_errors;
++	data[5] = dev->stats.tx_errors;
++	data[6] = dev->stats.tx_dropped;
++	data[7] = dev->stats.rx_dropped;
++	data[8] = dev->stats.rx_length_errors;
++	data[9] = dev->stats.rx_over_errors;
++	data[10] =dev->stats.rx_crc_errors;
++	data[11] = dev->stats.rx_frame_errors;
++	data[12] = adapterData->RxGoodFrames;
++	data[13] = adapterData->RxCrcErrors;
++	data[14] = adapterData->RxRuntFrameErrors;
++	data[15] = adapterData->RxAlignmentErrors;
++	data[16] = adapterData->RxFrameTooLongError;
++	data[17] = adapterData->RxLaterCollisionError;
++	data[18] = adapterData->RxBadFrames;
++	data[19] = adapterData->RxFifoDroppedFrames;
++	data[20] = adapterData->TxGoodFrames;
++	data[21] = adapterData->TxPauseFrames;
++	data[22] = adapterData->TxSingleCollisions;
++	data[23] = adapterData->TxMultipleCollisions;
++	data[24] = adapterData->TxExcessiveCollisionErrors;
++	data[25] = adapterData->TxLateCollisionErrors;
++	data[26] = adapterData->TxBufferUnderrunErrors;
++	data[27] = adapterData->TxExcessiveDeferralErrors;
++	data[28] = adapterData->TxCarrierErrors;
++	data[29] = adapterData->TxBadFrames;	
++}
++
++static void smsc9500_get_strings(struct net_device *netdev, u32 stringset,u8 *data)
++{
++	memcpy(data, ethtool_stats_keys, sizeof(ethtool_stats_keys));
++}
++#if (LINUX_VERSION_CODE < KERNEL_VERSION(2,6,24))
++static int smsc9500_get_sset_count(struct net_device *netdev) 
++{	
++	return ARRAY_SIZE(ethtool_stats_keys);
++}
++#else
++static int smsc9500_get_sset_count(struct net_device *netdev, int sset)
++
++{
++	switch (sset) {
++		case ETH_SS_STATS:
++			return ARRAY_SIZE(ethtool_stats_keys);
++
++		default:
++			return -EOPNOTSUPP;
++	}
++}
++#endif
++
++/* We need to override some ethtool_ops so we require our
++   own structure so we don't interfere with other usbnet
++   devices that may be connected at the same time. */
++static struct ethtool_ops smsc9500_ethtool_ops = {
++	.get_settings		= smsc9500_get_settings,
++	.set_settings		= smsc9500_set_settings,
++	.get_drvinfo		= smsc9500_get_drvinfo,
++	.get_regs_len		= smsc9500_regs_len,
++	.get_regs		= smsc9500_get_regs,
++	.get_wol		= smsc9500_get_wol,
++	.set_wol		= smsc9500_set_wol,
++	.get_msglevel		= smsc9500_get_msglevel,
++	.set_msglevel		= smsc9500_set_msglevel,
++	.nway_reset		= smsc9500_nway_reset,
++	.get_link		= smsc9500_get_link,	
++	.get_eeprom_len		= smsc9500_get_eeprom_len,
++	.get_eeprom		= smsc9500_get_eeprom,
++	.set_eeprom		= smsc9500_set_eeprom,
++#if (LINUX_VERSION_CODE <= KERNEL_VERSION(3,2,31))
++	.get_tx_csum		= smsc9500_ethtool_get_tx_csum,
++	.set_tx_csum		= smsc9500_ethtool_set_tx_csum,
++	.get_rx_csum		= smsc9500_ethtool_get_rx_csum,
++	.set_rx_csum		= smsc9500_ethtool_set_rx_csum,
++#endif
++	.get_strings		= smsc9500_get_strings,
++	.get_ethtool_stats	= smsc9500_get_ethtool_stats,
++#if (LINUX_VERSION_CODE < KERNEL_VERSION(2,6,24))
++	.get_stats_count	= smsc9500_get_sset_count,
++#else
++	.get_sset_count		= smsc9500_get_sset_count,
++#endif
++};
++
++static int Smsc9500_do_ioctl( struct net_device *netdev, struct ifreq *ifr, int cmd)
++{
++	u32 dwValue;
++	int result = 0;
++	void __user *userAddr = NULL;
++	struct usbnet *dev = netdev_priv(netdev);
++	PADAPTER_DATA adapterData = (PADAPTER_DATA)(dev->data[0]);
++
++	SMSC_TRACE(DBG_IOCTL, "Smsc9500_do_ioctl");
++
++	if (netdev == NULL) {
++		SMSC_WARNING("netdev == NULL");
++		result = -EFAULT;
++		goto DONE;
++	}
++
++	if(ifr == NULL) {
++		SMSC_WARNING("ifr == NULL");
++		result = -EFAULT;
++		goto DONE;
++	}
++	userAddr = ifr->ifr_data;
++
++	switch(cmd) {
++	case SIOCGMIIPHY:
++	case SIOCDEVPRIVATE:
++		SMSC_TRACE(DBG_IOCTL, "SIOCGMIIPHY");
++		if (adapterData->LanInitialized) {
++			struct mii_ioctl_data *miiData =
++				(struct mii_ioctl_data *) & (ifr->ifr_data);
++			miiData->phy_id = 1;
++		}
++		break;
++	case SIOCGMIIREG:
++	case SIOCDEVPRIVATE+1:
++		SMSC_TRACE(DBG_IOCTL, "SIOCGMIIREG");
++		if (MdioDisable & MDIO_DISABLE_IOCTL_ACCESS) {
++			SMSC_WARNING("Phy Mdio ioctl access disabled\n");
++			result = -EFAULT;
++			break;
++		}
++		if (adapterData->LanInitialized) {
++			struct mii_ioctl_data *miiData =
++				(struct mii_ioctl_data *) & (ifr->ifr_data);
++			if (smsc9500_read_phy(dev, miiData->reg_num, &dwValue) < 0) {
++				result = -EFAULT;
++			}
++			miiData->val_out = (u16)dwValue;
++		}
++		break;
++	case SIOCSMIIREG:
++	case SIOCDEVPRIVATE+2:
++		SMSC_TRACE(DBG_IOCTL, "SIOCSMIIREG");
++		if (MdioDisable & MDIO_DISABLE_IOCTL_ACCESS) {
++			SMSC_WARNING("Phy Mdio ioctl access disabled\n");
++			result = -EFAULT;
++			break;
++		}
++		if (adapterData->LanInitialized) {
++			struct mii_ioctl_data *miiData =
++				(struct mii_ioctl_data *) & (ifr->ifr_data);
++			dwValue = miiData->val_in;
++			if (smsc9500_write_phy(dev, miiData->reg_num, dwValue) < 0) {
++				result = -EFAULT;
++			}
++		}
++		break;
++	case SMSC9500_IOCTL:
++		result = smsc9500_private_ioctl(adapterData, dev, (PSMSC9500_IOCTL_DATA)userAddr);
++		break;
++
++	default:
++		result = -EOPNOTSUPP;
++		break;
++	}
++DONE:
++	return result;
++}
++
++static int smsc9500_private_ioctl(PADAPTER_DATA privateData, struct usbnet *dev, PSMSC9500_IOCTL_DATA ioctlData)
++{
++	int i;
++        BYTE cBuf;
++	BYTE *dataBuf;
++	u32 dwBuf, offset, len, phyAddr;
++	BOOLEAN success = FALSE;
++
++	if (ioctlData == NULL) {
++		return SMSC9500_FAIL;
++	}
++
++	if(ioctlData->dwSignature != SMSC9500_APP_SIGNATURE) {
++		goto DONE;
++	}
++
++	switch (ioctlData->dwCommand) {
++	case COMMAND_GET_SIGNATURE:
++		success = TRUE;
++		break;
++	case COMMAND_GET_CONFIGURATION:
++		privateData->eepromSize = smsc9500_eeprom_size(dev);
++		ioctlData->Data[0] = DRIVER_VERSION;
++		ioctlData->Data[1] = link_mode;
++		ioctlData->Data[2] = privateData->macAddrHi16;
++		ioctlData->Data[3] = privateData->MmacAddrLo32;
++		ioctlData->Data[4] = debug_mode;
++		ioctlData->Data[5] = privateData->dwIdRev;
++		ioctlData->Data[6] = privateData->dwFpgaRev;
++		ioctlData->Data[7] = 1;
++		ioctlData->Data[8] = privateData->dwPhyId;
++		ioctlData->Data[9] = privateData->bPhyModel;
++		ioctlData->Data[10] = privateData->bPhyRev;
++		ioctlData->Data[11] = privateData->dwLinkSpeed;
++		ioctlData->Data[12] = privateData->eepromSize / 128; //Unit is 128B
++		success = TRUE;
++		break;
++	case COMMAND_LAN_GET_REG:
++		offset = ioctlData->Data[0];
++		if ((ioctlData->Data[0] <= LAN_REGISTER_RANGE) && ((ioctlData->Data[0]&0x3UL)==0))
++		{
++			if (smsc9500_read_reg(dev, offset, &dwBuf) >= 0) {
++				ioctlData->Data[1] = dwBuf;
++				success=TRUE;
++			}
++		} else {
++			SMSC_WARNING("Reading LAN9500 Mem Map Failed");
++			goto MEM_MAP_ACCESS_FAILED;
++		}
++		break;
++	case COMMAND_LAN_SET_REG:
++		if((ioctlData->Data[0] <= LAN_REGISTER_RANGE) && ((ioctlData->Data[0]&0x3UL)==0)) {
++			offset = ioctlData->Data[0];
++			dwBuf = ioctlData->Data[1];
++			if(smsc9500_write_reg(dev, offset, dwBuf) >= 0) {
++				success = TRUE;
++			}
++		} else {
++			SMSC_WARNING("Writing LAN9500 Mem Map Failed");
++MEM_MAP_ACCESS_FAILED:
++			SMSC_WARNING("  Invalid offset == 0x%08lX",ioctlData->Data[0]);
++			if(ioctlData->Data[0] > LAN_REGISTER_RANGE) {
++				SMSC_WARNING("    Out of range");
++			}
++			if(ioctlData->Data[0]&0x3UL) {
++				SMSC_WARNING("    Not u32 aligned");
++			}
++		}
++		break;
++	case COMMAND_MAC_GET_REG:
++		if ((ioctlData->Data[0] >= MAC_REGISTER_RANGE_MIN) && 
++			(ioctlData->Data[0] <= MAC_REGISTER_RANGE_MAX) && 
++			((ioctlData->Data[0]&0x3UL)==0)) {
++			offset = ioctlData->Data[0];
++			if (smsc9500_read_reg(dev, offset, &dwBuf) >= 0) {
++				ioctlData->Data[1] = dwBuf;
++				success = TRUE;
++			}
++		} else {
++			SMSC_WARNING("Reading Mac Register Failed");
++			goto MAC_ACCESS_FAILURE;
++		}
++		break;
++	case COMMAND_MAC_SET_REG:
++		if ((ioctlData->Data[0] >= MAC_REGISTER_RANGE_MIN) && 
++			(ioctlData->Data[0] <= MAC_REGISTER_RANGE_MAX) && 
++			((ioctlData->Data[0]&0x3UL)==0)) {
++			offset = ioctlData->Data[0];
++			dwBuf = ioctlData->Data[1];
++			if (smsc9500_write_reg(dev, offset, dwBuf) >= 0) {
++				ioctlData->Data[1] = dwBuf;
++				success = TRUE;
++			}
++		} else {
++			SMSC_WARNING("Writing Mac Register Failed");
++MAC_ACCESS_FAILURE:
++			if (!(privateData->LanInitialized)) {
++				SMSC_WARNING("  LAN Not Initialized,");
++				SMSC_WARNING("    Use ifconfig to bring interface UP");
++			}
++			if (!((ioctlData->Data[0] >= MAC_REGISTER_RANGE_MIN)&& 
++				(ioctlData->Data[0] <= MAC_REGISTER_RANGE_MAX))) {
++				SMSC_WARNING("  Invalid index = 0x%08lX",ioctlData->Data[0]);
++			}
++		}
++		break;
++	case COMMAND_PHY_GET_REG:
++		if (MdioDisable & MDIO_DISABLE_IOCTL_ACCESS) {
++			SMSC_WARNING("Phy Mdio ioctl access disabled\n");
++			success = FALSE;
++			break;
++		}
++		if ((ioctlData->Data[0] < 32) && (privateData->LanInitialized)) {
++			offset = ioctlData->Data[0];
++			phyAddr = ioctlData->Data[1];
++			if (smsc9500_read_phy_address(dev, phyAddr, offset, &dwBuf) >= 0) {
++				ioctlData->Data[1] = dwBuf;
++				success = TRUE;
++			}
++		} else {
++			SMSC_WARNING("Reading Phy Register Failed");
++			if (!(privateData->LanInitialized)) {
++				SMSC_WARNING("  Lan Not Initialized,");
++				SMSC_WARNING("  Use ifconfig to bring interface UP");
++			}
++			if (!(ioctlData->Data[0] < 32)) {
++				SMSC_WARNING("  Invalid index == 0x%ld",ioctlData->Data[0]);
++			}
++		}
++		break;
++	case COMMAND_PHY_SET_REG:
++		if (MdioDisable & MDIO_DISABLE_IOCTL_ACCESS) {
++			SMSC_WARNING("Phy Mdio ioctl access disabled\n");
++			success = FALSE;
++			break;
++		}
++		if ((ioctlData->Data[0]<32) && (privateData->LanInitialized)) {
++			offset = ioctlData->Data[0];
++			dwBuf = ioctlData->Data[1];
++			phyAddr = ioctlData->Data[2];
++			if (smsc9500_write_phy_address(dev, phyAddr, offset, dwBuf) >= 0) {
++				success = TRUE;
++			}
++		} else {
++			SMSC_WARNING("Writing Phy Register Failed");
++			if (!(privateData->LanInitialized)) {
++				SMSC_WARNING("  Lan Not Initialized,");
++				SMSC_WARNING("  Use ifconfig to bring interface UP");
++			}
++			if (!(ioctlData->Data[0] < 32)) {
++				SMSC_WARNING("  Invalid index = 0x%ld",ioctlData->Data[0]);
++			}
++		}
++		break;
++	case COMMAND_GET_EEPROM:
++		offset = ioctlData->Data[0];
++		privateData->eepromSize = smsc9500_eeprom_size(dev);
++		if(offset < privateData->eepromSize) {
++			if(smsc9500_read_eeprom(dev, offset, 1, &cBuf) >= 0){
++				success = TRUE;
++				ioctlData->Data[1] = cBuf;
++			}
++		} else {
++		    SMSC_WARNING("Reading EEPROM Failed");
++		}
++		break;
++	case COMMAND_SET_EEPROM:
++		offset = ioctlData->Data[0];
++		cBuf = (BYTE)ioctlData->Data[1];
++		privateData->eepromSize = smsc9500_eeprom_size(dev);
++		if(offset < privateData->eepromSize) {
++		    if (smsc9500_write_eeprom(dev, offset, 1, &cBuf) >= 0) {
++			success = TRUE;
++		    }
++		} else {
++		    SMSC_WARNING("Writing EEPROM Failed");
++		    if (!(offset < privateData->eepromSize)) {
++			SMSC_WARNING("  Invalid eeprom offset == 0x%d",offset);
++		    }
++		}
++		break;
++	case COMMAND_SET_EEPROM_BUFFER:
++		offset = ioctlData->Data[0];
++		len = ioctlData->Data[1];
++		dataBuf = (BYTE *)&ioctlData->Data[2];
++		privateData->eepromSize = smsc9500_eeprom_size(dev);
++		if (offset < privateData->eepromSize) {
++		    if (smsc9500_write_eeprom(dev, offset, len, dataBuf) >= 0) {
++			success = TRUE;
++		    } 
++		} else {
++			SMSC_WARNING("Writing EEPROM Failed");
++			if (!(offset < privateData->eepromSize)) {
++				SMSC_WARNING("  Invalid eeprom offset == 0x%d",offset);
++			}
++		}
++		break;
++	case COMMAND_DUMP_LAN_REGS:
++		success = TRUE;
++		for(i = 0; i < MAX_LAN_REG_NUM; i++){
++			if (smsc9500_read_reg(dev, LanRegMap[i], &dwBuf) < 0) {
++				SMSC_WARNING("Failed to read LAN reg 0x%x", (unsigned int)LanRegMap[i]);
++				success = FALSE;
++			} else {
++				ioctlData->Data[i] = dwBuf;
++			}
++		}
++		break;
++	case COMMAND_DUMP_MAC_REGS:
++		if (privateData->LanInitialized) {
++			success=TRUE;
++			for(i=0; i<MAX_MAC_REG_NUM; i++){
++				if (smsc9500_read_reg(dev, MacRegMap[i], &dwBuf) < 0) {
++					SMSC_WARNING("Failed to read MAC reg 0x%x", (unsigned int)MacRegMap[i]);
++					success = FALSE;
++				} else {
++					ioctlData->Data[i] = dwBuf;
++				}
++	        	}
++		} else {
++			SMSC_WARNING("Mac Not Initialized,");
++			SMSC_WARNING("  Use ifconfig to bring interface UP");
++		}
++		break;
++	case COMMAND_DUMP_PHY_REGS:
++		if (MdioDisable & MDIO_DISABLE_IOCTL_ACCESS) {
++			SMSC_WARNING("Phy Mdio ioctl access disabled\n");
++			success = FALSE;
++			break;
++		}
++		if (privateData->LanInitialized) {
++			success = TRUE;
++			for(i=0; i<MAX_PHY_REG_NUM; i++) {
++				if (smsc9500_read_phy(dev, PhyRegMap[i], &dwBuf) < 0){
++					SMSC_WARNING("Failed to read PHY reg 0x%x", (unsigned int)PhyRegMap[i]);
++					success = FALSE;
++				} else {
++					ioctlData->Data[i] = dwBuf;
++				}
++			}
++		} else {
++			SMSC_WARNING("Phy Not Initialized,");
++			SMSC_WARNING("  Use ifconfig to bring interface UP");
++		}
++		break;
++	case COMMAND_DUMP_EEPROM:
++		success = TRUE;
++		privateData->eepromSize = smsc9500_eeprom_size(dev);
++		if(smsc9500_read_eeprom(dev, 0, privateData->eepromSize,  (BYTE*)ioctlData->Data) < 0) {
++			success = FALSE;
++		}
++		break;
++	case COMMAND_GET_MAC_ADDRESS:
++		if (privateData->LanInitialized) {
++			CHECK_RETURN_STATUS(smsc9500_read_reg(dev, ADDRH, &dwBuf));
++			ioctlData->Data[0] = dwBuf;
++			CHECK_RETURN_STATUS(smsc9500_read_reg(dev, ADDRL, &dwBuf));
++			ioctlData->Data[1] = dwBuf;
++			success = TRUE;
++		} else {
++			SMSC_WARNING("Lan Not Initialized,");
++			SMSC_WARNING("  Use ifconfig to bring interface UP");
++		}
++		break;
++	case COMMAND_SET_MAC_ADDRESS:
++		if(privateData->LanInitialized) {
++			u32 dwLow32 = ioctlData->Data[1];
++			u32 dwHigh16 = ioctlData->Data[0];
++
++			if ((((dwHigh16 & 0xFFFF) == 0x0UL) && (dwLow32 == 0x0UL))
++				|| (0x01 & LOBYTE(LOWORD(dwLow32)))) {
++				SMSC_WARNING("Not a Valid MAC Address");
++			} else {
++				CHECK_RETURN_STATUS(smsc9500_write_reg(dev, ADDRH, dwHigh16));
++				CHECK_RETURN_STATUS(smsc9500_write_reg(dev, ADDRL, dwLow32));
++				dev->net->dev_addr[0]=LOBYTE(LOWORD(dwLow32));
++				dev->net->dev_addr[1]=HIBYTE(LOWORD(dwLow32));
++				dev->net->dev_addr[2]=LOBYTE(HIWORD(dwLow32));
++				dev->net->dev_addr[3]=HIBYTE(HIWORD(dwLow32));
++				dev->net->dev_addr[4]=LOBYTE(LOWORD(dwHigh16));
++				dev->net->dev_addr[5]=HIBYTE(LOWORD(dwHigh16));
++				success = TRUE;
++			} 
++		} else {
++			SMSC_WARNING("Lan Not Initialized,");
++			SMSC_WARNING("Use ifconfig to bring interface UP");
++		}
++		break;
++	case COMMAND_LOAD_MAC_ADDRESS:
++		if (privateData->LanInitialized) {
++			if (privateData->eepromContentValid == TRUE) {
++				if(smsc9500_read_eeprom(dev, EEPROM_MAC_OFFSET, 6,  dev->net->dev_addr) == 0) {
++					dwBuf = dev->net->dev_addr[0] | dev->net->dev_addr[1] << 8 | 
++						dev->net->dev_addr[2] << 16 | dev->net->dev_addr[3] << 24;
++					ioctlData->Data[1] = dwBuf;
++					CHECK_RETURN_STATUS(smsc9500_write_reg(dev, ADDRL, ioctlData->Data[1]));
++					dwBuf = dev->net->dev_addr[4] | dev->net->dev_addr[5] << 8;
++					ioctlData->Data[0] = dwBuf;
++					CHECK_RETURN_STATUS(smsc9500_write_reg(dev, ADDRH, ioctlData->Data[0]));
++					success = TRUE;
++				} else {
++					SMSC_WARNING("Failed to Load Mac Address");
++				}
++			} else {
++				SMSC_WARNING("EEPROM contents not valid");
++			}	
++		} else {
++			SMSC_WARNING("Lan Not Initialized");
++			SMSC_WARNING("Use ifconfig to bring interface UP");
++		}
++		break;
++	case COMMAND_SAVE_MAC_ADDRESS:
++		if (privateData->LanInitialized) {
++			if (privateData->eepromContentValid == TRUE) {
++				u32 dwLow32 = ioctlData->Data[1];
++				u32 dwHigh16 = ioctlData->Data[0];
++
++				cpu_to_le32s((u32*)&dwLow32);
++				cpu_to_le32s((u32*)&dwHigh16);
++
++				if ((smsc9500_write_eeprom(dev, EEPROM_MAC_OFFSET, 4, (BYTE*)&dwLow32) == 0) &&
++					(smsc9500_write_eeprom(dev, EEPROM_MAC_OFFSET+4, 2, (BYTE*)&dwHigh16) == 0)) {
++					success = TRUE;
++				}
++			} else {
++				SMSC_WARNING("EEPROM contents not valid");
++			}
++		} else {
++			SMSC_WARNING("Lan Not Initialized,");
++			SMSC_WARNING("Use ifconfig to bring interface UP");
++		}
++		break;
++	case COMMAND_SET_DEBUG_MODE:
++		debug_mode = ioctlData->Data[0];
++		if (debug_mode & 0x04UL) {
++			CHECK_RETURN_STATUS(smsc9500_write_reg(dev, GPIO_CFG, 0x00670700UL));
++			success = TRUE;
++		} else {
++			CHECK_RETURN_STATUS(smsc9500_write_reg(dev, GPIO_CFG, 0x70070000));
++			success = TRUE;
++		}
++		success = TRUE;
++		break;
++	case COMMAND_SET_LINK_MODE:
++		link_mode = (ioctlData->Data[0] & 0x7FUL);
++		if (privateData->LanInitialized) {
++			phy_SetLink(dev, link_mode);
++		}
++		success = TRUE;
++		break;
++	case COMMAND_GET_LINK_MODE:
++		ioctlData->Data[0] = link_mode;
++		success = TRUE;
++		break;
++	case COMMAND_CHECK_LINK:
++		Phy_UpdateLinkMode(dev);
++		success = TRUE;
++		break;
++	case COMMAND_SET_LINK_STATUS:
++		if (!(MdioDisable & MDIO_DISABLE_INTERNAL_ACCESS)) {
++			SMSC_WARNING("This ioctl available only when Phy Mdio internal access disabled\n");
++			success = FALSE;
++			break;
++		}
++		/* Assign the link status from user, link check will
++		set the link */
++		privateData->DefaultLinkStatus = (ioctlData->Data[0] & 0x1UL); 
++		success = TRUE;
++		break;
++	case COMMAND_GET_LINK_STATUS:
++		if (!(MdioDisable & MDIO_DISABLE_INTERNAL_ACCESS)) {
++			SMSC_WARNING("This ioctl available only when Phy Mdio internal access disabled\n");
++			success = FALSE;
++			break;
++		}
++		ioctlData->Data[0] = privateData->DefaultLinkStatus & MDIO_DEFAULT_LINK_INIT_MASK;
++		success = TRUE;
++		break;
++	case COMMAND_GET_ERRORS:
++		ioctlData->Data[0] = dev->extra_error_cnts.tx_epipe;
++		ioctlData->Data[1] = dev->extra_error_cnts.tx_eproto;
++		ioctlData->Data[2] = dev->extra_error_cnts.tx_etimeout;
++		ioctlData->Data[3] = dev->extra_error_cnts.tx_eilseq;
++
++		ioctlData->Data[4] = dev->extra_error_cnts.rx_epipe;
++		ioctlData->Data[5] = dev->extra_error_cnts.rx_eproto;
++		ioctlData->Data[6] = dev->extra_error_cnts.rx_etimeout;
++		ioctlData->Data[7] = dev->extra_error_cnts.rx_eilseq;
++		ioctlData->Data[8] = dev->extra_error_cnts.rx_eoverflow;
++		success = TRUE;
++		break;
++	case COMMAND_READ_BYTE:
++		ioctlData->Data[1] = (*((volatile BYTE *)(ioctlData->Data[0])));
++		success = TRUE;
++		break;
++	case COMMAND_READ_WORD:
++		ioctlData->Data[1] = (*((volatile u16 *)(ioctlData->Data[0])));
++		success = TRUE;
++		break;
++	case COMMAND_READ_DWORD:
++		ioctlData->Data[1] = (*((volatile u32 *)(ioctlData->Data[0])));
++		success = TRUE;
++		break;
++	case COMMAND_WRITE_BYTE:
++		(*((volatile BYTE *)(ioctlData->Data[0])))= ((BYTE)(ioctlData->Data[1]));
++		success = TRUE;
++		break;
++	case COMMAND_WRITE_WORD:
++		(*((volatile u16 *)(ioctlData->Data[0])))= ((u16)(ioctlData->Data[1]));
++		success = TRUE;
++		break;
++	case COMMAND_WRITE_DWORD:
++		(*((volatile u32 *)(ioctlData->Data[0])))= ((u32)(ioctlData->Data[1]));
++		success = TRUE;
++		break;
++	case COMMAND_SET_AMDIX_STS:
++		auto_mdix = (ioctlData->Data[0]);
++		if (privateData->LanInitialized) {
++			Phy_SetAutoMdix(dev, (u16)auto_mdix);
++		}
++		success = TRUE;
++		break;
++	case COMMAND_GET_AMDIX_STS:
++		ioctlData->Data[0] = auto_mdix;
++		success = TRUE;
++		break;
++
++	default:
++		break;
++	}
++
++DONE:
++	if ((success) && (ioctlData!=NULL)) {
++		ioctlData->dwSignature = SMSC9500_DRIVER_SIGNATURE;
++		return SMSC9500_SUCCESS;
++	}
++	return SMSC9500_FAIL;
++}
++
++static int smsc9500_eth_mac_addr(struct net_device *netdev, void *p)
++{
++	struct sockaddr *addr = p;
++	struct usbnet *dev = netdev_priv(netdev);
++	PADAPTER_DATA adapterData = (PADAPTER_DATA)(dev->data[0]);
++
++        if (netif_running(netdev))
++                return -EBUSY;
++        if (!is_valid_ether_addr((u8 *)addr->sa_data))
++                return -EADDRNOTAVAIL;
++        memcpy(dev->net->dev_addr, addr->sa_data, ETH_ALEN);
++
++	adapterData->MmacAddrLo32 = dev->net->dev_addr[0] | dev->net->dev_addr[1] << 8 |
++		dev->net->dev_addr[2] << 16 | dev->net->dev_addr[3] << 24;
++	adapterData->macAddrHi16 = dev->net->dev_addr[4] | dev->net->dev_addr[5] << 8;
++
++	return 0;
++}
++
++#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,29))
++static const struct net_device_ops smsc95xx_netdev_ops = 
++{
++        .ndo_open               = smscusbnet_open,
++        .ndo_stop               = smscusbnet_stop,
++        .ndo_start_xmit         = smscusbnet_start_xmit,
++        .ndo_tx_timeout         = smscusbnet_tx_timeout,
++        .ndo_change_mtu         = smscusbnet_change_mtu,
++        .ndo_set_mac_address    = smsc9500_eth_mac_addr,
++        .ndo_validate_addr      = eth_validate_addr,
++        .ndo_do_ioctl           = Smsc9500_do_ioctl,
++#if (LINUX_VERSION_CODE <= KERNEL_VERSION(3,1,10))
++	.ndo_set_multicast_list = smsc9500_set_multicast,
++#else
++	.ndo_set_rx_mode=smsc9500_set_multicast,
++#endif
++        .ndo_get_stats          = smscusbnet_get_stats,
++};
++#endif //linux 2.6.29
++
++static int smsc9500_bind(struct usbnet *dev, struct usb_interface *intf)
++{
++	u32 dwBuf;
++	int ret = 0;
++	PADAPTER_DATA adapterData = NULL;
++	char version[15];
++
++	SMSC_TRACE(DBG_INIT, "smsc9500_bind");
++
++	/* Init system control and status regsiter map */
++	LanRegMap[LAN_REG_ID_REV] = ID_REV;
++	LanRegMap[LAN_REG_FPGA_REV] = FPGA_REV;
++	LanRegMap[LAN_REG_INT_STS] = INT_STS;
++	LanRegMap[LAN_REG_RX_CFG] = RX_CFG;
++	LanRegMap[LAN_REG_TX_CFG] = TX_CFG;
++	LanRegMap[LAN_REG_HW_CFG] = HW_CFG;
++	LanRegMap[LAN_REG_RX_FIFO_INF] = RX_FIFO_INF;
++	LanRegMap[LAN_REG_TX_FIFO_INF] = TX_FIFO_INF;
++	LanRegMap[LAN_REG_PMT_CTRL] = PM_CTRL;
++	LanRegMap[LAN_REG_LED_GPIO_CFG] = LED_GPIO_CFG;
++	LanRegMap[LAN_REG_GPIO_CFG] = GPIO_CFG;
++	LanRegMap[LAN_REG_AFC_CFG] = AFC_CFG;
++	LanRegMap[LAN_REG_E2P_CMD] = E2P_CMD;
++	LanRegMap[LAN_REG_E2P_DATA] = E2P_DATA;
++	LanRegMap[LAN_REG_BURST_CAP] = BURST_CAP;
++	LanRegMap[LAN_REG_STRAP_DBG] = STRAP_DBG;
++	LanRegMap[LAN_REG_DP_SEL] = DP_SEL;
++	LanRegMap[LAN_REG_DP_CMD] = DP_CMD;
++	LanRegMap[LAN_REG_DP_ADDR] = DP_ADDR;
++	LanRegMap[LAN_REG_DP_DATA0] = DP_DATA0;
++	LanRegMap[LAN_REG_DP_DATA1] = DP_DATA1;
++	LanRegMap[LAN_REG_GPIO_WAKE] = GPIO_WAKE;
++	LanRegMap[LAN_REG_INT_EP_CTL] = INT_EP_CTL;
++	LanRegMap[LAN_REG_BULK_IN_DLY] = BULK_IN_DLY;
++
++	/* Init MAC register map */
++	MacRegMap[MAC_REG_MAC_CR] = MAC_CR;
++	MacRegMap[MAC_REG_ADDRH] = ADDRH;
++	MacRegMap[MAC_REG_ADDRL] = ADDRL;
++	MacRegMap[MAC_REG_HASHH] = HASHH;
++	MacRegMap[MAC_REG_HASHL] = HASHL;
++	MacRegMap[MAC_REG_MII_ADDR] = MII_ADDR;
++	MacRegMap[MAC_REG_MII_DATA] = MII_DATA;
++	MacRegMap[MAC_REG_FLOW] = FLOW;
++	MacRegMap[MAC_REG_VLAN1] = VLAN1;
++	MacRegMap[MAC_REG_VLAN2] = VLAN2;
++	MacRegMap[MAC_REG_WUFF] = WUFF;
++	MacRegMap[MAC_REG_WUCSR] = WUCSR;
++	MacRegMap[MAC_REG_COE_CR] = COE_CR;
++
++	/* Init PHY map */
++	PhyRegMap[PHY_REG_BCR] = PHY_BCR;
++	PhyRegMap[PHY_REG_BSR] = PHY_BSR;
++	PhyRegMap[PHY_REG_ID1] = PHY_ID_1;
++	PhyRegMap[PHY_REG_ID2] = PHY_ID_2;
++	PhyRegMap[PHY_REG_ANEG_ADV] = PHY_ANEG_ADV;
++	PhyRegMap[PHY_REG_ANEG_LPA] = PHY_ANEG_LPA;
++	PhyRegMap[PHY_REG_ANEG_ER] = PHY_ANEG_REG;
++	PhyRegMap[PHY_REG_SILICON_REV] = PHY_SILICON_REV;
++	PhyRegMap[PHY_REG_MODE_CTRL_STS] = PHY_MODE_CTRL_STS;
++	PhyRegMap[PHY_REG_SPECIAL_MODES] = PHY_SPECIAL_MODES;
++	PhyRegMap[PHY_REG_TSTCNTL] = PHY_TSTCNTL;
++	PhyRegMap[PHY_REG_TSTREAD1] = PHY_TSTREAD1;
++	PhyRegMap[PHY_REG_TSTREAD2] = PHY_TSTREAD2;
++	PhyRegMap[PHY_REG_TSTWRITE] = PHY_TSTWRITE;
++	PhyRegMap[PHY_REG_SPECIAL_CTRL_STS] = PHY_SPECIAL_CTRL_STS;
++	PhyRegMap[PHY_REG_SITC] = PHY_SITC;
++	PhyRegMap[PHY_REG_INT_SRC] = PHY_INT_SRC;
++	PhyRegMap[PHY_REG_INT_MASK] = PHY_INT_MASK;
++	PhyRegMap[PHY_REG_SPECIAL] = PHY_SPECIAL;
++
++	sprintf(version,"%lX.%02lX.%02lX",
++		(DRIVER_VERSION >> 16),(DRIVER_VERSION >> 8)&0xFF,(DRIVER_VERSION&0xFFUL));
++	SMSC_TRACE(DBG_INIT, "Driver smsc9500.ko verison %s",version);
++
++	ret = smscusbnet_get_endpoints(dev,intf);
++	if (ret < 0)
++		goto out1;
++
++	dev->data[0] = (unsigned long) kmalloc(sizeof(ADAPTER_DATA),GFP_KERNEL);
++
++	if ((PADAPTER_DATA)dev->data[0] == NULL) {
++		SMSC_WARNING("Unable to allocate ADAPTER_DATA");
++		ret = -ENOMEM;
++		goto out1;
++	}
++	memset((PADAPTER_DATA)dev->data[0],0,sizeof(ADAPTER_DATA));
++	adapterData = (PADAPTER_DATA)(dev->data[0]);
++
++	sema_init(&adapterData->phy_mutex, 1);
++	sema_init(&adapterData->eeprom_mutex, 1);
++	sema_init(&adapterData->internal_ram_mutex, 1);
++	sema_init(&adapterData->RxFilterLock, 1);
++
++	if ((ret = smsc9500_read_reg(dev,HW_CFG,&dwBuf)< 0)) {
++		SMSC_WARNING("Failed to read HW_CFG: %d", ret);
++		return ret;
++	}
++	if (dwBuf & HW_CFG_SMDET_STS) {
++		SMSC_TRACE(DBG_INIT, "Come back from net detach");
++	}
++
++	adapterData->macAddrHi16 = mac_addr_hi16;
++	adapterData->MmacAddrLo32 = mac_addr_lo32;
++
++	/* set initial value for eeprom related variables */
++	adapterData->eepromContentValid = IsEepromContentValid(dev);
++
++	adapterData->LinkActLedCfg = LinkActLedCfg;
++	adapterData->LinkLedOnGpio = LinkLedOnGpio;
++	adapterData->LinkLedOnGpioBufType = LinkLedBufType;
++	adapterData->LinkLedOnGpioPolarity = LinkLedPolarity;
++
++	adapterData->eepromSize = smsc9500_eeprom_size(dev);
++
++	/* Reset and Init all registers */
++	ret = smsc9500_reset(dev);
++	if (ret < 0)
++		goto out1;
++
++#if (LINUX_VERSION_CODE < KERNEL_VERSION(2,6,29))
++	dev->net->do_ioctl = Smsc9500_do_ioctl;
++	dev->net->set_multicast_list = smsc9500_set_multicast;
++	dev->net->set_mac_address = smsc9500_eth_mac_addr;
++#else
++        dev->net->netdev_ops = &smsc95xx_netdev_ops;
++#endif 
++	dev->net->ethtool_ops = &smsc9500_ethtool_ops;
++	dev->net->flags |= IFF_MULTICAST;
++	dev->linkDownSuspend = linkdownsuspend;
++	dev->dynamicSuspend = dynamicsuspend;
++
++	if (dev->udev->config->desc.bmAttributes & USB_CONFIG_ATT_WAKEUP) {
++		SMSC_TRACE(DBG_INIT, "The device is configed to support remote wakes");
++	} else {
++		SMSC_WARNING("The device not configed to support remote wakes, " 
++			"Over write to disable linkdownsuspend and dynamicsuspend");
++		if (dev->dynamicSuspend || dev->linkDownSuspend) {
++			dev->dynamicSuspend = dev->linkDownSuspend = 0;
++		}
++	} 
++	if (dev->linkDownSuspend && (MdioDisable & MDIO_DISABLE_INTERNAL_ACCESS)) {
++		SMSC_WARNING("linkdownsuspend cannot be supported when mdio access is disabled, "
++			"Over write to disable linkdownsuspend\n");
++		dev->linkDownSuspend = 0;
++	}
++	
++#ifndef CONFIG_PM
++	if (dev->dynamicSuspend || dev->linkDownSuspend) {
++		SMSC_WARNING("Power management has to be enabled in the kernel configuration "
++			"to support dynamicsuspend and linkdownsuspend");
++		dev->dynamicSuspend = dev->linkDownSuspend = 0;
++	}
++#endif //CONFIG_PM
++	if (dev->chipDependFeatures[FEATURE_SMARTDETACH]) {
++		dev->netDetach = netdetach;
++		/* If net detach is enabled, link down suspend should be disabled */
++		if (dev->netDetach)
++			dev->linkDownSuspend = 0;
++	}
++#if (LINUX_VERSION_CODE > KERNEL_VERSION(2,6,18)) && defined(CONFIG_PM)
++	if (dev->dynamicSuspend || dev->linkDownSuspend) {
++#if ((LINUX_VERSION_CODE > KERNEL_VERSION(2,6,21)) && (LINUX_VERSION_CODE < KERNEL_VERSION(2,6,35)))
++		if (dev->udev->autosuspend_disabled) {
++#endif
++			SMSC_WARNING("Autosuspend should be enabled by "
++				"shell cmd \"echo auto > /sys/bus/usb/devices/X-XX/power/level\"");
++#if ((LINUX_VERSION_CODE > KERNEL_VERSION(2,6,21)) && (LINUX_VERSION_CODE < KERNEL_VERSION(2,6,35)))
++		}
++#endif
++	}
++#endif
++	adapterData->UseTxCsum = tx_Csum;
++	adapterData->UseRxCsum = rx_Csum;
++	if (tx_Csum)
++		SMSC_TRACE(DBG_INIT, "Tx HW Checksum");
++	if (rx_Csum)
++		SMSC_TRACE(DBG_INIT, "Rx HW Checksum");
++
++	if (adapterData->UseTxCsum)
++		dev->net->features = (NETIF_F_HW_CSUM);
++	else
++		dev->net->features = 0;
++
++	adapterData->dwTxQueueDisableMask = 0;
++	spin_lock_init(&(adapterData->TxQueueLock));
++	adapterData->TxInitialized = TRUE;
++	adapterData->WolWakeupOpts = WAKE_PHY;
++	adapterData->LanInitialized = TRUE;
++
++	/* Indicate carrier off explicitly. Link check will indicate if link is up */
++	netif_carrier_off(dev->net);
++	/* Get the default link status for MDIO-less operation */
++	adapterData->DefaultLinkStatus = MdioDefaultLinkStatus; 
++
++	SMSC_TRACE(DBG_INIT, "smsc9500_bind, return 0");
++	return 0;
++out1:
++	if (adapterData != NULL){
++		kfree(adapterData);
++		adapterData = NULL;
++	}
++	SMSC_TRACE(DBG_INIT, "smsc9500_bind, return %x", ret);
++	return ret;
++}
++
++
++static void smsc9500_unbind(struct usbnet *dev, struct usb_interface *intf)
++{
++	PADAPTER_DATA adapterData = (PADAPTER_DATA)(dev->data[0]);
++	SMSC_TRACE(DBG_CLOSE, "smsc9500_unbind");
++
++	if (adapterData != NULL) {
++		SMSC_TRACE(DBG_CLOSE, "free adapterData");
++		kfree(adapterData);
++		adapterData = NULL;
++	}
++}
++
++static int smsc9500_rx_fixup(struct usbnet *dev, struct sk_buff *skb)
++{
++	u16 size;
++	char *packet;
++	struct sk_buff *ax_skb;
++	u32 header, AlignCount = 0;
++	int ret = RX_FIXUP_VALID_SKB;
++	u16 *vlan_tag;
++
++	PADAPTER_DATA adapterData = (PADAPTER_DATA)(dev->data[0]);
++
++	SMSC_TRACE(DBG_RX, "smsc9500_rx_fixup");
++
++	while (skb->len > 0) {
++		memcpy(&header, skb->data, sizeof(header));
++		le32_to_cpus(&header);
++		skb_pull(skb, 4 + RX_OFFSET);
++		packet = (char *)skb->data;
++
++		/* get the packet length */
++		size = (u16) ((header & RX_STS_FL_) >> 16);
++		AlignCount = (STATUS_WORD_LEN - ((size + RX_OFFSET) % STATUS_WORD_LEN)) % STATUS_WORD_LEN;
++
++		if (header & RX_STS_ES_) {
++			dev->stats.rx_errors++;
++			if (header & RX_STS_CRC_) {
++				dev->stats.rx_crc_errors++;
++			} else {
++				if (header & (RX_STS_TL_ | RX_STS_RF_)) {
++					dev->stats.rx_frame_errors++;
++				}
++				if (((header & RX_STS_LE_) != 0L) && ((header & RX_STS_FT_) == 0L)) {
++					dev->stats.rx_length_errors++;
++				}
++			}
++			/* last packet */
++			if (size == skb->len) {
++				return RX_FIXUP_INVALID_SKB;
++			} else {
++				skb_pull(skb, size + AlignCount);
++				if (skb->len == 0) {
++					return RX_FIXUP_INVALID_SKB;
++				}
++				continue;
++			}
++		}
++
++		if ((size == skb->len)) {
++			if (adapterData->UseRxCsum) {
++				u16 wHwCsum;
++#ifdef NET_SKBUFF_DATA_USES_OFFSET
++				wHwCsum = *(u16*)(skb_tail_pointer(skb) - 2);
++#else
++				wHwCsum = *(u16*)(skb->tail - 2);
++#endif
++				skb->csum = wHwCsum;
++			}
++
++			if (adapterData->UseRxCsum) {
++				skb->ip_summed = CHECKSUM_COMPLETE;
++			} else {
++				skb->ip_summed = CHECKSUM_NONE;
++			}
++
++			if (adapterData->UseRxCsum) {
++				skb_trim(skb, size - 2 - 4);
++
++			} else {
++				skb_trim(skb, size - 4);
++			}
++
++			if (dev->rx_skb_copy) { 
++				if (dev->turbo_mode) {
++					ax_skb = alloc_skb(skb->len + dev->net_ip_align, GFP_ATOMIC);
++					skb_reserve(ax_skb, dev->net_ip_align);
++					skb_put(ax_skb, skb->len);
++					memcpy(ax_skb->data, skb->data, skb->len);
++
++					vlan_tag = (u16*)&ax_skb->cb[0];
++					*vlan_tag = VLAN_DUMMY; //Reserved value
++					smscusbnet_skb_return(dev, ax_skb);
++					ret = RX_FIXUP_INVALID_SKB;
++				} else {
++					if (dev->rx_use_prealloc_buffs) {
++						ax_skb = alloc_skb(skb->len + dev->net_ip_align, GFP_ATOMIC);
++						skb_reserve(ax_skb, dev->net_ip_align);
++						skb_put(ax_skb, skb->len);
++						memcpy(ax_skb->data, skb->data, skb->len);
++
++						vlan_tag = (u16*)&ax_skb->cb[0];
++						*vlan_tag = VLAN_DUMMY; //Reserved value
++						smscusbnet_skb_return(dev, ax_skb);
++						ret = RX_FIXUP_INVALID_SKB;
++					} else {
++						ret = RX_FIXUP_VALID_SKB;
++						vlan_tag = (u16*)&skb->cb[0];
++						*vlan_tag = VLAN_DUMMY; //Reserved value
++					}
++				}
++			} else {
++				/* FIXME: We are not supposed to change truesize,
++				but this is the easy way to cheat kernel without
++				memory copy */
++				skb->truesize = skb->len + sizeof(struct sk_buff);
++				vlan_tag = (u16*)&skb->cb[0];
++				*vlan_tag = VLAN_DUMMY; //Reserved value
++			}
++			return ret;
++		}
++
++		if (size > (ETH_FRAME_LEN+12)) {//  ETH_FRAME_LEN+4(CRC)+2(COE)+4(Vlan)
++			SMSC_TRACE(DBG_RX, "size > (ETH_FRAME_LEN+12), hearder = 0x%08x", header);
++			return RX_FIXUP_ERROR;
++		}
++
++		if (dev->rx_skb_copy) {
++			ax_skb = alloc_skb(size + dev->net_ip_align, GFP_ATOMIC);
++			skb_reserve(ax_skb, dev->net_ip_align);
++		} else {
++			ax_skb = skb_clone(skb, GFP_ATOMIC);
++		}
++
++		if (ax_skb) {
++			if (dev->rx_skb_copy) {
++				skb_put(ax_skb, size);
++				memcpy(ax_skb->data, packet, size);
++			} else {
++				ax_skb->len = size;
++				ax_skb->data = (u8 *)packet;
++				skb_trim(ax_skb, 0);
++				skb_put(ax_skb, size);
++			}
++
++			if (adapterData->UseRxCsum) {
++				u16 wHwCsum;
++#ifdef NET_SKBUFF_DATA_USES_OFFSET
++				wHwCsum = *(u16*)(skb_tail_pointer(ax_skb) - 2);
++#else
++				wHwCsum = *(u16*)(ax_skb->tail - 2);
++#endif
++				ax_skb->csum = wHwCsum;
++			}
++
++			if (adapterData->UseRxCsum) {
++				ax_skb->ip_summed = CHECKSUM_COMPLETE;
++			} else {
++				ax_skb->ip_summed = CHECKSUM_NONE;
++			}
++
++			if (adapterData->UseRxCsum) {
++				skb_trim(ax_skb, size-2-4);
++
++			} else {
++				skb_trim(ax_skb, size-4);
++			}
++
++			if (!dev->rx_skb_copy) {
++				/* FIXME: We are not supposed to change truesize,
++				but this is the easy way to cheat kernel without
++				memory copy */
++				ax_skb->truesize = ax_skb->len + sizeof(struct sk_buff);
++			}
++
++			vlan_tag = (u16*)&ax_skb->cb[0];
++			*vlan_tag = VLAN_DUMMY; //Reserved value
++			smscusbnet_skb_return(dev, ax_skb);
++		} else {
++			SMSC_TRACE(DBG_RX, "no ax_skb");
++			return RX_FIXUP_ERROR;
++		}
++
++		skb_pull(skb, size + AlignCount);
++
++		if (skb->len == 0) {
++			SMSC_TRACE(DBG_RX, "skb->len == 0 left");
++			break;
++		}
++	}
++
++	if (skb->len < 0) {
++		SMSC_WARNING("invalid rx length < 0 %d", skb->len);
++		return RX_FIXUP_ERROR;
++	}
++
++	return ret;
++}
++
++static struct sk_buff *smsc9500_tx_fixup(struct usbnet *dev, struct sk_buff *skb, int flags)
++{
++	int i;
++	u8 * prt;
++	u32 TxCommandA,TxCommandB;
++	int headroom = skb_headroom(skb);
++	int tailroom = skb_tailroom(skb);
++	int SkbSize, CopySize, AlignmentSize;
++	unsigned skbFragCnt = skb_shinfo(skb)->nr_frags + 1;
++	PADAPTER_DATA adapterData = (PADAPTER_DATA)(dev->data[0]);
++
++	SMSC_TRACE(DBG_TX, "smsc9500_tx_fixup");
++
++	if (adapterData->UseTxCsum) {
++		u32 dwTxCsumPreamble = 0;
++		if (skb->ip_summed == CHECKSUM_PARTIAL) {
++#if (LINUX_VERSION_CODE < KERNEL_VERSION(2,6,22))
++			int Chsum_start_offset = 0;
++			CalculateTxChecksumOffset( skb, &Chsum_start_offset);
++
++			/* tx checksum problem workaround */
++			if (skb->len <= 45) {
++				u32 csum;
++				csum = csum_partial(skb->data + Chsum_start_offset, 
++					skb->len - (skb->data + Chsum_start_offset - skb->data), 0);
++				*((u16 *)(skb->data + Chsum_start_offset + skb->csum)) = csum_fold(csum);
++				goto Non_CheckSumOffLoad;
++			}
++			dwTxCsumPreamble = (((u16) (Chsum_start_offset + skb->csum)) << 16) | ((u16) Chsum_start_offset);
++#else
++			/* tx checksum problem workaround */
++			if (skb->len <= 45) {
++				u32 csum;
++				csum = csum_partial(skb->head + skb->csum_start, skb->len - 
++					(skb->head + skb->csum_start - skb->data), 0);
++				*((u16 *)(skb->head + (skb->csum_start + skb->csum_offset))) = csum_fold(csum);
++				goto Non_CheckSumOffLoad;
++			}
++			dwTxCsumPreamble = (((u16) (skb->csum_offset+skb->csum_start-(skb->data - skb->head))) << 16)
++				 | ((u16) (skb->csum_start-(skb->data - skb->head)));
++#endif
++		}
++		if(skb->ip_summed == CHECKSUM_PARTIAL) {
++			if (skbFragCnt == 1) {
++				/* ip_summed, one Fragament */
++				SMSC_TRACE(DBG_TX, "ip_summed, Onefrag");
++
++				AlignmentSize = skb->len % STATUS_WORD_LEN;
++				if(AlignmentSize)AlignmentSize = STATUS_WORD_LEN - AlignmentSize;
++				if (tx_skb_clone && (!skb_cloned(skb))
++   					 && ((headroom + tailroom) >= (12 + AlignmentSize))) {
++					if( (headroom < 12 ) || (tailroom < AlignmentSize) ){
++						skb->data = memmove(skb->head +12, skb->data, skb->len);
++						SkbSize = skb->len;
++						skb_trim(skb, 0);
++						skb_put(skb, SkbSize);
++					}
++				} else {
++					struct sk_buff *skb2;
++					skb2 = skb_copy_expand(skb, 12, AlignmentSize, flags);
++					dev_kfree_skb_any(skb);
++					skb = skb2;
++					if (!skb)
++						return NULL;
++				}
++
++				skb_push(skb, STATUS_WORD_LEN);
++				memcpy(skb->data, &dwTxCsumPreamble, STATUS_WORD_LEN);
++
++				skb_push(skb, STATUS_WORD_LEN);
++				TxCommandB = (u32)(skb->len-STATUS_WORD_LEN)|TX_CMD_B_CSUM_ENABLE;
++				cpu_to_le32s((u32*)&TxCommandB);
++				memcpy(skb->data, &TxCommandB, STATUS_WORD_LEN);
++				skb_push(skb, STATUS_WORD_LEN);
++				TxCommandA = TX_CMD_A_FIRST_SEG_ | TX_CMD_A_LAST_SEG_ | (u32)(skb->len-8);
++				cpu_to_le32s((u32*)&TxCommandA);
++				memcpy(skb->data, &TxCommandA, STATUS_WORD_LEN);
++				skb_put(skb, AlignmentSize);
++				return skb;
++			} else {
++				/* ip_summed, Multi Fragament */
++				struct sk_buff *skb2;
++				SkbSize = skb->len+4*4*(skbFragCnt+1);
++				skb2 = dev_alloc_skb(SkbSize);
++
++				SMSC_TRACE(DBG_TX, "ip_summed, Multifrags");
++
++				if (!skb2)
++					return NULL;
++
++				skb_put(skb2, SkbSize);
++				{
++					TxCommandA = TX_CMD_A_FIRST_SEG_ |((u32)sizeof(u32));
++
++					TxCommandB = TX_CMD_B_CSUM_ENABLE |((u32)(skb->len+STATUS_WORD_LEN)) ;
++					cpu_to_le32s((u32*)&TxCommandA);
++					cpu_to_le32s((u32*)&TxCommandB);
++
++					memcpy(skb2->data, &TxCommandA, STATUS_WORD_LEN);
++					memcpy(skb2->data + STATUS_WORD_LEN, &TxCommandB, STATUS_WORD_LEN);
++					memcpy(skb2->data + 8, &dwTxCsumPreamble, STATUS_WORD_LEN);
++				}
++				{
++					TxCommandA =
++						((((unsigned long)(skb->data))&0x03UL)<<16) | //u32 alignment adjustment
++				  		  ((u32)((skb->len)-(skb->data_len)));
++					TxCommandB = ((u32)(skb->len+STATUS_WORD_LEN));
++					cpu_to_le32s((u32*)&TxCommandA);
++					cpu_to_le32s((u32*)&TxCommandB);
++					CopySize = ((((u32)(skb->len - skb->data_len))+3+(((unsigned long)(skb->data))&0x03UL))>>2)*4;
++					memcpy(skb2->data + 12, &TxCommandA, STATUS_WORD_LEN);
++					memcpy(skb2->data + 12 + STATUS_WORD_LEN, &TxCommandB, STATUS_WORD_LEN);
++					memcpy(skb2->data + 12 + STATUS_WORD_LEN * 2, (u32 *)(((unsigned long)(skb->data))&0xFFFFFFFCUL),CopySize);
++				}
++
++				prt = (u8 *)skb2->data+20+CopySize;
++
++				for(i = 1; i < skbFragCnt;i++) {
++					skb_frag_t *frag = &skb_shinfo(skb)->frags[i - 1];
++#if (LINUX_VERSION_CODE < KERNEL_VERSION(3,2,0))
++					void *frag_addr = ((unsigned char *) page_address(frag->page) + frag->page_offset);
++#else
++					void *frag_addr = (void *)skb_frag_address(frag);
++#endif
++
++					TxCommandA = ((((unsigned long)(frag_addr))&0x03UL)<<16) | //alignment adjustment
++			 			 ((u32)(frag->size));
++
++					if (i == (skbFragCnt-1)) {
++						TxCommandA |= TX_CMD_A_LAST_SEG_ ;
++					}
++
++					TxCommandB = ((u32)(skb->len+STATUS_WORD_LEN));
++					cpu_to_le32s((u32*)&TxCommandA);
++					cpu_to_le32s((u32*)&TxCommandB);
++					memcpy(prt, &TxCommandA, STATUS_WORD_LEN);
++					prt = prt + STATUS_WORD_LEN;
++					memcpy(prt, &TxCommandB, STATUS_WORD_LEN);
++					prt = prt + STATUS_WORD_LEN;
++					CopySize = ((((unsigned long)(frag->size)) + 3 + 
++							(((unsigned long)(frag_addr))&0x03UL)) >> 2) * 4;
++					memcpy(prt, (u32 *)(((unsigned long)(frag_addr)) & 0xFFFFFFFCUL), CopySize);
++					prt = prt+CopySize;
++				}
++
++				skb_trim(skb2,prt-skb2->data);
++				dev_kfree_skb_any(skb);
++				return skb2;
++			}
++
++		} else {
++			if (skbFragCnt > 1) {
++				/* Non ip_summed, Multifrags */
++
++				struct sk_buff *skb2;
++				SkbSize = skb->len+4*4*skbFragCnt;
++				skb2 = dev_alloc_skb(SkbSize);
++				SMSC_TRACE(DBG_TX, "Non ip_summed, Multifrags");
++
++				if (!skb2)
++					return NULL;
++
++				skb_put(skb2, SkbSize);
++				{
++					TxCommandA =((((unsigned long)(skb->data)) & 0x03UL) << 16) | //u32 alignment adjustment
++							TX_CMD_A_FIRST_SEG_ | (u32)((skb->len) - (skb->data_len));
++
++					TxCommandB = TX_CMD_B_CSUM_ENABLE |((u32)(skb->len));
++					cpu_to_le32s((u32*)&TxCommandA);
++					cpu_to_le32s((u32*)&TxCommandB);
++					SMSC_TRACE(DBG_TX, "first frag.");
++					CopySize = ((((unsigned long)((skb->len) - (skb->data_len))) + 3 +
++							(((unsigned long)(skb->data))&0x03UL)) >> 2)*4;
++					memcpy(skb2->data, &TxCommandA, STATUS_WORD_LEN);
++					memcpy(skb2->data + STATUS_WORD_LEN, &TxCommandB, STATUS_WORD_LEN);
++					memcpy(skb2->data + STATUS_WORD_LEN * 2, 
++						(void *)(((unsigned long)(skb->data)) & 0xFFFFFFFCUL),CopySize);
++				}
++
++				prt = (u8 *)skb2->data+8+CopySize;
++				for(i = 1; i < skbFragCnt; i++) {
++					skb_frag_t *frag = &skb_shinfo(skb)->frags[i - 1];
++#if (LINUX_VERSION_CODE < KERNEL_VERSION(3,2,0))
++
++					void *frag_addr = ((unsigned char *)page_address(frag->page) + frag->page_offset);
++#else
++					void *frag_addr = (void *)skb_frag_address(frag);
++#endif
++					TxCommandA = ((((unsigned long)(frag_addr))&0x03UL)<<16) | //u32 alignment adjustment
++							 ((u32)(frag->size));
++
++					if (i == (skbFragCnt - 1)) {
++						TxCommandA |= TX_CMD_A_LAST_SEG_ ;
++					}
++
++					TxCommandB = ((u32)(skb->len));
++					cpu_to_le32s((u32*)&TxCommandA);
++					cpu_to_le32s((u32*)&TxCommandB);
++					memcpy(prt, &TxCommandA, STATUS_WORD_LEN);
++					prt = prt + STATUS_WORD_LEN;
++					memcpy(prt, &TxCommandB, STATUS_WORD_LEN);
++					prt = prt + STATUS_WORD_LEN;
++
++					CopySize = ((((unsigned long)(frag->size)) + 3 + 
++							(((unsigned long)(frag_addr)) & 0x03UL)) >> 2) * 4;
++					memcpy(prt, (void *)(((unsigned long)(frag_addr)) & 0xFFFFFFFCUL), CopySize);
++					prt = prt+CopySize;
++				}
++
++					skb_trim(skb2,prt-skb2->data);
++					dev_kfree_skb_any(skb);
++					SMSC_TRACE(DBG_TX, "return from Nonip_summed, Multifrags");
++					return skb2;
++			} else {
++				goto Non_CheckSumOffLoad;
++			}
++		}
++	} else {
++Non_CheckSumOffLoad:
++		/* Non ip_summed, onefrag */
++		SMSC_TRACE(DBG_TX, "Non ip_summed, onefrag");
++		AlignmentSize = skb->len % STATUS_WORD_LEN;
++		if (AlignmentSize)
++			AlignmentSize = STATUS_WORD_LEN - AlignmentSize;
++
++		if (tx_skb_clone && (!skb_cloned(skb))
++		    && ((headroom + tailroom) >= (2*STATUS_WORD_LEN + AlignmentSize))) {
++			if ((headroom < (2*STATUS_WORD_LEN)) || (tailroom < AlignmentSize)){
++				skb->data = memmove(skb->head + 2 * STATUS_WORD_LEN, skb->data, skb->len);
++				SkbSize = skb->len;
++				skb_trim(skb, 0);
++				skb_put(skb, SkbSize);
++			}
++		} else {
++			struct sk_buff *skb2;
++			skb2 = skb_copy_expand(skb, 2*STATUS_WORD_LEN, AlignmentSize, flags);
++			dev_kfree_skb_any(skb);
++			skb = skb2;
++			if (!skb)
++				return NULL;
++		}
++
++		skb_push(skb, STATUS_WORD_LEN);
++		TxCommandB = (u32)(skb->len - STATUS_WORD_LEN);
++		cpu_to_le32s((u32*)&TxCommandB);
++
++		memcpy(skb->data, &TxCommandB, STATUS_WORD_LEN);
++		skb_push(skb, STATUS_WORD_LEN);
++		TxCommandA = TX_CMD_A_FIRST_SEG_ | TX_CMD_A_LAST_SEG_ | (u32)(skb->len - 2*STATUS_WORD_LEN);
++		cpu_to_le32s((u32*)&TxCommandA);
++		memcpy(skb->data, &TxCommandA, STATUS_WORD_LEN);
++
++		skb_put(skb, AlignmentSize);
++		return skb;
++	}
++}
++
++static int smsc9500_reset(struct usbnet *dev)
++{
++	int ret=0, Timeout;
++	PADAPTER_DATA adapterData = (PADAPTER_DATA)(dev->data[0]);
++	u32 dwReadBuf, dwAddrH, dwAddrL, dwWriteBuf,dwMacCr,DwTemp, dwBurstCap;
++
++	u32 dwLedGpioCfg;
++
++	SMSC_TRACE(DBG_INIT, "smsc9500_reset");
++
++	if ((ret = smsc9500_read_reg(dev,HW_CFG,&dwReadBuf)< 0)) {
++		SMSC_WARNING("Failed to read HW_CFG: %d", ret);
++		return ret;
++	}
++	dwReadBuf |= HW_CFG_LRST_;
++	if ((ret = smsc9500_write_reg(dev, HW_CFG, dwReadBuf)) < 0) {
++		SMSC_WARNING("Failed to write HW_CFG_LRST_ bit in HW_CFG register, ret = %d",ret);
++		return ret;
++		}
++
++	Timeout = 0;
++	do {
++		if ((ret = smsc9500_read_reg(dev, HW_CFG, &dwReadBuf)< 0)) {
++			SMSC_WARNING("Failed to read HW_CFG: %d", ret);
++			return ret;
++		}
++		/* wait for 100 */
++		msleep(100);
++		Timeout++;
++	} while ((dwReadBuf & HW_CFG_LRST_) && (Timeout < 100));
++
++	if(Timeout >= 100) {
++		SMSC_WARNING("Timeout waiting for completion of Lite Reset");
++		return SMSC9500_FAIL;
++	}
++
++	if((ret = smsc9500_read_reg(dev, ID_REV, &dev->chipID)) < 0) {
++		SMSC_WARNING("Failed to read GPIO_CFG: %d", ret);
++		return ret;
++	  }
++	dev->chipID = dev->chipID >> 16;
++
++	/* Enable chip specific features */
++	if (dev->chipID == PID_LAN9512) {
++		dev->chipDependFeatures[FEATURE_WUFF_8] = TRUE;
++	} else if (dev->chipID == PID_LAN9500A) {
++		int i;
++		for(i = 0; i < FEATURE_MAX_NO; i++)
++			dev->chipDependFeatures[i] = TRUE;
++		dev->chipDependFeatures[FEATURE_EEE] = FALSE;
++	} else if ((dev->chipID == PID_LAN9530) || (dev->chipID == PID_LAN9730) || (dev->chipID == PID_LAN89530)) {
++		int i;
++		for(i = 0; i < FEATURE_MAX_NO; i++)
++			dev->chipDependFeatures[i] = TRUE;
++	}
++
++	if ((ret = smsc9500_read_reg(dev, PM_CTRL, &DwTemp) < 0)) {
++	    SMSC_WARNING("Failed to read PM_CTRL: %d", ret);
++	    return ret;
++	}
++
++	if ((ret = smsc9500_write_reg(dev, PM_CTRL, (DwTemp | PM_CTL_PHY_RST_)) < 0)) {
++		SMSC_WARNING("Failed to write PM_CTRL: %d", ret);
++		return ret;
++	}
++
++	Timeout = 0;
++	do {
++		if ((ret = smsc9500_read_reg(dev, PM_CTRL, &dwReadBuf) < 0)) {
++			SMSC_WARNING("Failed to read PM_CTRL: %d", ret);
++			return ret;
++		}
++		msleep(100);
++		Timeout++;
++	} while ((dwReadBuf & PM_CTL_PHY_RST_) && (Timeout < 100));
++
++	if (Timeout >= 100) {
++		SMSC_WARNING("Timeout waiting for PHY Reset");
++		return SMSC9500_FAIL;
++	}
++	dwAddrH = 0x0000FFFFUL;
++	dwAddrL = 0xFFFFFFFF;
++
++
++	if (adapterData->macAddrHi16 != 0xFFFFFFFF || adapterData->MmacAddrLo32 != 0xFFFFFFFF) {
++		dwAddrH = adapterData->macAddrHi16 & 0xFFFF;
++		dwAddrL = adapterData->MmacAddrLo32;
++	} else {
++		//add by lm
++		if (dev->chipID == PID_LAN9512)
++			adapterData->eepromContentValid=TRUE;
++		//end
++				
++		if ((adapterData->eepromContentValid == TRUE) &&
++			(smsc9500_read_eeprom(dev, EEPROM_MAC_OFFSET, 6,  dev->net->dev_addr) == 0)) {
++
++			if (smsc9500_is_valid_ether_addr(dev->net->dev_addr)) {
++				dwAddrL = dev->net->dev_addr[0] | dev->net->dev_addr[1] << 8 | 
++						dev->net->dev_addr[2] << 16 | dev->net->dev_addr[3] << 24;
++				dwAddrH = dev->net->dev_addr[4] | dev->net->dev_addr[5] << 8;
++			}
++		} else {
++			/* LAN9500's descriptor RAM may provide Mac address */
++			MAC_ADDR_IN_RAM macRam;
++			if (ReadDataPort(dev, RAMSEL_EEPROM, 0, sizeof(MAC_ADDR_IN_RAM) / 4, 
++				(u32*)&macRam, NULL) == SMSC9500_SUCCESS) {
++				cpu_to_le32s(&macRam.signature);
++				cpu_to_le32s(&macRam.MacAddrL);
++				cpu_to_le32s(&macRam.MacAddrH);
++				cpu_to_le16s(&macRam.crc);
++				cpu_to_le16s(&macRam.crcComplement);
++				if(macRam.signature == 0x736D7363){ /* Signature "smsc" */
++					u16 crc = CalculateCrc16((BYTE *)&macRam, 12, FALSE);
++					if((crc == macRam.crc) && (crc == (u16)~macRam.crcComplement)) {
++						dwAddrL = macRam.MacAddrL;
++						dwAddrH = macRam.MacAddrH;
++					}
++				}
++			}
++		}
++	}
++
++	/* Mac address could be initialized by system firmware. Lan9500A
++	will implement this way */
++	if ((dwAddrH==0x0000FFFFUL)&&(dwAddrL==0xFFFFFFFF)) {
++		if ((ret = smsc9500_read_reg(dev,ADDRL, &dwAddrL) < 0)) {
++			SMSC_WARNING("Failed to read ADDRL: %d", ret);
++			return ret;
++		}
++		if ((ret = smsc9500_read_reg(dev,ADDRH, &dwAddrH) < 0)) {
++			SMSC_WARNING("Failed to read ADDRH: %d", ret);
++			return ret;
++		}
++	}
++
++	if ((((dwAddrH & 0xFFFF) == 0x0000FFFFUL) && (dwAddrL == 0xFFFFFFFF)) || 
++		(((dwAddrH & 0xFFFF) == 0x0UL) && (dwAddrL == 0x0UL)) || 
++		(0x01 & LOBYTE(LOWORD(dwAddrL)))) {
++		dwAddrH=0x00000070UL;
++		dwAddrL=0x110F8000UL;
++		SMSC_TRACE(DBG_INIT, "Mac Address is set by default to 0x%04X%08X", dwAddrH, dwAddrL);
++	}
++	adapterData->macAddrHi16 = dwAddrH;
++	adapterData->MmacAddrLo32 = dwAddrL;
++
++	if ((ret = smsc9500_write_reg(dev, ADDRL, dwAddrL) < 0)) {
++		SMSC_WARNING("Failed to write ADDRL: %d", ret);
++		return ret;
++	}
++	if ((ret = smsc9500_write_reg(dev, ADDRH, dwAddrH) < 0)) {
++		SMSC_WARNING("Failed to write ADDRH: %d", ret);
++		return ret;
++	}
++
++	dev->net->dev_addr[0] = LOBYTE(LOWORD(dwAddrL));
++	dev->net->dev_addr[1] = HIBYTE(LOWORD(dwAddrL));
++	dev->net->dev_addr[2] = LOBYTE(HIWORD(dwAddrL));
++	dev->net->dev_addr[3] = HIBYTE(HIWORD(dwAddrL));
++	dev->net->dev_addr[4] = LOBYTE(LOWORD(dwAddrH));
++	dev->net->dev_addr[5] = HIBYTE(LOWORD(dwAddrH));
++
++	SMSC_TRACE(DBG_INIT, "dev->net->dev_addr %02x:%02x:%02x:%02x:%02x:%02x",
++			dev->net->dev_addr [0], dev->net->dev_addr [1],
++			dev->net->dev_addr [2], dev->net->dev_addr [3],
++			dev->net->dev_addr [4], dev->net->dev_addr [5]);
++
++#ifdef PME_EEPROMLESS
++	if ((ret=EepromLessPMESetting(dev))<0)
++	    return ret;
++#endif
++	if (!(smscusbnet_IsOperationalMode(dev))) {
++		if ((ret = smsc9500_read_reg(dev, HW_CFG, &dwReadBuf) < 0)) {
++			SMSC_WARNING("Failed to read HW_CFG: %d", ret);
++			return ret;
++		}
++
++		dwReadBuf |= HW_CFG_BIR_;
++		if ((ret = smsc9500_write_reg(dev, HW_CFG, dwReadBuf)) < 0) {
++			SMSC_WARNING("Failed to write HW_CFG_BIR_ bit in HW_CFG register, ret = %d ",ret);
++			return ret;
++		}
++
++		if ((ret = smsc9500_read_reg(dev, HW_CFG, &dwReadBuf) < 0)) {
++			SMSC_WARNING("Failed to read HW_CFG: %d", ret);
++			return ret;
++		}
++	}
++
++	if (dev->turbo_mode) {
++		if(dev->udev->speed == USB_SPEED_HIGH)
++			dwBurstCap = dev->rx_urb_size / HS_USB_PKT_SIZE;
++		else
++			dwBurstCap = dev->rx_urb_size / FS_USB_PKT_SIZE;
++	} else {
++		dwBurstCap = 0;
++	}
++
++	if ((ret = smsc9500_write_reg(dev, BURST_CAP, dwBurstCap)) < 0) {
++		SMSC_WARNING("Failed to write BURST_CAP");
++		return ret;
++	}
++	if ((ret = smsc9500_read_reg(dev, BURST_CAP, &dwReadBuf) < 0)) {
++		SMSC_WARNING("Failed to read BURST_CAP: %d", ret);
++		return ret;
++	}
++	SMSC_TRACE(DBG_INIT, "BURST_CAP after writing: 0x%08x", dwReadBuf);
++
++	if ((ret = smsc9500_write_reg(dev, BULK_IN_DLY, bulkin_delay)) < 0) {
++		SMSC_WARNING("Failed to write BULK_IN_DLY");
++		return ret;
++	}
++	if ((ret = smsc9500_read_reg(dev, BULK_IN_DLY, &dwReadBuf)< 0)) {
++		SMSC_WARNING("Failed to read BULK_IN_DLY: %d", ret);
++		return ret;
++	}
++	SMSC_TRACE(DBG_INIT, "BULK_IN_DLY: 0x%08x", dwReadBuf);
++
++	if ((ret = smsc9500_read_reg(dev, HW_CFG, &dwReadBuf) < 0)) {
++		SMSC_WARNING("Failed to read HW_CFG: %d", ret);
++		return ret;
++	}
++
++	if (dev->turbo_mode) {
++		dwReadBuf |= (HW_CFG_MEF_|HW_CFG_BCE_);
++	}
++
++	dwReadBuf &= ~HW_CFG_RXDOFF_;
++	dwReadBuf |= RX_OFFSET  << 9; //set Rx data offset=2, Make IP header aligns on word boundary.
++
++	if ((ret = smsc9500_write_reg(dev, HW_CFG, dwReadBuf)) < 0) {
++		SMSC_WARNING("Failed to write HW_CFG_BIR_ bit in HW_CFG register, ret = %d \n",ret);
++		return ret;
++	}
++
++	if ((ret = smsc9500_read_reg(dev, HW_CFG, &dwReadBuf) < 0)) {
++		SMSC_WARNING("Failed to read HW_CFG: %d", ret);
++		return ret;
++	}
++	SMSC_TRACE(DBG_INIT, "HW_CFG: 0x%08x", dwReadBuf);
++
++	if ((ret = smsc9500_write_reg(dev, INT_STS, 0xFFFFFFFFUL))<0) {
++		SMSC_WARNING("Failed to write INT_STS register, ret = %d",ret);
++		return ret;
++	}
++
++
++	if ((ret = smsc9500_read_reg(dev, ID_REV, &dwReadBuf) < 0)) {
++		SMSC_WARNING("Failed to read ID_REV: %d", ret);
++		return ret;
++	}
++	adapterData->dwIdRev = dwReadBuf;
++	SMSC_TRACE(DBG_INIT, "ID_REV = 0x%08x", dwReadBuf);
++
++
++	if ((ret = smsc9500_read_reg(dev, FPGA_REV, &dwReadBuf) < 0)) {
++		SMSC_WARNING("Failed to read FPGA_REV: %d", ret);
++		return ret;
++	}
++	adapterData->dwFpgaRev = dwReadBuf;
++
++	if (smscusbnet_IsOperationalMode(dev)) {
++
++		if ((ret = smsc9500_read_reg(dev, INT_EP_CTL, &dwReadBuf) < 0)) {
++			SMSC_WARNING("Failed to read INT_EP_CTL: %d", ret);
++			return ret;
++		}
++		SMSC_TRACE(DBG_INIT, "INT_EP_CTL: 0x%08x", dwReadBuf);
++
++		dwReadBuf |= INT_EP_CTL_RX_FIFO_EN_;
++		if ((ret = smsc9500_write_reg(dev, INT_EP_CTL, dwReadBuf)) < 0) {
++			SMSC_WARNING("Failed to write INT_EP_CTL register,ret = %d",ret);
++			return ret;
++		}
++
++		if ((ret = smsc9500_read_reg(dev, INT_EP_CTL, &dwReadBuf) < 0)) {
++			SMSC_WARNING("Failed to read INT_EP_CTL: %d", ret);
++			return ret;
++		}
++		SMSC_TRACE(DBG_INIT, "INT_EP_CTL: 0x%08x", dwReadBuf);
++	}
++
++	/* Set TX COE */
++	if(adapterData->UseTxCsum) {
++ 		if ((ret = smsc9500_read_reg(dev, COE_CR, &dwReadBuf) < 0)) {
++			SMSC_WARNING("Failed to read COE_CR: %d", ret);
++			return ret;
++		}
++		dwReadBuf |= Tx_COE_EN_;
++
++		if ((ret = smsc9500_write_reg(dev, COE_CR, dwReadBuf) < 0)) {
++			SMSC_WARNING("Failed to write COE_CR: %d", ret);
++			return ret;
++		}
++
++		if ((ret = smsc9500_read_reg(dev, COE_CR, &DwTemp) < 0)) {
++			SMSC_WARNING("Failed to read COE_CR: %d", ret);
++			return ret;
++		}
++		SMSC_TRACE(DBG_INIT, "COE_CR = 0x%08x", DwTemp);
++	}
++
++	if ((ret = smsc9500_write_reg(dev, FLOW, 0x0UL) < 0)) {
++			SMSC_WARNING("Failed to write FLOW: %d", ret);
++			return ret;
++	}
++
++	if ((ret = smsc9500_write_reg(dev, AFC_CFG, AFC_CFG_DEFAULT) < 0)) {
++			SMSC_WARNING("Failed to write AFC_CFG: %d", ret);
++			return ret;
++	}
++
++	if ((ret = smsc9500_read_reg(dev, MAC_CR, &dwMacCr) < 0)) {
++			SMSC_WARNING("Failed to read MAC_CR: %d", ret);
++			return ret;
++	}
++	dwMacCr |= (MAC_CR_TXEN_);
++	if ((ret = smsc9500_write_reg(dev, MAC_CR, dwMacCr) < 0)) {
++			SMSC_WARNING("Failed to read MAC_CR: %d", ret);
++			return ret;
++	}
++	dwWriteBuf = TX_CFG_ON_;
++	if ((ret = smsc9500_write_reg(dev, TX_CFG, dwWriteBuf) < 0)) {
++			SMSC_WARNING("Failed to write TX_CFG: %d", ret);
++			return ret;
++	}
++
++	/* Set Vlan */
++	dwWriteBuf = (u32)ETH_P_8021Q;
++	if ((ret = smsc9500_write_reg(dev, VLAN1, dwWriteBuf) < 0)) {
++		SMSC_WARNING("Failed to write VAN1: %d", ret);
++		return ret;
++	}
++
++	/* Set Rx COE */
++	if (adapterData->UseRxCsum) {
++		if ((ret = smsc9500_read_reg(dev, COE_CR, &dwReadBuf) < 0)) {
++			SMSC_WARNING("Failed to read COE_CR: %d", ret);
++			return ret;
++		}
++
++#if (LINUX_VERSION_CODE < KERNEL_VERSION(2,6,15))
++		dwReadBuf |= (Rx_COE_EN_ |  Rx_COE_MODE_);
++#else
++		dwReadBuf |= Rx_COE_EN_;
++#endif
++		if ((ret = smsc9500_write_reg(dev, COE_CR, dwReadBuf) < 0)) {
++			SMSC_WARNING("Failed to write COE_CR: %d", ret);
++			return ret;
++		}
++
++		if ((ret = smsc9500_read_reg(dev, COE_CR, &DwTemp) < 0)) {
++			SMSC_WARNING("Failed to read COE_CR: %d", ret);
++			return ret;
++		}
++		SMSC_TRACE(DBG_INIT, "COE_CR = 0x%08x", DwTemp);
++
++	}
++
++	if ((ret = smsc9500_read_reg(dev, MAC_CR, &dwMacCr) < 0)) {
++		SMSC_WARNING("Failed to read MAC_CR: %d", ret);
++		return ret;
++	}
++
++	dwMacCr |= MAC_CR_RXEN_;
++
++	if ((ret = smsc9500_write_reg(dev, MAC_CR, dwMacCr) < 0)) {
++		SMSC_WARNING("Failed to read MAC_CR: %d", ret);
++		return ret;
++	}
++
++	/* Enable the LEDs by default */
++	if ((ret = smsc9500_read_reg(dev, LED_GPIO_CFG, &DwTemp) < 0)) {
++		SMSC_WARNING("Failed to read LED_GPIO_CFG: %d", ret);
++		return ret;
++	}
++	DwTemp &= (~LED_GPIO_CFG_GPCTL_10_ | ~LED_GPIO_CFG_GPCTL_09_ | ~LED_GPIO_CFG_GPCTL_08_);
++
++	if ((ret = smsc9500_write_reg( dev, LED_GPIO_CFG,
++			(LED_GPIO_CFG_GPCTL_LED_ << LED_GPIO_CFG_GPCTL_10_SH) |
++			(LED_GPIO_CFG_GPCTL_LED_ << LED_GPIO_CFG_GPCTL_09_SH) |
++			(LED_GPIO_CFG_GPCTL_LED_ << LED_GPIO_CFG_GPCTL_08_SH))) < 0) {
++		SMSC_WARNING("Failed to write LED_GPIO_CFG: %d", ret);
++		return ret;
++	}
++
++	//adapterData->LinkActLedCfg=TRUE;
++	if (adapterData->LinkActLedCfg) { 
++		 /* Driver parameter enables separate Link and Activity
++		 LEDs for supported devices */
++		if (1/*dev->chipDependFeatures[FEATURE_SEP_LEDS]*/) {
++			dwLedGpioCfg = (LED_GPIO_CFG_GPCTL_LED_ << LED_GPIO_CFG_GPCTL_10_SH) |
++					(LED_GPIO_CFG_GPCTL_LED_ << LED_GPIO_CFG_GPCTL_09_SH) |
++					(LED_GPIO_CFG_GPCTL_LED_ << LED_GPIO_CFG_GPCTL_08_SH);
++
++			/* Enable separate Link/Act LEDs */
++			dwLedGpioCfg |= LED_GPIO_CFG_LED_SEL_;
++			
++			/* Set LED GPIO Config */
++			if((ret = smsc9500_write_reg(dev, LED_GPIO_CFG, dwLedGpioCfg)) < 0) {
++					SMSC_WARNING("Failed to write LED_GPIO_CFG: %d", ret);
++					return ret;
++			}
++		} else {
++			/* Reset to default value */
++			adapterData->LinkActLedCfg = 0;
++			/* Disable Software control LinkLed GPIO in case it is set */
++			adapterData->LinkLedOnGpio = 11;
++		}
++	} else if (adapterData->LinkLedOnGpio <= 10) { 
++		/* Software control LinkLed GPIO is enable.
++		If selected GPIO is GPIO0-GPIO7, make sure external PHY is not enable.
++		GPIO0-GPIO7 pins are multiplexed with MII signals */
++		if (adapterData->LinkLedOnGpio < 8) {
++		    /* Check PHY Strap */
++		    if((ret = smsc9500_read_reg(dev, HW_CFG, &DwTemp)) < 0){
++				SMSC_WARNING("Failed to read HW_CFG: %d", ret);
++				return ret;
++		    }
++		    if (DwTemp & HW_CFG_PSEL_) { 
++			/* External PHY is enable */
++			SMSC_WARNING("External PHY Enable::GPIO%d can not be set as Link Up/Down Led\n", adapterData->LinkLedOnGpio);
++			/* Disable Software control LinkLed GPIO */
++			adapterData->LinkLedOnGpio = 11;
++		    } else {
++			u32 dwGpioCfg;
++			if((ret = smsc9500_read_reg(dev, GPIO_CFG, &dwGpioCfg)) < 0){
++				SMSC_WARNING("Failed to read GPIO_CFG: %d", ret);
++				return ret;
++			}
++
++			dwGpioCfg &= ~(GPIO_CFG_GPO0_EN_ << adapterData->LinkLedOnGpio);
++			dwGpioCfg |= GPIO_CFG_GPO0_DIR_ << adapterData->LinkLedOnGpio;
++
++			/* Check GPIO buffer type */
++			if (!adapterData->LinkLedOnGpioBufType) {// Push-Pull output
++			    dwGpioCfg |= GPIO_CFG_GPO0_TYPE_ << adapterData->LinkLedOnGpio;
++			}
++
++			/* Check GPIO Polarity */
++			if (adapterData->LinkLedOnGpioPolarity) { // Active low
++			    dwGpioCfg |= GPIO_CFG_GPO0_DATA_ << adapterData->LinkLedOnGpio;
++			}
++
++			/* Set GPIO Config register */
++			if((ret = smsc9500_write_reg(dev, GPIO_CFG, dwGpioCfg)) < 0) {
++				SMSC_WARNING("Failed to write GPIO_CFG: %d", ret);
++				return ret;
++			}
++		    }
++		} else {
++			u32 dwLedGpioCfg = (LED_GPIO_CFG_GPCTL_LED_ << LED_GPIO_CFG_GPCTL_10_SH) |
++						(LED_GPIO_CFG_GPCTL_LED_ << LED_GPIO_CFG_GPCTL_09_SH) |
++						(LED_GPIO_CFG_GPCTL_LED_ << LED_GPIO_CFG_GPCTL_08_SH);
++			switch (adapterData->LinkLedOnGpio) {
++			case 8:
++				/* Enable GPIO 8 */
++				dwLedGpioCfg &= (~(LED_GPIO_CFG_GPCTL_LED_ << LED_GPIO_CFG_GPCTL_08_SH));
++				/* Set Output Direction */
++				dwLedGpioCfg |= LED_GPIO_CFG_GPDIR_08_;
++				/* Set Buffer Type */
++				if (!adapterData->LinkLedOnGpioBufType) {// Push-Pull Output
++					dwLedGpioCfg |= LED_GPIO_CFG_GPBUF_08_;
++				}
++				/* Check GPIO Polarity */
++				if (adapterData->LinkLedOnGpioPolarity) { // Active low
++					dwLedGpioCfg |= LED_GPIO_CFG_GPDATA_08_;
++				}
++				break;
++			case 9:
++				/* Enable GPIO 9 */
++				dwLedGpioCfg &= (~(LED_GPIO_CFG_GPCTL_LED_ << LED_GPIO_CFG_GPCTL_09_SH));
++				/* Set Output Direction */
++				dwLedGpioCfg |= LED_GPIO_CFG_GPDIR_09_;
++				/* Set Buffer Type */
++				if (!adapterData->LinkLedOnGpioBufType) { // Push-Pull Output
++					dwLedGpioCfg |= LED_GPIO_CFG_GPBUF_09_;
++				}
++				/* Check GPIO Polarity */
++				if (adapterData->LinkLedOnGpioPolarity) { // Active low
++					dwLedGpioCfg |= LED_GPIO_CFG_GPDATA_09_;
++				}
++				break;
++			case 10:
++				/* Enable GPIO 10 */
++				dwLedGpioCfg &= (~(LED_GPIO_CFG_GPCTL_LED_ << LED_GPIO_CFG_GPCTL_10_SH));
++				/* Set Output Direction */
++				dwLedGpioCfg |= LED_GPIO_CFG_GPDIR_10_;
++				/* Set Buffer Type */
++				if (!adapterData->LinkLedOnGpioBufType) {// Push-Pull Output
++					dwLedGpioCfg |= LED_GPIO_CFG_GPBUF_10_;
++				}
++				/* Check GPIO Polarity */
++				if (adapterData->LinkLedOnGpioPolarity) {// Active low
++					dwLedGpioCfg |= LED_GPIO_CFG_GPDATA_10_;
++				}
++				break;
++			}
++			/* Set LED GPIO Config */
++			if((ret = smsc9500_write_reg( dev, LED_GPIO_CFG, dwLedGpioCfg)) < 0) {
++				SMSC_WARNING("Failed to write LED_GPIO_CFG: %d", ret);
++				return ret;
++			}
++		}
++	}
++	smsc9500_rx_setmulticastlist(dev);
++
++	adapterData->dwSavedLinkSettings = link_mode;
++	if (!Phy_Initialize(dev, phy_addr, link_mode))
++		return SMSC9500_FAIL;
++
++	return 0;
++}
++
++static int smsc9500_link_reset(struct usbnet *dev)
++{
++	int ret = 0;
++
++	SMSC_TRACE(DBG_LINK, "smsc9500_link_reset");
++
++	ret = Phy_CheckLink(dev);
++
++	if (dev->StopLinkPolling) {
++		clear_bit (EVENT_DEV_RECOVERY, &dev->flags);
++	}
++
++	if (test_bit (EVENT_DEV_RECOVERY, &dev->flags)) {
++		ret = smsc9500_device_recovery(dev);
++		clear_bit (EVENT_DEV_RECOVERY, &dev->flags);
++	}
++	return ret;
++}
++
++
++static int smsc9500_stopTxPath(struct usbnet * dev)
++{
++	u32 Value32;
++	int ret = SMSC9500_FAIL;
++	int Count = 0;
++
++	SMSC_TRACE(DBG_TX, "smsc9500_stopTxPath");
++
++	/* Stop the Transmit path at SCSRs */
++	CHECK_RETURN_STATUS(smsc9500_write_reg(dev, TX_CFG, TX_CFG_STOP_));
++	/* The bit should self clear as soon as the packet makes it out
++	of the Mac, worst case is 10 Mbps HD and frame deferred to the
++	maximum. This will be ~100ms tops. Assuming one register read per
++	(micro)frame the case of high speed USB - 125us register read
++	cycle time - is the worse and
++	 would need up to 800 reads. Let's just round up to 1000 */
++	do
++	{
++		CHECK_RETURN_STATUS(smsc9500_read_reg(dev, TX_CFG, &Value32));
++		/* Let it try to do the 1000 reads even if the reg reads
++		are failing If the previous write did go thru at least
++		this way we have a better chance of making sure the
++		transmit path did stop. */
++	} while ( (++Count<1000) && ((Value32 & (TX_CFG_STOP_ | TX_CFG_ON_)) != 0) );
++
++	/* Disable Mac TX */
++	CHECK_RETURN_STATUS(smsc9500_read_reg(dev, MAC_CR, &Value32));
++	Value32 &= ~MAC_CR_TXEN_;
++	CHECK_RETURN_STATUS(smsc9500_write_reg(dev, MAC_CR,  Value32 ));
++
++	ret = SMSC9500_SUCCESS;
++DONE:
++	return ret;
++}
++
++static int smsc9500_stopAndFlushTxPath(struct usbnet *dev)
++{
++	u32 Value32;
++	int ret = SMSC9500_FAIL;
++
++	SMSC_TRACE(DBG_TX, "smsc9500_stopAndFlushTxPath");
++	if(smsc9500_stopTxPath(dev) < 0)return ret;
++
++	/* Flush the transmit path */
++	CHECK_RETURN_STATUS(smsc9500_write_reg(dev, TX_CFG, TX_CFG_FIFO_FLUSH_));
++
++	/* Should self clear way before the read. */
++	CHECK_RETURN_STATUS(smsc9500_read_reg(dev, TX_CFG, &Value32));
++
++	if (Value32 & TX_CFG_FIFO_FLUSH_) {
++		/* Flush did not self clear! */
++		goto DONE;
++	}
++	ret = SMSC9500_SUCCESS;
++DONE:
++	return ret;
++}
++
++
++static int smsc9500_stopRxPath(struct usbnet * dev)
++{
++	u32 Value32;
++	int Count = 0;
++	int ret = SMSC9500_FAIL;
++
++	SMSC_TRACE(DBG_RX, "smsc9500_stopRxPath");
++
++	/* Clr the Rx Stop bit if not already */
++	CHECK_RETURN_STATUS(smsc9500_write_reg(dev, INT_STS, INT_STS_RX_STOP_));
++
++	/* Disable the receiver at the Mac */
++	CHECK_RETURN_STATUS(smsc9500_read_reg(dev, MAC_CR, &Value32));
++	CHECK_RETURN_STATUS(smsc9500_write_reg(dev, MAC_CR, Value32 & (~MAC_CR_RXEN_)));
++
++	/* The Rx Stop bit should assert as soon as the packet "in
++	flight" makes it into the Mac, worst case is 10 Mbps HD. This
++	will be ~2ms tops Assuming one register read per (micro)frame
++	the case of high speed USB - 125us register read cycle time -
++	is the worse and would need up to
++	 16 reads. Let's just round up to 20. */
++	do {
++		CHECK_RETURN_STATUS(smsc9500_read_reg(dev, INT_STS, &Value32));
++		/* Let it try to do the 20 reads even if the reg reads
++		are failing If the previous write did go thru at least
++		this way we have a better chance of making sure the
++		receiver did stop */
++	} while ( (++Count<20) && ((Value32 & INT_STS_RX_STOP_) == 0) );
++
++	/* Disable Mac RX */
++	//CHECK_RETURN_STATUS(smsc9500_read_reg(dev, MAC_CR, &Value32));
++	//Value32 &= ~MAC_CR_RXEN_;
++	//CHECK_RETURN_STATUS(smsc9500_write_reg(dev, MAC_CR, Value32));
++
++	ret = SMSC9500_SUCCESS;
++DONE:
++	return ret;
++}
++
++static int smsc9500_stopAndFlushRxPath(struct usbnet *dev)
++{
++	u32 Value32;
++	int ret = SMSC9500_FAIL;
++
++	SMSC_TRACE(DBG_RX, "smsc9500_stopAndFlushRxPath");
++
++	if (smsc9500_stopRxPath(dev) < 0)
++		goto DONE;
++	CHECK_RETURN_STATUS(smsc9500_write_reg(dev, RX_CFG, RX_FIFO_FLUSH_));
++
++	/* Should self clear way before the read */
++	CHECK_RETURN_STATUS(smsc9500_read_reg(dev, RX_CFG, &Value32));
++
++	if (Value32 & RX_FIFO_FLUSH_) {
++		/* Flush did not self clear! */
++		goto DONE;
++	}
++	ret = SMSC9500_SUCCESS;
++DONE:
++	return ret;
++}
++
++
++#ifdef PME_EEPROMLESS
++static int EepromLessPMESetting(struct usbnet *dev)
++{
++	PADAPTER_DATA adapterData = (PADAPTER_DATA)(dev->data[0]);
++	u32 dwReadBuf, dwAddrH, dwAddrL, dwWrite,dwRead;
++	int ret;
++
++	//API for customer to provide MAC address
++/*		
++	GetMacAddr(&dev->net->dev_addr);
++			
++	dwAddrL = dev->net->dev_addr[0] | dev->net->dev_addr[1] << 8 | dev->net->dev_addr[2] << 16 | dev->net->dev_addr[3] << 24;
++	dwAddrH = dev->net->dev_addr[4] | dev->net->dev_addr[5] << 8;
++			
++	if ((ret = smsc9500_write_reg(dev,ADDRL, dwAddrL)< 0)) {
++		SMSC_WARNING("Failed to write ADDRL: %d", ret);
++		return ret;
++	}
++	if ((ret = smsc9500_write_reg(dev,ADDRH, dwAddrH)< 0)) {
++		SMSC_WARNING("Failed to write ADDRH: %d", ret);
++		return ret;
++	}
++*/
++	if ((ret = smsc9500_read_reg(dev,FLAG_ATTR, &dwRead)< 0)) {
++		SMSC_WARNING("Failed to read FLAG_ATTR: %d", ret);
++		return ret;
++	}
++
++	//define your PME configuration here by setting theses values:
++	//FLAG_ATTR_PME_ENABLE               The device supports GPIO PME signaling.
++	//FLAG_ATTR_PME_CFG_PULSE          GPIO PME is signaled via a pulse,otherwise it's signal via a level
++	// FLAG_ATTR_PME_LEN_150MS         GPIO PME pulse length is 150 mS, otherwisw it's 1.5mS
++	//FLAG_ATTR_PME_POL                    GPIO PME signaling polarity is high
++	//FLAG_ATTR_PME_BUFF_TYPE          Push-Pull driver, otherwise Open drain driver
++	//FLAG_ATTR_PME_WAKE_PHY           PHY linkup wakeup supported, otherwise Magic packet wakeup supported
++	//FLAG_ATTR_PME_GPIO10_HIGH        Active-high detection for GPIO10
++	dwRead |= FLAG_ATTR_PME_ENABLE | FLAG_ATTR_PME_POL;
++               		
++	if ((ret = smsc9500_write_reg(dev,FLAG_ATTR, dwRead)< 0)) {
++		SMSC_WARNING("Failed to write FLAG_ATTR: %d", ret);
++		return ret;
++	}	
++	if ((ret = smsc9500_read_reg(dev,HW_CFG, &dwRead)< 0)) {
++		SMSC_WARNING("Failed to read HW_CFG: %d", ret);
++		return ret;
++	}
++
++	dwRead |= HW_CFG_EEM|HW_CFG_RST_PROTECT;
++	if ((ret = smsc9500_write_reg(dev,HW_CFG, dwRead)< 0)) {
++		SMSC_WARNING("Failed to write HW_CFG: %d", ret);
++		return ret;
++	}
++	return ret;		
++    }
++#endif /* PME_EEPROMLESS */
++
++
++static u16 CalculateCrc16(const BYTE * bpData,const u32 dwLen, const BOOLEAN fBitReverse)
++{
++	const u16 wCrc16Poly = 0x8005U;	// s/b international standard for CRC-16
++					// x^16 + x^15 + x^2 + 1
++	//u16 wCrc16Poly = 0xA001;	// reverse
++	u16 wMsb;
++	u16 i, j, bit;
++	u16 wCrcOut=0;
++	u16 wCrc = 0xFFFFU;
++	BYTE bCurrentByte;
++	u16 wNumOfBits = 16U;
++
++	wNumOfBits = wNumOfBits; // to avoid lint warning
++
++	for (i = 0; i < (u16)dwLen; i++) {
++		bCurrentByte = *bpData++;
++
++		for (bit = (u16)0U; bit < (u16)8U; bit++) {
++			wMsb = wCrc >> 15;
++			wCrc <<= 1;
++
++			if (wMsb ^ (u16)(bCurrentByte & 1)) {
++				wCrc ^= wCrc16Poly;
++				wCrc |= (u16)0x0001U;
++			}
++			bCurrentByte >>= 1;
++		}
++	}
++	/* bit reverse if needed
++	 so far we do not need this for 117
++	 but the standard CRC-16 seems to require this */
++	if (fBitReverse) {
++		j = 1;
++		for (i=(u16)(1<<(wNumOfBits-(u16)1U)); i; i = i>>1) {
++			if (wCrc & i) {
++				wCrcOut |= j;
++			}
++			j <<= 1;
++		}
++		wCrc = wCrcOut;
++	}
++	return wCrc;
++}
++
++/*
++
++Routine Description:
++
++    This routine set/reset General Purpose Output.
++
++Arguments:
++
++    Adapter - pointer to our Adapter
++    Gpo - Gpo [0:10]
++    State - 1 = ON or 0 = OFF
++
++Return Value:
++*/
++
++static int SetGpo(struct usbnet * dev,  u32 Gpo, u32 State)
++{
++	u32 Value32, Status;
++	int ret = SMSC9500_FAIL;
++
++	if ((Gpo > 10) || (State > 1)) {
++		if (State > 1) {
++			SMSC_WARNING("Gpo%d state (%d) is out of range [0:1] in NICSetGpo\n", Gpo, State);
++		}
++		goto Exit_NICSetGpo;
++	}
++
++	if (Gpo < 8) {
++		if (smsc9500_read_reg( dev, GPIO_CFG, &Value32 ) < 0) {
++			SMSC_WARNING("Failed to read GPIO_CFG\n");
++		    goto Exit_NICSetGpo;
++		}
++		Value32 &= (~(GPIO_CFG_GPO0_DATA_ << Gpo));
++		Value32 |= (State << Gpo);
++
++		Status = smsc9500_write_reg(dev, GPIO_CFG, Value32);
++		if (Status < 0) 
++		    goto Exit_NICSetGpo;
++	} else {
++		Status = smsc9500_read_reg(dev, LED_GPIO_CFG, &Value32 );
++		if (Status < 0)
++		     goto Exit_NICSetGpo;
++
++		Value32 &= (~(LED_GPIO_CFG_GPDATA_08_ << (Gpo-8)));
++		Value32 |= (State << (Gpo-8));
++
++		Status = smsc9500_write_reg(dev, LED_GPIO_CFG, Value32 );
++		if (Status < 0)
++		     goto Exit_NICSetGpo;
++	}
++
++	ret = SMSC9500_SUCCESS;
++Exit_NICSetGpo:
++	return ret;
++}
++
++/*
++Routine Description:
++
++    This routine set device at suspend3 state
++
++Arguments:
++
++    netdev - pointer to our device
++
++Return Value:
++
++*/
++static int SetWakeupOnSuspend3(struct net_device *netdev)
++{
++	u32 Value32;
++	int ret = SMSC9500_FAIL;
++	struct usbnet *dev = netdev_priv(netdev);
++
++	BUG_ON(!dev);
++
++	SMSC_TRACE(DBG_PWR, "Setting Suspend3 mode");
++
++	CHECK_RETURN_STATUS(smsc9500_read_reg(dev, RX_FIFO_INF, &Value32));
++
++	if ((Value32 & 0xFFFF) != 0) {
++		SMSC_TRACE(DBG_PWR, "Rx FIFO is not empty");
++		Value32 = RX_FIFO_FLUSH_;
++		CHECK_RETURN_STATUS(smsc9500_write_reg(dev, RX_CFG, Value32));	
++	} else {
++		SMSC_TRACE(DBG_PWR, "Rx FIFO is empty, continue suspend");
++	}
++
++	CHECK_RETURN_STATUS(smsc9500_read_reg(dev, PM_CTRL, &Value32));
++	Value32 &= (~(PM_CTL_SUS_MODE_ | PM_CTL_WUPS_ | PM_CTL_PHY_RST_));
++	Value32 |= PM_CTL_SUS_MODE_3 | PM_CTL_RES_CLR_WKP_STS;
++	CHECK_RETURN_STATUS(smsc9500_write_reg(dev, PM_CTRL, Value32));
++	Value32 &= ~PM_CTL_WUPS_;
++	Value32 |= PM_CTL_WUPS_WOL_; //Clear wol status
++	CHECK_RETURN_STATUS(smsc9500_write_reg(dev, PM_CTRL, Value32));
++
++	CHECK_RETURN_STATUS(smsc9500_set_feature(dev,USB_DEVICE_REMOTE_WAKEUP));
++
++	ret = SMSC9500_SUCCESS;
++DONE:
++	return ret;
++}
++
++static int SetWakeupEvents(struct net_device *netdev)
++{
++	u16 wValue;
++	WAKEUP_FILTER sFilter;
++	u32 dwValue, dwTemp, Value32;
++	int i = 0, ret = SMSC9500_FAIL;
++	int filterMaskCnt = 0, filterCmdCnt = 0, filterOffsetCnt = 0, filterCrcCnt = 0;
++	struct usbnet *dev = netdev_priv(netdev);
++	PADAPTER_DATA adapterData = (PADAPTER_DATA)(dev->data[0]);
++	u32 opts = adapterData->WolWakeupOpts;
++	BYTE bBcast[BCAST_LEN] = {0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF};
++	BYTE bMcast[MCAST_LEN] = {0x01, 0x00, 0x5E};
++	BYTE bArp[ARP_LEN] = {0x08, 0x06};
++
++	BUG_ON(!netdev);
++
++	SMSC_TRACE(DBG_PWR, "SetWakeupEvents");
++
++	if(opts & (WAKE_PHY | WAKE_UCAST | WAKE_BCAST | WAKE_MCAST | WAKE_ARP | WAKE_MAGIC)) {
++		if ((!(MdioDisable & MDIO_DISABLE_INTERNAL_ACCESS)) && (opts & WAKE_PHY)) {
++			/* Clear any pending Phy interrupt and enable the mask for it */
++			adapterData->systemSuspendPHYEvent = PHY_INT_MASK_LINK_DOWN_;
++			if (adapterData->dwLinkSettings&LINK_AUTO_NEGOTIATE)
++				adapterData->systemSuspendPHYEvent |= PHY_INT_MASK_ANEG_COMP_;
++
++			EnablePHYWakeupInterrupt(dev, adapterData->systemSuspendPHYEvent);
++
++			/* If there's currently no link we can use Suspend1 */
++			/* read PHY_BSR twice: link status bit is LL */
++			CHECK_RETURN_STATUS(smsc9500_read_phy(dev, PHY_BSR, &Value32));
++			CHECK_RETURN_STATUS(smsc9500_read_phy(dev, PHY_BSR, &Value32));
++			wValue = (u16)Value32;
++			if (!(wValue & PHY_BSR_LINK_STATUS_)) {
++				SMSC_TRACE(DBG_PWR, "Setting PHY in PD/ED Mode");
++
++				/* If we are in force mode, set the NWAY */
++				if ((adapterData->dwSavedLinkSettings&LINK_AUTO_NEGOTIATE) == 0) {
++					CHECK_RETURN_STATUS(smsc9500_read_phy(dev, PHY_BCR, &Value32));
++					Value32 |= PHY_BCR_AUTO_NEG_ENABLE_;
++					CHECK_RETURN_STATUS(smsc9500_write_phy(dev, PHY_BCR, Value32));
++				}
++
++				/* Enable the energy detect power-down mode */
++				CHECK_RETURN_STATUS(smsc9500_read_phy(dev, PHY_MODE_CTRL_STS, &dwValue));
++				wValue = (u16)dwValue;
++				wValue |= MODE_CTRL_STS_EDPWRDOWN_;
++				CHECK_RETURN_STATUS(smsc9500_write_phy(dev, PHY_MODE_CTRL_STS, wValue));
++
++				CHECK_RETURN_STATUS(smsc9500_read_phy(dev, PHY_INT_SRC, &dwTemp)); //Read to clear
++				/* Enable ENERGYON interrupt source */
++
++				CHECK_RETURN_STATUS(smsc9500_read_phy(dev, PHY_INT_MASK, &dwValue));
++				wValue = (u16)dwValue;
++				wValue |= PHY_INT_MASK_ENERGY_ON_;
++				CHECK_RETURN_STATUS(smsc9500_write_phy(dev, PHY_INT_MASK, wValue));
++
++				/* Put Lan9500 in Suspend1 */
++				SMSC_TRACE(DBG_PWR, "Setting Suspend1 mode");
++				CHECK_RETURN_STATUS(smsc9500_read_reg(dev, PM_CTRL, &Value32));
++				Value32 &= (~(PM_CTL_SUS_MODE_ | PM_CTL_WUPS_ | PM_CTL_PHY_RST_));
++				Value32 |= PM_CTL_SUS_MODE_1;
++				CHECK_RETURN_STATUS(smsc9500_write_reg(dev, PM_CTRL, Value32));
++				Value32 &= ~PM_CTL_WUPS_;
++				/* Clear wol status, enable energy detection */
++				Value32 |= (PM_CTL_WUPS_ED_ | PM_CTL_ED_EN_); 
++				CHECK_RETURN_STATUS(smsc9500_write_reg(dev, PM_CTRL, Value32));
++
++				CHECK_RETURN_STATUS(smsc9500_set_feature(dev, USB_DEVICE_REMOTE_WAKEUP));
++			} else {
++				/* Put Lan9500 in Suspend0 */
++				SMSC_TRACE(DBG_PWR, "Setting Suspend0 mode");
++				CHECK_RETURN_STATUS(smsc9500_read_reg(dev, PM_CTRL, &Value32));
++				Value32 &= (~(PM_CTL_SUS_MODE_ | PM_CTL_WUPS_ | PM_CTL_PHY_RST_));
++				Value32 |= PM_CTL_SUS_MODE_0;
++				CHECK_RETURN_STATUS(smsc9500_write_reg(dev, PM_CTRL, Value32));
++				Value32 &= ~PM_CTL_WUPS_;
++				/* Clear wol status */
++				Value32 |= PM_CTL_WUPS_ED_;
++				CHECK_RETURN_STATUS(smsc9500_write_reg(dev, PM_CTRL, Value32));
++				CHECK_RETURN_STATUS(smsc9500_set_feature(dev, USB_DEVICE_REMOTE_WAKEUP));
++			}
++		} else if (!(MdioDisable & MDIO_DISABLE_INTERNAL_ACCESS)) {
++			/* Clear any pending Phy interrupt and disable
++			the mask for it */
++			Value32 = PHY_INT_MASK_LINK_DOWN_;
++			if(adapterData->dwLinkSettings&LINK_AUTO_NEGOTIATE)
++				Value32 |= PHY_INT_MASK_ANEG_COMP_;
++			DisablePHYWakeupInterrupt(dev, Value32);
++		}
++
++		if (opts & (WAKE_BCAST | WAKE_MCAST | WAKE_ARP | WAKE_UCAST| WAKE_MAGIC)) {
++			if (opts & (WAKE_BCAST | WAKE_MCAST | WAKE_ARP | WAKE_UCAST)) {
++				int filter = 0;
++
++				memset(&sFilter,0,sizeof(sFilter));
++
++				if (opts & WAKE_BCAST) {
++					SMSC_TRACE(DBG_PWR, "Set broadicast detection");
++					sFilter.dwFilterMask[filter * 4] = 0x003F;
++					sFilter.dwFilterMask[filter * 4 + 1] = 0x00;
++					sFilter.dwFilterMask[filter * 4 + 2] = 0x00;
++					sFilter.dwFilterMask[filter * 4 + 3] = 0x00;
++					sFilter.dwCommad[filter/4] |= 0x05UL << ((filter % 4) * 8); //set command
++					sFilter.dwOffset[filter/4] |= 0x00 << ((filter % 4) * 8);
++					sFilter.dwCRC[filter/2] |= CalculateCrc16(bBcast, BCAST_LEN, FALSE) << ((filter % 2) * 16);
++					filter++;
++				}
++				if (opts & WAKE_MCAST) {
++					SMSC_TRACE(DBG_PWR, "Set multicast detection");
++					sFilter.dwFilterMask[filter * 4] = 0x0007;
++					sFilter.dwFilterMask[filter * 4 + 1] = 0x00;
++					sFilter.dwFilterMask[filter * 4 + 2] = 0x00;
++					sFilter.dwFilterMask[filter * 4 + 3] = 0x00;
++					sFilter.dwCommad[filter/4] |= 0x09UL << ((filter % 4) * 8); //set command
++					sFilter.dwOffset[filter/4] |= 0x00  << ((filter % 4) * 8);
++					sFilter.dwCRC[filter/2] |= (CalculateCrc16(bMcast, MCAST_LEN, FALSE) << ((filter % 2) * 16));
++					filter++;
++				}
++				if (opts & WAKE_ARP) {
++					SMSC_TRACE(DBG_PWR, "Set ARP detection");
++					sFilter.dwFilterMask[filter * 4] = 0x0003; //Check two bytes for ARP
++					sFilter.dwFilterMask[filter * 4 + 1] = 0x00;
++					sFilter.dwFilterMask[filter * 4 + 2] = 0x00;
++					sFilter.dwFilterMask[filter * 4 + 3] = 0x00;
++					sFilter.dwCommad[filter/4] |= 0x05UL << ((filter % 4) * 8); //set command
++					sFilter.dwOffset[filter/4] |= 0x0C << ((filter % 4) * 8);
++					sFilter.dwCRC[filter/2]= CalculateCrc16(bArp, ARP_LEN, FALSE) << ((filter % 2) * 16); //This is ARP type
++					filter++;
++				}
++				if (opts & WAKE_UCAST) {
++					SMSC_TRACE(DBG_PWR, "Set UCAST detection");
++					sFilter.dwFilterMask[filter * 4] = 0x003F; //Check nothing
++					sFilter.dwFilterMask[filter * 4 + 1] = 0x00;
++					sFilter.dwFilterMask[filter * 4 + 2] = 0x00;
++					sFilter.dwFilterMask[filter * 4 + 3] = 0x00;
++					sFilter.dwCommad[filter/4] |= 0x01UL << ((filter % 4) * 8); //set command
++					sFilter.dwOffset[filter/4] |= 0x00 << ((filter % 4) * 8);
++					sFilter.dwCRC[filter/2] |= CalculateCrc16(&netdev->dev_addr[0], 6, FALSE) << ((filter % 2) * 16);
++					filter++;
++				}
++
++				if (!dev->chipDependFeatures[FEATURE_WUFF_8]) {
++					filterMaskCnt = LAN9500_WUFF_NUM * 4;
++					filterCmdCnt = LAN9500_WUFF_NUM / 4;
++					filterOffsetCnt = LAN9500_WUFF_NUM / 4;
++					filterCrcCnt = LAN9500_WUFF_NUM / 2;
++				} else {
++					filterMaskCnt = LAN9500A_WUFF_NUM * 4;
++					filterCmdCnt = LAN9500A_WUFF_NUM / 4;
++					filterOffsetCnt = LAN9500A_WUFF_NUM / 4;
++					filterCrcCnt = LAN9500A_WUFF_NUM / 2;
++				}
++
++				for(i = 0; i < filterMaskCnt; i++) {
++					CHECK_RETURN_STATUS(smsc9500_write_reg(dev, WUFF, sFilter.dwFilterMask[i]));
++				}
++				for(i = 0; i < filterCmdCnt; i++) {
++					CHECK_RETURN_STATUS(smsc9500_write_reg(dev, WUFF, sFilter.dwCommad[i]));
++				}
++				for(i = 0; i < filterOffsetCnt; i++) {
++					CHECK_RETURN_STATUS(smsc9500_write_reg(dev, WUFF, sFilter.dwOffset[i]));
++				}
++				for(i = 0; i < filterCrcCnt; i++) {
++					CHECK_RETURN_STATUS(smsc9500_write_reg(dev, WUFF, sFilter.dwCRC[i]));
++				}
++
++				/* Clear any pending pattern match packet status */
++				CHECK_RETURN_STATUS(smsc9500_read_reg(dev, WUCSR, &Value32));
++				Value32 |= WUCSR_WUFR_;
++				CHECK_RETURN_STATUS(smsc9500_write_reg(dev, WUCSR, Value32));
++
++				/* Enable pattern match packet wake */
++				CHECK_RETURN_STATUS(smsc9500_read_reg(dev, WUCSR, &Value32));
++				Value32 |= WUCSR_WAKE_EN_;
++				CHECK_RETURN_STATUS(smsc9500_write_reg(dev, WUCSR, Value32));
++
++				CHECK_RETURN_STATUS(smsc9500_read_reg(dev, PM_CTRL, &Value32));
++				Value32 |= PM_CTL_WOL_EN_;
++				CHECK_RETURN_STATUS(smsc9500_write_reg(dev, PM_CTRL, Value32));
++
++			} else {
++				CHECK_RETURN_STATUS(smsc9500_read_reg(dev, WUCSR, &Value32));
++				Value32 &= (~WUCSR_WAKE_EN_);
++				CHECK_RETURN_STATUS(smsc9500_write_reg(dev, WUCSR, Value32));
++			}
++
++			if (opts & WAKE_MAGIC) {
++				SMSC_TRACE(DBG_PWR, "Setting magic packet detection");
++				/* Clear any pending magic packet status */
++				CHECK_RETURN_STATUS(smsc9500_read_reg(dev, WUCSR, &Value32));
++				Value32 |=  WUCSR_MPR_;
++				CHECK_RETURN_STATUS(smsc9500_write_reg(dev, WUCSR, Value32));
++
++				/* Enable MP wake */
++				CHECK_RETURN_STATUS(smsc9500_read_reg(dev, WUCSR, &Value32));
++				Value32 |=  WUCSR_MPEN_;
++				CHECK_RETURN_STATUS(smsc9500_write_reg(dev, WUCSR, Value32));
++
++				CHECK_RETURN_STATUS(smsc9500_read_reg(dev, PM_CTRL, &Value32));
++				Value32 |=  PM_CTL_WOL_EN_;
++				CHECK_RETURN_STATUS(smsc9500_write_reg(dev, PM_CTRL, Value32 ));
++			} else {
++				CHECK_RETURN_STATUS(smsc9500_read_reg(dev, WUCSR, &Value32));
++				Value32 &= (~WUCSR_MPEN_);
++				CHECK_RETURN_STATUS(smsc9500_write_reg(dev, WUCSR, Value32));
++			}
++
++			/* Enable recevier */
++			CHECK_RETURN_STATUS(smsc9500_read_reg(dev, MAC_CR, &dwValue));
++			dwValue |= MAC_CR_RXEN_;
++			if(opts & WAKE_MCAST) {
++				dwValue |= MAC_CR_MCPAS_;
++			}
++			CHECK_RETURN_STATUS(smsc9500_write_reg(dev,MAC_CR, dwValue));
++
++			SMSC_TRACE(DBG_PWR, "Setting Suspend0 mode");
++			CHECK_RETURN_STATUS(smsc9500_read_reg(dev, PM_CTRL, &Value32));
++			Value32 &= (~(PM_CTL_SUS_MODE_ | PM_CTL_WUPS_ | PM_CTL_PHY_RST_));
++			Value32 |= PM_CTL_SUS_MODE_0;
++			CHECK_RETURN_STATUS(smsc9500_write_reg(dev, PM_CTRL,  Value32));
++			Value32 &= ~PM_CTL_WUPS_;
++			/* Clear wol status, should not change suspned_mode while clearing WUPS_sts[1] */
++			Value32 |= PM_CTL_WUPS_WOL_; 
++			CHECK_RETURN_STATUS(smsc9500_write_reg(dev, PM_CTRL, Value32));
++			CHECK_RETURN_STATUS(smsc9500_read_reg(dev, PM_CTRL, &Value32));
++			CHECK_RETURN_STATUS(smsc9500_set_feature(dev, USB_DEVICE_REMOTE_WAKEUP));
++		}
++	} else {
++		SMSC_TRACE(DBG_PWR, "Disabling Wake events in ESS Regs");
++
++		/* Disable Energy detect (Link up) & Wake up events to do USB wake */
++		CHECK_RETURN_STATUS(smsc9500_read_reg(dev, WUCSR, &Value32));
++		Value32 |=~(WUCSR_MPEN_ | WUCSR_WAKE_EN_ );
++		CHECK_RETURN_STATUS(smsc9500_write_reg(dev, WUCSR, Value32));
++
++		CHECK_RETURN_STATUS(smsc9500_read_reg(dev, PM_CTRL, &Value32));
++		Value32 &= ~(PM_CTL_ED_EN_ | PM_CTL_WOL_EN_);
++		CHECK_RETURN_STATUS(smsc9500_write_reg(dev, PM_CTRL, Value32));
++
++		/* Put Lan9500 in Suspend2 */
++		SMSC_TRACE(DBG_PWR, "Setting Suspend2 mode");
++		CHECK_RETURN_STATUS(smsc9500_read_reg(dev, PM_CTRL, &Value32));
++		Value32 &= (~(PM_CTL_SUS_MODE_ | PM_CTL_WUPS_ | PM_CTL_PHY_RST_));
++		Value32 |= PM_CTL_SUS_MODE_2;
++		CHECK_RETURN_STATUS(smsc9500_write_reg(dev, PM_CTRL, Value32));
++	}
++
++	ret = 0;
++DONE:
++	return ret;
++}
++
++static int ResetWakeupEvents(struct net_device *netdev)
++{
++	u32 dwValue;
++	u16 wValue;
++	int ret = SMSC9500_FAIL;
++	struct usbnet *dev = netdev_priv(netdev);
++	PADAPTER_DATA adapterData = (PADAPTER_DATA)(dev->data[0]);
++
++	BUG_ON(!adapterData);
++	SMSC_TRACE(DBG_PWR, "ResetWakeupEvents");
++
++	if (!(adapterData->WolWakeupOpts & 
++		(WAKE_PHY | WAKE_UCAST | WAKE_BCAST | WAKE_MCAST | WAKE_ARP | WAKE_MAGIC))) {
++		return ret;
++	}
++
++	smsc9500_clear_feature(dev,USB_DEVICE_REMOTE_WAKEUP);
++	if ((adapterData->WolWakeupOpts & WAKE_PHY) && (!(MdioDisable & MDIO_DISABLE_INTERNAL_ACCESS))) {
++		//Disable the energy detect power-down mode
++		CHECK_RETURN_STATUS(smsc9500_read_phy(dev, PHY_MODE_CTRL_STS, &dwValue));
++		wValue = (u16)dwValue;
++		wValue &= ~MODE_CTRL_STS_EDPWRDOWN_;
++		CHECK_RETURN_STATUS(smsc9500_write_phy(dev, PHY_MODE_CTRL_STS, wValue));
++
++		//Disable energy-detect wake-up
++		CHECK_RETURN_STATUS(smsc9500_read_reg(dev, PM_CTRL, &dwValue));
++		dwValue &= ~PM_CTL_PHY_RST_;
++		dwValue |= PM_CTL_WUPS_; //Clear wake-up status
++		CHECK_RETURN_STATUS(smsc9500_write_reg(dev, PM_CTRL, dwValue));
++
++		if (!(MdioDisable & MDIO_DISABLE_INTERNAL_ACCESS)) {
++			DisablePHYWakeupInterrupt(dev, adapterData->systemSuspendPHYEvent);
++		}
++
++		smsc9500_eth_phy_boost(dev, 1);
++	} 
++
++	if (adapterData->WolWakeupOpts & (WAKE_BCAST | WAKE_MCAST | WAKE_ARP | WAKE_UCAST)) {
++		CHECK_RETURN_STATUS(smsc9500_read_reg(dev, WUCSR, &dwValue));
++		dwValue &= ~WUCSR_WAKE_EN_;   //Disable Wake-up frame detection
++		CHECK_RETURN_STATUS(smsc9500_write_reg(dev, WUCSR, dwValue));
++
++	}
++
++	if (adapterData->WolWakeupOpts & WAKE_MAGIC) {
++		//Set Magic packet detection
++		CHECK_RETURN_STATUS(smsc9500_read_reg(dev, WUCSR, &dwValue));
++		dwValue &= ~WUCSR_MPEN_;   //Disable magic frame detection
++		CHECK_RETURN_STATUS(smsc9500_write_reg(dev, WUCSR, dwValue));
++	}
++
++	//Disable wake-up frame interrupt
++	CHECK_RETURN_STATUS(smsc9500_read_reg(dev, PM_CTRL, &dwValue));
++	dwValue &= ~PM_CTL_WOL_EN_;
++	dwValue |= PM_CTL_WUPS_; //Clear wake-up status
++	CHECK_RETURN_STATUS(smsc9500_write_reg(dev, PM_CTRL, dwValue));
++
++	ret = 0;
++DONE:
++	return ret;
++}
++
++static int SetLinkDownWakeupEvents(struct usbnet *dev, int wakeUpMode)
++{
++	u32 dwValue;
++	u16 wValue;
++	int ret = SMSC9500_FAIL;
++	PADAPTER_DATA adapterData = (PADAPTER_DATA)(dev->data[0]);
++
++	BUG_ON(!dev);
++
++	SMSC_TRACE(DBG_PWR, "SetLinkDownWakeupEvents");
++
++	if (MdioDisable & MDIO_DISABLE_INTERNAL_ACCESS) {
++		return ret;
++	}
++
++	CHECK_RETURN_STATUS(smsc9500_read_reg(dev, PM_CTRL, &dwValue));
++	dwValue |= PM_CTL_ED_EN_;
++	CHECK_RETURN_STATUS(smsc9500_write_reg(dev, PM_CTRL, dwValue));
++
++	SMSC_TRACE(DBG_PWR, "Setting PHY in PD/ED Mode");
++
++	if (wakeUpMode == WAKEPHY_ENERGY) {
++
++		/* If we are in force mode, set the NWAY */
++		if ((adapterData->dwSavedLinkSettings&LINK_AUTO_NEGOTIATE) == 0) {
++			CHECK_RETURN_STATUS(smsc9500_read_phy(dev, PHY_BCR, &dwValue));
++			dwValue |= PHY_BCR_AUTO_NEG_ENABLE_;
++			CHECK_RETURN_STATUS(smsc9500_write_phy(dev, PHY_BCR, dwValue));
++		}
++		
++		/* Enable the energy detect power-down mode */
++		CHECK_RETURN_STATUS(smsc9500_read_phy(dev, PHY_MODE_CTRL_STS, &dwValue));
++		wValue = (u16)dwValue;
++		wValue |= MODE_CTRL_STS_EDPWRDOWN_;
++		CHECK_RETURN_STATUS(smsc9500_write_phy(dev, PHY_MODE_CTRL_STS, wValue));
++
++		CHECK_RETURN_STATUS(smsc9500_read_phy(dev, PHY_INT_SRC, &dwValue)); //Read to clear
++		CHECK_RETURN_STATUS(smsc9500_read_phy(dev, PHY_INT_SRC, &dwValue)); //Read two times
++
++		/* Enable interrupt source */
++		CHECK_RETURN_STATUS(smsc9500_read_phy(dev, PHY_INT_MASK, &dwValue));
++		wValue |= (PHY_INT_MASK_ENERGY_ON_ | PHY_INT_MASK_ANEG_COMP_);
++		CHECK_RETURN_STATUS(smsc9500_write_phy(dev, PHY_INT_MASK, wValue));
++
++		CHECK_RETURN_STATUS(smsc9500_read_reg(dev, PM_CTRL, &dwValue));
++		dwValue &= (~(PM_CTL_SUS_MODE_ | PM_CTL_WUPS_ | PM_CTL_PHY_RST_));
++		dwValue |= PM_CTL_SUS_MODE_1;
++		CHECK_RETURN_STATUS(smsc9500_write_reg(dev, PM_CTRL, dwValue));
++
++		CHECK_RETURN_STATUS(smsc9500_set_feature(dev, USB_DEVICE_REMOTE_WAKEUP));
++
++		SMSC_TRACE(DBG_PWR, "Setting Suspend1 mode");
++
++	} else if (wakeUpMode == WAKEPHY_NEGO_COMPLETE) {
++		/* Disable the energy detect power-down mode */
++		CHECK_RETURN_STATUS(smsc9500_read_phy(dev, PHY_MODE_CTRL_STS, &dwValue));
++		dwValue &= ~MODE_CTRL_STS_EDPWRDOWN_;
++		CHECK_RETURN_STATUS(smsc9500_write_phy(dev, PHY_MODE_CTRL_STS, dwValue));
++
++		CHECK_RETURN_STATUS(smsc9500_read_phy(dev, PHY_INT_SRC, &dwValue)); //Read to clear
++		CHECK_RETURN_STATUS(smsc9500_read_phy(dev, PHY_INT_SRC, &dwValue)); //Read two times
++		/* Enable interrupt source */
++		CHECK_RETURN_STATUS(smsc9500_read_phy(dev, PHY_INT_MASK, &dwValue));
++		dwValue |= PHY_INT_MASK_ANEG_COMP_;
++		CHECK_RETURN_STATUS(smsc9500_write_phy(dev, PHY_INT_MASK, dwValue));
++
++		CHECK_RETURN_STATUS(smsc9500_read_reg(dev, PM_CTRL, &dwValue));
++		dwValue &= (~(PM_CTL_SUS_MODE_ | PM_CTL_WUPS_ | PM_CTL_PHY_RST_));
++		dwValue |= PM_CTL_SUS_MODE_0;
++		CHECK_RETURN_STATUS(smsc9500_write_reg(dev, PM_CTRL, dwValue));
++
++		CHECK_RETURN_STATUS(smsc9500_set_feature(dev, USB_DEVICE_REMOTE_WAKEUP));
++
++		SMSC_TRACE(DBG_PWR, "Setting Suspend0 mode");
++	}
++	ret = 0;
++DONE:
++	return ret;
++}
++
++static int ResetLinkDownWakeupEvents(struct usbnet *dev)
++{
++	u32 dwValue;
++	u16 wValue;
++	int ret = SMSC9500_FAIL;
++	PADAPTER_DATA adapterData = (PADAPTER_DATA)(dev->data[0]);
++
++	SMSC_TRACE(DBG_PWR, "ResetLinkDownWakeupEvents");
++
++	smsc9500_clear_feature(dev, USB_DEVICE_REMOTE_WAKEUP);
++
++	/* Disable the energy detect power-down mode */
++	CHECK_RETURN_STATUS(smsc9500_read_phy(dev, PHY_MODE_CTRL_STS, &dwValue));
++	wValue = (u16)dwValue;
++	wValue &= ~MODE_CTRL_STS_EDPWRDOWN_;
++	CHECK_RETURN_STATUS(smsc9500_write_phy(dev, PHY_MODE_CTRL_STS, wValue));
++
++	//Disable ENERGYON interrupt source
++	CHECK_RETURN_STATUS(smsc9500_read_phy(dev, PHY_INT_MASK, &dwValue));
++	wValue = (u16)dwValue;
++	wValue &= ~PHY_INT_MASK_ENERGY_ON_;
++	if (dev->linkDownSuspend == WAKEPHY_ENERGY) {
++		wValue &= ~(PHY_INT_MASK_ENERGY_ON_ | PHY_INT_MASK_ANEG_COMP_);
++	} else if (dev->linkDownSuspend == WAKEPHY_NEGO_COMPLETE) {
++		wValue &= ~PHY_INT_MASK_ANEG_COMP_;
++	}
++
++	CHECK_RETURN_STATUS(smsc9500_write_phy(dev, PHY_INT_MASK, wValue));
++
++	/* Disable energy-detect wake-up */
++	CHECK_RETURN_STATUS(smsc9500_read_reg(dev, PM_CTRL, &dwValue));
++	dwValue &= ~PM_CTL_ED_EN_;
++	CHECK_RETURN_STATUS(smsc9500_write_reg(dev, PM_CTRL, dwValue));
++
++	smsc9500_eth_phy_boost(dev, 1);
++
++	/* If we are in force mode, re-set the NWAY */
++	if((adapterData->dwSavedLinkSettings&LINK_AUTO_NEGOTIATE) == 0) {
++		phy_SetLink(dev, adapterData->dwSavedLinkSettings);
++  	}	
++	ret = 0;
++DONE:
++	return ret;
++}
++
++/*++
++
++Routine Description:
++
++    This routine enables PHY interrupt
++
++Arguments:
++	interrupt:  Bit mask for PHY interrupt
++Return Value:
++
++--*/
++
++static int EnablePHYWakeupInterrupt(struct usbnet *dev, u32 interrupt)
++{
++	u32 dwValue;
++	int ret = SMSC9500_FAIL;
++
++	BUG_ON(!dev);
++
++	SMSC_TRACE(DBG_PWR, "EnablePHYWakeupInterrupt");
++
++	if (MdioDisable & MDIO_DISABLE_INTERNAL_ACCESS) {
++		/* Return Success here. During dynamic suspend, mac
++		will be configured to wake and pretend (no phy access)
++		phy is configured.*/
++		return SMSC9500_SUCCESS;
++	}
++
++	CHECK_RETURN_STATUS(smsc9500_read_phy(dev, PHY_INT_SRC, &dwValue)); //Read to clear
++
++	/* Enable interrupt source */
++	CHECK_RETURN_STATUS(smsc9500_read_phy(dev, PHY_INT_MASK, &dwValue));
++	dwValue |= interrupt;
++	CHECK_RETURN_STATUS(smsc9500_write_phy(dev, PHY_INT_MASK, dwValue));
++
++	if (dwValue) {
++		CHECK_RETURN_STATUS(smsc9500_read_reg(dev, PM_CTRL, &dwValue));
++		dwValue &= ~PM_CTL_PHY_RST_;
++		dwValue |= PM_CTL_ED_EN_;
++		CHECK_RETURN_STATUS(smsc9500_write_reg(dev, PM_CTRL, dwValue));
++	}
++
++	ret = SMSC9500_SUCCESS;
++DONE:
++	return ret;
++}
++
++/*++
++
++Routine Description:
++
++    This routine Disables linkdown interrupt in the PHY
++
++Arguments:
++
++Return Value:
++
++--*/
++
++static int DisablePHYWakeupInterrupt(struct usbnet *dev, u32 interrupt)
++{
++	u32 dwValue;
++	int ret = SMSC9500_FAIL;
++
++	BUG_ON(!dev);
++
++	SMSC_TRACE(DBG_PWR, "DisablePHYWakeupInterrupt");
++
++	CHECK_RETURN_STATUS(smsc9500_read_phy(dev, PHY_INT_SRC, &dwValue)); //Read to clear
++
++	if (MdioDisable & MDIO_DISABLE_INTERNAL_ACCESS) {
++		/* Return Success here. During dynamic suspend resume,
++		mac wake disabled and pretend (no phy access) phy wake
++		disabled. */
++		return SMSC9500_SUCCESS;
++	}
++
++	/* Disable interrupt source */
++	CHECK_RETURN_STATUS(smsc9500_read_phy(dev, PHY_INT_MASK, &dwValue));
++	dwValue &= PHY_INT_MASK_ALL;
++	dwValue &= ~interrupt;
++	CHECK_RETURN_STATUS(smsc9500_write_phy(dev, PHY_INT_MASK, dwValue));
++
++	if (dwValue == 0) {
++		/* All interrupt sources are disabled */
++		CHECK_RETURN_STATUS(smsc9500_read_reg(dev, PM_CTRL, &dwValue));
++		dwValue &= ~(PM_CTL_PHY_RST_ | PM_CTL_ED_EN_);
++		CHECK_RETURN_STATUS(smsc9500_write_reg(dev, PM_CTRL, dwValue));
++	}
++
++	ret = SMSC9500_SUCCESS;
++
++DONE:
++	return ret;
++}
++
++/*
++Routine Description:
++
++    This routine Starts the Tx path at the MAC and sets the flag to accept
++    bulk out requests
++
++*/
++static int StartTxPath(struct usbnet * dev )
++{
++	u32 Value32;
++	int ret = SMSC9500_FAIL;
++
++	/* Enable Tx at MAC */
++	CHECK_RETURN_STATUS(smsc9500_read_reg(dev, MAC_CR, &Value32));
++	Value32 |= MAC_CR_TXEN_;
++	CHECK_RETURN_STATUS(smsc9500_write_reg(dev, MAC_CR, Value32));
++
++	/* Enable Tx at SCSRs */
++	Value32 = TX_CFG_ON_;
++	CHECK_RETURN_STATUS(smsc9500_write_reg(dev, TX_CFG, Value32));
++
++	ret = 0;
++DONE:
++	return ret;
++}
++
++/*
++Routine Description:
++
++    Starts the Receive path.
++
++    Note that if we are operating in USB bandwidth friendly mode we defer
++    starting the bulk in requests for now (will start when operational mode pipe signals
++    receive data available).
++
++*/
++static int StartRxPath(struct usbnet *dev )
++{
++	u32 Value32;
++	int ret = SMSC9500_FAIL;
++
++	CHECK_RETURN_STATUS(smsc9500_read_reg(dev, MAC_CR, &Value32));
++	Value32 |= MAC_CR_RXEN_;
++	CHECK_RETURN_STATUS(smsc9500_write_reg(dev, MAC_CR, Value32));
++
++	ret = 0;
++DONE:
++	return ret;
++}
++
++
++#if (LINUX_VERSION_CODE < KERNEL_VERSION(2,6,11))
++static int Smsc9500_suspend (struct usb_interface *intf,  u32 state)
++#else
++static int Smsc9500_suspend (struct usb_interface *intf, pm_message_t state)
++#endif
++{
++	u32 dwValue;
++	int ret = SMSC9500_SUCCESS;
++	struct usbnet *dev = usb_get_intfdata(intf);
++
++	SMSC_TRACE(DBG_PWR, "Smsc9500_suspend");
++
++	BUG_ON(!dev);
++	BUG_ON(!dev->udev);
++
++	smsc9500_read_reg(dev,WUCSR,&dwValue);
++
++#if (LINUX_VERSION_CODE > KERNEL_VERSION(2,6,18))
++#ifdef CONFIG_PM
++#if (LINUX_VERSION_CODE < KERNEL_VERSION(2,6,33))
++	if(dev->udev->auto_pm) //Internal pm event, autosuspend
++#else
++	if (state.event & PM_EVENT_AUTO)
++#endif
++#else
++	if(0)
++#endif //CONFIG_PM
++#else
++	if(0)
++#endif
++	{
++		/* Auto suspend */
++		ret = Smsc9500AutoSuspend(intf, state);
++	} else {
++		/* It is system suspend */
++		ret = Smsc9500SystemSuspend(intf, state);
++	}
++
++	return ret;
++}
++
++#if (LINUX_VERSION_CODE < KERNEL_VERSION(2,6,11))
++static int Smsc9500AutoSuspend (struct usb_interface *intf, u32 state)
++#else
++static int Smsc9500AutoSuspend (struct usb_interface *intf, pm_message_t state)
++#endif
++{
++	u32 Value32;
++	bool LinkUp = FALSE;
++	int ret = SMSC9500_SUCCESS;
++	struct usbnet *dev = usb_get_intfdata(intf);
++	PADAPTER_DATA adapterData = (PADAPTER_DATA)(dev->data[0]);
++	int suspendFlag = dev->suspendFlag;
++
++	SMSC_TRACE(DBG_PWR, "Smsc9500AutoSuspend, suspendFlag = 0x%x", suspendFlag);
++
++	dev->suspendFlag = 0;
++
++	if (netif_running (dev->net)) {
++		adapterData->wakeupOptsBackup = adapterData->WolWakeupOpts;
++
++		if (MdioDisable & MDIO_DISABLE_INTERNAL_ACCESS) {
++			if (adapterData->DefaultLinkStatus & MDIO_DEFAULT_LINK_INIT_MASK) {
++				LinkUp = TRUE;
++			} else {
++				LinkUp = FALSE;
++			}
++		} else {
++			/* last minute link check */
++			/* read PHY_BSR twice: link status bit is LL */
++			smsc9500_read_phy(dev, PHY_BSR, &Value32);
++			if (smsc9500_read_phy(dev, PHY_BSR, &Value32) < 0) {
++				return SMSC9500_FAIL;
++			}
++			if (Value32 & PHY_BSR_LINK_STATUS_) {
++				LinkUp = TRUE;
++			} else {
++				LinkUp = FALSE;
++			}
++		}
++
++		if (LinkUp == FALSE) {
++			/* Link is down */
++			if (dev->netDetach) {
++				/* NetDetach highest priority */
++				if (!dev->pmLock) {
++					/* Resume immediately, then detach device from USB bus */
++					smscusbnet_defer_myevent(dev, EVENT_IDLE_RESUME);
++				}
++				ret = SMSC9500_FAIL;
++				goto _SUSPEND_EXIT;
++			} else if (dev->linkDownSuspend || (suspendFlag & AUTOSUSPEND_LINKDOWN)) {
++				dev->suspendFlag |= AUTOSUSPEND_LINKDOWN;
++				if (!(MdioDisable & MDIO_DISABLE_INTERNAL_ACCESS)) { 
++					ret = SetLinkDownWakeupEvents(dev, dev->linkDownSuspend);
++				}
++			} else if (suspendFlag & AUTOSUSPEND_DYNAMIC) {
++				dev->suspendFlag |= AUTOSUSPEND_DYNAMIC;
++				adapterData->WolWakeupOpts = (WAKE_UCAST | WAKE_BCAST | WAKE_MCAST | WAKE_ARP);
++				ret = SetWakeupEvents(dev->net);
++				if (!(MdioDisable & MDIO_DISABLE_INTERNAL_ACCESS)) {
++					/* Save PHY interrupt event, so we can clear it after waking up */
++					adapterData->dynamicSuspendPHYEvent = PHY_INT_MASK_ENERGY_ON_ | 
++										PHY_INT_MASK_ANEG_COMP_;
++					ret = EnablePHYWakeupInterrupt(dev, adapterData->dynamicSuspendPHYEvent);
++				}
++			} else if (suspendFlag & AUTOSUSPEND_DYNAMIC_S3) {
++				/* LAN9500A on wards supports suspend3 */
++				dev->suspendFlag |= AUTOSUSPEND_DYNAMIC_S3;
++				ret = SetWakeupOnSuspend3(dev->net);
++				if ((ret != SMSC9500_FAIL) && (!(MdioDisable & MDIO_DISABLE_INTERNAL_ACCESS))) {
++					/* Save PHY interrupt event, so we can clear it after waking up */
++					adapterData->dynamicSuspendPHYEvent = PHY_INT_MASK_ENERGY_ON_ | 
++										PHY_INT_MASK_ANEG_COMP_;
++					ret = EnablePHYWakeupInterrupt(dev, adapterData->dynamicSuspendPHYEvent);
++				}
++			} else {
++				SMSC_WARNING("auto suspend event is null\n");
++				ret = SMSC9500_FAIL;
++			}
++		} else {
++			/* Link Up */
++			if (suspendFlag & AUTOSUSPEND_DYNAMIC) {
++				dev->suspendFlag |= AUTOSUSPEND_DYNAMIC;
++				adapterData->WolWakeupOpts = (WAKE_UCAST | WAKE_BCAST | WAKE_MCAST | WAKE_ARP);
++				ret = SetWakeupEvents(dev->net);
++				if (!(MdioDisable & MDIO_DISABLE_INTERNAL_ACCESS)) {
++					/* Save PHY interrupt event, so we can clear it after waking up */
++					adapterData->dynamicSuspendPHYEvent = PHY_INT_MASK_LINK_DOWN_;
++					ret = EnablePHYWakeupInterrupt(dev, adapterData->dynamicSuspendPHYEvent);
++				}
++			} else if(suspendFlag & AUTOSUSPEND_DYNAMIC_S3) {
++				dev->suspendFlag |= AUTOSUSPEND_DYNAMIC_S3;
++				ret = SetWakeupOnSuspend3(dev->net);
++				if ((ret != SMSC9500_FAIL) && (!(MdioDisable & MDIO_DISABLE_INTERNAL_ACCESS))) {
++					/* Save PHY interrupt event, so we can clear it after waking up */
++					adapterData->dynamicSuspendPHYEvent = PHY_INT_MASK_LINK_DOWN_;
++					ret = EnablePHYWakeupInterrupt(dev, adapterData->dynamicSuspendPHYEvent);
++				}
++			} else {
++				/* if(suspendFlag & AUTOSUSPEND_LINKDOWN) Resume immediately */
++				ret = SMSC9500_FAIL;
++			}
++		}
++
++		if (ret != SMSC9500_SUCCESS) {
++			SMSC_WARNING("Failed to suspend device\n");
++			dev->suspendFlag = 0;
++			if (!dev->pmLock) {
++				/* Resume immediately */
++				smscusbnet_defer_myevent(dev, EVENT_IDLE_RESUME);
++			}
++			goto _SUSPEND_EXIT;
++		} else {
++			smscusbnet_FreeQueue(dev);
++			del_timer_sync(&dev->LinkPollingTimer);
++		}
++	} else {
++		/* Interface down */
++		u32 Value32;
++		SMSC_TRACE(DBG_PWR, "Interface is down, set suspend2 mode");
++		smsc9500_read_reg(dev, PM_CTRL, &Value32);
++		Value32 &= (~(PM_CTL_SUS_MODE_ | PM_CTL_WUPS_ | PM_CTL_PHY_RST_));
++		Value32 |= PM_CTL_SUS_MODE_2;
++		smsc9500_write_reg(dev, PM_CTRL, Value32);
++		dev->suspendFlag |= AUTOSUSPEND_INTFDOWN;
++	}
++_SUSPEND_EXIT:
++	return ret;
++}
++
++#if (LINUX_VERSION_CODE < KERNEL_VERSION(2,6,11))
++static int Smsc9500SystemSuspend (struct usb_interface *intf, u32 state)
++#else
++static int Smsc9500SystemSuspend (struct usb_interface *intf, pm_message_t state)
++#endif
++{
++	struct usbnet *dev = usb_get_intfdata(intf);
++
++	SMSC_TRACE(DBG_PWR, "Smsc9500SystemSuspend");
++
++	dev->idleCount = 0;
++	dev->suspendFlag = 0;
++
++	if (dev->net && netif_running (dev->net) && netif_device_present (dev->net)) {
++		netif_device_detach (dev->net);
++		smscusbnet_FreeQueue(dev);
++
++		dev->StopLinkPolling = TRUE;
++		del_timer_sync(&dev->LinkPollingTimer);
++
++		Tx_StopQueue(dev,0x04UL);
++		smsc9500_stopAndFlushTxPath(dev);
++		smsc9500_stopAndFlushRxPath(dev);
++
++		SetWakeupEvents(dev->net);
++	} else {
++		/* Put device to Suspend2 */
++		u32 Value32;
++		SMSC_TRACE(DBG_PWR, "Setting Suspend2 mode");
++		smsc9500_read_reg(dev, PM_CTRL, &Value32);
++		Value32 &= (~(PM_CTL_SUS_MODE_ | PM_CTL_WUPS_ | PM_CTL_PHY_RST_));
++		Value32 |= PM_CTL_SUS_MODE_2;
++		smsc9500_write_reg(dev, PM_CTRL, Value32);
++		dev->suspendFlag |= AUTOSUSPEND_INTFDOWN;
++	}
++
++	return SMSC9500_SUCCESS;
++}
++
++static int Smsc9500_resume(struct usb_interface *intf)
++{
++	int ret = SMSC9500_SUCCESS;
++	struct usbnet *dev = usb_get_intfdata(intf);
++
++	SMSC_TRACE(DBG_PWR, "Smsc9500_resume");
++
++	BUG_ON(!dev);
++	BUG_ON(!dev->udev);
++
++#if (LINUX_VERSION_CODE > KERNEL_VERSION(2,6,18))
++	 /* autoresume */
++	if(dev->suspendFlag)
++#else
++	if(0)
++#endif
++	{
++		ret = Smsc9500AutoResume(intf);
++	} else {
++		ret = Smsc9500SystemResume(intf);
++	}
++	return ret;
++}
++
++static int Smsc9500AutoResume(struct usb_interface *intf)
++{
++	u32 dwValue;
++	struct usbnet *dev = usb_get_intfdata(intf);
++	PADAPTER_DATA adapterData = (PADAPTER_DATA)(dev->data[0]);
++
++	SMSC_TRACE(DBG_PWR, "Smsc9500AutoResume");
++
++	clear_bit(EVENT_DEV_RECOVERY, &dev->flags);
++
++	if (dev->suspendFlag & AUTOSUSPEND_INTFDOWN) {
++		SMSC_TRACE(DBG_PWR, "Resume from interface down");
++		goto _EXIT_AUTORESUME;
++	}
++
++	if (!dev->pmLock) {
++		smscusbnet_defer_myevent(dev, EVENT_IDLE_RESUME);
++	}
++
++	if (dev->suspendFlag & AUTOSUSPEND_LINKDOWN) {
++		if (!(MdioDisable & MDIO_DISABLE_INTERNAL_ACCESS)) {
++			ResetLinkDownWakeupEvents(dev);
++		}
++	} else if(dev->suspendFlag & AUTOSUSPEND_DYNAMIC) {
++		if (!(MdioDisable & MDIO_DISABLE_INTERNAL_ACCESS)) {
++			DisablePHYWakeupInterrupt(dev, adapterData->dynamicSuspendPHYEvent);
++		}
++		ResetWakeupEvents(dev->net);
++	} else if(dev->suspendFlag & AUTOSUSPEND_DYNAMIC_S3) {
++		/* Resume from suspend3 */
++		smsc9500_clear_feature(dev,USB_DEVICE_REMOTE_WAKEUP);
++
++		if (!(MdioDisable & MDIO_DISABLE_INTERNAL_ACCESS)) {
++			DisablePHYWakeupInterrupt(dev, adapterData->dynamicSuspendPHYEvent);
++		}
++
++		if (smsc9500_read_reg(dev, PM_CTRL, &dwValue) < 0) {
++			SMSC_WARNING("Failed to read PM_CTRL");
++		}
++		dwValue &= (~(PM_CTL_SUS_MODE_ | PM_CTL_PHY_RST_));
++		dwValue |= PM_CTL_SUS_MODE_2;
++
++		if (smsc9500_write_reg(dev, PM_CTRL, dwValue) < 0) {
++			SMSC_WARNING("Failed to write PM_CTRL");
++		}
++		dwValue &= ~PM_CTL_WUPS_;
++		dwValue |= PM_CTL_WUPS_WOL_;
++
++		/* Should not change suspend_mode while clearing WUPS_sts[1] */
++		if (smsc9500_write_reg(dev, PM_CTRL, dwValue) < 0) {
++			SMSC_WARNING("Failed to write PM_CTRL");
++		}
++	}
++	//if(dev->delay.function)(dev->delay.function)((unsigned long)dev);
++	tasklet_schedule(&dev->bh);
++
++	if (adapterData->wakeupOptsBackup) {
++		adapterData->WolWakeupOpts = adapterData->wakeupOptsBackup;
++		adapterData->wakeupOptsBackup = 0;
++	}
++
++	Tx_WakeQueue(dev,0x04UL);
++
++_EXIT_AUTORESUME:
++	dev->idleCount = 0;
++	dev->suspendFlag = 0;
++
++	return SMSC9500_SUCCESS;
++}
++
++static int Smsc9500SystemResume(struct usb_interface *intf)
++{
++	int ret = 0;
++	u32 dwValue;
++	struct usbnet *dev = usb_get_intfdata(intf);
++
++	SMSC_TRACE(DBG_PWR, "Smsc9500SystemResume\n");
++
++	if (netif_running(dev->net) && !netif_device_present (dev->net)) {
++		netif_device_attach(dev->net);
++	}
++
++	/* Test if hcd is still alive */
++	if (smsc9500_read_reg_async(dev, MAC_CR, &dwValue, TRUE) == ASYNC_RW_SUCCESS) {
++		SMSC_TRACE(DBG_PWR, "hcd is alive");
++		ret = smsc9500_reset(dev);
++		if (ret < 0)
++			return ret;
++		StartTxPath(dev);
++		StartRxPath(dev);
++		ResetWakeupEvents(dev->net);
++	} else { 
++		/* This will happen on suspend-to-disk, if we access usb bus,
++		will hang on usb_kill_urb */
++		SMSC_TRACE(DBG_PWR, "no hcd");
++	}
++
++	Tx_WakeQueue(dev,0x04UL);
++
++	init_timer(&(dev->LinkPollingTimer));
++	dev->StopLinkPolling = FALSE;
++	dev->LinkPollingTimer.function = smscusbnet_linkpolling;
++	dev->LinkPollingTimer.data = (unsigned long) dev;
++	dev->LinkPollingTimer.expires = jiffies+HZ;
++	add_timer(&(dev->LinkPollingTimer));
++	tasklet_schedule (&dev->bh);
++
++	dev->idleCount = 0;
++
++	return SMSC9500_SUCCESS;
++}
++
++static int smsc9500_device_recovery(struct usbnet *dev)
++{
++	u32 dwReadBuf;
++
++	BUG_ON(!dev);
++
++	if (dev->net && netif_device_present (dev->net)) {
++		SMSC_WARNING("Device recovery is in progress\n");
++
++		if (smsc9500_read_reg(dev,INT_STS,&dwReadBuf) < 0)
++			return SMSC9500_FAIL;
++
++		smscusbnet_FreeQueue(dev);
++
++		dev->StopLinkPolling = TRUE;
++		del_timer_sync(&dev->LinkPollingTimer);
++
++		Tx_StopQueue(dev,0x04UL);
++
++		if (smsc9500_stopAndFlushTxPath(dev) < 0)
++			return SMSC9500_FAIL;
++		if (smsc9500_stopAndFlushRxPath(dev) < 0)
++			return SMSC9500_FAIL;
++
++		if (dwReadBuf & INT_STS_TXE_) {
++			/* reset only when TXE */
++			if (smsc9500_reset(dev) < 0)
++				return SMSC9500_FAIL;
++		}
++
++		if(StartTxPath(dev) < 0)
++			return SMSC9500_FAIL;
++		if(StartRxPath(dev) < 0)
++			return SMSC9500_FAIL;
++
++		Tx_WakeQueue(dev,0x04UL);
++
++		init_timer(&(dev->LinkPollingTimer));
++		dev->StopLinkPolling = FALSE;
++		dev->LinkPollingTimer.function = smscusbnet_linkpolling;
++		dev->LinkPollingTimer.data = (unsigned long) dev;
++		dev->LinkPollingTimer.expires = jiffies+HZ;
++		add_timer(&(dev->LinkPollingTimer));
++
++		tasklet_schedule (&dev->bh);
++
++		SMSC_WARNING("Device recovery is done\n");
++	}
++
++	return SMSC9500_SUCCESS;
++}
++
++static int smsc9500_eth_phy_boost(struct usbnet *dev, int mode)
++{
++	u32 dwTemp;
++	int Count;
++	PADAPTER_DATA adapterData = (PADAPTER_DATA)(dev->data[0]);
++
++	/* If mdio access is disabled return */
++	if (MdioDisable & MDIO_DISABLE_INTERNAL_ACCESS) {
++		return 0;
++	}
++	if ((adapterData->internalPhy) && ((dev->chipID == PID_LAN9730) || 
++		(dev->chipID == PID_LAN9530) || (dev->chipID == PID_LAN89530))) {
++		if (mode == 1) {
++			/* set boost */
++			dwTemp = PHY_TSTCNTL_TEST_MODE;
++			CHECK_RETURN_STATUS(smsc9500_write_phy(dev, PHY_TSTCNTL, dwTemp));	
++			CHECK_RETURN_STATUS(smsc9500_write_phy(dev, PHY_TSTCNTL, 0 ));	
++			CHECK_RETURN_STATUS(smsc9500_write_phy(dev, PHY_TSTCNTL, dwTemp));	
++
++			dwTemp = 0x85E8;
++			CHECK_RETURN_STATUS(smsc9500_write_phy(dev, PHY_TSTWRITE, dwTemp));	
++			/* dwTemp = 0x4416; */
++			dwTemp = (PHY_TSTCNTL_WRITE | PHY_TSTCNTL_TEST_MODE | 0x16);
++			CHECK_RETURN_STATUS(smsc9500_write_phy(dev, PHY_TSTCNTL, dwTemp));	
++			/* Loop until write is completed w/timeout */
++			for(Count = 1; Count < 100; Count++) {
++				dwTemp = 0;
++				CHECK_RETURN_STATUS(smsc9500_read_phy(dev, PHY_TSTCNTL, &dwTemp));	
++				if(!(dwTemp & PHY_TSTCNTL_WRITE))
++					break;
++				udelay(1);
++			}
++
++			if (Count == 100) {
++				SMSC_WARNING("Timed out writing PHY_TSTWRITE\n");
++			}
++
++			#if 0
++			/* read and verify the value */
++			/* dwTemp = 0x86C0 */
++			dwTemp = (PHY_TSTCNTL_READ | PHY_TSTCNTL_TEST_MODE | 0xC0);
++			CHECK_RETURN_STATUS(smsc9500_write_phy(dev, PHY_TSTCNTL, dwTemp));	
++			/* Loop until read is completed w/timeout */
++			for(Count = 1; Count < 100; Count++) {
++				dwTemp = 0;
++				CHECK_RETURN_STATUS(smsc9500_read_phy(dev, PHY_TSTCNTL, &dwTemp));	
++				if(!(dwTemp & PHY_TSTCNTL_READ))
++					break;
++				udelay(1);
++			}
++
++			if (Count < 100) {
++				dwTemp = 0;
++				CHECK_RETURN_STATUS(smsc9500_read_phy(dev, PHY_TSTREAD1, &dwTemp));	
++				if (dwTemp != 0x85E8) {
++					SMSC_WARNING("Failed to set Ethernet Boost: 0x%x", dwTemp);
++				} else{
++					SMSC_TRACE(DBG_INIT, "Ethernet Boost: 0x%x", dwTemp);
++				}
++			
++			} else {
++				SMSC_WARNING("Timed out reading PHY_TSTREAD1 register\n");
++				return 1;
++			}
++			#endif
++
++			CHECK_RETURN_STATUS(smsc9500_write_phy(dev, PHY_TSTCNTL, 0 ));	
++		} else {
++			#if 0
++                        dwTemp = PHY_TSTCNTL_TEST_MODE;
++			CHECK_RETURN_STATUS(smsc9500_write_phy(dev, PHY_TSTCNTL, dwTemp));	
++			CHECK_RETURN_STATUS(smsc9500_write_phy(dev, PHY_TSTCNTL, 0 ));	
++			CHECK_RETURN_STATUS(smsc9500_write_phy(dev, PHY_TSTCNTL, dwTemp));	
++
++			/* read and verify the value */
++			/* dwTemp = 0x86C0; */
++			dwTemp = (PHY_TSTCNTL_READ | PHY_TSTCNTL_TEST_MODE | 0xC0);
++			CHECK_RETURN_STATUS(smsc9500_write_phy(dev, PHY_TSTCNTL, dwTemp));	
++			/* Loop until read is completed w/timeout */
++			for(Count= 1; Count < 100; Count++) {
++				dwTemp = 0;
++				CHECK_RETURN_STATUS(smsc9500_read_phy(dev, PHY_TSTCNTL, &dwTemp));	
++				if (!(dwTemp & PHY_TSTCNTL_READ))
++					break;
++				udelay(1);
++			}
++
++			if (Count < 100) {
++				dwTemp = 0;
++				CHECK_RETURN_STATUS(smsc9500_read_phy(dev, PHY_TSTREAD1, &dwTemp));	
++				if (dwTemp != 0x85E8) {
++					SMSC_WARNING("Failed to set Ethernet Boost: 0x%x", dwTemp);
++				} else {
++					SMSC_TRACE(DBG_INIT, "Ethernet Boost: 0x%x", dwTemp);
++				}
++			
++			} else {
++				SMSC_WARNING("Timed out reading PHY_TSTREAD1 register");
++				return 1;
++			}
++
++                        CHECK_RETURN_STATUS(smsc9500_write_phy(dev, PHY_TSTCNTL, 0 ));
++			#endif
++		}
++	}
++	return 0;
++DONE:
++	return 1;
++}
++	
++
++static const struct driver_info smsc9500_info = {
++	.description = "smsc9500 USB 2.0 Ethernet",
++	.bind = smsc9500_bind,
++	.unbind=smsc9500_unbind,
++	.status = smsc9500_status,
++	.link_reset = smsc9500_link_reset,
++	.reset = smsc9500_reset,
++	.flags = FLAG_ETHER,
++	.rx_fixup = smsc9500_rx_fixup,
++	.tx_fixup = smsc9500_tx_fixup,
++	.rx_setmulticastlist=smsc9500_rx_setmulticastlist,
++};
++
++static const struct usb_device_id products [] = {
++	{
++		/* SMSC9500 USB Ethernet Device */
++		USB_DEVICE (0x0424, PID_LAN9500),
++		.driver_info = (unsigned long) &smsc9500_info,
++	},
++	{
++		/* SMSC9512/9514 USB hub with Ethernet Device */
++		USB_DEVICE (0x0424, PID_LAN9512),
++		.driver_info = (unsigned long) &smsc9500_info,
++	},
++	{
++		/* SMSC9500A USB Ethernet Device */
++		USB_DEVICE (0x0424, PID_LAN9500A),
++		.driver_info = (unsigned long) &smsc9500_info,
++	},
++	{
++		/* LAN9530 USB Ethernet Device */
++		USB_DEVICE (0x0424, PID_LAN9530 ),
++		.driver_info = (unsigned long) &smsc9500_info,
++	},
++	{
++		/* LAN9730 USB Ethernet Device */
++		USB_DEVICE (0x0424, PID_LAN9730),
++		.driver_info = (unsigned long) &smsc9500_info,
++	},
++	{
++		/* LAN89530 USB Ethernet Device */
++		USB_DEVICE (0x0424, PID_LAN89530),
++		.driver_info = (unsigned long) &smsc9500_info,
++	},
++	{ },	/* END */
++};
++
++MODULE_DEVICE_TABLE(usb, products);
++
++static struct usb_driver smsc9500_driver = {
++	.name		= "smsc9500",
++	.id_table	= products,
++	.probe		= smscusbnet_probe,
++	.suspend	= Smsc9500_suspend,
++	.resume		= Smsc9500_resume,
++	.disconnect	= smscusbnet_disconnect,
++#if (LINUX_VERSION_CODE > KERNEL_VERSION(2,6,22))
++	.reset_resume = Smsc9500SystemResume,
++#endif
++#if (LINUX_VERSION_CODE > KERNEL_VERSION(2,6,18))
++    .supports_autosuspend = 1,
++#endif
++};
++
++static int __init smsc9500_init(void)
++{
++ 	return usb_register(&smsc9500_driver);
++}
++module_init(smsc9500_init);
++
++static void __exit smsc9500_exit(void)
++{
++ 	usb_deregister(&smsc9500_driver);
++}
++module_exit(smsc9500_exit);
++
++MODULE_AUTHOR("Nancy Lin and Sean(Xiang) Chen");
++MODULE_DESCRIPTION("SMSC9500 USB 2.0 Ethernet Devices");
++MODULE_LICENSE("GPL");
++
+diff --git a/drivers/net/ethernet/smsc9514/smsc9500.h b/drivers/net/ethernet/smsc9514/smsc9500.h
+new file mode 100755
+index 0000000..09f8093
+--- /dev/null
++++ b/drivers/net/ethernet/smsc9514/smsc9500.h
+@@ -0,0 +1,859 @@
++/***************************************************************************
++ *
++ * Copyright (C) 2007-2008  SMSC
++ *
++ * This program is free software; you can redistribute it and/or
++ * modify it under the terms of the GNU General Public License
++ * as published by the Free Software Foundation; either version 2
++ * of the License, or (at your option) any later version.
++ *
++ * This program is distributed in the hope that it will be useful,
++ * but WITHOUT ANY WARRANTY; without even the implied warranty of
++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
++ * GNU General Public License for more details.
++ *
++ * You should have received a copy of the GNU General Public License
++ * along with this program; if not, write to the Free Software
++ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
++ *
++ ***************************************************************************
++ * File: smsc9500.h
++ *****************************************************************************/
++
++#ifndef _LAN9500_H
++#define _LAN9500_H
++
++typedef unsigned char BYTE;
++
++#define STATUS_WORD_LEN			4
++
++#define LAN_REGISTER_RANGE		0xFF
++#define MAC_REGISTER_RANGE_MIN		0x100
++#define MAC_REGISTER_RANGE_MAX		0x130
++
++/* product id definition */
++#define PID_LAN9500			0x9500
++#define PID_LAN9500A			0x9E00
++#define PID_LAN9512			0xEC00
++#define PID_LAN9530			0x9530
++#define PID_LAN9535			0x9535
++#define PID_LAN9730			0x9730
++#define PID_LAN9735			0x9735
++#define PID_LAN89530			0x9E08
++
++/* Tx MAT Cmds */
++#define TX_CMD_A_DATA_OFFSET_		(0x001F0000UL)
++#define TX_CMD_A_FIRST_SEG_		(0x00002000UL)
++#define TX_CMD_A_LAST_SEG_		(0x00001000UL)
++#define TX_CMD_A_BUF_SIZE_		(0x000007FFUL)
++
++#define TX_CMD_B_CSUM_ENABLE		(0x00004000UL)
++#define TX_CMD_B_ADD_CRC_DISABLE_	(0x00002000UL)
++#define TX_CMD_B_DISABLE_PADDING_	(0x00001000UL)
++#define TX_CMD_B_PKT_BYTE_LENGTH_	(0x000007FFUL)
++
++/* Rx sts Wd */
++#define	RX_STS_FF_			0x40000000UL	// Filter Fail
++#define	RX_STS_FL_			0x3FFF0000UL	// Frame Length
++#define RX_STS_DL_SHIFT_			16UL
++#define	RX_STS_ES_			0x00008000UL	// Error Summary
++#define	RX_STS_BF_			0x00002000UL	// Broadcast Frame
++#define	RX_STS_LE_			0x00001000UL	// Length Error
++#define	RX_STS_RF_			0x00000800UL	// Runt Frame
++#define	RX_STS_MF_			0x00000400UL	// Multicast Frame
++#define	RX_STS_TL_			0x00000080UL	// Frame too long
++#define	RX_STS_CS_			0x00000040UL	// Collision Seen
++#define	RX_STS_FT_			0x00000020UL	// Frame Type
++#define	RX_STS_RW_			0x00000010UL	// Receive Watchdog
++#define	RX_STS_ME_			0x00000008UL	// Mii Error
++#define RX_STS_DB_			0x00000004UL	// Dribbling
++#define RX_STS_CRC_			0x00000002UL	// CRC Error
++#define RX_STS_ERR_MASK_		0x000088DEUL
++
++
++/* SCSRs */
++#define ID_REV				(0x00UL)
++	#define ID_REV_CHIP_ID_MASK_   		(0xffff0000UL)
++	#define ID_REV_CHIP_REV_MASK_  		(0x0000ffffUL)
++	#define ID_REV_CHIP_ID_9500_        	(0x9500UL)
++	#define GetChipIdFromID_REV(dwReg)     	((dwReg & ID_REV_CHIP_ID_MASK_) >> 16)
++	#define GetChiprevFromID_REV(dwReg)    	(dwReg & ID_REV_CHIP_REV_MASK_)
++
++#define	FPGA_REV			(0x04UL)
++
++#define INT_STS                  	(0x08UL)
++	#define INT_STS_TX_STOP_		(0x00020000UL)
++	#define INT_STS_RX_STOP_		(0x00010000UL)
++	#define INT_STS_PHY_INT_		(0x00008000UL)
++	#define INT_STS_TXE_			(0x00004000UL)
++	#define INT_STS_TDFU_			(0x00002000UL)
++	#define INT_STS_TDFO_			(0x00001000UL)
++	#define INT_STS_RXDF_			(0x00000800UL)
++	#define INT_STS_GPIOS_	    		(0x000007FFUL)
++
++#define RX_CFG                  	(0x0CUL)
++	#define RX_FIFO_FLUSH_			(0x00000001UL)
++
++#define TX_CFG				(0x10UL)
++	#define TX_CFG_ON_			(0x00000004UL)
++	#define TX_CFG_STOP_			(0x00000002UL)
++	#define TX_CFG_FIFO_FLUSH_		(0x00000001UL)
++
++#define HW_CFG                  	(0x14UL)
++	#define HW_CFG_SMDET_STS		(0x00040000UL)
++	#define HW_CFG_SMDET_EN			(0x00020000UL)
++	#define HW_CFG_EEM			(0x00010000UL)
++	#define HW_CFG_RST_PROTECT		(0x00008000UL)
++	#define HW_CFG_PHY_BOOST		(0x00006000UL)
++		#define HW_CFG_PHY_BOOST_NORMAL	(0x00000000UL)
++		#define HW_CFG_PHY_BOOST_4	(0x00002000UL)
++		#define HW_CFG_PHY_BOOST_8	(0x00004000UL)
++		#define HW_CFG_PHY_BOOST_12	(0x00006000UL)
++	#define HW_CFG_BIR_			(0x00001000UL)
++	#define HW_CFG_LEDB_			(0x00000800UL)
++	#define HW_CFG_RXDOFF_			(0x00000600UL)
++	#define HW_CFG_RXDOFF_2_		(0x00000400UL)
++	#define HW_CFG_SBP_			(0x00000100UL)
++	#define HW_CFG_IME_			(0x00000080UL)
++	#define HW_CFG_DRP_			(0x00000040UL)
++	#define HW_CFG_MEF_			(0x00000020UL)
++	#define HW_CFG_ETC_			(0x00000010UL)
++	#define HW_CFG_LRST_			(0x00000008UL)
++	#define HW_CFG_PSEL_			(0x00000004UL)
++	#define HW_CFG_BCE_			(0x00000002UL)
++	#define HW_CFG_SRST_			(0x00000001UL)
++
++#define RX_FIFO_INF			(0x18UL)
++
++#define TX_FIFO_INF			(0x1CUL)
++
++#define PM_CTRL				(0x20UL)
++	#define PM_CTL_RES_CLR_WKP_STS		(0x00000200UL)
++	#define PM_CTL_RES_CLR_WKP_EN		(0x00000100UL)
++	#define PM_CTL_DEV_RDY_			(0x00000080UL)
++	#define	PM_CTL_SUS_MODE_		(0x00000060UL)
++	#define	PM_CTL_SUS_MODE_0		(0x00000000UL)
++	#define	PM_CTL_SUS_MODE_1		(0x00000020UL)
++	#define	PM_CTL_SUS_MODE_2		(0x00000040UL)
++	#define	PM_CTL_SUS_MODE_3		(0x00000060UL)
++	#define PM_CTL_PHY_RST_			(0x00000010UL)
++	#define PM_CTL_WOL_EN_			(0x00000008UL)
++	#define PM_CTL_ED_EN_			(0x00000004UL)
++	#define PM_CTL_WUPS_			(0x00000003UL)
++	#define PM_CTL_WUPS_NO_			(0x00000000UL)
++	#define PM_CTL_WUPS_ED_			(0x00000001UL)
++	#define PM_CTL_WUPS_WOL_		(0x00000002UL)
++	#define PM_CTL_WUPS_MULTI_		(0x00000003UL)
++
++#define LED_GPIO_CFG			(0x24UL)
++	#define LED_GPIO_CFG_LED_SEL_		(0x80000000UL)
++	#define LED_GPIO_CFG_GPCTL_10_		(0x03000000UL)
++	#define LED_GPIO_CFG_GPCTL_10_SH	24
++	#define LED_GPIO_CFG_GPCTL_09_		(0x00300000UL)
++	#define LED_GPIO_CFG_GPCTL_09_SH	20
++	#define LED_GPIO_CFG_GPCTL_08_		(0x00030000UL)
++	#define LED_GPIO_CFG_GPCTL_08_SH	16
++
++	#define LED_GPIO_CFG_GPCTL_DIAG2_	(0x3UL)
++	#define LED_GPIO_CFG_GPCTL_DIAG1_	(0x2UL)
++	#define LED_GPIO_CFG_GPCTL_LED_		(0x1UL)
++	#define LED_GPIO_CFG_GPCTL_GPIO_	(0x0UL)
++
++	#define LED_GPIO_CFG_GPBUF_		(0x00000700UL)
++	#define LED_GPIO_CFG_GPBUF_10_		(0x00000400UL)
++	#define LED_GPIO_CFG_GPBUF_09_		(0x00000200UL)
++	#define LED_GPIO_CFG_GPBUF_08_		(0x00000100UL)
++	#define LED_GPIO_CFG_GPDIR_		(0x00000070UL)
++	#define LED_GPIO_CFG_GPDIR_10_		(0x00000040UL)
++	#define LED_GPIO_CFG_GPDIR_09_		(0x00000020UL)
++	#define LED_GPIO_CFG_GPDIR_08_		(0x00000010UL)
++	#define LED_GPIO_CFG_GPDATA_		(0x00000007UL)
++	#define LED_GPIO_CFG_GPDATA_10_		(0x00000004UL)
++	#define LED_GPIO_CFG_GPDATA_09_		(0x00000002UL)
++	#define LED_GPIO_CFG_GPDATA_08_		(0x00000001UL)
++
++#define GPIO_CFG			(0x28UL)
++	#define GPIO_CFG_GPEN_			(0xFF000000UL)
++	#define GPIO_CFG_GPO0_EN_		(0x01000000UL)
++	#define GPIO_CFG_GPTYPE_		(0x00FF0000UL)
++	#define GPIO_CFG_GPO0_TYPE_		(0x00010000UL)
++	#define GPIO_CFG_GPDIR_			(0x0000FF00UL)
++	#define GPIO_CFG_GPO0_DIR_		(0x00000100UL)
++	#define GPIO_CFG_GPDATA_		(0x000000FFUL)
++	#define GPIO_CFG_GPO0_DATA_		(0x00000001UL)
++
++#define AFC_CFG				(0x2CUL)
++	#define AFC_CFG_DEFAULT			(0x00f830A1UL)	// Hi watermark = 15.5Kb (~10 mtu pkts)
++								// low watermark = 3k (~2 mtu pkts)
++								// backpressure duration = ~ 350us
++								// Apply FC on any frame.
++#define E2P_CMD				(0x30UL)
++	#define	E2P_CMD_BUSY_			0x80000000UL
++	#define	E2P_CMD_MASK_			0x70000000UL
++	#define	E2P_CMD_READ_			0x00000000UL
++	#define	E2P_CMD_EWDS_			0x10000000UL
++	#define	E2P_CMD_EWEN_			0x20000000UL
++	#define	E2P_CMD_WRITE_			0x30000000UL
++	#define	E2P_CMD_WRAL_			0x40000000UL
++	#define	E2P_CMD_ERASE_			0x50000000UL
++	#define	E2P_CMD_ERAL_			0x60000000UL
++	#define	E2P_CMD_RELOAD_			0x70000000UL
++	#define	E2P_CMD_TIMEOUT_		0x00000400UL
++	#define	E2P_CMD_LOADED_			0x00000200UL
++	#define	E2P_CMD_ADDR_			0x000001FFUL
++#define E2P_DATA			(0x34UL)
++	#define	E2P_DATA_MASK_			0x000000FFUL
++
++#define BURST_CAP			(0x38UL)
++#define STRAP_DBG			(0x3CUL)
++	#define EEPROM_DISABLE			(0x1)
++	#define EEPROM_SIZE			(0x4)
++#define DP_SEL				(0x40UL)
++	#define DP_SEL_DPRDY			(0x80000000UL)
++	#define DP_SEL_RSEL			(0x00000006UL)
++		#define DP_SEL_RSEL_FCT		(0x00000000UL)
++		#define DP_SEL_RSEL_EEPROM	(0x00000002UL)
++		#define DP_SEL_RSEL_TXTLI	(0x00000004UL)
++		#define DP_SEL_RSEL_RXTLI	(0x00000006UL)
++	#define DP_SEL_TESTEN			(0x00000001UL)
++#define DP_CMD				(0x44UL)
++	#define DP_CMD_READ			(0x0)
++	#define DP_CMD_WRITE			(0x1)
++#define DP_ADDR 			(0x48UL)
++#define DP_DATA0			(0x4CUL)
++#define DP_DATA1			(0x50UL)
++#define RAM_BIST0			(0x54UL)
++#define RAM_BIST1			(0x58UL)
++#define RAM_BIST2			(0x5CUL)
++#define RAM_BIST3			(0x60UL)
++#define GPIO_WAKE			(0x64UL)
++#define BULK_IN_DLY			(0x6CUL)
++
++#define INT_EP_CTL			(0x68UL)
++	#define	INT_EP_CTL_INTEP_		(0x80000000UL)
++	#define	INT_EP_CTL_MACRTO_		(0x00080000UL)
++	#define	INT_EP_CTL_RX_FIFO_EN_		(0x00040000UL)
++	#define	INT_EP_CTL_TX_STOP_		(0x00020000UL)
++	#define	INT_EP_CTL_RX_STOP_		(0x00010000UL)
++	#define	INT_EP_CTL_PHY_INT_		(0x00008000UL)
++	#define	INT_EP_CTL_TXE_			(0x00004000UL)
++	#define	INT_EP_CTL_TDFU_  		(0x00002000UL)
++	#define	INT_EP_CTL_TDFO_  		(0x00001000UL)
++	#define	INT_EP_CTL_RXDF_  		(0x00000800UL)
++	#define	INT_EP_CTL_GPIOS_ 		(0x000007FFUL)
++
++#define FLAG_ATTR			(0xB0UL)
++	#define FLAG_ATTR_RMT_WKP		(0x20000UL)
++	#define FLAG_ATTR_SELF_PWR		(0x10000UL)
++	#define FLAG_ATTR_PME_ENABLE		(0x80UL)
++	#define FLAG_ATTR_PME_CFG_PULSE		(0x40UL)
++	#define FLAG_ATTR_PME_LEN_150MS		(0x20UL)
++	#define FLAG_ATTR_PME_POL		(0x10UL)
++	#define FLAG_ATTR_PME_BUFF_TYPE		(0x8UL)
++	#define FLAG_ATTR_PME_WAKE_PHY		(0x4UL)
++	#define FLAG_ATTR_PME_GPIO10_HIGH	(0x2UL)
++	
++#define MAC_CR			(0x100UL)
++	#define MAC_CR_RXALL_			0x80000000UL
++	#define MAC_CR_ENABLE_EEE		0x02000000UL
++	#define MAC_CR_RCVOWN_			0x00800000UL
++	#define MAC_CR_LOOPBK_			0x00200000UL
++	#define MAC_CR_FDPX_			0x00100000UL
++	#define MAC_CR_MCPAS_			0x00080000UL
++	#define MAC_CR_PRMS_			0x00040000UL
++	#define MAC_CR_INVFILT_			0x00020000UL
++	#define MAC_CR_PASSBAD_		    	0x00010000UL
++	#define MAC_CR_HFILT_			0x00008000UL
++	#define MAC_CR_HPFILT_			0x00002000UL
++	#define MAC_CR_LCOLL_			0x00001000UL
++	#define MAC_CR_BCAST_			0x00000800UL
++	#define MAC_CR_DISRTY_			0x00000400UL
++	#define MAC_CR_PADSTR_			0x00000100UL
++	#define MAC_CR_BOLMT_MASK		0x000000C0UL
++	#define MAC_CR_DFCHK_			0x00000020UL
++	#define MAC_CR_TXEN_			0x00000008UL
++	#define MAC_CR_RXEN_			0x00000004UL
++#define ADDRH				(0x104UL)
++#define ADDRL				(0x108UL)
++#define HASHH				(0x10CUL)
++#define HASHL				(0x110UL)
++
++#define MII_ADDR			(0x114UL)
++	#define MII_WRITE_			(0x02UL)
++	#define MII_BUSY_			(0x01UL)
++	#define MII_READ_			(0x00UL) // ~of MII Write bit
++#define MII_DATA			(0x118UL)
++#define FLOW				(0x11CUL)
++	#define FLOW_FCPT_			(0xFFFF0000UL)
++	#define FLOW_FCPASS_			(0x00000004UL)
++	#define FLOW_FCEN_			(0x00000002UL)
++	#define FLOW_FCBSY_			(0x00000001UL)
++
++#define VLAN1				(0x120UL)
++#define VLAN2				(0x124UL)
++#define WUFF				(0x128UL)
++#define WUCSR				(0x12CUL)
++	#define WUCSR_GUE_			(0x00000200UL)
++	#define WUCSR_WUFR_			(0x00000040UL)
++	#define WUCSR_MPR_			(0x00000020UL)
++	#define WUCSR_WAKE_EN_			(0x00000004UL)
++	#define WUCSR_MPEN_			(0x00000002UL)
++
++#define COE_CR				(0x130UL)
++	#define Tx_COE_EN_			(0x00010000UL)
++	#define Rx_COE_MODE_			(0x00000002UL)
++	#define Rx_COE_EN_			(0x00000001UL)
++
++/* PHY Definitions */
++#define LAN_PHY_ADDR			(1UL)
++
++#define PHY_BCR				((u32)0U)
++	#define PHY_BCR_RESET_			((u16)0x8000U)
++	#define PHY_BCR_LOOPBACK_		((u16)0x4000U)
++	#define PHY_BCR_SPEED_SELECT_		((u16)0x2000U)
++	#define PHY_BCR_AUTO_NEG_ENABLE_	((u16)0x1000U)
++	#define PHY_BCR_POWER_DOWN              ((u16)0x0800U)
++	#define PHY_BCR_ISOLATE                	((u16)0x0400U)
++	#define PHY_BCR_RESTART_AUTO_NEG_	((u16)0x0200U)
++	#define PHY_BCR_DUPLEX_MODE_		((u16)0x0100U)
++
++#define PHY_BSR				((u32)1U)
++	#define PHY_BSR_AUTO_NEG_COMP_		((u16)0x0020U)
++	#define PHY_BSR_REMOTE_FAULT_		((u16)0x0010U)
++	#define PHY_BSR_LINK_STATUS_		((u16)0x0004U)
++
++#define PHY_ID_1			((u32)2U)
++#define PHY_ID_2			((u32)3U)
++
++#define PHY_ANEG_ADV			((u32)4U)
++	#define PHY_ANEG_NEXT_PAGE		((u16)0x8000)
++	#define PHY_ANEG_ADV_PAUSE_		((u16)0x0C00)
++	#define PHY_ANEG_ADV_ASYMP_		((u16)0x0800)
++	#define PHY_ANEG_ADV_SYMP_		((u16)0x0400)
++	#define PHY_ANEG_ADV_SPEED_		((u16)0x1E0)
++	#define PHY_ANEG_ADV_100F_		((u16)0x100)
++	#define PHY_ANEG_ADV_100H_		((u16)0x80)
++	#define PHY_ANEG_ADV_10F_		((u16)0x40)
++	#define PHY_ANEG_ADV_10H_		((u16)0x20)
++
++#define PHY_ANEG_LPA			((u32)5U)
++#define PHY_ANEG_LPA_ASYMP_			((u16)0x0800)
++#define PHY_ANEG_LPA_SYMP_			((u16)0x0400)
++#define PHY_ANEG_LPA_T4_			((u16)0x0200)
++#define PHY_ANEG_LPA_100FDX_			((u16)0x0100)
++#define PHY_ANEG_LPA_100HDX_			((u16)0x0080)
++#define PHY_ANEG_LPA_10FDX_			((u16)0x0040)
++#define PHY_ANEG_LPA_10HDX_			((u16)0x0020)
++
++#define PHY_ANEG_REG			((u32)6U)
++	#define PHY_LP_AN_ABLE			((u16)0x0001)
++
++#define PHY_SILICON_REV			((u32)16U)
++	#define PHY_SILICON_REV_TX_NLP_EN_	 BIT_15
++	#define PHY_SILICON_REV_TX_NLP_I_MSK_	(BIT_14 | BIT13)
++	#define PHY_SILICON_REV_TX_NLP_I_256_	(BIT_14 | BIT13)
++	#define PHY_SILICON_REV_TX_NLP_I_512_	BIT_14
++	#define PHY_SILICON_REV_TX_NLP_I_768_	BIT_13
++	#define PHY_SILICON_REV_TX_NLP_I_1S_	0
++	#define PHY_SILICON_REV_RX_1_NLP_	BIT_12
++	#define PHY_SILICON_REV_EEE_ENABLE	BIT_2
++	#define PHY_SILICON_REV_EDPD_XTD_XOVR	BIT_1
++	#define PHY_SILICON_REV_AMDIX_XTD_	BIT_0
++	#define EDPD_CFG_DEFAULT		(PHY_SILICON_REV_TX_NLP_EN_ | \
++						PHY_SILICON_REV_TX_NLP_I_768_ | PHY_SILICON_REV_RX_1_NLP_)
++
++#define PHY_MODE_CTRL_STS		((u32)17)
++	#define MODE_CTRL_STS_FASTRIP_		((u16)0x4000U)
++	#define MODE_CTRL_STS_EDPWRDOWN_	((u16)0x2000U)
++	#define MODE_CTRL_STS_LOWSQEN_		((u16)0x0800U)
++	#define MODE_CTRL_STS_MDPREBP_		((u16)0x0400U)
++	#define MODE_CTRL_STS_FARLOOPBACK_	((u16)0x0200U)
++	#define MODE_CTRL_STS_FASTEST_		((u16)0x0100U)
++	#define MODE_CTRL_STS_REFCLKEN_		((u16)0x0010U)
++	#define MODE_CTRL_STS_PHYADBP_		((u16)0x0008U)
++	#define MODE_CTRL_STS_FORCE_G_LINK_	((u16)0x0004U)
++	#define MODE_CTRL_STS_ENERGYON_		((u16)0x0002U)
++
++#define PHY_SPECIAL_MODES		((u32)18)
++
++#define PHY_TSTCNTL			((u32)20)
++	#define PHY_TSTCNTL_READ		((u16)0x8000U)
++	#define PHY_TSTCNTL_WRITE		((u16)0x4000U)
++	#define PHY_TSTCNTL_TEST_MODE		((u16)0x0400U)
++	#define PHY_TSTCNTL_READ_MASK		((u16)0x02E0U)
++	#define PHY_TSTCNTL_WRITE_MASK		((u16)0x001FU)
++
++#define PHY_TSTREAD1			((u32)21)	// Testability data Read for LSB
++#define PHY_TSTREAD2			((u32)22)	// Testability data Read for MSB
++#define PHY_TSTWRITE			((u32)23)	// Testability/Configuration data Write
++
++#define PHY_SPECIAL_CTRL_STS                ((u32)27)
++	#define SPECIAL_CTRL_STS_OVRRD_AMDIX_   ((u16)0x8000U)
++	#define SPECIAL_CTRL_STS_AMDIX_ENABLE_  ((u16)0x4000U)
++	#define SPECIAL_CTRL_STS_AMDIX_STATE_   ((u16)0x2000U)
++
++#define PHY_SITC			((u32)28) 
++
++#define PHY_INT_SRC			((u32)29)
++	#define PHY_INT_SRC_ENERGY_ON_		((u16)0x0080U)
++	#define PHY_INT_SRC_ANEG_COMP_		((u16)0x0040U)
++	#define PHY_INT_SRC_REMOTE_FAULT_	((u16)0x0020U)
++	#define PHY_INT_SRC_LINK_DOWN_		((u16)0x0010U)
++
++#define PHY_INT_MASK			((u32)30)
++	#define PHY_INT_MASK_ALL		((u16)0x00FFU)
++	#define PHY_INT_MASK_ENERGY_ON_		((u16)0x0080U)
++	#define PHY_INT_MASK_ANEG_COMP_		((u16)0x0040U)
++	#define PHY_INT_MASK_REMOTE_FAULT_	((u16)0x0020U)
++	#define PHY_INT_MASK_LINK_DOWN_		((u16)0x0010U)
++
++#define PHY_SPECIAL			((u32)31)
++	#define PHY_SPECIAL_SPD_		((u16)0x001CU)
++	#define PHY_SPECIAL_SPD_10HALF_		((u16)0x0004U)
++	#define PHY_SPECIAL_SPD_10FULL_		((u16)0x0014U)
++	#define PHY_SPECIAL_SPD_100HALF_	((u16)0x0008U)
++	#define PHY_SPECIAL_SPD_100FULL_	((u16)0x0018U)
++
++#define AMDIX_DISABLE_STRAIGHT		((u16)0x0U)
++#define AMDIX_DISABLE_CROSSOVER		((u16)0x01U)
++#define AMDIX_ENABLE			((u16)0x02U)
++
++#define PHY_LAN83C180_INT_ACK_REG	0x15
++#define PHY_LAN83C180_OPTIONS		0x18
++
++#define PHY_LAN83C183_STATUS_OUTPUT	0x12
++#define PHY_LAN83C183_INT_MASK		0x13
++#define PHY_LAN83C183_MASK_BASE		0xFFC0
++#define PHY_LAN83C183_MASK_INT		~0x8000
++#define PHY_LAN83C183_MASK_LINK		~0x4000
++
++#define PHY_FOX_INT_SOURCE		0x1D
++#define PHY_FOX_INT_ENERGY_ON		BIT_7
++#define PHY_FOX_INT_NWAY_DONE		BIT_6
++#define PHY_FOX_INT_REMOTE_FAULT	BIT_5
++#define PHY_FOX_INT_LINK_DOWN		BIT_4
++#define PHY_FOX_INT_NWAY_LP_ACK		BIT_3
++#define PHY_FOX_INT_PARALLEL_DET	BIT_2
++#define PHY_FOX_INT_NWAY_PAGE_RX	BIT_1
++#define PHY_FOX_INT_RESERVED		BIT_0
++
++#define PHY_FOX_INT_MASK		0x1E
++
++#define PHY_QSI_INT_SOURCE_REG		0x1D 
++#define PHY_QSI_AN_COMPLETE_INT    	BIT_6
++#define	PHY_QSI_REM_FAULT_INT       	BIT_5
++#define	PHY_QSI_LINK_DOWN_INT       	BIT_4
++#define	PHY_QSI_AN_LP_ACK_INT       	BIT_3
++#define	PHY_QSI_PAR_DET_INT         	BIT_2
++#define	PHY_QSI_AN_PAGE_RCVD_INT    	BIT_1
++#define	PHY_QSI_RCV_ERR_CNT_INT     	BIT_0
++#define PHY_QSI_INT_MASK_REG		0x1E
++#define PHY_QSI_INT_MODE		BIT_15
++
++/* Bit Mask definitions  */
++#define BIT_NONE			0x00000000
++#define BIT_0				0x0001
++#define BIT_1				0x0002
++#define BIT_2				0x0004
++#define BIT_3				0x0008
++#define BIT_4				0x0010
++#define BIT_5				0x0020
++#define BIT_6				0x0040
++#define BIT_7				0x0080
++#define BIT_8				0x0100
++#define BIT_9				0x0200
++#define BIT_10				0x0400
++#define BIT_11				0x0800
++#define BIT_12				0x1000
++#define BIT_13				0x2000
++#define BIT_14				0x4000
++#define BIT_15				0x8000
++#define BIT_16				0x10000
++#define BIT_17				0x20000
++#define BIT_18				0x40000
++#define BIT_19				0x80000
++#define BIT_20				0x100000
++#define BIT_21				0x200000
++#define BIT_22				0x400000
++#define BIT_23				0x800000
++#define BIT_24				0x1000000
++#define BIT_25				0x2000000
++#define BIT_26				0x4000000
++#define BIT_27				0x8000000
++#define BIT_28				0x10000000
++#define BIT_29				0x20000000
++#define BIT_30				0x40000000
++#define BIT_31				0x80000000
++
++/* Vendor Requests */
++#define	USB_VENDOR_REQUEST_WRITE_REGISTER	0xA0
++#define	USB_VENDOR_REQUEST_READ_REGISTER	0xA1
++#define	USB_VENDOR_REQUEST_GET_STATS		0xA2
++
++#define MDIO_DISABLE_INTERNAL_ACCESS		BIT_0
++#define MDIO_DISABLE_IOCTL_ACCESS		BIT_1
++#define MDIO_DEFAULT_LINK_INIT_MASK		BIT_0
++
++#define rx_stat_count			8
++#define tx_stat_count			10
++
++/* Stats block structures */
++typedef struct _SMSC9500_RX_STATS {
++	u32 RxGoodFrames;
++	u32 RxCrcErrors;
++	u32 RxRuntFrameErrors;
++	u32 RxAlignmentErrors;
++	u32 RxFrameTooLongError;
++	u32 RxLaterCollisionError;
++	u32 RxBadFrames;
++	u32 RxFifoDroppedFrames;
++	u32 EeeRxLpiTransitions;
++	u32 EeeRxLpiTime;
++} SMSC9500_RX_STATS, *pSMSC9500_RX_STATS;
++
++typedef struct _SMSC9500_TX_STATS {
++	u32 TxGoodFrames;
++	u32 TxPauseFrames;
++	u32 TxSingleCollisions;
++	u32 TxMultipleCollisions;
++	u32 TxExcessiveCollisionErrors;
++	u32 TxLateCollisionErrors;
++	u32 TxBufferUnderrunErrors;
++	u32 TxExcessiveDeferralErrors;
++	u32 TxCarrierErrors;
++	u32 TxBadFrames;
++	u32 EeeTxLpiTransitions;
++	u32 EeeTxLpiTime;
++} SMSC9500_TX_STATS, *pSMSC9500_TX_STATS;
++
++/* Interrupt Endpoint status word bitfields */
++#define	INT_ENP_RFHF_			(0x00040000UL)
++#define	INT_ENP_TX_STOP_		ETH_INT_STS_TX_STOP_
++#define	INT_ENP_RX_STOP_		ETH_INT_STS_RX_STOP_
++#define	INT_ENP_PHY_INT_		ETH_INT_STS_PHY_INT_
++#define	INT_ENP_TXE_			ETH_INT_STS_TXE_
++#define	INT_ENP_TDFU_			ETH_INT_STS_TDFU_
++#define	INT_ENP_TDFO_			ETH_INT_STS_TDFO_
++#define	INT_ENP_RXDF_			ETH_INT_STS_RXDF_
++#define	INT_ENP_GPIOS_			ETH_INT_STS_GPIOS_
++
++struct USB_CONTEXT{
++	struct usb_ctrlrequest req;
++	struct completion notify;
++};
++
++enum{
++	ASYNC_RW_SUCCESS,
++	ASYNC_RW_FAIL,
++	ASYNC_RW_TIMEOUT,
++};
++
++#define USE_DEBUG
++#ifdef USE_DEBUG
++#define USE_WARNING
++#define USE_TRACE
++#define USE_ASSERT
++#endif //USE_DEBUG
++
++#define HIBYTE(word)  ((BYTE)(((u16)(word))>>8))
++#define LOBYTE(word)  ((BYTE)(((u16)(word))&0x00FFU))
++#define HIWORD(dWord) ((u16)(((u32)(dWord))>>16))
++#define LOWORD(dWord) ((u16)(((u32)(dWord))&0x0000FFFFUL))
++
++/*******************************************************
++* Macro: SMSC_TRACE
++* Description:
++*    This macro is used like printf.
++*    It can be used anywhere you want to display information
++*    For any release version it should not be left in
++*      performance sensitive Tx and Rx code paths.
++*    To use this macro define USE_TRACE and set bit 0 of debug_mode
++*******************************************************/
++#ifdef USING_LINT
++extern void SMSC_TRACE(unsigned long dbgBit, const char * a, ...);
++#else //not USING_LINT
++#ifdef USE_TRACE
++extern u32 debug_mode;
++#ifndef USE_WARNING
++#define USE_WARNING
++#endif
++#   define SMSC_TRACE(dbgBit,msg,args...)   \
++    if(debug_mode&dbgBit) {                 \
++        printk("SMSC_9500: " msg "\n", ## args);    \
++    }
++#else
++#   define SMSC_TRACE(dbgBit,msg,args...)
++#endif
++#endif //end of not USING_LINT
++
++/*
++* Macro: SMSC_WARNING
++* Description:
++*    This macro is used like printf.
++*    It can be used anywhere you want to display warning information
++*    For any release version it should not be left in
++*      performance sensitive Tx and Rx code paths.
++*    To use this macro define USE_TRACE or
++*      USE_WARNING and set bit 1 of debug_mode
++*/
++#ifdef USING_LINT
++extern void SMSC_WARNING(const char * a, ...);
++#else //not USING_LINT
++#ifdef USE_WARNING
++extern u32 debug_mode;
++#ifndef USE_ASSERT
++#define USE_ASSERT
++#endif
++#   define SMSC_WARNING(msg, args...)               \
++	if(debug_mode&DBG_WARNING) {                    \
++		printk("SMSC_9500_WARNING: ");\
++		printk(__FUNCTION__);\
++		printk(": " msg "\n",## args);\
++	}
++#else
++#define SMSC_WARNING(msg, args...)
++#endif
++#endif //end of not USING_LINT
++
++/*
++* Macro: SMSC_ASSERT
++* Description:
++*    This macro is used to test assumptions made when coding.
++*    It can be used anywhere, but is intended only for situations
++*      where a failure is fatal.
++*    If code execution where allowed to continue it is assumed that
++*      only further unrecoverable errors would occur and so this macro
++*      includes an infinite loop to prevent further corruption.
++*    Assertions are only intended for use during developement to
++*      insure consistency of logic through out the driver.
++*    A driver should not be released if assertion failures are
++*      still occuring.
++*    To use this macro define USE_TRACE or USE_WARNING or
++*      USE_ASSERT
++*/
++#ifdef USING_LINT
++extern void SMSC_ASSERT(BOOLEAN condition);
++#else //not USING_LINT
++#ifdef USE_ASSERT
++    #define SMSC_ASSERT(condition) \
++    if(!(condition)) { \
++        printk("SMSC_9500_ASSERTION_FAILURE: \n"); \
++        printk("    Condition = " #condition "\n"); \
++        printk("    Function  = ");printk(__FUNCTION__);printk("\n"); \
++        printk("    File      = " __FILE__ "\n"); \
++        printk("    Line      = %d\n",__LINE__); \
++        while(1); \
++    }
++#else
++#define SMSC_ASSERT(condition)
++#endif
++#endif //end of not USING_LINT
++
++#define LINK_INIT			(0xFFFF)
++#define LINK_OFF			(0x00UL)
++#define LINK_SPEED_10HD			(0x01UL)
++#define LINK_SPEED_10FD			(0x02UL)
++#define LINK_SPEED_100HD		(0x04UL)
++#define LINK_SPEED_100FD		(0x08UL)
++#define LINK_SYMMETRIC_PAUSE		(0x10UL)
++#define LINK_ASYMMETRIC_PAUSE		(0x20UL)
++#define LINK_AUTO_NEGOTIATE		(0x40UL)
++
++#define INT_END_MACRTO_INT_		(0x00080000UL)
++#define INT_END_RXFIFO_HAS_FRAME_	(0x00040000UL)
++#define INT_END_TXSTOP_INT_		(0x00020000UL)
++#define INT_END_RXSTOP_INT_		(0x00010000UL)
++#define INT_END_PHY_INT_		(0x00008000UL)
++#define INT_END_TXE_			(0x00004000UL)
++#define INT_END_TDFU_			(0x00002000UL)
++#define INT_END_TDFO_			(0x00001000UL)
++#define INT_END_RXDF_INT_		(0x00000800UL)
++#define INT_END_GPIO_INT_		(0x000007FFUL)
++
++#define DBG_TRACE			(0x01UL)
++#define DBG_WARNING			(0x02UL)
++#define DBG_INIT			(0x80000000UL)
++#define DBG_CLOSE			(0x40000000UL)
++#define DBG_INTR			(0x20000000UL)
++#define DBG_PWR				(0x10000000UL)
++#define DBG_IOCTL			(0x08000000UL)
++#define DBG_LINK			(0x04000000UL)
++#define DBG_RX				(0x02000000UL)
++#define DBG_TX				(0x01000000UL)
++#define DBG_MCAST			(0x00800000UL)
++#define DBG_HOST			(0x00400000UL)
++#define DBG_LINK_CHANGE			(0x00200000UL)
++
++#define DEFAULT_BULK_IN_DELAY		(0x00002000UL)
++#define ETH_HEADER_SIZE			14
++#define ETH_MAX_DATA_SIZE		1500
++#define ETH_MAX_PACKET_SIZE		(ETH_MAX_DATA_SIZE + ETH_HEADER_SIZE)
++#define LAN9500_EEPROM_MAGIC		0x9500UL
++#define EEPROM_MAC_OFFSET		0x01
++
++struct smsc9500_int_data {
++	u32 IntEndPoint;
++} __attribute__ ((packed));
++
++#define MAX_WUFF_NUM			8
++#define LAN9500_WUFF_NUM		4
++#define LAN9500A_WUFF_NUM		8
++
++typedef struct _WAKEUP_FILTER {
++	u32 dwFilterMask[MAX_WUFF_NUM*4];
++	u32 dwCommad[MAX_WUFF_NUM/4];
++	u32 dwOffset[MAX_WUFF_NUM/4];
++	u32 dwCRC[MAX_WUFF_NUM/2];
++} WAKEUP_FILTER, *PWAKEUP_FILTER;
++
++static struct {
++	const char str[ETH_GSTRING_LEN];
++} ethtool_stats_keys[] = {
++	{ "rx_packets"},
++	{ "tx_packets"},
++	{ "rx_bytes"},
++	{ "tx_bytes"},
++	{ "rx_errors"},
++	{ "tx_errors"},
++	{ "tx_dropped"},
++	{ "rx_no_buffer_count"},
++	{ "rx_length_errors"},
++	{ "rx_over_errors"},
++	{ "rx_crc_errors"},
++	{ "rx_frame_errors"},
++	{ "RxGoodFrames"},
++	{ "RxCrcErrors"},
++	{ "RxRuntFrameErrors"},
++	{ "RxAlignmentErrors"},
++	{ "RxFrameTooLongError"},
++	{ "RxLaterCollisionError"},
++	{ "RxBadFrames"},
++	{ "RxFifoDroppedFrames"},
++	{ "TxGoodFrames"},
++	{ "TxPauseFrames"},
++	{ "TxSingleCollisions"},
++	{ "TxMultipleCollisions"},
++	{ "TxExcessiveCollisionErrors"},
++	{ "TxLateCollisionErrors"},
++	{ "TxBufferUnderrunErrors"},
++	{ "TxExcessiveDeferralErrors"},
++	{ "TxCarrierErrors"},
++	{ "TxBadFrames"},
++};
++
++typedef struct _ADAPTER_DATA {
++	u32 dwIdRev;
++	u32 dwPhyAddress;
++	u32 dwPhyId;
++	u32 dwFpgaRev;
++	u32 macAddrHi16;	//Mac address high 16 bits
++	u32 MmacAddrLo32;	//Mac address Low 32 bits
++	BOOLEAN internalPhy;
++
++	BOOLEAN UseTxCsum;
++	BOOLEAN UseRxCsum;
++
++	BOOLEAN LanInitialized;
++	BYTE bPhyModel;
++	BYTE bPhyRev;
++	u32 dwLinkSpeed;
++	u32 dwLinkSettings;
++	u32 dwSavedLinkSettings;
++	u32 DefaultLinkStatus;
++	struct semaphore phy_mutex;		// Mutex for PHY access
++	struct semaphore eeprom_mutex;		//Mutex for eeprom access
++	struct semaphore internal_ram_mutex;	//Mutex for internal ram operation
++	struct semaphore RxFilterLock;
++
++	u16 wLastADV;
++	u16 wLastADVatRestart;
++
++	spinlock_t TxQueueLock;
++	BOOLEAN TxInitialized;
++	u32 dwTxQueueDisableMask;
++	BOOLEAN TxQueueDisabled;
++
++	u32 WolWakeupOpts;
++	u32 wakeupOptsBackup;
++	u32 dwWUFF[20];
++
++	/* for Rx Multicast work around */
++	volatile u32 HashLo;
++	volatile u32 HashHi;
++	volatile BOOLEAN MulticastUpdatePending;
++	volatile u32 set_bits_mask;
++	volatile u32 clear_bits_mask;
++
++	u32 LinkLedOnGpio;		//Gpio port number for link led
++	u32 LinkLedOnGpioPolarity;	//Gpio Output polarity
++	u32 LinkActLedCfg;
++	u32 LinkLedOnGpioBufType;
++
++	u32 dynamicSuspendPHYEvent;	//Store PHY interrupt source for dynamic suspend
++	u32 systemSuspendPHYEvent;	//Store PHY interrupt source for system suspend
++
++	u16 eepromSize;
++	BOOLEAN eepromContentValid;
++
++	/* Count of transmit errors & other stats */
++	u64 TxGoodFrames;
++	u32 TxPauseFrames;
++	u32 TxSingleCollisions;
++	u32 TxMultipleCollisions;
++	u32 TxExcessiveCollisionErrors;
++	u32 TxLateCollisionErrors;
++	u32 TxBufferUnderrunErrors;
++	u32 TxExcessiveDeferralErrors;
++	u32 TxCarrierErrors;
++	u32 TxBadFrames;
++	u32 EeeTxLpiTransitions;
++	u32 EeeTxLpiTime;
++
++	/* Count of receive errors */
++	u64 RxGoodFrames;
++	u32 RxCrcErrors;
++	u32 RxRuntFrameErrors;
++	u32 RxAlignmentErrors;
++	u32 RxFrameTooLongError;
++	u32 RxLaterCollisionError;
++	u32 RxBadFrames;
++	u32 RxFifoDroppedFrames;
++	u32 EeeRxLpiTransitions;
++	u32 EeeRxLpiTime;
++	
++	SMSC9500_RX_STATS rx_statistics;
++	SMSC9500_TX_STATS tx_statistics;
++	
++} ADAPTER_DATA, *PADAPTER_DATA;
++
++typedef struct _MAC_ADDR_IN_RAM {
++	u32 signature;
++	u32 MacAddrL;
++	u32 MacAddrH;
++	u16 crc;
++	u16 crcComplement;
++} MAC_ADDR_IN_RAM;
++
++enum {
++	RAMSEL_FCT,
++	RAMSEL_EEPROM,
++	RAMSEL_TXTLI,
++	RAMSEL_RXTLI
++};
++
++#ifndef min
++#define    min(_a, _b)      (((_a) < (_b)) ? (_a) : (_b))
++#endif
++
++#ifndef max
++#define    max(_a, _b)      (((_a) > (_b)) ? (_a) : (_b))
++#endif
++
++#define BCAST_LEN   6
++#define MCAST_LEN   3
++#define ARP_LEN     2
++
++#endif /* _LAN9500_H */
++
++
++
+diff --git a/drivers/net/ethernet/smsc9514/smscusbnet.c b/drivers/net/ethernet/smsc9514/smscusbnet.c
+new file mode 100755
+index 0000000..ede03de
+--- /dev/null
++++ b/drivers/net/ethernet/smsc9514/smscusbnet.c
+@@ -0,0 +1,2157 @@
++/*
++ * USB Network driver infrastructure
++ * Copyright (C) 2000-2005 by David Brownell
++ * Copyright (C) 2003-2005 David Hollis <dhollis@davehollis.com>
++ *
++ * This program is free software; you can redistribute it and/or modify
++ * it under the terms of the GNU General Public License as published by
++ * the Free Software Foundation; either version 2 of the License, or
++ * (at your option) any later version.
++ *
++ * This program is distributed in the hope that it will be useful,
++ * but WITHOUT ANY WARRANTY; without even the implied warranty of
++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
++ * GNU General Public License for more details.
++ *
++ * You should have received a copy of the GNU General Public License
++ * along with this program; if not, write to the Free Software
++ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
++ */
++
++/*
++ * This is a generic "USB networking" framework that works with several
++ * kinds of full and high speed networking devices:  host-to-host cables,
++ * smart usb peripherals, and actual Ethernet adapters.
++ *
++ * These devices usually differ in terms of control protocols (if they
++ * even have one!) and sometimes they define new framing to wrap or batch
++ * Ethernet packets.  Otherwise, they talk to USB pretty much the same,
++ * so interface (un)binding, endpoint I/O queues, fault handling, and other
++ * issues can usefully be addressed by this framework.
++ */
++
++#include <linux/version.h>
++#include <linux/module.h>
++#include <linux/moduleparam.h>
++#include <linux/module.h>
++#include <linux/sched.h>
++#include <linux/init.h>
++#include <linux/netdevice.h>
++#include <linux/etherdevice.h>
++#include <linux/ethtool.h>
++#include <linux/workqueue.h>
++#include <linux/mii.h>
++#include <linux/usb.h>
++#include <linux/if_vlan.h>
++#include "smscusbnet.h"
++#include "version.h"
++
++/*
++ * Nineteen USB 1.1 max size bulk transactions per frame (ms), max.
++ * Several dozen bytes of IPv4 data can fit in two such transactions.
++ * One maximum size Ethernet packet takes twenty four of them.
++ * For high speed, each frame comfortably fits almost 36 max size
++ * Ethernet packets (so queues should be bigger).
++ *
++ * REVISIT qlens should be members of 'struct usbnet'; the goal is to
++ * let the USB host controller be busy for 5msec or more before an irq
++ * is required, under load.  Jumbograms change the equation.
++ */
++#define	RX_QLEN(dev) ((dev)->rx_qlen)
++#define	TX_QLEN(dev) ((dev)->tx_qlen)
++
++// reawaken network queue this soon after stopping; else watchdog barks
++#define TX_TIMEOUT_JIFFIES	(5*HZ)
++
++#define Link_Check_Delay      (1*HZ)
++
++// throttle rx/tx briefly after some faults, so khubd might disconnect()
++// us (it polls at HZ/4 usually) before we report too many false errors.
++#define THROTTLE_JIFFIES	(HZ/8)
++
++// between wakeups
++#define UNLINK_TIMEOUT_MS	3
++
++// randomly generated ethernet address
++static u8 node_id [ETH_ALEN];
++
++static const char driver_name [] = "smscusbnet";
++
++/* use ethtool to change the level for any given device */
++static int msg_level = -1;
++module_param (msg_level, int, 0);
++MODULE_PARM_DESC (msg_level, "Override default message level");
++
++/*
++operational_mode = 0 (low latency)
++operational_mode = 1 (low power)
++*/
++static int operational_mode = 0;
++module_param(operational_mode,int, 0);
++MODULE_PARM_DESC(operational_mode,"Enable operational mode");
++
++bool TurboMode = TRUE;
++module_param(TurboMode,bool, 0);
++MODULE_PARM_DESC(TurboMode,"Enable Turbo Mode");
++
++static unsigned long rx_queue_size = 6UL;
++module_param(rx_queue_size, ulong, 0);
++MODULE_PARM_DESC(rx_queue_size,"Specifies the size of the rx queue lenght");
++
++static unsigned long tx_queue_size = 6UL;
++module_param(tx_queue_size, ulong, 0);
++MODULE_PARM_DESC(tx_queue_size,"Specifies the size of the tx queue lenght");
++
++int tx_hold_on_completion = TRUE;
++module_param(tx_hold_on_completion, int, 0);
++MODULE_PARM_DESC(tx_hold_on_completion,"Hold tx until USB completion, must be true when tx_use_prealloc_buffers is true");
++
++int tx_use_prealloc_buffers = TRUE;
++module_param(tx_use_prealloc_buffers, int, 0);
++MODULE_PARM_DESC(tx_use_prealloc_buffers,"Uses pre allocated buffers for usb tx (tx_hold_on_completion must me true)");
++
++int rx_use_prealloc_buffers = TRUE;
++module_param(rx_use_prealloc_buffers, int, 0);
++MODULE_PARM_DESC(rx_use_prealloc_buffers,"Uses pre allocated buffers for usb rx. rx_skb_copy must be set to 1");
++
++int rx_urb_buf_alignment = 0;
++module_param(rx_urb_buf_alignment, int, 0);
++MODULE_PARM_DESC(rx_urb_buf_alignment,"rx urb buffer alignment in bytes. 0 - default alignment from skb_alloc");
++
++int tx_urb_buf_alignment = 0;
++module_param(tx_urb_buf_alignment, int, 0);
++MODULE_PARM_DESC(tx_urb_buf_alignment,"tx urb buffer alignment in bytes. 0 - default alignment from skb_alloc");
++
++int rx_skb_copy = 1;
++module_param(rx_skb_copy, int, 0);
++MODULE_PARM_DESC(rx_skb_copy,"default 1 - use skb_alloc for received packets, 0 - use skb_clone, for pre allocated buffers set this to 1");
++
++int net_ip_align = 0;
++module_param(net_ip_align, int, 0);
++MODULE_PARM_DESC(net_ip_align,"ip alignment for Rx packets, default 0 = NET_IP_ALIGN");
++
++static int smscusbnet_xmit (struct sk_buff *skb, struct net_device *net);
++static int smscusbnet_bundle_skb_ximt(struct usbnet *dev, struct sk_buff_head *q);
++#if (LINUX_VERSION_CODE < KERNEL_VERSION(2,6,29))
++static struct net_device_stats *smscusbnet_get_stats (struct net_device *net);
++static int smscusbnet_stop (struct net_device *net);
++static int smscusbnet_open (struct net_device *net);
++static int smscusbnet_start_xmit (struct sk_buff *skb, struct net_device *net);
++static void smscusbnet_tx_timeout (struct net_device *net);
++static int smscusbnet_change_mtu (struct net_device *net, int new_mtu);
++#endif
++static void intr_complete (struct urb *urb);
++static void rx_complete (struct urb *urb);
++
++static int smscusbnet_alloc_rx_pool(struct usbnet *dev, int size)
++{
++	struct sk_buff *skb;	
++	int i;
++
++	for (i = 0; i < dev->rx_qlen; i++) {
++		skb = alloc_skb(size + dev->rx_urb_buf_alignment, GFP_ATOMIC);
++		if (!skb)
++			return 1;
++		if (dev->rx_urb_buf_alignment) {
++			skb->data = (unsigned char *)(((ulong)skb->head + dev->rx_urb_buf_alignment - 1) &
++				~(dev->rx_urb_buf_alignment - 1));
++			skb_reset_tail_pointer(skb);
++		}
++		__skb_queue_tail(&dev->rx_pool_queue, skb);
++	}
++	return 0;
++}
++
++static inline void smscusbnet_free_rx_pool(struct usbnet *dev)
++{
++	if (!skb_queue_empty(&dev->rx_pool_queue))
++		skb_queue_purge(&dev->rx_pool_queue);
++}
++
++static inline struct sk_buff *smscusbnet_get_rx_buffer(struct usbnet *dev)
++{
++	if (!skb_queue_empty(&dev->rx_pool_queue))
++		return(skb_dequeue(&dev->rx_pool_queue));
++	else
++		return NULL;
++}
++
++static inline void smscusbnet_return_rx_buffer(struct usbnet *dev, struct sk_buff *skb)
++{
++	unsigned long lockflags;	
++
++	if (dev->rx_urb_buf_alignment) {
++		skb->data = (unsigned char *)(((ulong)skb->head + dev->rx_urb_buf_alignment - 1) &
++			~(dev->rx_urb_buf_alignment - 1));
++	} else {
++		skb->data = skb->head;
++	}
++	skb_reset_tail_pointer(skb);
++	skb->len = 0;
++	skb->data_len = 0;
++	spin_lock_irqsave(&dev->rx_pool_queue.lock, lockflags);
++	__skb_queue_tail(&dev->rx_pool_queue, skb);
++	spin_unlock_irqrestore(&dev->rx_pool_queue.lock, lockflags);
++}
++
++static int smscusbnet_alloc_tx_pool(struct usbnet *dev, int size)
++{
++	struct sk_buff *skb;	
++	int i;
++
++	for (i = 0; i < dev->tx_qlen; i++) {
++		skb = alloc_skb(size, GFP_ATOMIC);
++		if (!skb)
++			return 1;		
++		if (dev->tx_urb_buf_alignment) {
++			skb->data = (unsigned char *)(((ulong)skb->head + dev->tx_urb_buf_alignment - 1) &
++				~(dev->tx_urb_buf_alignment - 1));
++			skb_reset_tail_pointer(skb);
++		}
++		__skb_queue_tail(&dev->tx_pool_queue, skb);
++	}
++	return 0;
++}
++
++static inline void smscusbnet_free_tx_pool(struct usbnet *dev)
++{
++	if (!skb_queue_empty(&dev->tx_pool_queue))
++		skb_queue_purge(&dev->tx_pool_queue);
++}
++
++static inline struct sk_buff *smscusbnet_get_tx_buffer(struct usbnet *dev)
++{
++	if (!skb_queue_empty(&dev->tx_pool_queue))
++		return(skb_dequeue(&dev->tx_pool_queue));
++	else
++		return NULL;
++}
++
++static inline void smscusbnet_return_tx_buffer(struct usbnet *dev, struct sk_buff *skb)
++{
++	unsigned long lockflags;	
++
++	if (dev->tx_urb_buf_alignment) {
++		skb->data = (unsigned char *)(((ulong)skb->head + dev->tx_urb_buf_alignment - 1) &
++			~(dev->tx_urb_buf_alignment - 1));
++		skb_reset_tail_pointer(skb);
++	} else {
++		skb->data = skb->head;
++	}
++	skb_reset_tail_pointer(skb);
++	skb->len = 0;
++	skb->data_len = 0;
++	spin_lock_irqsave(&dev->tx_pool_queue.lock, lockflags);
++	__skb_queue_tail(&dev->tx_pool_queue, skb);
++	spin_unlock_irqrestore(&dev->tx_pool_queue.lock, lockflags);
++}
++
++#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,29))
++static const struct net_device_ops smscusbnet_netdev_ops =
++{
++        .ndo_open               = smscusbnet_open,
++        .ndo_stop               = smscusbnet_stop,
++        .ndo_start_xmit         = smscusbnet_start_xmit,
++        .ndo_tx_timeout         = smscusbnet_tx_timeout,
++        .ndo_change_mtu         = smscusbnet_change_mtu,
++        .ndo_get_stats          = smscusbnet_get_stats,
++        .ndo_validate_addr      = eth_validate_addr,
++};
++#endif 
++
++int smscusbnet_IsOperationalMode(struct usbnet *dev)
++{
++	return operational_mode;
++}
++
++/* handles CDC Ethernet and many other network "bulk data" interfaces */
++int smscusbnet_get_endpoints(struct usbnet *dev, struct usb_interface *intf)
++{
++	int				tmp;
++	struct usb_host_interface	*alt = NULL;
++	struct usb_host_endpoint	*in = NULL, *out = NULL;
++	struct usb_host_endpoint	*status = NULL;
++
++	for (tmp = 0; tmp < intf->num_altsetting; tmp++) {
++		unsigned	ep;
++
++		in = out = status = NULL;
++		alt = intf->altsetting + tmp;
++
++		/* take the first altsetting with in-bulk + out-bulk;
++		 * remember any status endpoint, just in case;
++		 * ignore other endpoints and altsetttings.
++		 */
++		for (ep = 0; ep < alt->desc.bNumEndpoints; ep++) {
++			struct usb_host_endpoint	*e;
++			int				intr = 0;
++
++			e = alt->endpoint + ep;
++			switch (e->desc.bmAttributes) {
++			case USB_ENDPOINT_XFER_INT:
++				if (!(e->desc.bEndpointAddress & USB_DIR_IN))
++					continue;
++				intr = 1;
++				/* FALLTHROUGH */
++			case USB_ENDPOINT_XFER_BULK:
++				break;
++			default:
++				continue;
++			}
++			if (e->desc.bEndpointAddress & USB_DIR_IN) {
++				if (!intr && !in)
++					in = e;
++				else if (intr && !status)
++					status = e;
++			} else {
++				if (!out)
++					out = e;
++			}
++		}
++		if (in && out)
++			break;
++	}
++	if (!alt || !in || !out)
++	{
++        devdbg (dev, "return EINVAL = %d", EINVAL);
++
++		return -EINVAL;
++	}
++	if (alt->desc.bAlternateSetting != 0
++			|| !(dev->driver_info->flags & FLAG_NO_SETINT)) {
++		tmp = usb_set_interface (dev->udev, alt->desc.bInterfaceNumber,
++				alt->desc.bAlternateSetting);
++		if (tmp < 0)
++		{
++            devdbg (dev, "return tmp = %d", tmp);
++			return tmp;
++
++		}
++	}
++
++	dev->in = usb_rcvbulkpipe (dev->udev,
++			in->desc.bEndpointAddress & USB_ENDPOINT_NUMBER_MASK);
++	dev->out = usb_sndbulkpipe (dev->udev,
++			out->desc.bEndpointAddress & USB_ENDPOINT_NUMBER_MASK);
++	dev->status = status;
++
++	return 0;
++}
++
++static int init_status (struct usbnet *dev, struct usb_interface *intf)
++{
++	unsigned	pipe = 0;
++	unsigned	maxp;
++	unsigned	period;
++
++	if (!dev->driver_info->status)
++		return 0;
++	
++	pipe = usb_rcvintpipe (dev->udev,
++			dev->status->desc.bEndpointAddress
++				& USB_ENDPOINT_NUMBER_MASK);
++	maxp = usb_maxpacket (dev->udev, pipe, 0);
++
++	period = dev->status->desc.bInterval;
++	dev->interrupt_urb_buffer = NULL;
++
++	if(operational_mode){
++		dev->interrupt_urb_buffer = kmalloc (maxp, GFP_KERNEL);
++		if (dev->interrupt_urb_buffer) {
++			dev->interrupt = usb_alloc_urb (0, GFP_KERNEL);
++			if (!dev->interrupt) {
++                devdbg (dev, "failed to alloc interrupt urb\n!!!");
++				kfree (dev->interrupt_urb_buffer);
++				dev->interrupt_urb_buffer = NULL;
++				return -ENOMEM;
++			} else {
++				usb_fill_int_urb(dev->interrupt, dev->udev, pipe,
++					dev->interrupt_urb_buffer, maxp, intr_complete, dev, period);
++				devdbg (dev,"status ep%din, %d bytes period %d\n",
++					usb_pipeendpoint(pipe), maxp, period);
++			}
++		}
++	}
++
++	return  0;
++}
++
++/* Passes this packet up the stack, updating its accounting.
++ * Some link protocols batch packets, so their rx_fixup paths
++ * can return clones as well as just modify the original skb.
++ */
++void smscusbnet_skb_return(struct usbnet *dev, struct sk_buff *skb)
++{
++	int	status;
++	u16 vlan_tag = *((u16 *)&skb->cb[0]);
++
++	skb->dev = dev->net;
++	skb->protocol = eth_type_trans (skb, dev->net);
++
++	if (netif_msg_rx_status (dev))
++		devdbg (dev, "< rx, len %zu, type 0x%x", skb->len + sizeof (struct ethhdr), skb->protocol);
++	memset (skb->cb, 0, sizeof (struct skb_data));
++
++	if (vlan_tag == VLAN_DUMMY) {
++		/* No vlan tag acceleration */
++		status = netif_rx (skb);
++	} else {
++		/* Vlan tag acceleration */
++#if (LINUX_VERSION_CODE <= KERNEL_VERSION(3,0,31))
++		status = vlan_hwaccel_rx(skb, dev->vlgrp, vlan_tag);   
++#else
++#if (LINUX_VERSION_CODE < KERNEL_VERSION(3,10,0))
++		__vlan_hwaccel_put_tag(skb, vlan_tag);
++#else
++		__vlan_hwaccel_put_tag(skb, htons(ETH_P_8021Q), vlan_tag);
++#endif
++		status = netif_rx(skb);
++#endif
++	}
++
++	if (status == NET_RX_DROP) {
++		dev->stats.rx_dropped++;
++	} else {
++		dev->stats.rx_packets++;
++		dev->stats.rx_bytes += skb->len;
++	}
++
++	if (status != NET_RX_SUCCESS && netif_msg_rx_err (dev))
++		devdbg (dev, "netif_rx status %d", status);
++}
++
++#if (LINUX_VERSION_CODE < KERNEL_VERSION(2,6,29))
++static 
++#endif
++int smscusbnet_change_mtu (struct net_device *net, int new_mtu)
++{
++	struct usbnet	*dev = netdev_priv(net);
++	int		ll_mtu = new_mtu + net->hard_header_len;
++
++#ifdef JUMBO_FRAME
++	if (new_mtu <= 0)
++		return -EINVAL;
++	// no second zero-length packet read wanted after mtu-sized packets
++	if ((ll_mtu % dev->maxpacket) == 0)
++		return -EDOM;
++	if(dev->driver_info->set_max_frame_size(dev, net->hard_header_len + new_mtu - EXTRA_HEADER_LEN) < 0){
++		return -EINVAL;
++	}
++	net->mtu = new_mtu;
++	dev->hard_mtu = net->mtu + net->hard_header_len;
++#else
++	if (new_mtu <= 0 || ll_mtu > dev->hard_mtu)
++		return -EINVAL;
++	// no second zero-length packet read wanted after mtu-sized packets
++	if ((ll_mtu % dev->maxpacket) == 0)
++		return -EDOM;
++	net->mtu = new_mtu;
++#endif
++	return 0;
++}
++
++#if (LINUX_VERSION_CODE < KERNEL_VERSION(2,6,29))
++static 
++#endif
++struct net_device_stats *smscusbnet_get_stats (struct net_device *net)
++{
++	struct usbnet	*dev = netdev_priv(net);
++	return &dev->stats;
++}
++
++
++/* some LK 2.4 HCDs oopsed if we freed or resubmitted urbs from
++ * completion callbacks.  2.5 should have fixed those bugs...
++ */
++static void defer_bh(struct usbnet *dev, struct sk_buff *skb, struct sk_buff_head *list)
++{
++	unsigned long		flags;
++
++	spin_lock_irqsave(&list->lock, flags);
++	__skb_unlink(skb, list);
++	spin_unlock(&list->lock);
++	spin_lock(&dev->done.lock);
++	__skb_queue_tail(&dev->done, skb);
++	if (dev->done.qlen == 1)
++		tasklet_schedule(&dev->bh);
++	spin_unlock_irqrestore(&dev->done.lock, flags);
++}
++
++/* some work can't be done in tasklets, so we use keventd
++ *
++ * NOTE:  annoying asymmetry:  if it's active, schedule_work() fails,
++ * but tasklet_schedule() doesn't.  hope the failure is rare.
++ */
++void smscusbnet_defer_kevent (struct usbnet *dev, int work)
++{
++	set_bit (work, &dev->flags);
++	if (!schedule_work (&dev->kevent)){
++		devdbg (dev, "kevent %d may have been dropped", work);
++	}
++	//else
++		//devdbg (dev, "kevent %d scheduled", work);
++}
++
++/* some work can't be done in tasklets, so we use keventd
++ *
++ * We use myevent to schedule Rx Bulk in
++ *
++ */
++void smscusbnet_defer_myevent (struct usbnet *dev, int work)
++{
++	set_bit (work, &dev->flags);
++	if (!queue_work(dev->MyWorkQueue,&dev->myevent)){
++		//deverr (dev, "myevent %d may have been dropped", work);
++	}
++	//else
++		//devdbg (dev,"myevent %d scheduled", work);
++}
++
++void smscusbnet_linkpolling(unsigned long ptr)
++{
++	struct usbnet * dev = (struct usbnet *) ptr;
++
++	if (dev == NULL)
++		return;	
++	smscusbnet_defer_myevent(dev, EVENT_LINK_RESET);
++
++#if (LINUX_VERSION_CODE > KERNEL_VERSION(2,6,18)) && defined(CONFIG_PM)
++	if (dev->dynamicSuspend) {
++		smscusbnet_defer_myevent(dev, EVENT_IDLE_CHECK);
++	}
++#endif 
++#if (LINUX_VERSION_CODE > KERNEL_VERSION(2,6,18)) && defined(CONFIG_PM)
++	if (dev->linkDownSuspend || dev->netDetach) {
++#else
++	if (dev->netDetach) {
++#endif 
++		/* Check 2 times in case of conflict with resume */
++		if (!netif_carrier_ok(dev->net) && dev->linkcheck++ > 2) {
++			smscusbnet_defer_myevent(dev, EVENT_LINK_DOWN_DETACH);
++			dev->linkcheck = 0;
++		}
++	}
++}
++
++static inline struct sk_buff *smscusbnet_allocate_rx_skb_buffer(struct usbnet *dev, int flags)
++{
++	struct sk_buff *skb = NULL;
++	size_t size = dev->rx_urb_size;
++	
++	if (dev->rx_use_prealloc_buffs) {
++		skb = smscusbnet_get_rx_buffer(dev);
++	} else {
++		skb = alloc_skb(size + dev->net_ip_align + dev->rx_urb_buf_alignment, flags);
++		/* This skb will be submitted to usb host for receive,
++		align skb->data to rx_urb_buf_alignment. */
++		if (skb && dev->rx_urb_buf_alignment) {
++			skb->data = (unsigned char *)(((ulong)skb->head + dev->rx_urb_buf_alignment - 1) &
++				~(dev->rx_urb_buf_alignment - 1));
++			skb_reset_tail_pointer(skb);
++		}
++	}
++
++	return skb;
++}
++
++static int rx_submit(struct usbnet *dev, struct urb *urb, int flags)
++{
++	struct sk_buff *skb;
++	struct skb_data	*entry;
++	int retval = 0;
++	unsigned long lockflags;
++	size_t size = dev->rx_urb_size;
++
++	skb = smscusbnet_allocate_rx_skb_buffer(dev, flags);
++	if (!skb) {
++		if (netif_msg_rx_err (dev))
++			devdbg (dev,"no rx skb\n");
++		/* When using pre allocated memory, no rx skb means all
++		are submitted. rx_complete should resubmit */
++		if (!dev->rx_use_prealloc_buffs) 
++			smscusbnet_defer_kevent(dev, EVENT_RX_MEMORY);
++		usb_free_urb(urb);
++		return -ENOMEM;
++	}
++
++	entry = (struct skb_data *) skb->cb;
++	entry->urb = urb;
++	entry->dev = dev;
++	entry->state = rx_start;
++	entry->length = 0;
++
++	usb_fill_bulk_urb (urb, dev->udev, dev->in,
++		skb->data, size, rx_complete, skb);
++
++	spin_lock_irqsave (&dev->rxq.lock, lockflags);
++
++	if (netif_running (dev->net)
++			&& netif_device_present (dev->net)
++			&& !test_bit (EVENT_RX_HALT, &dev->flags)
++			&& netif_carrier_ok(dev->net)) {
++		switch (retval = usb_submit_urb (urb, GFP_ATOMIC)) {
++		case -EPIPE:
++			smscusbnet_defer_kevent (dev, EVENT_RX_HALT);
++			break;
++		case -ENOMEM:
++			smscusbnet_defer_kevent (dev, EVENT_RX_MEMORY);
++			break;
++		case -ENODEV:
++			if (netif_msg_ifdown (dev))
++				devdbg (dev, "device gone");
++			netif_device_detach (dev->net);
++			break;
++		default:
++			if (netif_msg_rx_err (dev))
++				devdbg (dev, "rx submit, %d", retval);
++			tasklet_schedule (&dev->bh);
++			break;
++		case 0:
++			__skb_queue_tail (&dev->rxq, skb);
++		}
++	} else {
++		if (netif_msg_ifdown (dev))
++			devdbg (dev, "rx: stopped");
++		retval = -ENOLINK;
++	}
++	spin_unlock_irqrestore (&dev->rxq.lock, lockflags);
++	if (retval) {
++		dev_kfree_skb_any (skb);
++		usb_free_urb(urb);
++	}
++	return retval;
++}
++
++static inline void rx_process (struct usbnet *dev, struct sk_buff *skb)
++{
++	int ret;
++
++	if (!dev->driver_info->rx_fixup)
++		return;
++
++	ret = dev->driver_info->rx_fixup(dev, skb);
++	if (ret == RX_FIXUP_INVALID_SKB) {
++		skb_queue_tail(&dev->done, skb);
++	} else if (ret == RX_FIXUP_ERROR) {
++		dev->stats.rx_errors++;
++		skb_queue_tail(&dev->done, skb);
++	} else {
++		if (skb->len) {
++			smscusbnet_skb_return(dev, skb);
++		} else {
++			if (netif_msg_rx_err(dev))
++				devdbg(dev, "drop");
++			dev->stats.rx_errors++;
++			skb_queue_tail(&dev->done, skb);
++		}
++	}
++}
++
++static void rx_complete (struct urb *urb)
++{
++	struct sk_buff *skb = (struct sk_buff *) urb->context;
++	struct skb_data *entry = (struct skb_data *) skb->cb;
++	struct usbnet *dev = entry->dev;
++	int urb_status = urb->status;
++
++	dev->idleCount = 0;
++
++	skb_put(skb, urb->actual_length);
++	entry->state = rx_done;
++	entry->urb = NULL;
++
++	switch (urb_status) {
++		/* success */
++		case 0:
++			if (operational_mode) {
++				if ((skb->len < dev->net->hard_header_len) && (skb->len != 0)) {
++					entry->state = rx_cleanup;
++					dev->stats.rx_errors++;
++					dev->stats.rx_length_errors++;
++					if (netif_msg_rx_err (dev))
++						devdbg (dev, "rx length %d", skb->len);
++				}
++
++				if (skb->len == 0) {
++					entry->state = rx_cleanup;
++					dev->StopSummitUrb = 1;
++				} else {
++					dev->StopSummitUrb = 0;
++				}
++			} else {
++				if (skb->len < dev->net->hard_header_len) {
++					entry->state = rx_cleanup;
++					dev->stats.rx_errors++;
++					dev->stats.rx_length_errors++;
++					if (netif_msg_rx_err (dev))
++						devdbg (dev, "rx length %d", skb->len);
++				}
++			}
++			break;
++
++		// stalls need manual reset. this is rare ... except that
++		// when going through USB 2.0 TTs, unplug appears this way.
++		// we avoid the highspeed version of the ETIMEOUT/EILSEQ
++		// storm, recovering as needed.
++		case -EPIPE:
++			dev->extra_error_cnts.rx_epipe++;
++			dev->stats.rx_errors++;
++			devdbg (dev,"in rx_complete,case -EPIPE, dev->stats.rx_errors=0x%08lx\n", dev->stats.rx_errors);
++			smscusbnet_defer_kevent (dev, EVENT_RX_HALT);
++			// FALLTHROUGH
++			// software-driven interface shutdown
++		case -ECONNRESET:		// async unlink
++		case -ESHUTDOWN:		// hardware gone
++			if (netif_msg_ifdown (dev))
++				devdbg (dev, "rx shutdown, code %d", urb_status);
++			goto block;
++
++		// we get controller i/o faults during khubd disconnect() delays.
++		// throttle down resubmits, to avoid log floods; just temporarily,
++		// so we still recover when the fault isn't a khubd delay.
++		case -EPROTO:			 // ehci
++			dev->extra_error_cnts.rx_eproto++;
++			goto _HANDLE;
++		case -ETIMEDOUT:		// ohci
++		case -ETIME:			// ohci
++			dev->extra_error_cnts.rx_etimeout++;
++			goto _HANDLE;
++		case -EILSEQ:			// uhci
++			dev->extra_error_cnts.rx_eilseq++;
++_HANDLE:
++			dev->stats.rx_errors++;
++			devdbg (dev,"in rx_complete,case -EPROTO, dev->stats.rx_errors=0x%08lx\n", dev->stats.rx_errors);
++				if (!timer_pending (&dev->delay)) {
++					mod_timer (&dev->delay, jiffies + THROTTLE_JIFFIES);
++					if (netif_msg_link (dev))
++						devdbg (dev, "rx throttle %d", urb_status);
++				}
++			//Set recovery flag
++			set_bit (EVENT_DEV_RECOVERY, &dev->flags);
++block:
++			entry->state = rx_cleanup;
++			entry->urb = urb;
++			urb = NULL;
++			break;
++		    // data overrun ... flush fifo?
++		case -EOVERFLOW:
++			dev->extra_error_cnts.rx_eoverflow++;
++			dev->stats.rx_over_errors++;
++			// FALLTHROUGH
++			/* Set recovery flag */
++			set_bit (EVENT_DEV_RECOVERY, &dev->flags);
++		default:
++			entry->state = rx_cleanup;
++			dev->stats.rx_errors++;
++			devdbg (dev,"in rx_complete,case default dev->stats.rx_errors=0x%08lx\n", dev->stats.rx_errors);
++			if (netif_msg_rx_err (dev))
++			devdbg (dev, "rx status %d", urb_status);
++			break;
++	}
++
++	defer_bh(dev, skb, &dev->rxq);
++
++	if (urb) {
++		if (operational_mode) {
++			if (netif_running (dev->net)
++				&& !test_bit (EVENT_RX_HALT, &dev->flags)
++				&& !dev->StopSummitUrb) {
++				rx_submit (dev, urb, GFP_ATOMIC);
++				return;
++			}
++
++		} else {
++
++			if (netif_running (dev->net)
++				&& !test_bit (EVENT_RX_HALT, &dev->flags)) {
++				rx_submit(dev, urb, GFP_ATOMIC);
++				return;
++			}
++		}
++		usb_free_urb(urb);
++	}
++	if (netif_msg_rx_err (dev))
++		devdbg (dev, "no read resubmitted");
++}
++
++static void intr_complete (struct urb *urb)
++{
++	int status = urb->status;
++	struct usbnet *dev = urb->context;
++
++	switch (status) {
++	    /* success */
++	    case 0:
++		dev->driver_info->status(dev, urb);
++		break;
++
++	    /* software-driven interface shutdown */
++	    case -ENOENT:		// urb killed
++	    case -ESHUTDOWN:		// hardware gone
++		if (netif_msg_ifdown (dev))
++			devdbg (dev,"intr shutdown, code %d", status);
++		return;
++
++	// we get controller i/o faults during khubd disconnect() delays.
++	// throttle down resubmits, to avoid log floods; just temporarily,
++	// so we still recover when the fault isn't a khubd delay.
++        /* We need throttling here like RX/TX, because flood events occur on slow ppc platform
++         * when the device is being disconnected.
++         */
++        case -EPROTO:       // ehci
++        case -ETIMEDOUT:    // ohci
++        case -ETIME:        // ohci
++        case -EILSEQ:       // uhci
++
++        devdbg (dev,"in intr_complete,case -EPROTO\n");
++        if (!timer_pending (&dev->delay)) {
++            mod_timer (&dev->delay, jiffies + THROTTLE_JIFFIES);
++            if (netif_msg_link (dev))
++                devdbg (dev, "intr throttle %d", status);
++        }
++        dev->intr_urb_delay_submit = TRUE;
++        return;
++
++	    default:
++		devdbg (dev,"intr status %d", status);
++		break;
++	}
++
++	if (!netif_running (dev->net)){
++		return;
++    }
++
++	memset(urb->transfer_buffer, 0, urb->transfer_buffer_length);
++	status = usb_submit_urb (urb, GFP_ATOMIC);
++	if (status != 0 && netif_msg_timer (dev))
++		deverr(dev, "intr resubmit --> %d", status);
++}
++
++// unlink pending rx/tx; completion handlers do all other cleanup
++
++static int unlink_urbs (struct usbnet *dev, struct sk_buff_head *q)
++{
++	unsigned long		flags;
++	struct sk_buff		*skb, *skbnext;
++	int			count = 0;
++
++	spin_lock_irqsave (&q->lock, flags);
++	for (skb = q->next; skb != (struct sk_buff *) q; skb = skbnext) {
++		struct skb_data		*entry;
++		struct urb		*urb;
++		int			retval;
++
++		entry = (struct skb_data *) skb->cb;
++		urb = entry->urb;
++		skbnext = skb->next;
++
++		/* Get reference count of the URB to avoid it to be
++		 * freed during usb_unlink_urb, which may trigger
++		 * use-after-free problem inside usb_unlink_urb since
++		 * usb_unlink_urb is always racing with .complete
++		 * handler(include defer_bh).
++		 */
++		usb_get_urb(urb);
++		spin_unlock_irqrestore (&q->lock, flags);
++
++		// during some PM-driven resume scenarios,
++		// these (async) unlinks complete immediately
++		retval = usb_unlink_urb (urb);
++		if (retval != -EINPROGRESS && retval != 0)
++			devdbg (dev, "unlink urb err, %d", retval);
++		else
++			count++;
++
++		usb_put_urb(urb);
++		spin_lock_irqsave (&q->lock, flags);
++	}
++	spin_unlock_irqrestore (&q->lock, flags);
++	return count;
++}
++
++static void smscusbnet_free_rx_buffer(struct usbnet *dev, struct sk_buff *skb)
++{
++	if (dev->rx_use_prealloc_buffs) {
++		smscusbnet_return_rx_buffer(dev, skb);
++	} else {
++		dev_kfree_skb(skb);
++	}
++}
++static void smscusbnet_free_tx_buffer(struct usbnet *dev, struct sk_buff *skb)
++{
++	if (dev->tx_use_prealloc_buffs) {
++		smscusbnet_return_tx_buffer(dev, skb);
++	} else {
++		dev_kfree_skb(skb);
++	}
++}
++
++/* tasklet (work deferred from completions, in_irq) or timer */
++static void  smscusbnet_bh(unsigned long param)
++{
++	int ret = 0;
++	unsigned long flags;
++	struct sk_buff *skb = NULL;
++	struct skb_data *entry = NULL;
++	struct usbnet *dev = (struct usbnet *) param;
++
++	if (dev == NULL) 
++		return;
++
++	while ((skb = skb_dequeue(&dev->done))) {
++		entry = (struct skb_data *) skb->cb;
++		switch (entry->state) {
++		    case rx_done:
++			entry->state = rx_cleanup;
++			rx_process(dev, skb);
++			continue;
++		    case tx_done:
++			usb_free_urb(entry->urb);
++			smscusbnet_free_tx_buffer(dev, skb);
++			spin_lock_irqsave(&dev->txq.lock, flags);
++			if (!dev->txq.qlen)
++				smscusbnet_bundle_skb_ximt(dev, &dev->tx_pending_q);
++			spin_unlock_irqrestore(&dev->txq.lock, flags);
++			continue;
++		    case rx_cleanup:
++			if (entry->urb) 
++				usb_free_urb(entry->urb);
++			smscusbnet_free_rx_buffer(dev, skb);
++			continue;
++		    default:
++			devdbg (dev, "bogus skb state %d", entry->state);
++		}
++	}
++
++	if (netif_running(dev->net) && netif_device_present(dev->net) && !timer_pending(&dev->delay)) {
++		/* submit delayed interrupt urb */
++		if (operational_mode && dev->interrupt && dev->intr_urb_delay_submit) {
++			int status = usb_submit_urb(dev->interrupt, GFP_ATOMIC);
++			dev->intr_urb_delay_submit = FALSE;
++			if (status != 0 && netif_msg_timer (dev))
++				deverr(dev, "intr resubmit --> %d", status);
++		}
++	}
++
++	/* waiting for all pending urbs to complete? */
++	if (dev->wait) {
++		if ((dev->txq.qlen + dev->rxq.qlen + dev->done.qlen) == 0) {
++			wake_up(dev->wait);
++		}
++	/* or are we maybe short a few urbs? */
++	} else if (netif_running(dev->net)
++			&& netif_device_present(dev->net)
++			&& !timer_pending(&dev->delay)
++			&& !test_bit(EVENT_RX_HALT, &dev->flags)
++			&& netif_carrier_ok(dev->net)) {
++
++		if (((operational_mode) && (!dev->StopSummitUrb)) ||(!(operational_mode) ))  {
++			int temp = dev->rxq.qlen;
++			int qlen = RX_QLEN(dev);
++
++			if (temp < qlen) {
++				struct urb *urb;
++				int i;
++
++				/* don't refill the queue all at once */
++				for (i = 0; i < 5 && dev->rxq.qlen < qlen; i++) {
++					urb = usb_alloc_urb(0,GFP_ATOMIC);
++					if (urb != NULL) {
++						ret = rx_submit(dev, urb, GFP_ATOMIC);
++						if (ret)
++							break;
++					}
++				}
++				if (dev->rxq.qlen < qlen)
++					tasklet_schedule(&dev->bh);
++			}
++
++		}
++		if (!dev->tx_hold_on_completion) {
++			if (dev->txq.qlen < TX_QLEN(dev))
++				netif_wake_queue(dev->net);
++		}
++	}
++}
++
++// precondition: never called in_interrupt
++int smscusbnet_stop (struct net_device *net)
++{
++	int temp;
++	struct usbnet *dev = netdev_priv(net);
++	
++	DECLARE_WAIT_QUEUE_HEAD (unlink_wakeup);
++	DECLARE_WAITQUEUE (wait, current);
++
++	netif_stop_queue (net);
++	if (netif_msg_ifdown (dev))
++		devinfo (dev, "stop stats: rx/tx %ld/%ld, errs %ld/%ld",
++		
++		dev->stats.rx_packets, dev->stats.tx_packets,
++		dev->stats.rx_errors, dev->stats.tx_errors
++		);
++	if(!skb_queue_empty(&dev->tx_pending_q)){
++		skb_queue_purge(&dev->tx_pending_q);
++	}
++	// ensure there are no more active urbs
++	add_wait_queue (&unlink_wakeup, &wait);
++	dev->wait = &unlink_wakeup;
++	temp = unlink_urbs (dev, &dev->txq) + unlink_urbs (dev, &dev->rxq);
++	// maybe wait for deletions to finish.
++	while (!skb_queue_empty(&dev->rxq) &&
++	       !skb_queue_empty(&dev->txq) &&
++	       !skb_queue_empty(&dev->done)) {
++		msleep(UNLINK_TIMEOUT_MS);
++		if (netif_msg_ifdown (dev))
++			devdbg (dev, "waited for %d urb completions", temp);
++	}
++	dev->wait = NULL;
++	remove_wait_queue (&unlink_wakeup, &wait);
++	if(operational_mode){
++		usb_kill_urb(dev->interrupt);
++	}
++
++	/* deferred work (task, timer, softirq) must also stop.
++	 * can't flush_scheduled_work() until we drop rtnl (later),
++	 * else workers could deadlock; so make workers a NOP.
++	 */
++	dev->flags = 0;
++	//Clean up the counters
++	memset(&dev->stats, 0, sizeof(dev->stats));
++	memset(&dev->extra_error_cnts, 0, sizeof(dev->extra_error_cnts));
++
++	dev->StopLinkPolling=TRUE;
++	tasklet_kill (&dev->bh);
++	netif_carrier_off(dev->net);
++	
++#if (LINUX_VERSION_CODE > KERNEL_VERSION(2,6,18))
++	/* if device is in suspend0 status already, resume it first. So
++	we can set suspend2 in Smsc9500_suspend(); */
++	down(&dev->pm_mutex);
++	if (!dev->pmLock){
++		dev->pmLock = TRUE;
++		usb_autopm_get_interface(dev->uintf);
++	}
++	up(&dev->pm_mutex);
++
++	msleep(100);
++
++	down(&dev->pm_mutex);
++	if (dev->pmLock) {
++		usb_autopm_put_interface(dev->uintf);
++	}
++	dev->pmLock = FALSE;
++	up(&dev->pm_mutex);
++#endif
++
++	return 0;
++}
++
++// posts reads, and enables write queuing
++
++// precondition: never called in_interrupt
++
++#if (LINUX_VERSION_CODE < KERNEL_VERSION(2,6,29))
++static 
++#endif
++int smscusbnet_open (struct net_device *net)
++{
++	int retval = 0;
++	struct usbnet *dev = netdev_priv(net);
++	struct driver_info *info = dev->driver_info;
++	
++#if (LINUX_VERSION_CODE > KERNEL_VERSION(2,6,18))
++	down(&dev->pm_mutex);
++	dev->pmLock = TRUE;
++	usb_autopm_get_interface(dev->uintf);
++	up(&dev->pm_mutex);
++#endif
++
++	dev->suspendFlag = 0;
++	dev->netDetachDone = FALSE;
++
++	// put into "known safe" state
++	if (info->reset && (retval = info->reset (dev)) < 0) {
++	devdbg (dev,"info->reset && (retval = info->reset (dev)) \n");
++		if (netif_msg_ifup (dev))
++			devinfo (dev,
++				"open reset fail (%d) usbnet usb-%s-%s, %s",
++				retval,
++				dev->udev->bus->bus_name, dev->udev->devpath,
++			info->description);
++		goto done;
++	}
++
++	dev->intr_urb_delay_submit = FALSE;
++
++	// insist peer be connected
++	if (info->check_connect && (retval = info->check_connect (dev)) < 0) {
++		if (netif_msg_ifup (dev))
++			devdbg (dev, "can't open; %d", retval);
++		goto done;
++	}
++
++	/* start any status interrupt transfer */
++	if(operational_mode){
++		if (dev->interrupt) {
++		devdbg (dev,"dev->interrupt \n");
++			retval = usb_submit_urb(dev->interrupt, GFP_KERNEL);
++			if (retval < 0) {
++				if (netif_msg_ifup (dev))
++					deverr (dev, "intr submit %d", retval);
++				goto done;
++			}
++		}
++	}
++
++	netif_start_queue(net);
++	if (netif_msg_ifup(dev)) {
++		char	*framing;
++		devdbg (dev,"netif_msg_ifup \n");
++		if (dev->driver_info->flags & FLAG_FRAMING_NC)
++			framing = "NetChip";
++		else if (dev->driver_info->flags & FLAG_FRAMING_GL)
++			framing = "GeneSys";
++		else if (dev->driver_info->flags & FLAG_FRAMING_Z)
++			framing = "Zaurus";
++		else if (dev->driver_info->flags & FLAG_FRAMING_RN)
++			framing = "RNDIS";
++		else if (dev->driver_info->flags & FLAG_FRAMING_AX)
++			framing = "ASIX";
++		else
++			framing = "simple";
++
++		devinfo(dev, "open: enable queueing "
++				"(rx %lx, tx %lx) mtu %d %s framing",
++			RX_QLEN (dev), TX_QLEN (dev), dev->net->mtu,
++			framing);
++	}
++
++	// delay posting reads until we're fully open
++	tasklet_schedule(&dev->bh);
++	dev->StopLinkPolling = FALSE;
++	if ((!(dev->StopLinkPolling)) && (!timer_pending(&dev->LinkPollingTimer))) {
++		dev->LinkPollingTimer.expires = jiffies+HZ;
++		add_timer(&(dev->LinkPollingTimer));
++	}
++done:
++	return retval;
++}
++
++/* work that cannot be done in interrupt context uses keventd.
++ *
++ * NOTE:  with 2.5 we could do more of this using completion callbacks,
++ * especially now that control transfers can be queued.
++ */
++ #if (LINUX_VERSION_CODE < KERNEL_VERSION(2,6,20))
++static void kevent (void *data)
++{
++	struct usbnet *dev = data;
++#else
++static void kevent(struct work_struct *work)
++{
++	struct usbnet *dev = container_of(work,struct usbnet,kevent);
++#endif
++
++	int status;
++
++	if (dev == NULL)
++		return;
++
++	/* usb_clear_halt() needs a thread context */
++	if (test_bit(EVENT_TX_HALT, &dev->flags)) {
++		unlink_urbs(dev, &dev->txq);
++		status = usb_clear_halt (dev->udev, dev->out);
++
++        	/* Set recovery flag, the device will be reset in the smsc9500.c */
++		set_bit(EVENT_DEV_RECOVERY, &dev->flags);
++
++		if (status < 0 && status != -EPIPE && status != -ESHUTDOWN) {
++			if (netif_msg_tx_err(dev))
++				deverr(dev, "can't clear tx halt, status %d", status);
++		} else {
++			clear_bit(EVENT_TX_HALT, &dev->flags);
++			if (status != -ESHUTDOWN){
++				netif_wake_queue(dev->net);
++		   }
++		}
++	}
++	if (test_bit(EVENT_RX_HALT, &dev->flags)) {
++		unlink_urbs(dev, &dev->rxq);
++		status = usb_clear_halt(dev->udev, dev->in);
++
++		/* Set recovery flag */
++		set_bit(EVENT_DEV_RECOVERY, &dev->flags);
++
++		if (status < 0 && status != -EPIPE && status != -ESHUTDOWN) {
++			if (netif_msg_rx_err (dev))
++				deverr(dev, "can't clear rx halt, status %d",
++					status);
++		} else {
++			clear_bit(EVENT_RX_HALT, &dev->flags);
++			tasklet_schedule(&dev->bh);
++		}
++	}
++
++	/* tasklet could resubmit itself forever if memory is tight */
++	if (test_bit(EVENT_RX_MEMORY, &dev->flags)) {
++		struct urb *urb = NULL;
++
++		if (netif_running (dev->net))
++			urb = usb_alloc_urb(0,GFP_KERNEL);
++		else
++			clear_bit(EVENT_RX_MEMORY, &dev->flags);
++		if (urb != NULL) {
++			clear_bit(EVENT_RX_MEMORY, &dev->flags);
++			rx_submit(dev, urb, GFP_KERNEL);
++			tasklet_schedule(&dev->bh);
++		}
++	}
++
++	//if (dev->flags)
++		//devdbg (dev, "kevent done, flags = 0x%lx \n", dev->flags);
++}
++
++#if (LINUX_VERSION_CODE > KERNEL_VERSION(2,6,18))
++/*-------------------------------------------------------------------------*/
++
++/* Stop all traffic so kernel will suspend our device.
++ *
++ */
++#ifdef CONFIG_PM
++static int suspendDevice(struct usbnet *dev)
++{
++	if(operational_mode){
++		usb_kill_urb(dev->interrupt); //stop interrupt urb
++	 }else{
++		 DECLARE_WAIT_QUEUE_HEAD (unlink_wakeup);
++		 DECLARE_WAITQUEUE (wait, current);
++
++		 add_wait_queue (&unlink_wakeup, &wait);
++		 dev->wait = &unlink_wakeup;
++		 unlink_urbs (dev, &dev->txq);
++		 unlink_urbs (dev, &dev->rxq);
++		 // maybe wait for deletions to finish.
++		 while (!skb_queue_empty(&dev->rxq) &&
++				!skb_queue_empty(&dev->txq) &&
++				!skb_queue_empty(&dev->done)) {
++			 msleep(UNLINK_TIMEOUT_MS);
++		 }
++		 dev->wait = NULL;
++		 remove_wait_queue (&unlink_wakeup, &wait);
++	 }
++
++	 dev->StopLinkPolling = TRUE;  //stop accessing registers
++	 down(&dev->pm_mutex);
++	 if(dev->pmLock){
++		 dev->pmLock = FALSE;
++		 usb_autopm_put_interface(dev->uintf);
++	 }
++	 up(&dev->pm_mutex);
++
++	 return 0;
++}
++#endif //CONFIG_PM
++#endif
++
++/* work that cannot be done in interrupt context uses keventd.
++ *
++ * NOTE:  with 2.5 we could do more of this using completion callbacks,
++ * especially now that control transfers can be queued.
++ */
++#if (LINUX_VERSION_CODE < KERNEL_VERSION(2,6,20))
++static void myevent(void *data)
++{
++	struct usbnet		*dev = data;
++#else
++static void myevent(struct work_struct *work)
++{
++	struct usbnet *dev = container_of(work,struct usbnet,myevent);
++#endif
++
++	if (dev == NULL)
++		return;
++
++	if (dev->disconnected) {
++		printk("myevent: Disconnected\n");
++		return;
++	}
++
++#if (LINUX_VERSION_CODE > KERNEL_VERSION(2,6,18)) && defined(CONFIG_PM)
++    if (test_bit (EVENT_IDLE_CHECK, &dev->flags)) {
++        clear_bit (EVENT_IDLE_CHECK, &dev->flags);
++        //autosuspend_disabled should be enabled by shell cmd "echo auto > /sys/bus/usb/devices/X-XX/power/level"
++        if(dev->dynamicSuspend 
++#if ((LINUX_VERSION_CODE > KERNEL_VERSION(2,6,21)) && (LINUX_VERSION_CODE < KERNEL_VERSION(2,6,35)))
++		&& !dev->udev->autosuspend_disabled
++#endif
++			){
++			if((dev->idleCount >= PM_IDLE_DELAY) && 
++#if (LINUX_VERSION_CODE > KERNEL_VERSION(2,6,31))
++				(atomic_read(&dev->uintf->pm_usage_cnt) > 0)){
++#else
++				(dev->uintf->pm_usage_cnt > 0)){
++#endif
++				
++				if(dev->chipDependFeatures[FEATURE_SUSPEND3]){
++					dev->suspendFlag |= AUTOSUSPEND_DYNAMIC_S3;
++				}else{
++					dev->suspendFlag |= AUTOSUSPEND_DYNAMIC;
++				}
++				
++				suspendDevice(dev);
++			}
++			if(dev->idleCount < PM_IDLE_DELAY)dev->idleCount++;
++        }
++    }
++#endif //(LINUX_VERSION_CODE > KERNEL_VERSION(2,6,18)) && defined(CONFIG_PM)
++    if (test_bit (EVENT_LINK_DOWN_DETACH, &dev->flags)) {
++    	clear_bit (EVENT_LINK_DOWN_DETACH, &dev->flags);
++		if(dev->netDetach){
++        	dev->suspendFlag |= AUTOSUSPEND_DETACH;
++		}
++#if (LINUX_VERSION_CODE > KERNEL_VERSION(2,6,18)) && defined(CONFIG_PM)
++		else if(dev->linkDownSuspend 
++#if ((LINUX_VERSION_CODE > KERNEL_VERSION(2,6,21)) && (LINUX_VERSION_CODE < KERNEL_VERSION(2,6,35)))
++		&& !dev->udev->autosuspend_disabled
++#endif		
++		){
++        	dev->suspendFlag |= AUTOSUSPEND_LINKDOWN;
++        	suspendDevice(dev);
++        }
++#endif //(LINUX_VERSION_CODE > KERNEL_VERSION(2,6,18)) && defined(CONFIG_PM)
++    }
++#if (LINUX_VERSION_CODE > KERNEL_VERSION(2,6,18)) && defined(CONFIG_PM)
++    if (test_bit (EVENT_IDLE_RESUME, &dev->flags)) {
++        clear_bit (EVENT_IDLE_RESUME, &dev->flags);
++
++        if (dev->dynamicSuspend || dev->linkDownSuspend) {
++			down(&dev->pm_mutex);
++			if (!dev->pmLock) {
++				dev->pmLock = TRUE;
++				usb_autopm_get_interface(dev->uintf);
++			}
++			up(&dev->pm_mutex);
++
++			if (operational_mode) {
++				if (dev->interrupt) {
++					if (usb_submit_urb(dev->interrupt, GFP_KERNEL) < 0) {
++						deverr(dev, "intr submit ");
++					}
++				}
++			}
++			if( (!timer_pending(&dev->LinkPollingTimer))) {
++			   dev->LinkPollingTimer.expires = jiffies+HZ;
++			   add_timer(&(dev->LinkPollingTimer));
++			}
++			dev->StopLinkPolling = FALSE;
++			netif_wake_queue(dev->net);
++        }
++    }
++
++#endif //(LINUX_VERSION_CODE > KERNEL_VERSION(2,6,18)) && defined(CONFIG_PM)
++	if (test_bit (EVENT_LINK_RESET, &dev->flags)) {
++		struct driver_info 	*info = dev->driver_info;
++		int			retval = 0;
++
++		clear_bit (EVENT_LINK_RESET, &dev->flags);
++
++        if(info->link_reset && (retval = info->link_reset(dev)) < 0) {
++			devinfo(dev, "link reset failed (%d) usbnet usb-%s-%s, %s",
++				retval,
++				dev->udev->bus->bus_name, dev->udev->devpath,
++				info->description);
++		}
++
++		if (test_bit (EVENT_LINK_UP, &dev->flags)) {
++		     clear_bit (EVENT_LINK_UP, &dev->flags);
++		     tasklet_schedule (&dev->bh);
++        
++	    }
++        if (test_bit (EVENT_LINK_DOWN, &dev->flags)) {
++		     clear_bit (EVENT_LINK_DOWN, &dev->flags);
++		     unlink_urbs (dev, &dev->rxq);
++        
++	    }
++	}
++
++	if (test_bit (EVENT_SET_MULTICAST, &dev->flags)) {
++		struct driver_info 	*info = dev->driver_info;
++		int			retval = 0;
++
++		clear_bit (EVENT_SET_MULTICAST, &dev->flags);
++		if(info->rx_setmulticastlist&& (retval = info->rx_setmulticastlist(dev)) < 0) {
++			devinfo(dev, "Set Multicast failed (%d) usbnet usb-%s-%s, %s",
++				retval,
++				dev->udev->bus->bus_name, dev->udev->devpath,
++				info->description);
++		}
++	}
++
++	//if (dev->flags)
++		//devdbg (dev, "myevent done, flags = 0x%lx", dev->flags);
++}
++
++static void tx_complete(struct urb *urb)
++{
++	struct sk_buff *skb = (struct sk_buff *)urb->context;
++	struct skb_data *entry = (struct skb_data *)skb->cb;
++	struct usbnet *dev = entry->dev;
++
++	dev->idleCount = 0;
++
++	if (urb->status == 0) {
++		if (dev->tx_hold_on_completion) {
++			if (dev->tx_pending_q.qlen < (TX_QLEN(dev) / 2))
++				netif_wake_queue(dev->net);
++
++			dev->stats.tx_packets += entry->pkt_cnt;
++		} else {
++			dev->stats.tx_packets++;
++		}
++		dev->stats.tx_bytes += entry->length;
++	} else {
++		dev->stats.tx_errors++;
++
++		switch (urb->status) {
++		case -EPIPE:
++			smscusbnet_defer_kevent(dev, EVENT_TX_HALT);
++			dev->extra_error_cnts.tx_epipe++;
++			break;
++
++		/* software-driven interface shutdown */
++		case -ECONNRESET:	// async unlink
++		case -ESHUTDOWN:	// hardware gone
++			break;
++
++		/* like rx, tx gets controller i/o faults during khubd delays
++		   and so it uses the same throttling mechanism */
++		case -EPROTO:		// ehci
++			dev->extra_error_cnts.tx_eproto++;
++			goto _HANDLE;
++		case -ETIMEDOUT:	// ohci
++		case -ETIME:		// ohci
++			dev->extra_error_cnts.tx_etimeout++;
++			goto _HANDLE;
++		case -EILSEQ:		// uhci
++			dev->extra_error_cnts.tx_eilseq++;
++_HANDLE:
++			if (!timer_pending(&dev->delay)) {
++				mod_timer(&dev->delay,
++					jiffies + THROTTLE_JIFFIES);
++				if (netif_msg_link (dev))
++					devdbg(dev, "tx throttle %d",
++							urb->status);
++			}
++			netif_stop_queue(dev->net);
++			/* Set recovery flag */
++			set_bit (EVENT_DEV_RECOVERY, &dev->flags);
++
++			break;
++		default:
++			if (netif_msg_tx_err(dev))
++				devdbg(dev, "tx err %d", entry->urb->status);
++			break;
++		}
++	}
++
++	urb->dev = NULL;
++	entry->state = tx_done;
++	defer_bh(dev, skb, &dev->txq);
++}
++
++#if (LINUX_VERSION_CODE < KERNEL_VERSION(2,6,29))
++static
++#endif
++void smscusbnet_tx_timeout (struct net_device *net)
++{
++	struct usbnet *dev = netdev_priv(net);
++
++	unlink_urbs (dev, &dev->txq);
++	tasklet_schedule (&dev->bh);
++
++	// FIXME: device recovery -- reset?
++}
++
++/*txq.lock will be acquired by caller*/
++static int smscusbnet_bundle_skb_ximt(struct usbnet *dev, struct sk_buff_head *q)
++{
++	unsigned long flags;
++	struct sk_buff *skb = NULL, *skbnext = NULL;
++	int count = 0, pkt_cnt = 0;
++	int SkbSize = 0;
++	struct skb_data *entry;
++	int retval = NET_XMIT_SUCCESS;
++	struct urb *urb = NULL;
++
++	if ((struct sk_buff *)q == q->next)
++		return retval;
++
++	if (dev->tx_use_prealloc_buffs) {
++		spin_lock_irqsave(&q->lock, flags);
++
++		if (!q->qlen) {
++			spin_unlock_irqrestore(&q->lock, flags);
++			return retval;
++		}
++		
++		skb = smscusbnet_get_tx_buffer(dev);
++		if (!skb) {
++			devdbg (dev, "smscusbnet_bundle_skb_ximt(): no tx buffer available\n");
++			spin_unlock_irqrestore(&q->lock, flags);
++			return retval;
++		}
++		count = 0;
++		while((skbnext = __skb_dequeue(q)) != NULL) {
++			if ((count + skbnext->len) < dev->tx_urb_size) {
++				memcpy(skb->data + count, skbnext->data, skbnext->len);
++				count += skbnext->len;
++				pkt_cnt++;
++				skb_put(skb, skbnext->len);
++				kfree_skb(skbnext);
++			} else {
++				__skb_queue_head(q, skbnext);	
++				break;
++			}
++		}
++		SkbSize = count;
++
++		spin_unlock_irqrestore(&q->lock, flags);
++
++	} else {
++		spin_lock_irqsave(&q->lock, flags);
++
++		for(skbnext = q->next; skbnext != (struct sk_buff *) q; skbnext = skbnext->next) {
++			SkbSize += skbnext->len;
++			pkt_cnt++;
++		}
++		if(SkbSize == 0) {
++			spin_unlock_irqrestore(&q->lock, flags);
++			return retval;
++		}
++
++		if(pkt_cnt > 1) {
++			skb = dev_alloc_skb(SkbSize);
++			if (!skb){
++				devdbg (dev, "smscusbnet_merge_skb, skb is NULL, CX_SkbSize = %d", SkbSize);
++				spin_unlock_irqrestore(&q->lock, flags);
++				return retval;
++			}
++			if (dev->tx_urb_buf_alignment) {
++				skb->data = (unsigned char *)(((ulong)skb->head + dev->tx_urb_buf_alignment - 1) &
++					~(dev->tx_urb_buf_alignment - 1));
++				skb_reset_tail_pointer(skb);
++			}
++			skb_put(skb, SkbSize);
++			count = 0;
++
++			for(skbnext = q->next; skbnext != (struct sk_buff *) q; skbnext = skbnext->next) {
++				memcpy(skb->data + count, skbnext->data, skbnext->len);
++				count += skbnext->len;
++			}
++			while((skbnext = __skb_dequeue(q)) != NULL){
++				kfree_skb(skbnext);
++			}
++
++		} else { //one packet
++			skb = __skb_dequeue(q);
++		}
++		spin_unlock_irqrestore(&q->lock, flags);
++	}
++
++	netif_wake_queue(dev->net);
++
++	if (!(urb = usb_alloc_urb(0, GFP_ATOMIC))) {
++		if (netif_msg_tx_err(dev))
++			devdbg(dev, "no urb");
++		retval = NET_XMIT_SUCCESS;
++		dev->stats.tx_dropped += pkt_cnt;
++		if (skb){
++			dev_kfree_skb_any(skb);
++			skb = NULL;
++		}
++
++		goto drop;
++	} else {
++		entry = (struct skb_data *) skb->cb;
++		entry->urb = urb;
++		entry->dev = dev;
++		entry->state = tx_start;
++		entry->length = SkbSize;
++		entry->pkt_cnt = pkt_cnt;
++
++		usb_fill_bulk_urb(urb, dev->udev, dev->out,
++				skb->data, skb->len, tx_complete, skb);
++	}
++
++	switch ((retval = usb_submit_urb(urb, GFP_ATOMIC))) {
++	case -EPIPE:
++		devdbg(dev," in smscusbnet_bundle_skb_ximt,-EPIPE\n");
++		netif_stop_queue(dev->net);
++		smscusbnet_defer_kevent(dev, EVENT_TX_HALT);
++		break;
++	default:
++		if (netif_msg_tx_err(dev))
++			devdbg(dev, "tx: submit urb err %d", retval);
++		break;
++	case 0:
++#if (LINUX_VERSION_CODE < KERNEL_VERSION(4,7,10))
++		dev->net->trans_start = jiffies;
++#else
++		netif_trans_update(dev->net);
++#endif
++		__skb_queue_tail(&dev->txq, skb);
++
++		if (dev->txq.qlen >= TX_QLEN(dev))
++			netif_stop_queue(dev->net);
++	}
++
++	if (retval) {
++		if (netif_msg_tx_err(dev))
++			devdbg(dev, "drop, code %d", retval);
++drop:
++		retval = NET_XMIT_SUCCESS;
++
++		dev->stats.tx_dropped += pkt_cnt;
++		if (skb)
++			dev_kfree_skb_any(skb);
++		usb_free_urb (urb);
++	} else if (netif_msg_tx_queued(dev)) {
++		devdbg(dev, "> tx, len %d, type 0x%x",
++			SkbSize, skb->protocol);
++	}
++
++	return retval;
++}
++
++/*-------------------------------------------------------------------------*/
++#if (LINUX_VERSION_CODE < KERNEL_VERSION(2,6,29))
++static
++#endif
++int smscusbnet_start_xmit (struct sk_buff *skb, struct net_device *net)
++{
++	int retval = NET_XMIT_SUCCESS;
++	struct usbnet *dev = netdev_priv(net);
++	struct driver_info *info = dev->driver_info;
++
++#if defined(CONFIG_PM)
++#if (LINUX_VERSION_CODE > KERNEL_VERSION(2,6,31))
++	if (atomic_read(&dev->uintf->pm_usage_cnt) <= 0) {
++#else
++	if(dev->uintf->pm_usage_cnt <= 0) {
++#endif
++		netif_stop_queue (net);
++		smscusbnet_defer_myevent(dev, EVENT_IDLE_RESUME);
++		return NET_XMIT_DROP;
++	}
++#endif //CONFIG_PM 
++
++        /* We do not advertise SG, so skbs should be already linearized */
++        BUG_ON(skb_shinfo(skb)->nr_frags);
++
++	/* some devices want funky USB-level framing, for win32 driver
++	(usually) and/or hardware quirks */
++	if (info->tx_fixup) {
++		skb = info->tx_fixup(dev, skb, GFP_ATOMIC);
++		if (!skb) {
++			if (netif_msg_tx_err (dev))
++				devdbg (dev, "can't tx_fixup skb");
++			retval = NET_XMIT_SUCCESS;
++			dev->stats.tx_dropped++;
++			return NET_XMIT_DROP;
++		}
++	}
++
++	if (dev->tx_hold_on_completion) {
++		unsigned long flags;
++
++		skb_queue_tail(&dev->tx_pending_q, skb);
++		spin_lock_irqsave (&dev->txq.lock, flags);
++		if (dev->txq.qlen != 0) {
++			if (dev->tx_pending_q.qlen >= (TX_QLEN(dev) / 2)) {
++				netif_stop_queue (net);
++			}
++		} else {
++			retval = smscusbnet_bundle_skb_ximt(dev, &dev->tx_pending_q);
++		}
++		spin_unlock_irqrestore(&dev->txq.lock, flags);
++	} else {
++		retval = smscusbnet_xmit(skb, net);
++	}
++	return retval;
++}
++
++static int smscusbnet_xmit(struct sk_buff *skb, struct net_device *net)
++{
++	int retval = NET_XMIT_SUCCESS;
++	struct usbnet *dev = netdev_priv(net);
++	struct urb *urb = NULL;
++	struct skb_data *entry;
++	unsigned long flags;
++
++	if (!(urb = usb_alloc_urb(0, GFP_ATOMIC))) {
++		if (netif_msg_tx_err(dev))
++			devdbg(dev, "no urb");
++		goto drop;
++	}
++
++	entry = (struct skb_data *) skb->cb;
++	entry->urb = urb;
++	entry->dev = dev;
++	entry->state = tx_start;
++	entry->length = skb->len;
++
++	usb_fill_bulk_urb(urb, dev->udev, dev->out,
++			skb->data, skb->len, tx_complete, skb);
++
++	/* don't assume the hardware handles USB_ZERO_PACKET
++	 * NOTE:  strictly conforming cdc-ether devices should expect
++	 * the ZLP here, but ignore the one-byte packet.
++	 *
++	 * FIXME zero that byte, if it doesn't require a new skb.
++	 */
++	if ((skb->len % dev->maxpacket) == 0) {
++		urb->transfer_buffer_length++;
++		if (skb_tailroom(skb)) {
++			skb->data[skb->len] = 0;
++			__skb_put(skb, 1);
++		}
++	}
++	spin_lock_irqsave(&dev->txq.lock, flags);
++
++	switch ((retval = usb_submit_urb(urb, GFP_ATOMIC))) {
++	case -EPIPE:
++		devdbg (dev," in tx_fixup,-EPIPE\n");
++		netif_stop_queue (net);
++		smscusbnet_defer_kevent(dev, EVENT_TX_HALT);
++		break;
++	default:
++		if (netif_msg_tx_err(dev))
++			devdbg(dev, "tx: submit urb err %d", retval);
++		break;
++	case 0:
++#if (LINUX_VERSION_CODE < KERNEL_VERSION(4,7,10))
++		dev->net->trans_start = jiffies;
++#else
++		netif_trans_update(dev->net);
++#endif
++		__skb_queue_tail(&dev->txq, skb);
++
++		if (dev->txq.qlen >= TX_QLEN(dev))
++			netif_stop_queue(net);
++	}
++	spin_unlock_irqrestore(&dev->txq.lock, flags);
++
++	if (retval) {
++		devdbg (dev," in tx_fixup,drop\n");
++		if (netif_msg_tx_err(dev))
++			devdbg (dev, "drop, code %d", retval);
++drop:
++		retval = NET_XMIT_SUCCESS;
++		dev->stats.tx_dropped++;
++		if (skb)
++			dev_kfree_skb_any(skb);
++		usb_free_urb (urb);
++	} else if (netif_msg_tx_queued(dev)) {
++		devdbg(dev, "> tx, len %d, type 0x%x",
++			skb->len, skb->protocol);
++	}
++
++	return retval;
++}
++
++/*-------------------------------------------------------------------------
++ *
++ * USB Device Driver support
++ *
++ *-------------------------------------------------------------------------*/
++
++// precondition: never called in_interrupt
++
++void smscusbnet_disconnect (struct usb_interface *intf)
++{
++	struct usbnet *dev = NULL;
++	struct usb_device *xdev = NULL;
++	struct net_device *net = NULL;
++
++	dev = usb_get_intfdata(intf);
++	usb_set_intfdata(intf, NULL);
++	if (!dev)
++		return;
++
++	dev->disconnected = TRUE;
++	xdev = interface_to_usbdev (intf);
++
++	if (netif_msg_probe (dev))
++		devinfo (dev, "unregister '%s' usb-%s-%s, %s",
++			intf->dev.driver->name,
++			xdev->bus->bus_name, xdev->devpath,
++			dev->driver_info->description);
++
++	net = dev->net;
++	unregister_netdev (net);
++
++	if(operational_mode && dev->interrupt){
++		usb_free_urb(dev->interrupt);
++	}
++	if(dev->interrupt_urb_buffer){
++		kfree(dev->interrupt_urb_buffer);
++		dev->interrupt_urb_buffer = NULL;
++	}
++
++	if (dev->driver_info->unbind) {
++		dev->driver_info->unbind (dev, intf);
++	}
++
++	/* we don't hold rtnl here ... */
++	flush_scheduled_work ();
++	flush_workqueue(dev->MyWorkQueue);
++	destroy_workqueue(dev->MyWorkQueue);
++
++	del_timer_sync (&dev->LinkPollingTimer);
++	del_timer_sync (&dev->delay);
++
++	if (dev->rx_use_prealloc_buffs)
++		smscusbnet_free_rx_pool(dev);
++	if (dev->tx_use_prealloc_buffs)
++		smscusbnet_free_tx_pool(dev);
++
++	free_netdev(net);
++	usb_put_dev (xdev);
++
++}
++
++// precondition: never called in_interrupt
++int
++smscusbnet_probe (struct usb_interface *udev, const struct usb_device_id *prod)
++{
++	struct usbnet			*dev = NULL;
++	struct net_device 		*net = NULL;
++	struct usb_host_interface	*interface = NULL;
++	struct driver_info		*info = NULL;
++	struct usb_device		*xdev = NULL;
++	int				status = 0;
++	char version[15];
++	
++	info = (struct driver_info *) prod->driver_info;
++	if (!info) {
++		return -ENODEV;
++	}
++	xdev = interface_to_usbdev (udev);
++	interface = udev->cur_altsetting;
++
++	usb_get_dev (xdev);
++
++	sprintf(version,"%lX.%02lX.%02lX", (DRIVER_VERSION>>16),(DRIVER_VERSION>>8)&0xFF,(DRIVER_VERSION&0xFFUL));
++	printk("Driver smscusbnet.ko verison %s\n",version);
++
++	// set up our own records
++	net = alloc_etherdev(sizeof(*dev));
++	if (!net) {
++		goto out;
++	}
++	dev = netdev_priv(net);
++
++	sema_init(&dev->pm_mutex, 1);
++
++	dev->udev = xdev;
++	dev->uintf = udev;
++	dev->driver_info = info;
++	dev->msg_enable = netif_msg_init (msg_level, NETIF_MSG_DRV
++				| NETIF_MSG_PROBE | NETIF_MSG_LINK);
++	skb_queue_head_init (&dev->rxq);
++	skb_queue_head_init (&dev->txq);
++	skb_queue_head_init (&dev->tx_pending_q);
++	skb_queue_head_init (&dev->done);
++	dev->bh.func = smscusbnet_bh;
++	dev->bh.data = (unsigned long) dev;
++
++	dev->idVendor = prod->idVendor;
++	dev->idProduct = prod->idProduct;
++	dev->disconnected = FALSE;
++
++#if (LINUX_VERSION_CODE < KERNEL_VERSION(2,6,20))
++		INIT_WORK (&dev->kevent, kevent,dev);
++#else
++		INIT_WORK (&dev->kevent, kevent);
++#endif
++
++	if (operational_mode)
++		devdbg (dev,"Operational mode enabled\n");
++
++	dev->MyWorkQueue=create_singlethread_workqueue("intr_work");
++	if (!dev->MyWorkQueue) {
++		devdbg (dev,"can't create MyWorkQueue!\n");
++		goto out1;
++	}
++#if (LINUX_VERSION_CODE < KERNEL_VERSION(2,6,20))
++	INIT_WORK (&dev->myevent, myevent,dev);
++#else
++	INIT_WORK (&dev->myevent, myevent);
++#endif
++	dev->delay.function = smscusbnet_bh;
++	dev->delay.data = (unsigned long) dev;
++	init_timer (&dev->delay);
++
++	dev->tx_qlen = tx_queue_size;
++	dev->rx_qlen = rx_queue_size;
++	dev->turbo_mode = TurboMode;
++
++        if (TurboMode) {
++                if(dev->udev->speed == USB_SPEED_HIGH)
++			dev->rx_urb_size = DEFAULT_HS_BURST_CAP_SIZE;
++                else
++			dev->rx_urb_size = DEFAULT_FS_BURST_CAP_SIZE;
++        }else{
++                dev->rx_urb_size = MAX_SINGLE_PACKET_SIZE;
++        }
++
++	dev->tx_hold_on_completion = tx_hold_on_completion;
++	dev->tx_urb_buf_alignment = tx_urb_buf_alignment;
++	dev->rx_urb_buf_alignment = rx_urb_buf_alignment;
++	if (net_ip_align) {
++		dev->net_ip_align = net_ip_align;
++	} else {
++		dev->net_ip_align = NET_IP_ALIGN;
++	}
++	dev->rx_skb_copy = rx_skb_copy;
++
++	dev->rx_use_prealloc_buffs = rx_use_prealloc_buffers;
++	skb_queue_head_init(&dev->rx_pool_queue);
++	/* allocate rx usb buffers if enabled */
++	if (dev->rx_use_prealloc_buffs) {
++		status = smscusbnet_alloc_rx_pool(dev, dev->rx_urb_size);
++		if (status) {
++			smscusbnet_free_rx_pool(dev);
++			status = ENOMEM;
++			goto out1;
++		}
++	}
++
++	dev->tx_use_prealloc_buffs = tx_use_prealloc_buffers;
++	dev->tx_urb_size = DEFAULT_TX_BUFFER_SIZE;
++	skb_queue_head_init(&dev->tx_pool_queue);
++	/* allocate tx usb buffers if enabled */
++	if (dev->tx_use_prealloc_buffs) {
++		status = smscusbnet_alloc_tx_pool(dev, dev->tx_urb_size);
++		if (status) {
++			smscusbnet_free_tx_pool(dev);
++			status = ENOMEM;
++			goto out1;
++		}
++	}
++
++	dev->StopLinkPolling = FALSE;
++	dev->LinkPollingTimer.function = smscusbnet_linkpolling;
++	dev->LinkPollingTimer.data = (unsigned long) dev;
++	init_timer(&(dev->LinkPollingTimer));
++
++	dev->net = net;
++	strcpy (net->name, "eth%d");
++	memcpy (net->dev_addr, node_id, sizeof node_id);
++
++	/* rx and tx sides can use different message sizes;
++	 * bind() should set rx_urb_size in that case.
++	 */
++	/* Reserve extra 8 bytes for control word to eliminate memcpy
++	in tx_fixup() */
++	net->hard_header_len += EXTRA_HEADER_LEN; 
++	dev->hard_mtu = net->mtu + net->hard_header_len;
++#if 0
++	/* dma_supported() is deeply broken on almost all architectures
++	   possible with some EHCI controllers */
++	if (dma_supported (&udev->dev, DMA_64BIT_MASK))
++		net->features |= NETIF_F_HIGHDMA;
++#endif
++
++#if (LINUX_VERSION_CODE < KERNEL_VERSION(2,6,29))
++	net->change_mtu = smscusbnet_change_mtu;
++	net->get_stats = smscusbnet_get_stats;
++	net->hard_start_xmit = smscusbnet_start_xmit;
++	net->open = smscusbnet_open;
++	net->stop = smscusbnet_stop;
++	net->tx_timeout = smscusbnet_tx_timeout;
++#else
++        net->netdev_ops = &smscusbnet_netdev_ops;
++#endif //linux 2.6.29
++	net->watchdog_timeo = TX_TIMEOUT_JIFFIES;
++
++	/* allow device-specific bind/init procedures
++	   NOTE net->name still not usable */
++	if (info->bind) {
++		status = info->bind(dev, udev);
++		if (status < 0) {
++			devdbg(dev,"info->bind,status<0 \n");
++			goto out2;
++		}
++		/* heuristic:  "usb%d" for links we know are two-host,
++		   else "eth%d" when there's reasonable doubt.  userspace
++		   can rename the link if it knows better */
++		if ((dev->driver_info->flags & FLAG_ETHER) != 0
++				&& (net->dev_addr [0] & 0x02) == 0) {
++			strcpy (net->name, "eth%d");
++		}
++
++		/* maybe the remote can't receive an Ethernet MTU */
++		if (net->mtu > (dev->hard_mtu - net->hard_header_len))
++			net->mtu = dev->hard_mtu - net->hard_header_len;
++	} else if (!info->in || !info->out) {
++		status = smscusbnet_get_endpoints(dev, udev);
++	} else {
++		dev->in = usb_rcvbulkpipe(xdev, info->in);
++		dev->out = usb_sndbulkpipe(xdev, info->out);
++		if (!(info->flags & FLAG_NO_SETINT))
++			status = usb_set_interface (xdev,
++				interface->desc.bInterfaceNumber,
++				interface->desc.bAlternateSetting);
++		else
++			status = 0;
++	}
++	if (status >= 0 && dev->status) {
++		status = init_status (dev, udev);
++	}
++	if (status < 0) {
++		devdbg(dev,"status<0 \n");
++		goto out3;
++	}
++
++	if (!dev->rx_urb_size)
++		dev->rx_urb_size = dev->hard_mtu;
++
++	dev->StopSummitUrb = 1;
++
++	dev->maxpacket = usb_maxpacket(dev->udev, dev->out, 1);
++	SET_NETDEV_DEV(net, &udev->dev);
++	status = register_netdev(net);
++
++	if (status) {
++		goto out3;
++	}
++	if (netif_msg_probe(dev))
++		devinfo(dev, "register '%s' at usb-%s-%s, %s, "
++				"%02x:%02x:%02x:%02x:%02x:%02x",
++			udev->dev.driver->name,
++			xdev->bus->bus_name, xdev->devpath,
++			dev->driver_info->description,
++			net->dev_addr [0], net->dev_addr [1],
++			net->dev_addr [2], net->dev_addr [3],
++			net->dev_addr [4], net->dev_addr [5]);
++
++	/* ok, it's ready to go */
++	usb_set_intfdata(udev, dev);
++
++	/* start as if the link is up */
++	netif_device_attach(net);
++	
++	return 0;
++out3:
++	if (info->unbind)
++		info->unbind(dev, udev);
++out2:
++	if (dev->MyWorkQueue) {
++		destroy_workqueue(dev->MyWorkQueue);
++	}
++out1:
++	free_netdev(net);
++out:
++	usb_put_dev(xdev);
++	return status;
++}
++
++
++/* FIXME these suspend/resume methods assume non-CDC style
++ * devices, with only one interface.
++ */
++
++int smscusbnet_FreeQueue (struct usbnet		*dev)
++{
++	DECLARE_WAIT_QUEUE_HEAD (unlink_wakeup);
++	DECLARE_WAITQUEUE (wait, current);
++
++	/* accelerate emptying of the rx and queues, to avoid
++	 * having everything error out.
++	 */
++	/* ensure there are no more active urbs */
++	add_wait_queue (&unlink_wakeup, &wait);
++	dev->wait = &unlink_wakeup;
++	(void) unlink_urbs (dev, &dev->rxq);
++	(void) unlink_urbs (dev, &dev->txq);
++
++	/* maybe wait for deletions to finish. */
++	while (!skb_queue_empty(&dev->rxq) &&
++	       !skb_queue_empty(&dev->txq) &&
++	       !skb_queue_empty(&dev->done)) {
++		msleep(UNLINK_TIMEOUT_MS);
++	}
++	dev->wait = NULL;
++	remove_wait_queue (&unlink_wakeup, &wait);
++
++	return 0;
++}
++
++/* FIXME these suspend/resume methods assume non-CDC style
++ * devices, with only one interface.
++ */
++ #ifndef pm_message_t
++#define pm_message_t u32
++#endif
++int smscusbnet_suspend (struct usb_interface *intf, pm_message_t state)
++{
++	struct usbnet *dev = usb_get_intfdata(intf);
++
++	/* accelerate emptying of the rx and queues, to avoid
++	 * having everything error out.
++	 */
++	netif_device_detach (dev->net);
++
++	(void) unlink_urbs (dev, &dev->txq);
++	(void) unlink_urbs (dev, &dev->rxq);
++
++	return 0;
++}
++
++int smscusbnet_resume (struct usb_interface *intf)
++{
++	struct usbnet *dev = usb_get_intfdata(intf);
++	netif_device_attach (dev->net);
++	tasklet_schedule (&dev->bh);
++	return 0;
++}
++
++EXPORT_SYMBOL_GPL(smscusbnet_IsOperationalMode);
++EXPORT_SYMBOL_GPL(smscusbnet_get_endpoints);
++EXPORT_SYMBOL_GPL(smscusbnet_skb_return);
++EXPORT_SYMBOL_GPL(smscusbnet_defer_kevent);
++EXPORT_SYMBOL_GPL(smscusbnet_defer_myevent);
++EXPORT_SYMBOL_GPL(smscusbnet_disconnect);
++EXPORT_SYMBOL_GPL(smscusbnet_probe);
++EXPORT_SYMBOL_GPL(smscusbnet_FreeQueue);
++EXPORT_SYMBOL_GPL(smscusbnet_linkpolling);
++#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,29))
++EXPORT_SYMBOL(smscusbnet_stop);
++EXPORT_SYMBOL(smscusbnet_get_stats);
++EXPORT_SYMBOL(smscusbnet_open);
++EXPORT_SYMBOL(smscusbnet_start_xmit);
++EXPORT_SYMBOL(smscusbnet_tx_timeout);
++EXPORT_SYMBOL(smscusbnet_change_mtu);
++#endif
++
++static int __init smscusbnet_init(void)
++{
++	/* compiler should optimize this out */
++	BUG_ON (sizeof (((struct sk_buff *)0)->cb)
++			< sizeof (struct skb_data));
++
++	random_ether_addr(node_id);
++ 	return 0;
++}
++module_init(smscusbnet_init);
++
++static void __exit smscusbnet_exit(void)
++{
++}
++module_exit(smscusbnet_exit);
++
++MODULE_AUTHOR("David Brownell");
++MODULE_DESCRIPTION("USB network driver framework");
++MODULE_LICENSE("GPL");
+diff --git a/drivers/net/ethernet/smsc9514/smscusbnet.h b/drivers/net/ethernet/smsc9514/smscusbnet.h
+new file mode 100755
+index 0000000..00d30f4
+--- /dev/null
++++ b/drivers/net/ethernet/smsc9514/smscusbnet.h
+@@ -0,0 +1,328 @@
++/*
++ * USB Networking Link Interface
++ *
++ * Copyright (C) 2000-2005 by David Brownell <dbrownell@users.sourceforge.net>
++ * Copyright (C) 2003-2005 David Hollis <dhollis@davehollis.com>
++ *
++ * This program is free software; you can redistribute it and/or modify
++ * it under the terms of the GNU General Public License as published by
++ * the Free Software Foundation; either version 2 of the License, or
++ * (at your option) any later version.
++ *
++ * This program is distributed in the hope that it will be useful,
++ * but WITHOUT ANY WARRANTY; without even the implied warranty of
++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
++ * GNU General Public License for more details.
++ *
++ * You should have received a copy of the GNU General Public License
++ * along with this program; if not, write to the Free Software
++ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
++ */
++
++#ifndef	__SMSCUSBNET_H
++#define	__SMSCUSBNET_H
++
++#ifndef DEBUG
++#define DEBUG
++#endif
++
++typedef unsigned char BOOLEAN;
++#define TRUE	((BOOLEAN)1)
++#define FALSE	((BOOLEAN)0)
++
++#define HS_USB_PKT_SIZE		512
++#define FS_USB_PKT_SIZE		64
++
++#define RX_OFFSET		2 /* default NET_IP_ALIGN value */
++
++#define MAX_SINGLE_PACKET_SIZE	2048
++#define DEFAULT_HS_BURST_CAP_SIZE (16 *1024 + 5 * HS_USB_PKT_SIZE)
++#define DEFAULT_FS_BURST_CAP_SIZE (6 *1024 + 33 * FS_USB_PKT_SIZE)
++#define DEFAULT_TX_BUFFER_SIZE (7 * 1024)
++
++#define EXTRA_HEADER_LEN	8
++#define VLAN_DUMMY		0xFFFF
++
++enum{
++	RX_FIXUP_VALID_SKB,
++	RX_FIXUP_INVALID_SKB,
++	RX_FIXUP_ERROR,
++};
++
++struct ExtraErrorCounter
++{
++    u32 tx_epipe;
++    u32 tx_eproto;
++    u32 tx_etimeout;
++    u32 tx_eilseq;
++    u32 tx_eoverflow;
++
++    u32 rx_epipe;
++    u32 rx_eproto;
++    u32 rx_etimeout;
++    u32 rx_eilseq;
++    u32 rx_eoverflow;
++
++};
++
++#define AUTOSUSPEND_DYNAMIC 	0x01  //Suspend on s0, work for lan9500 and lan9500a
++#define AUTOSUSPEND_DYNAMIC_S3 	0x02  //Suspend on s3, only for lan9500a
++#define AUTOSUSPEND_LINKDOWN 	0x04  //Suspend when link is down
++#define AUTOSUSPEND_INTFDOWN 	0x08 //Suspend when interface is down
++#define AUTOSUSPEND_DETACH 	0x10 //Enable net detach
++
++enum{
++	FEATURE_SUSPEND3,
++	FEATURE_SMARTDETACH,
++	FEATURE_NEWSTATIS_CNT,
++	FEATURE_SEP_LEDS,
++	FEATURE_WUFF_8,
++	FEATURE_MDIX_MODE,
++	FEATURE_EEE,
++	FEATURE_MAX_NO
++};
++
++enum{
++	EVENT_TX_HALT,
++	EVENT_RX_HALT,
++	EVENT_RX_MEMORY,
++	EVENT_STS_SPLIT,
++	EVENT_LINK_RESET,
++	EVENT_SET_MULTICAST,
++	EVENT_HAS_FRAME,
++	EVENT_DEV_RECOVERY,
++	EVENT_IDLE_CHECK,
++	EVENT_IDLE_RESUME,
++	EVENT_LINK_DOWN_DETACH,
++	EVENT_LINK_UP,
++	EVENT_LINK_DOWN,
++};
++
++/* interface from usbnet core to each USB networking link we handle */
++struct usbnet {
++	/* housekeeping */
++	struct usb_device	*udev;
++	struct usb_interface	*uintf;
++	struct driver_info	*driver_info;
++	wait_queue_head_t	*wait;
++	int StopSummitUrb;
++
++	/* i/o info: pipes etc */
++	unsigned in, out;
++	struct usb_host_endpoint *status;
++	unsigned maxpacket;
++	struct timer_list delay;
++	struct timer_list  LinkPollingTimer;
++	BOOLEAN StopLinkPolling;
++	u16 idProduct;		//Product id from device descriptor
++	u16 idVendor;		//Vendor id from device descriptor
++	u32 linkDownSuspend;	//1. auto-negotiation complete; 2. energy detection;
++	u32 dynamicSuspend;	//Enable dynamic suspend when there are no traffic
++	u32 netDetach;  //Enable net detach, only for LAN9500A
++
++	/* protocol/interface state */
++	struct net_device	*net;
++	struct net_device_stats	stats;
++	struct ExtraErrorCounter extra_error_cnts;
++	int			msg_enable;
++	unsigned long		data [5];
++	u32			xid;
++	u32			hard_mtu;	/* count any extra framing */
++	size_t		        rx_urb_size;    /* size for rx urbs  */
++	size_t		        tx_urb_size;    /* size for tx urbs, for bundling */
++	struct mii_if_info	mii;
++
++	/* various kinds of pending driver work */
++	struct sk_buff_head	rxq;
++	struct sk_buff_head	txq;
++	struct sk_buff_head	tx_pending_q;
++	struct sk_buff_head	done;
++
++	struct urb		*tx_urb;
++
++	struct urb		*interrupt;
++	void *interrupt_urb_buffer;
++	struct tasklet_struct	bh;
++
++	struct work_struct	kevent;
++	struct work_struct	myevent;
++	struct workqueue_struct  * MyWorkQueue;
++	unsigned long		flags;
++	BOOLEAN intr_urb_delay_submit;
++
++	int idleCount;
++	int linkcheck;
++	BOOLEAN pmLock;
++	struct semaphore pm_mutex;
++	int suspendFlag;		//Flag indicates link down suspend and select suspend
++	BOOLEAN netDetachDone;
++	BOOLEAN disconnected;
++	u32 chipID;
++	u32 preRxFifoDroppedFrame; //Previous counter value
++
++	int chipDependFeatures[FEATURE_MAX_NO]; //Flag for chip-depend feratures
++	struct vlan_group	*vlgrp;  //vlan support
++
++	int turbo_mode;
++	int tx_hold_on_completion;
++	unsigned long tx_qlen;
++	unsigned long rx_qlen;
++	struct sk_buff_head rx_pool_queue;
++	int rx_use_prealloc_buffs;
++	struct sk_buff_head tx_pool_queue;
++	int tx_use_prealloc_buffs;
++
++	int tx_urb_buf_alignment;
++	int rx_urb_buf_alignment;
++	int net_ip_align;
++	int rx_skb_copy;
++};
++#define PM_IDLE_DELAY   3 //Time before auto-suspend
++enum{
++	WAKEPHY_OFF,
++	WAKEPHY_NEGO_COMPLETE,
++	WAKEPHY_ENERGY
++};
++
++static inline struct usb_driver *driver_of(struct usb_interface *intf)
++{
++	return to_usb_driver(intf->dev.driver);
++}
++/* interface from the device/framing level "minidriver" to core */
++struct driver_info {
++	char		*description;
++
++	int		flags;
++/* framing is CDC Ethernet, not writing ZLPs (hw issues), or optionally: */
++#define FLAG_FRAMING_NC	0x0001		/* guard against device dropouts */
++#define FLAG_FRAMING_GL	0x0002		/* genelink batches packets */
++#define FLAG_FRAMING_Z	0x0004		/* zaurus adds a trailer */
++#define FLAG_FRAMING_RN	0x0008		/* RNDIS batches, plus huge header */
++
++#define FLAG_NO_SETINT	0x0010		/* device can't set_interface() */
++#define FLAG_ETHER	0x0020		/* maybe use "eth%d" names */
++
++#define FLAG_FRAMING_AX 0x0040          /* AX88772/178 packets */
++
++	/* init device ... can sleep, or cause probe() failure */
++	int	(*bind)(struct usbnet *, struct usb_interface *);
++
++	/* cleanup device ... can sleep, but can't fail */
++	void	(*unbind)(struct usbnet *, struct usb_interface *);
++
++	/* reset device ... can sleep */
++	int	(*reset)(struct usbnet *);
++
++	/* see if peer is connected ... can sleep */
++	int	(*check_connect)(struct usbnet *);
++
++	/* for status polling */
++	void	(*status)(struct usbnet *, struct urb *);
++	/* Set max frame size*/
++	int	(*set_max_frame_size)(struct usbnet *, int size);
++	/* link reset handling, called from defer_kevent */
++	int	(*link_reset)(struct usbnet *);
++
++	/* fixup rx packet (strip framing) */
++	int	(*rx_fixup)(struct usbnet *dev, struct sk_buff *skb);
++
++	/*set multicast list */
++	int  (*rx_setmulticastlist) (struct usbnet *dev);
++
++	/* fixup tx packet (add framing) */
++	struct sk_buff	*(*tx_fixup)(struct usbnet *dev,
++				struct sk_buff *skb, int flags);
++
++	/* for new devices, use the descriptor-reading code instead */
++	int		in;		/* rx endpoint */
++	int		out;		/* tx endpoint */
++
++	unsigned long	data;		/* Misc driver specific data */
++
++};
++
++/* Minidrivers are just drivers using the "usbnet" core as a powerful
++ * network-specific subroutine library ... that happens to do pretty
++ * much everything except custom framing and chip-specific stuff.
++ */
++extern int smscusbnet_probe(struct usb_interface *, const struct usb_device_id *);
++extern void smscusbnet_disconnect(struct usb_interface *);
++extern void smscusbnet_linkpolling(unsigned long ptr);
++
++/* Drivers that reuse some of the standard USB CDC infrastructure
++ * (notably, using multiple interfaces according to the the CDC
++ * union descriptor) get some helper code.
++ */
++struct cdc_state {
++	struct usb_cdc_header_desc	*header;
++	struct usb_cdc_union_desc	*u;
++	struct usb_cdc_ether_desc	*ether;
++	struct usb_interface		*control;
++	struct usb_interface		*data;
++};
++
++extern int usbnet_generic_cdc_bind (struct usbnet *, struct usb_interface *);
++extern void usbnet_cdc_unbind (struct usbnet *, struct usb_interface *);
++
++/* CDC and RNDIS support the same host-chosen packet filters for IN transfers */
++#define	DEFAULT_FILTER	(USB_CDC_PACKET_TYPE_BROADCAST \
++ 			|USB_CDC_PACKET_TYPE_ALL_MULTICAST \
++ 			|USB_CDC_PACKET_TYPE_PROMISCUOUS \
++ 			|USB_CDC_PACKET_TYPE_DIRECTED)
++
++
++/* we record the state for each of our queued skbs */
++enum skb_state {
++	illegal = 0,
++	tx_start, tx_done,
++	rx_start, rx_done, rx_cleanup
++};
++
++struct skb_data {	/* skb->cb is one of these */
++	struct urb		*urb;
++	struct usbnet		*dev;
++	enum skb_state		state;
++	size_t			length;
++	size_t			pkt_cnt;
++};
++
++extern int smscusbnet_IsOperationalMode(struct usbnet *);
++extern int smscusbnet_get_endpoints(struct usbnet *, struct usb_interface *);
++extern void smscusbnet_defer_kevent (struct usbnet *, int);
++extern void smscusbnet_defer_myevent (struct usbnet *, int);
++extern void smscusbnet_skb_return (struct usbnet *, struct sk_buff *);
++extern int summit_IntrUrb (struct usbnet *dev);
++
++extern u32 smscusbnet_get_msglevel (struct net_device *);
++extern void smscusbnet_set_msglevel (struct net_device *, u32);
++extern void smscusbnet_get_drvinfo (struct net_device *, struct ethtool_drvinfo *);
++extern int smscusbnet_FreeQueue (struct usbnet		*dev);
++
++#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,29))
++extern int smscusbnet_stop (struct net_device *net);
++extern struct net_device_stats *smscusbnet_get_stats (struct net_device *net);
++extern int smscusbnet_open (struct net_device *net);
++extern int smscusbnet_start_xmit (struct sk_buff *skb, struct net_device *net);
++extern int smscusbnet_change_mtu (struct net_device *net, int new_mtu);
++extern void smscusbnet_tx_timeout (struct net_device *net);
++#endif
++/* messaging support includes the interface name, so it must not be
++ * used before it has one ... notably, in minidriver bind() calls.
++ */
++#ifdef DEBUG
++#define devdbg(usbnet, fmt, arg...) \
++	printk(KERN_DEBUG "%s: " fmt "\n" , (usbnet)->net->name , ## arg)
++#else
++#define devdbg(usbnet, fmt, arg...) do {} while(0)
++#endif
++
++#define deverr(usbnet, fmt, arg...) \
++	printk(KERN_ERR "%s: " fmt "\n" , (usbnet)->net->name , ## arg)
++#define devwarn(usbnet, fmt, arg...) \
++	printk(KERN_WARNING "%s: " fmt "\n" , (usbnet)->net->name , ## arg)
++
++#define devinfo(usbnet, fmt, arg...) \
++	printk(KERN_INFO "%s: " fmt "\n" , (usbnet)->net->name , ## arg); \
++
++
++#endif	/* __smscusbnet_H */
+diff --git a/drivers/net/ethernet/smsc9514/version.h b/drivers/net/ethernet/smsc9514/version.h
+new file mode 100755
+index 0000000..29426ce
+--- /dev/null
++++ b/drivers/net/ethernet/smsc9514/version.h
+@@ -0,0 +1,6 @@
++#ifndef SMSC9500_VERSION_H_
++#define SMSC9500_VERSION_H_
++
++#define DRIVER_VERSION  (0x00010205UL)
++
++#endif /*SMSC9500_VERSION_H_*/
+diff --git a/include/linux/usb.h b/include/linux/usb.h
+index 02bffcc..6621dd1 100644
+--- a/include/linux/usb.h
++++ b/include/linux/usb.h
+@@ -127,6 +127,7 @@ enum usb_interface_condition {
+  * @dev: driver model's view of this device
+  * @usb_dev: if an interface is bound to the USB major, this will point
+  *	to the sysfs representation for that device.
++ * @pm_usage_cnt: PM usage counter for this interface
+  * @reset_ws: Used for scheduling resets from atomic context.
+  * @resetting_device: USB core reset the device, so use alt setting 0 as
+  *	current; needs bandwidth alloc after reset.
+@@ -183,6 +184,7 @@ struct usb_interface {
+ 
+ 	struct device dev;		/* interface specific device info */
+ 	struct device *usb_dev;
++	atomic_t pm_usage_cnt;          /* usage counter for autosuspend */
+ 	struct work_struct reset_ws;	/* for resets in atomic context */
+ };
+ #define	to_usb_interface(d) container_of(d, struct usb_interface, dev)
+-- 
+2.7.4
+
diff --git a/layers/meta-balena-nanopc-t4/recipes-kernel/linux/files/4.4.185/0003-Added-mcp25xxfd-driver-support-for-LEC-PX30-A2.patch b/layers/meta-balena-nanopc-t4/recipes-kernel/linux/files/4.4.185/0003-Added-mcp25xxfd-driver-support-for-LEC-PX30-A2.patch
new file mode 100644
index 000000000..978eebdcc
--- /dev/null
+++ b/layers/meta-balena-nanopc-t4/recipes-kernel/linux/files/4.4.185/0003-Added-mcp25xxfd-driver-support-for-LEC-PX30-A2.patch
@@ -0,0 +1,4567 @@
+From cd4f6ab6020301a3373c8e7df00b262eec0c6faf Mon Sep 17 00:00:00 2001
+From: Dineshkumar V <dineshkumar.varadarajan@adlinktech.com>
+Date: Wed, 13 Nov 2019 15:25:51 +0530
+Subject: [PATCH 3/3] Added mcp25xxfd driver support for LEC-PX30 A2
+
+---
+ drivers/net/can/spi/Kconfig     |    6 +
+ drivers/net/can/spi/Makefile    |    1 +
+ drivers/net/can/spi/mcp25xxfd.c | 4522 +++++++++++++++++++++++++++++++++++++++
+ 3 files changed, 4529 insertions(+)
+ create mode 100755 drivers/net/can/spi/mcp25xxfd.c
+
+diff --git a/drivers/net/can/spi/Kconfig b/drivers/net/can/spi/Kconfig
+index 148cae5..7fbfbd3 100644
+--- a/drivers/net/can/spi/Kconfig
++++ b/drivers/net/can/spi/Kconfig
+@@ -7,4 +7,10 @@ config CAN_MCP251X
+ 	---help---
+ 	  Driver for the Microchip MCP251x SPI CAN controllers.
+ 
++config CAN_MCP25XXFD
++        tristate "Microchip MCP2517FD SPI CAN controllers"
++        depends on HAS_DMA
++        ---help---
++          Driver for the Microchip MCP25XXFD SPI CAN controllers.
++
+ endmenu
+diff --git a/drivers/net/can/spi/Makefile b/drivers/net/can/spi/Makefile
+index 0e86040..e0724f6 100644
+--- a/drivers/net/can/spi/Makefile
++++ b/drivers/net/can/spi/Makefile
+@@ -4,3 +4,4 @@
+ 
+ 
+ obj-$(CONFIG_CAN_MCP251X)	+= mcp251x.o
++obj-$(CONFIG_CAN_MCP25XXFD)     += mcp25xxfd.o
+diff --git a/drivers/net/can/spi/mcp25xxfd.c b/drivers/net/can/spi/mcp25xxfd.c
+new file mode 100755
+index 0000000..91d69da
+--- /dev/null
++++ b/drivers/net/can/spi/mcp25xxfd.c
+@@ -0,0 +1,4522 @@
++/*
++ * CAN bus driver for Microchip 25XXFD CAN Controller with SPI Interface
++ *
++ * Copyright 2017 Martin Sperl <kernel@xxxxxxxxxxxxxxxx>
++ *
++ * SPDX-License-Identifier: GPL-2.0 WITH Linux-syscall-note
++ *
++ * Based on Microchip MCP251x CAN controller driver written by
++ * David Vrabel, Copyright 2006 Arcom Control Systems Ltd.
++ *
++ */
++
++#include <linux/can/core.h>
++#include <linux/can/dev.h>
++#include <linux/can/led.h>
++#include <linux/clk.h>
++#include <linux/completion.h>
++#include <linux/debugfs.h>
++#include <linux/delay.h>
++#include <linux/device.h>
++#include <linux/dma-mapping.h>
++#include <linux/freezer.h>
++#include <linux/gpio/driver.h>
++#include <linux/interrupt.h>
++#include <linux/io.h>
++#include <linux/jiffies.h>
++#include <linux/kernel.h>
++#include <linux/module.h>
++#include <linux/netdevice.h>
++#include <linux/of.h>
++#include <linux/of_device.h>
++#include <linux/platform_device.h>
++#include <linux/slab.h>
++#include <linux/sort.h>
++#include <linux/spi/spi.h>
++#include <linux/uaccess.h>
++#include <linux/regulator/consumer.h>
++
++#define DEVICE_NAME "mcp25xxfd"
++
++/* device description and rational:
++ *
++ * the mcp25xxfd is a CanFD controller that also supports can2.0 only
++ * modes.
++ * It is connected via spi to the host and requires at minimum a single
++ * irq line in addition to the SPI lines - it is not mentioned explicitly
++ * in the documentation but in principle SPI 3-wire should be possible.
++ *
++ * The clock connected is typically 4MHz, 20MHz or 40MHz.
++ * For the 4MHz clock the controller contains 10x PLL circuitry.
++ *
++ * The controller itself has 2KB or ECC-SRAM for data.
++ * It also has 32 FIFOs (of up to 32 CAN-frames).
++ * There are 4 Fifo types which can get configured:
++ * * TEF - Transmission Event Fifo - which consumes FIFO 0
++ *   even if it is not configured
++ * * Tansmission Queue - for up to 32 Frames.
++ *   this queue reorders CAN frames to get transmitted following the
++ *   typical CAN dominant/recessive rules on the can bus itself.
++ *   This FIFO is optional.
++ * * TX FIFO: generic TX fifos that can contain arbitrary data
++ *   and which come with a configurable priority for transmission
++ *   It is also possible to have the Controller automatically trigger
++ *   a transfer when a Filter Rule for a RTR frame matches.
++ *   Each of these fifos in principle can get configured for distinct
++ *   dlc sizes (8 thru 64 bytes)
++ * * RX FIFO: generic RX fifo which is filled via filter-rules.
++ *   Each of these fifos in principle can get configured for distinct
++ *   dlc sizes (8 thru 64 bytes)
++ *   Unfortunately there is no filter rule that would allow triggering
++ *   on different frame sizes, so for all practical purposes the
++ *   RX fifos have to be of the same size (unless one wants to experience
++ *   lost data).
++ * When a Can Frame is transmitted fromthe TX Queue or an individual
++ * TX FIFO then a small TEF Frame can get added to the TEF FIFO queue
++ * to log the Transmission of the frame - this includes ID, Flags
++ * (including a custom identifier/index) .
++ *
++ * The controller provides an optional free running counter with a divider
++ * for timestamping of RX frames as well as for TEF entries.
++ *
++ * Driver Implementation details and rational:
++ * * The whole driver has been designed to give best performance
++ *   and as little packet loss as possible with 1MHZ Can frames with DLC=0
++ *   on small/slow devices like the Raspberry Pi 1
++ * * This means that some optimizations for full duplex communication
++ *   have been implemented to avoid CPU introduced latencies
++ *   (especially for spi_write_then_read cases) - this only applies to
++ *   4 wire SPI busses.
++ * * Due to the fact that the TXQ does reorder Can-Frames we do not make
++ *   use of it to avoid unexpected behaviour (say when running a
++ *   firmware upgrade via Can)
++ * * this means we use individual TX-fifos with a given priority and
++ *   we have to wait until all the TX fifos have been transmitted before
++ *   we can restart the networking queue to avoid reordering the frames on
++ *   the Can bus itself.
++ *   Still we can transmit a transmit only Duty-cycle of 66% to 90% on the
++ *   Can bus (at 1MHz).
++ *   The scaling factors here are:
++ *   * Can bus speed - lower Speeds increase Duty-cycle
++ *   * SPI Clock Rate - higher speeds increase duty-cycle
++ *   * CPU speed + SPI implementation - reduces latencies between transfers
++ * * There is a module parameter that allows the modification of the
++ *   number of tx_fifos, which is by default 7.
++ * * The driver offers some module parameters that allow to control the use
++ *   of some optimizations (prefer reading more data than necessary instead
++ *   of multiple SPI transfers - the idea here is that this way we may
++ *   allow the SPI-controller to use DMA instead of programmed IO to
++ *   limit latencies/number of interrupts)
++ *   When we have to read multiple RX frames in CanFD mode:
++ *   * we allow reading all 64 bytes of payload even if DLC <=8
++ *     this mode is used in Can2.0 only mode by default and can not get
++ *     disabled (SRAM Reads have to be a multiple of 4 bytes anyway)
++ *   * Releasing/freeing the RX queue requires writing of 1 byte per fifo.
++ *     unfortunately these 32-bit registers are not ajacent to each other,
++ *     so that for 2 consecutive RX Frames instead of writing 1 byte per
++ *     fifo (with protocol overhead of 2 bytes - so a total of 6 bytes in
++ *     2 transfers) we transmit 13 bytes (with a protocol overhead of 2 -
++ *     so a total of 15 bytes)
++ *     This optimization is only enabled by a module parameter.
++ * * we use TEF + time stamping to record the transmitted frames
++ *   including their timestamp - we use this to order TX and RX frames
++ *   when submitting them to the network stack.
++ * * due to the inability to "filter" based on DLC sizes we have to use
++ *   a common FIFO size. This is 8 bytes for Can2.0 and 64 bytes for CanFD.
++ * * the driver tries to detect the Controller only by reading registers,
++ *   but there are circumstances (e.g. after a crashed driver) where we
++ *   have to "blindly" configure the clock rate to get the controller to
++ *   respond correctly.
++ * * There is one situation where the controller will require a full POR
++ *   (total power off) to recover from a bad Clock configuration.
++ *   This happens when the wrong clock is configured in the device tree
++ *   (say 4MHz are configured, while 20 or 40MHz are used)
++ *   in such a situation the driver tries to enable the PLL, which will
++ *   never synchronize and the controller becomes unresponsive to further
++ *   spi requests until a POR.
++ */
++
++#define MCP25XXFD_OST_DELAY_MS		3
++#define MCP25XXFD_MIN_CLOCK_FREQUENCY	1000000
++#define MCP25XXFD_MAX_CLOCK_FREQUENCY	40000000
++#define MCP25XXFD_PLL_MULTIPLIER	10
++#define MCP25XXFD_AUTO_PLL_MAX_CLOCK_FREQUENCY				\
++	(MCP25XXFD_MAX_CLOCK_FREQUENCY / MCP25XXFD_PLL_MULTIPLIER)
++#define MCP25XXFD_SCLK_DIVIDER		2
++
++#define MCP25XXFD_OSC_POLLING_JIFFIES	(HZ / 2)
++
++#define TX_ECHO_SKB_MAX	32
++
++#define INSTRUCTION_RESET		0x0000
++#define INSTRUCTION_READ		0x3000
++#define INSTRUCTION_WRITE		0x2000
++#define INSTRUCTION_READ_CRC		0xB000
++#define INSTRUCTION_WRITE_CRC		0xA000
++#define INSTRUCTION_WRITE_SAVE		0xC000
++
++#define ADDRESS_MASK			0x0fff
++
++#define MCP25XXFD_SFR_BASE(x)		(0xE00 + (x))
++#define MCP25XXFD_OSC			MCP25XXFD_SFR_BASE(0x00)
++#  define MCP25XXFD_OSC_PLLEN		BIT(0)
++#  define MCP25XXFD_OSC_OSCDIS		BIT(2)
++#  define MCP25XXFD_OSC_SCLKDIV		BIT(4)
++#  define MCP25XXFD_OSC_CLKODIV_BITS	2
++#  define MCP25XXFD_OSC_CLKODIV_SHIFT	5
++#  define MCP25XXFD_OSC_CLKODIV_MASK			\
++	GENMASK(MCP25XXFD_OSC_CLKODIV_SHIFT		\
++		+ MCP25XXFD_OSC_CLKODIV_BITS - 1,	\
++		MCP25XXFD_OSC_CLKODIV_SHIFT)
++#  define MCP25XXFD_OSC_CLKODIV_10	3
++#  define MCP25XXFD_OSC_CLKODIV_4	2
++#  define MCP25XXFD_OSC_CLKODIV_2	1
++#  define MCP25XXFD_OSC_CLKODIV_1	0
++#  define MCP25XXFD_OSC_PLLRDY		BIT(8)
++#  define MCP25XXFD_OSC_OSCRDY		BIT(10)
++#  define MCP25XXFD_OSC_SCLKRDY		BIT(12)
++#define MCP25XXFD_IOCON			MCP25XXFD_SFR_BASE(0x04)
++#  define MCP25XXFD_IOCON_TRIS0		BIT(0)
++#  define MCP25XXFD_IOCON_TRIS1		BIT(1)
++#  define MCP25XXFD_IOCON_XSTBYEN	BIT(6)
++#  define MCP25XXFD_IOCON_LAT0		BIT(8)
++#  define MCP25XXFD_IOCON_LAT1		BIT(9)
++#  define MCP25XXFD_IOCON_GPIO0		BIT(16)
++#  define MCP25XXFD_IOCON_GPIO1		BIT(17)
++#  define MCP25XXFD_IOCON_PM0		BIT(24)
++#  define MCP25XXFD_IOCON_PM1		BIT(25)
++#  define MCP25XXFD_IOCON_TXCANOD	BIT(28)
++#  define MCP25XXFD_IOCON_SOF		BIT(29)
++#  define MCP25XXFD_IOCON_INTOD		BIT(29)
++#define MCP25XXFD_CRC			MCP25XXFD_SFR_BASE(0x08)
++#  define MCP25XXFD_CRC_MASK		GENMASK(15, 0)
++#  define MCP25XXFD_CRC_CRCERRIE	BIT(16)
++#  define MCP25XXFD_CRC_FERRIE		BIT(17)
++#  define MCP25XXFD_CRC_CRCERRIF	BIT(24)
++#  define MCP25XXFD_CRC_FERRIF		BIT(25)
++#define MCP25XXFD_ECCCON		MCP25XXFD_SFR_BASE(0x0C)
++#  define MCP25XXFD_ECCCON_ECCEN	BIT(0)
++#  define MCP25XXFD_ECCCON_SECIE	BIT(1)
++#  define MCP25XXFD_ECCCON_DEDIE	BIT(2)
++#  define MCP25XXFD_ECCCON_PARITY_BITS 6
++#  define MCP25XXFD_ECCCON_PARITY_SHIFT 8
++#  define MCP25XXFD_ECCCON_PARITY_MASK			\
++	GENMASK(MCP25XXFD_ECCCON_PARITY_SHIFT		\
++		+ MCP25XXFD_ECCCON_PARITY_BITS - 1,	\
++		MCP25XXFD_ECCCON_PARITY_SHIFT)
++#define MCP25XXFD_ECCSTAT		MCP25XXFD_SFR_BASE(0x10)
++#  define MCP25XXFD_ECCSTAT_SECIF	BIT(1)
++#  define MCP25XXFD_ECCSTAT_DEDIF	BIT(2)
++#  define MCP25XXFD_ECCSTAT_ERRADDR_SHIFT 8
++#  define MCP25XXFD_ECCSTAT_ERRADDR_MASK	      \
++	GENMASK(MCP25XXFD_ECCSTAT_ERRADDR_SHIFT + 11, \
++		MCP25XXFD_ECCSTAT_ERRADDR_SHIFT)
++
++#define CAN_SFR_BASE(x)			(0x000 + (x))
++#define CAN_CON				CAN_SFR_BASE(0x00)
++#  define CAN_CON_DNCNT_BITS		5
++#  define CAN_CON_DNCNT_SHIFT		0
++#  define CAN_CON_DNCNT_MASK					\
++	GENMASK(CAN_CON_DNCNT_SHIFT + CAN_CON_DNCNT_BITS - 1,	\
++		CAN_CON_DNCNT_SHIFT)
++#  define CAN_CON_ISOCRCEN		BIT(5)
++#  define CAN_CON_PXEDIS		BIT(6)
++#  define CAN_CON_WAKFIL		BIT(8)
++#  define CAN_CON_WFT_BITS		2
++#  define CAN_CON_WFT_SHIFT		9
++#  define CAN_CON_WFT_MASK					\
++	GENMASK(CAN_CON_WFT_SHIFT + CAN_CON_WFT_BITS - 1,	\
++		CAN_CON_WFT_SHIFT)
++#  define CAN_CON_BUSY			BIT(11)
++#  define CAN_CON_BRSDIS		BIT(12)
++#  define CAN_CON_RTXAT			BIT(16)
++#  define CAN_CON_ESIGM			BIT(17)
++#  define CAN_CON_SERR2LOM		BIT(18)
++#  define CAN_CON_STEF			BIT(19)
++#  define CAN_CON_TXQEN			BIT(20)
++#  define CAN_CON_OPMODE_BITS		3
++#  define CAN_CON_OPMOD_SHIFT		21
++#  define CAN_CON_OPMOD_MASK					\
++	GENMASK(CAN_CON_OPMOD_SHIFT + CAN_CON_OPMODE_BITS - 1,	\
++		CAN_CON_OPMOD_SHIFT)
++#  define CAN_CON_REQOP_BITS		3
++#  define CAN_CON_REQOP_SHIFT		24
++#  define CAN_CON_REQOP_MASK					\
++	GENMASK(CAN_CON_REQOP_SHIFT + CAN_CON_REQOP_BITS - 1,	\
++		CAN_CON_REQOP_SHIFT)
++#    define CAN_CON_MODE_MIXED			0
++#    define CAN_CON_MODE_SLEEP			1
++#    define CAN_CON_MODE_INTERNAL_LOOPBACK	2
++#    define CAN_CON_MODE_LISTENONLY		3
++#    define CAN_CON_MODE_CONFIG			4
++#    define CAN_CON_MODE_EXTERNAL_LOOPBACK	5
++#    define CAN_CON_MODE_CAN2_0			6
++#    define CAN_CON_MODE_RESTRICTED		7
++#  define CAN_CON_ABAT			BIT(27)
++#  define CAN_CON_TXBWS_BITS		3
++#  define CAN_CON_TXBWS_SHIFT		28
++#  define CAN_CON_TXBWS_MASK					\
++	GENMASK(CAN_CON_TXBWS_SHIFT + CAN_CON_TXBWS_BITS - 1,	\
++		CAN_CON_TXBWS_SHIFT)
++#  define CAN_CON_DEFAULT				\
++	(CAN_CON_ISOCRCEN |				\
++	 CAN_CON_PXEDIS |				\
++	 CAN_CON_WAKFIL |				\
++	 (3 << CAN_CON_WFT_SHIFT) |			\
++	 CAN_CON_STEF |					\
++	 CAN_CON_TXQEN |				\
++	 (CAN_CON_MODE_CONFIG << CAN_CON_OPMOD_SHIFT) |	\
++	 (CAN_CON_MODE_CONFIG << CAN_CON_REQOP_SHIFT))
++#  define CAN_CON_DEFAULT_MASK	\
++	(CAN_CON_DNCNT_MASK |	\
++	 CAN_CON_ISOCRCEN |	\
++	 CAN_CON_PXEDIS |	\
++	 CAN_CON_WAKFIL |	\
++	 CAN_CON_WFT_MASK |	\
++	 CAN_CON_BRSDIS |	\
++	 CAN_CON_RTXAT |	\
++	 CAN_CON_ESIGM |	\
++	 CAN_CON_SERR2LOM |	\
++	 CAN_CON_STEF |		\
++	 CAN_CON_TXQEN |	\
++	 CAN_CON_OPMOD_MASK |	\
++	 CAN_CON_REQOP_MASK |	\
++	 CAN_CON_ABAT |		\
++	 CAN_CON_TXBWS_MASK)
++#define CAN_NBTCFG			CAN_SFR_BASE(0x04)
++#  define CAN_NBTCFG_SJW_BITS		7
++#  define CAN_NBTCFG_SJW_SHIFT		0
++#  define CAN_NBTCFG_SJW_MASK					\
++	GENMASK(CAN_NBTCFG_SJW_SHIFT + CAN_NBTCFG_SJW_BITS - 1, \
++		CAN_NBTCFG_SJW_SHIFT)
++#  define CAN_NBTCFG_TSEG2_BITS		7
++#  define CAN_NBTCFG_TSEG2_SHIFT	8
++#  define CAN_NBTCFG_TSEG2_MASK					    \
++	GENMASK(CAN_NBTCFG_TSEG2_SHIFT + CAN_NBTCFG_TSEG2_BITS - 1, \
++		CAN_NBTCFG_TSEG2_SHIFT)
++#  define CAN_NBTCFG_TSEG1_BITS		8
++#  define CAN_NBTCFG_TSEG1_SHIFT	16
++#  define CAN_NBTCFG_TSEG1_MASK					    \
++	GENMASK(CAN_NBTCFG_TSEG1_SHIFT + CAN_NBTCFG_TSEG1_BITS - 1, \
++		CAN_NBTCFG_TSEG1_SHIFT)
++#  define CAN_NBTCFG_BRP_BITS		8
++#  define CAN_NBTCFG_BRP_SHIFT		24
++#  define CAN_NBTCFG_BRP_MASK					\
++	GENMASK(CAN_NBTCFG_BRP_SHIFT + CAN_NBTCFG_BRP_BITS - 1, \
++		CAN_NBTCFG_BRP_SHIFT)
++#define CAN_DBTCFG			CAN_SFR_BASE(0x08)
++#  define CAN_DBTCFG_SJW_BITS		4
++#  define CAN_DBTCFG_SJW_SHIFT		0
++#  define CAN_DBTCFG_SJW_MASK					\
++	GENMASK(CAN_DBTCFG_SJW_SHIFT + CAN_DBTCFG_SJW_BITS - 1, \
++		CAN_DBTCFG_SJW_SHIFT)
++#  define CAN_DBTCFG_TSEG2_BITS		4
++#  define CAN_DBTCFG_TSEG2_SHIFT	8
++#  define CAN_DBTCFG_TSEG2_MASK					    \
++	GENMASK(CAN_DBTCFG_TSEG2_SHIFT + CAN_DBTCFG_TSEG2_BITS - 1, \
++		CAN_DBTCFG_TSEG2_SHIFT)
++#  define CAN_DBTCFG_TSEG1_BITS		5
++#  define CAN_DBTCFG_TSEG1_SHIFT	16
++#  define CAN_DBTCFG_TSEG1_MASK					    \
++	GENMASK(CAN_DBTCFG_TSEG1_SHIFT + CAN_DBTCFG_TSEG1_BITS - 1, \
++		CAN_DBTCFG_TSEG1_SHIFT)
++#  define CAN_DBTCFG_BRP_BITS		8
++#  define CAN_DBTCFG_BRP_SHIFT		24
++#  define CAN_DBTCFG_BRP_MASK					\
++	GENMASK(CAN_DBTCFG_BRP_SHIFT + CAN_DBTCFG_BRP_BITS - 1, \
++		CAN_DBTCFG_BRP_SHIFT)
++#define CAN_TDC				CAN_SFR_BASE(0x0C)
++#  define CAN_TDC_TDCV_BITS		5
++#  define CAN_TDC_TDCV_SHIFT		0
++#  define CAN_TDC_TDCV_MASK					\
++	GENMASK(CAN_TDC_TDCV_SHIFT + CAN_TDC_TDCV_BITS - 1, \
++		CAN_TDC_TDCV_SHIFT)
++#  define CAN_TDC_TDCO_BITS		5
++#  define CAN_TDC_TDCO_SHIFT		8
++#  define CAN_TDC_TDCO_MASK					\
++	GENMASK(CAN_TDC_TDCO_SHIFT + CAN_TDC_TDCO_BITS - 1, \
++		CAN_TDC_TDCO_SHIFT)
++#  define CAN_TDC_TDCMOD_BITS		2
++#  define CAN_TDC_TDCMOD_SHIFT		16
++#  define CAN_TDC_TDCMOD_MASK					\
++	GENMASK(CAN_TDC_TDCMOD_SHIFT + CAN_TDC_TDCMOD_BITS - 1, \
++		CAN_TDC_TDCMOD_SHIFT)
++#  define CAN_TDC_TDCMOD_DISABLED	0
++#  define CAN_TDC_TDCMOD_MANUAL		1
++#  define CAN_TDC_TDCMOD_AUTO		2
++#  define CAN_TDC_SID11EN		BIT(24)
++#  define CAN_TDC_EDGFLTEN		BIT(25)
++#define CAN_TBC				CAN_SFR_BASE(0x10)
++#define CAN_TSCON			CAN_SFR_BASE(0x14)
++#  define CAN_TSCON_TBCPRE_BITS		10
++#  define CAN_TSCON_TBCPRE_SHIFT	0
++#  define CAN_TSCON_TBCPRE_MASK					    \
++	GENMASK(CAN_TSCON_TBCPRE_SHIFT + CAN_TSCON_TBCPRE_BITS - 1, \
++		CAN_TSCON_TBCPRE_SHIFT)
++#  define CAN_TSCON_TBCEN		BIT(16)
++#  define CAN_TSCON_TSEOF		BIT(17)
++#  define CAN_TSCON_TSRES		BIT(18)
++#define CAN_VEC				CAN_SFR_BASE(0x18)
++#  define CAN_VEC_ICODE_BITS		7
++#  define CAN_VEC_ICODE_SHIFT		0
++#  define CAN_VEC_ICODE_MASK					    \
++	GENMASK(CAN_VEC_ICODE_SHIFT + CAN_VEC_ICODE_BITS - 1,	    \
++		CAN_VEC_ICODE_SHIFT)
++#  define CAN_VEC_FILHIT_BITS		5
++#  define CAN_VEC_FILHIT_SHIFT		8
++#  define CAN_VEC_FILHIT_MASK					\
++	GENMASK(CAN_VEC_FILHIT_SHIFT + CAN_VEC_FILHIT_BITS - 1, \
++		CAN_VEC_FILHIT_SHIFT)
++#  define CAN_VEC_TXCODE_BITS		7
++#  define CAN_VEC_TXCODE_SHIFT		16
++#  define CAN_VEC_TXCODE_MASK					\
++	GENMASK(CAN_VEC_TXCODE_SHIFT + CAN_VEC_TXCODE_BITS - 1, \
++		CAN_VEC_TXCODE_SHIFT)
++#  define CAN_VEC_RXCODE_BITS		7
++#  define CAN_VEC_RXCODE_SHIFT		24
++#  define CAN_VEC_RXCODE_MASK					\
++	GENMASK(CAN_VEC_RXCODE_SHIFT + CAN_VEC_RXCODE_BITS - 1, \
++		CAN_VEC_RXCODE_SHIFT)
++#define CAN_INT				CAN_SFR_BASE(0x1C)
++#  define CAN_INT_IF_SHIFT		0
++#  define CAN_INT_TXIF			BIT(0)
++#  define CAN_INT_RXIF			BIT(1)
++#  define CAN_INT_TBCIF			BIT(2)
++#  define CAN_INT_MODIF			BIT(3)
++#  define CAN_INT_TEFIF			BIT(4)
++#  define CAN_INT_ECCIF			BIT(8)
++#  define CAN_INT_SPICRCIF		BIT(9)
++#  define CAN_INT_TXATIF		BIT(10)
++#  define CAN_INT_RXOVIF		BIT(11)
++#  define CAN_INT_SERRIF		BIT(12)
++#  define CAN_INT_CERRIF		BIT(13)
++#  define CAN_INT_WAKIF			BIT(14)
++#  define CAN_INT_IVMIF			BIT(15)
++#  define CAN_INT_IF_MASK		\
++	(CAN_INT_TXIF |			\
++	 CAN_INT_RXIF |			\
++	 CAN_INT_TBCIF	|		\
++	 CAN_INT_MODIF	|		\
++	 CAN_INT_TEFIF	|		\
++	 CAN_INT_ECCIF	|		\
++	 CAN_INT_SPICRCIF |		\
++	 CAN_INT_TXATIF |		\
++	 CAN_INT_RXOVIF |		\
++	 CAN_INT_CERRIF |		\
++	 CAN_INT_SERRIF |		\
++	 CAN_INT_WAKEIF |		\
++	 CAN_INT_IVMIF)
++#  define CAN_INT_IE_SHIFT		16
++#  define CAN_INT_TXIE			(CAN_INT_TXIF << CAN_INT_IE_SHIFT)
++#  define CAN_INT_RXIE			(CAN_INT_RXIF << CAN_INT_IE_SHIFT)
++#  define CAN_INT_TBCIE			(CAN_INT_TBCIF << CAN_INT_IE_SHIFT)
++#  define CAN_INT_MODIE			(CAN_INT_MODIF << CAN_INT_IE_SHIFT)
++#  define CAN_INT_TEFIE			(CAN_INT_TEFIF << CAN_INT_IE_SHIFT)
++#  define CAN_INT_ECCIE			(CAN_INT_ECCIF << CAN_INT_IE_SHIFT)
++#  define CAN_INT_SPICRCIE		\
++	(CAN_INT_SPICRCIF << CAN_INT_IE_SHIFT)
++#  define CAN_INT_TXATIE		(CAN_INT_TXATIF << CAN_INT_IE_SHIFT)
++#  define CAN_INT_RXOVIE		(CAN_INT_RXOVIF << CAN_INT_IE_SHIFT)
++#  define CAN_INT_CERRIE		(CAN_INT_CERRIF << CAN_INT_IE_SHIFT)
++#  define CAN_INT_SERRIE		(CAN_INT_SERRIF << CAN_INT_IE_SHIFT)
++#  define CAN_INT_WAKIE			(CAN_INT_WAKIF << CAN_INT_IE_SHIFT)
++#  define CAN_INT_IVMIE			(CAN_INT_IVMIF << CAN_INT_IE_SHIFT)
++#  define CAN_INT_IE_MASK		\
++	(CAN_INT_TXIE |			\
++	 CAN_INT_RXIE |			\
++	 CAN_INT_TBCIE	|		\
++	 CAN_INT_MODIE	|		\
++	 CAN_INT_TEFIE	|		\
++	 CAN_INT_ECCIE	|		\
++	 CAN_INT_SPICRCIE |		\
++	 CAN_INT_TXATIE |		\
++	 CAN_INT_RXOVIE |		\
++	 CAN_INT_CERRIE |		\
++	 CAN_INT_SERRIE |		\
++	 CAN_INT_WAKEIE |		\
++	 CAN_INT_IVMIE)
++#define CAN_RXIF			CAN_SFR_BASE(0x20)
++#define CAN_TXIF			CAN_SFR_BASE(0x24)
++#define CAN_RXOVIF			CAN_SFR_BASE(0x28)
++#define CAN_TXATIF			CAN_SFR_BASE(0x2C)
++#define CAN_TXREQ			CAN_SFR_BASE(0x30)
++#define CAN_TREC			CAN_SFR_BASE(0x34)
++#  define CAN_TREC_REC_BITS		8
++#  define CAN_TREC_REC_SHIFT		0
++#  define CAN_TREC_REC_MASK				    \
++	GENMASK(CAN_TREC_REC_SHIFT + CAN_TREC_REC_BITS - 1, \
++		CAN_TREC_REC_SHIFT)
++#  define CAN_TREC_TEC_BITS		8
++#  define CAN_TREC_TEC_SHIFT		8
++#  define CAN_TREC_TEC_MASK				    \
++	GENMASK(CAN_TREC_TEC_SHIFT + CAN_TREC_TEC_BITS - 1, \
++		CAN_TREC_TEC_SHIFT)
++#  define CAN_TREC_EWARN		BIT(16)
++#  define CAN_TREC_RXWARN		BIT(17)
++#  define CAN_TREC_TXWARN		BIT(18)
++#  define CAN_TREC_RXBP			BIT(19)
++#  define CAN_TREC_TXBP			BIT(20)
++#  define CAN_TREC_TXBO			BIT(21)
++#define CAN_BDIAG0			CAN_SFR_BASE(0x38)
++#  define CAN_BDIAG0_NRERRCNT_BITS	8
++#  define CAN_BDIAG0_NRERRCNT_SHIFT	0
++#  define CAN_BDIAG0_NRERRCNT_MASK				\
++	GENMASK(CAN_BDIAG0_NRERRCNT_SHIFT + CAN_BDIAG0_NRERRCNT_BITS - 1, \
++		CAN_BDIAG0_NRERRCNT_SHIFT)
++#  define CAN_BDIAG0_NTERRCNT_BITS	8
++#  define CAN_BDIAG0_NTERRCNT_SHIFT	8
++#  define CAN_BDIAG0_NTERRCNT_MASK					\
++	GENMASK(CAN_BDIAG0_NTERRCNT_SHIFT + CAN_BDIAG0_NTERRCNT_BITS - 1, \
++		CAN_BDIAG0_NTERRCNT_SHIFT)
++#  define CAN_BDIAG0_DRERRCNT_BITS	8
++#  define CAN_BDIAG0_DRERRCNT_SHIFT	16
++#  define CAN_BDIAG0_DRERRCNT_MASK					\
++	GENMASK(CAN_BDIAG0_DRERRCNT_SHIFT + CAN_BDIAG0_DRERRCNT_BITS - 1, \
++		CAN_BDIAG0_DRERRCNT_SHIFT)
++#  define CAN_BDIAG0_DTERRCNT_BITS	8
++#  define CAN_BDIAG0_DTERRCNT_SHIFT	24
++#  define CAN_BDIAG0_DTERRCNT_MASK					\
++	GENMASK(CAN_BDIAG0_DTERRCNT_SHIFT + CAN_BDIAG0_DTERRCNT_BITS - 1, \
++		CAN_BDIAG0_DTERRCNT_SHIFT)
++#define CAN_BDIAG1			CAN_SFR_BASE(0x3C)
++#  define CAN_BDIAG1_EFMSGCNT_BITS	16
++#  define CAN_BDIAG1_EFMSGCNT_SHIFT	0
++#  define CAN_BDIAG1_EFMSGCNT_MASK					\
++	GENMASK(CAN_BDIAG1_EFMSGCNT_SHIFT + CAN_BDIAG1_EFMSGCNT_BITS - 1, \
++		CAN_BDIAG1_EFMSGCNT_SHIFT)
++#  define CAN_BDIAG1_NBIT0ERR		BIT(16)
++#  define CAN_BDIAG1_NBIT1ERR		BIT(17)
++#  define CAN_BDIAG1_NACKERR		BIT(18)
++#  define CAN_BDIAG1_NSTUFERR		BIT(19)
++#  define CAN_BDIAG1_NFORMERR		BIT(20)
++#  define CAN_BDIAG1_NCRCERR		BIT(21)
++#  define CAN_BDIAG1_TXBOERR		BIT(23)
++#  define CAN_BDIAG1_DBIT0ERR		BIT(24)
++#  define CAN_BDIAG1_DBIT1ERR		BIT(25)
++#  define CAN_BDIAG1_DFORMERR		BIT(27)
++#  define CAN_BDIAG1_DSTUFERR		BIT(28)
++#  define CAN_BDIAG1_DCRCERR		BIT(29)
++#  define CAN_BDIAG1_ESI		BIT(30)
++#  define CAN_BDIAG1_DLCMM		BIT(31)
++#define CAN_TEFCON			CAN_SFR_BASE(0x40)
++#  define CAN_TEFCON_TEFNEIE		BIT(0)
++#  define CAN_TEFCON_TEFHIE		BIT(1)
++#  define CAN_TEFCON_TEFFIE		BIT(2)
++#  define CAN_TEFCON_TEFOVIE		BIT(3)
++#  define CAN_TEFCON_TEFTSEN		BIT(5)
++#  define CAN_TEFCON_UINC		BIT(8)
++#  define CAN_TEFCON_FRESET		BIT(10)
++#  define CAN_TEFCON_FSIZE_BITS		5
++#  define CAN_TEFCON_FSIZE_SHIFT	24
++#  define CAN_TEFCON_FSIZE_MASK					    \
++	GENMASK(CAN_TEFCON_FSIZE_SHIFT + CAN_TEFCON_FSIZE_BITS - 1, \
++		CAN_TEFCON_FSIZE_SHIFT)
++#define CAN_TEFSTA			CAN_SFR_BASE(0x44)
++#  define CAN_TEFSTA_TEFNEIF		BIT(0)
++#  define CAN_TEFSTA_TEFHIF		BIT(1)
++#  define CAN_TEFSTA_TEFFIF		BIT(2)
++#  define CAN_TEFSTA_TEVOVIF		BIT(3)
++#define CAN_TEFUA			CAN_SFR_BASE(0x48)
++#define CAN_RESERVED			CAN_SFR_BASE(0x4C)
++#define CAN_TXQCON			CAN_SFR_BASE(0x50)
++#  define CAN_TXQCON_TXQNIE		BIT(0)
++#  define CAN_TXQCON_TXQEIE		BIT(2)
++#  define CAN_TXQCON_TXATIE		BIT(4)
++#  define CAN_TXQCON_TXEN		BIT(7)
++#  define CAN_TXQCON_UINC		BIT(8)
++#  define CAN_TXQCON_TXREQ		BIT(9)
++#  define CAN_TXQCON_FRESET		BIT(10)
++#  define CAN_TXQCON_TXPRI_BITS		5
++#  define CAN_TXQCON_TXPRI_SHIFT	16
++#  define CAN_TXQCON_TXPRI_MASK					    \
++	GENMASK(CAN_TXQCON_TXPRI_SHIFT + CAN_TXQCON_TXPRI_BITS - 1, \
++		CAN_TXQCON_TXPRI_SHIFT)
++#  define CAN_TXQCON_TXAT_BITS		2
++#  define CAN_TXQCON_TXAT_SHIFT		21
++#  define CAN_TXQCON_TXAT_MASK					    \
++	GENMASK(CAN_TXQCON_TXAT_SHIFT + CAN_TXQCON_TXAT_BITS - 1, \
++		CAN_TXQCON_TXAT_SHIFT)
++#  define CAN_TXQCON_FSIZE_BITS		5
++#  define CAN_TXQCON_FSIZE_SHIFT	24
++#  define CAN_TXQCON_FSIZE_MASK					    \
++	GENMASK(CAN_TXQCON_FSIZE_SHIFT + CAN_TXQCON_FSIZE_BITS - 1, \
++		CAN_TXQCON_FSIZE_SHIFT)
++#  define CAN_TXQCON_PLSIZE_BITS	3
++#  define CAN_TXQCON_PLSIZE_SHIFT	29
++#  define CAN_TXQCON_PLSIZE_MASK				      \
++	GENMASK(CAN_TXQCON_PLSIZE_SHIFT + CAN_TXQCON_PLSIZE_BITS - 1, \
++		CAN_TXQCON_PLSIZE_SHIFT)
++#    define CAN_TXQCON_PLSIZE_8		0
++#    define CAN_TXQCON_PLSIZE_12	1
++#    define CAN_TXQCON_PLSIZE_16	2
++#    define CAN_TXQCON_PLSIZE_20	3
++#    define CAN_TXQCON_PLSIZE_24	4
++#    define CAN_TXQCON_PLSIZE_32	5
++#    define CAN_TXQCON_PLSIZE_48	6
++#    define CAN_TXQCON_PLSIZE_64	7
++
++#define CAN_TXQSTA			CAN_SFR_BASE(0x54)
++#  define CAN_TXQSTA_TXQNIF		BIT(0)
++#  define CAN_TXQSTA_TXQEIF		BIT(2)
++#  define CAN_TXQSTA_TXATIF		BIT(4)
++#  define CAN_TXQSTA_TXERR		BIT(5)
++#  define CAN_TXQSTA_TXLARB		BIT(6)
++#  define CAN_TXQSTA_TXABT		BIT(7)
++#  define CAN_TXQSTA_TXQCI_BITS		5
++#  define CAN_TXQSTA_TXQCI_SHIFT	8
++#  define CAN_TXQSTA_TXQCI_MASK					    \
++	GENMASK(CAN_TXQSTA_TXQCI_SHIFT + CAN_TXQSTA_TXQCI_BITS - 1, \
++		CAN_TXQSTA_TXQCI_SHIFT)
++
++#define CAN_TXQUA			CAN_SFR_BASE(0x58)
++#define CAN_FIFOCON(x)			CAN_SFR_BASE(0x5C + 12 * (x - 1))
++#define CAN_FIFOCON_TFNRFNIE		BIT(0)
++#define CAN_FIFOCON_TFHRFHIE		BIT(1)
++#define CAN_FIFOCON_TFERFFIE		BIT(2)
++#define CAN_FIFOCON_RXOVIE		BIT(3)
++#define CAN_FIFOCON_TXATIE		BIT(4)
++#define CAN_FIFOCON_RXTSEN		BIT(5)
++#define CAN_FIFOCON_RTREN		BIT(6)
++#define CAN_FIFOCON_TXEN		BIT(7)
++#define CAN_FIFOCON_UINC		BIT(8)
++#define CAN_FIFOCON_TXREQ		BIT(9)
++#define CAN_FIFOCON_FRESET		BIT(10)
++#  define CAN_FIFOCON_TXPRI_BITS	5
++#  define CAN_FIFOCON_TXPRI_SHIFT	16
++#  define CAN_FIFOCON_TXPRI_MASK					\
++	GENMASK(CAN_FIFOCON_TXPRI_SHIFT + CAN_FIFOCON_TXPRI_BITS - 1,	\
++		CAN_FIFOCON_TXPRI_SHIFT)
++#  define CAN_FIFOCON_TXAT_BITS		2
++#  define CAN_FIFOCON_TXAT_SHIFT	21
++#  define CAN_FIFOCON_TXAT_MASK					    \
++	GENMASK(CAN_FIFOCON_TXAT_SHIFT + CAN_FIFOCON_TXAT_BITS - 1, \
++		CAN_FIFOCON_TXAT_SHIFT)
++#  define CAN_FIFOCON_TXAT_ONE_SHOT	0
++#  define CAN_FIFOCON_TXAT_THREE_SHOT	1
++#  define CAN_FIFOCON_TXAT_UNLIMITED	2
++#  define CAN_FIFOCON_FSIZE_BITS	5
++#  define CAN_FIFOCON_FSIZE_SHIFT	24
++#  define CAN_FIFOCON_FSIZE_MASK					\
++	GENMASK(CAN_FIFOCON_FSIZE_SHIFT + CAN_FIFOCON_FSIZE_BITS - 1,	\
++		CAN_FIFOCON_FSIZE_SHIFT)
++#  define CAN_FIFOCON_PLSIZE_BITS	3
++#  define CAN_FIFOCON_PLSIZE_SHIFT	29
++#  define CAN_FIFOCON_PLSIZE_MASK					\
++	GENMASK(CAN_FIFOCON_PLSIZE_SHIFT + CAN_FIFOCON_PLSIZE_BITS - 1, \
++		CAN_FIFOCON_PLSIZE_SHIFT)
++#define CAN_FIFOSTA(x)			CAN_SFR_BASE(0x60 + 12 * (x - 1))
++#  define CAN_FIFOSTA_TFNRFNIF		BIT(0)
++#  define CAN_FIFOSTA_TFHRFHIF		BIT(1)
++#  define CAN_FIFOSTA_TFERFFIF		BIT(2)
++#  define CAN_FIFOSTA_RXOVIF		BIT(3)
++#  define CAN_FIFOSTA_TXATIF		BIT(4)
++#  define CAN_FIFOSTA_TXERR		BIT(5)
++#  define CAN_FIFOSTA_TXLARB		BIT(6)
++#  define CAN_FIFOSTA_TXABT		BIT(7)
++#  define CAN_FIFOSTA_FIFOCI_BITS	5
++#  define CAN_FIFOSTA_FIFOCI_SHIFT	8
++#  define CAN_FIFOSTA_FIFOCI_MASK					\
++	GENMASK(CAN_FIFOSTA_FIFOCI_SHIFT + CAN_FIFOSTA_FIFOCI_BITS - 1, \
++		CAN_FIFOSTA_FIFOCI_SHIFT)
++#define CAN_FIFOUA(x)			CAN_SFR_BASE(0x64 + 12 * (x - 1))
++#define CAN_FLTCON(x)			CAN_SFR_BASE(0x1D0 + (x & 0x1c))
++#  define CAN_FILCON_SHIFT(x)		((x & 3) * 8)
++#  define CAN_FILCON_BITS(x)		CAN_FILCON_BITS_
++#  define CAN_FILCON_BITS_		4
++	/* avoid macro reuse warning, so do not use GENMASK as above */
++#  define CAN_FILCON_MASK(x)					\
++	(GENMASK(CAN_FILCON_BITS_ - 1, 0) << CAN_FILCON_SHIFT(x))
++#  define CAN_FIFOCON_FLTEN(x)		BIT(7 + CAN_FILCON_SHIFT(x))
++#define CAN_FLTOBJ(x)			CAN_SFR_BASE(0x1F0 + 8 * x)
++#  define CAN_FILOBJ_SID_BITS		11
++#  define CAN_FILOBJ_SID_SHIFT		0
++#  define CAN_FILOBJ_SID_MASK					\
++	GENMASK(CAN_FILOBJ_SID_SHIFT + CAN_FILOBJ_SID_BITS - 1, \
++		CAN_FILOBJ_SID_SHIFT)
++#  define CAN_FILOBJ_EID_BITS		18
++#  define CAN_FILOBJ_EID_SHIFT		12
++#  define CAN_FILOBJ_EID_MASK					\
++	GENMASK(CAN_FILOBJ_EID_SHIFT + CAN_FILOBJ_EID_BITS - 1, \
++		CAN_FILOBJ_EID_SHIFT)
++#  define CAN_FILOBJ_SID11		BIT(29)
++#  define CAN_FILOBJ_EXIDE		BIT(30)
++#define CAN_FLTMASK(x)			CAN_SFR_BASE(0x1F4 + 8 * x)
++#  define CAN_FILMASK_MSID_BITS		11
++#  define CAN_FILMASK_MSID_SHIFT	0
++#  define CAN_FILMASK_MSID_MASK					\
++	GENMASK(CAN_FILMASK_MSID_SHIFT + CAN_FILMASK_MSID_BITS - 1, \
++		CAN_FILMASK_MSID_SHIFT)
++#  define CAN_FILMASK_MEID_BITS		18
++#  define CAN_FILMASK_MEID_SHIFT	12
++#  define CAN_FILMASK_MEID_MASK					\
++	GENMASK(CAN_FILMASK_MEID_SHIFT + CAN_FILMASK_MEID_BITS - 1, \
++		CAN_FILMASK_MEID_SHIFT)
++#  define CAN_FILMASK_MSID11		BIT(29)
++#  define CAN_FILMASK_MIDE		BIT(30)
++
++#define CAN_OBJ_ID_SID_BITS		11
++#define CAN_OBJ_ID_SID_SHIFT		0
++#define CAN_OBJ_ID_SID_MASK					\
++	GENMASK(CAN_OBJ_ID_SID_SHIFT + CAN_OBJ_ID_SID_BITS - 1, \
++		CAN_OBJ_ID_SID_SHIFT)
++#define CAN_OBJ_ID_EID_BITS		18
++#define CAN_OBJ_ID_EID_SHIFT		11
++#define CAN_OBJ_ID_EID_MASK					\
++	GENMASK(CAN_OBJ_ID_EID_SHIFT + CAN_OBJ_ID_EID_BITS - 1, \
++		CAN_OBJ_ID_EID_SHIFT)
++#define CAN_OBJ_ID_SID_BIT11		BIT(29)
++
++#define CAN_OBJ_FLAGS_DLC_BITS		4
++#define CAN_OBJ_FLAGS_DLC_SHIFT		0
++#define CAN_OBJ_FLAGS_DLC_MASK					      \
++	GENMASK(CAN_OBJ_FLAGS_DLC_SHIFT + CAN_OBJ_FLAGS_DLC_BITS - 1, \
++		CAN_OBJ_FLAGS_DLC_SHIFT)
++#define CAN_OBJ_FLAGS_IDE		BIT(4)
++#define CAN_OBJ_FLAGS_RTR		BIT(5)
++#define CAN_OBJ_FLAGS_BRS		BIT(6)
++#define CAN_OBJ_FLAGS_FDF		BIT(7)
++#define CAN_OBJ_FLAGS_ESI		BIT(8)
++#define CAN_OBJ_FLAGS_SEQ_BITS		7
++#define CAN_OBJ_FLAGS_SEQ_SHIFT		9
++#define CAN_OBJ_FLAGS_SEQ_MASK					      \
++	GENMASK(CAN_OBJ_FLAGS_SEQ_SHIFT + CAN_OBJ_FLAGS_SEQ_BITS - 1, \
++		CAN_OBJ_FLAGS_SEQ_SHIFT)
++#define CAN_OBJ_FLAGS_FILHIT_BITS	11
++#define CAN_OBJ_FLAGS_FILHIT_SHIFT	5
++#define CAN_OBJ_FLAGS_FILHIT_MASK				      \
++	GENMASK(CAN_FLAGS_FILHIT_SHIFT + CAN_FLAGS_FILHIT_BITS - 1, \
++		CAN_FLAGS_FILHIT_SHIFT)
++
++#define CAN_OBJ_FLAGS_CUSTOM_ISTEF	BIT(31)
++
++#define MCP25XXFD_BUFFER_TXRX_SIZE 2048
++
++static const char * const mcp25xxfd_mode_names[] = {
++	[CAN_CON_MODE_MIXED] = "can2.0+canfd",
++	[CAN_CON_MODE_SLEEP] = "sleep",
++	[CAN_CON_MODE_INTERNAL_LOOPBACK] = "internal loopback",
++	[CAN_CON_MODE_LISTENONLY] = "listen only",
++	[CAN_CON_MODE_CONFIG] = "config",
++	[CAN_CON_MODE_EXTERNAL_LOOPBACK] = "external loopback",
++	[CAN_CON_MODE_CAN2_0] = "can2.0",
++	[CAN_CON_MODE_RESTRICTED] = "restricted"
++};
++
++struct mcp25xxfd_obj {
++	u32 id;
++	u32 flags;
++};
++
++struct mcp25xxfd_obj_tx {
++	struct mcp25xxfd_obj header;
++	u32 data[];
++};
++
++static void mcp25xxfd_obj_to_le(struct mcp25xxfd_obj *obj)
++{
++	obj->id = cpu_to_le32(obj->id);
++	obj->flags = cpu_to_le32(obj->flags);
++}
++
++struct mcp25xxfd_obj_ts {
++	u32 id;
++	u32 flags;
++	u32 ts;
++};
++
++struct mcp25xxfd_obj_tef {
++	struct mcp25xxfd_obj_ts header;
++};
++
++struct mcp25xxfd_obj_rx {
++	struct mcp25xxfd_obj_ts header;
++	u8 data[];
++};
++
++static void mcp25xxfd_obj_ts_from_le(struct mcp25xxfd_obj_ts *obj)
++{
++	obj->id = le32_to_cpu(obj->id);
++	obj->flags = le32_to_cpu(obj->flags);
++	obj->ts = le32_to_cpu(obj->ts);
++}
++
++#define FIFO_DATA(x)			(0x400 + (x))
++#define FIFO_DATA_SIZE			0x800
++
++static const struct can_bittiming_const mcp25xxfd_nominal_bittiming_const = {
++	.name		= DEVICE_NAME,
++	.tseg1_min	= 2,
++	.tseg1_max	= BIT(CAN_NBTCFG_TSEG1_BITS),
++	.tseg2_min	= 1,
++	.tseg2_max	= BIT(CAN_NBTCFG_TSEG2_BITS),
++	.sjw_max	= BIT(CAN_NBTCFG_SJW_BITS),
++	.brp_min	= 1,
++	.brp_max	= BIT(CAN_NBTCFG_BRP_BITS),
++	.brp_inc	= 1,
++};
++
++static const struct can_bittiming_const mcp25xxfd_data_bittiming_const = {
++	.name		= DEVICE_NAME,
++	.tseg1_min	= 1,
++	.tseg1_max	= BIT(CAN_DBTCFG_TSEG1_BITS),
++	.tseg2_min	= 1,
++	.tseg2_max	= BIT(CAN_DBTCFG_TSEG2_BITS),
++	.sjw_max	= BIT(CAN_DBTCFG_SJW_BITS),
++	.brp_min	= 1,
++	.brp_max	= BIT(CAN_DBTCFG_BRP_BITS),
++	.brp_inc	= 1,
++};
++
++enum mcp25xxfd_model {
++	CAN_MCP2517FD	= 0x2517,
++};
++
++enum mcp25xxfd_gpio_mode {
++	gpio_mode_int		= 0,
++	gpio_mode_standby	= MCP25XXFD_IOCON_XSTBYEN,
++	gpio_mode_out_low	= MCP25XXFD_IOCON_PM0,
++	gpio_mode_out_high	= MCP25XXFD_IOCON_PM0 | MCP25XXFD_IOCON_LAT0,
++	gpio_mode_in		= MCP25XXFD_IOCON_PM0 | MCP25XXFD_IOCON_TRIS0
++};
++
++struct mcp25xxfd_trigger_tx_message {
++	struct spi_message msg;
++	struct spi_transfer fill_xfer;
++	struct spi_transfer trigger_xfer;
++	int fifo;
++	char fill_cmd[2];
++	char fill_obj[sizeof(struct mcp25xxfd_obj_tx)];
++	char fill_data[64];
++	char trigger_cmd[2];
++	char trigger_data;
++};
++
++struct mcp25xxfd_read_fifo_info {
++	struct mcp25xxfd_obj_ts *rxb[32];
++	int rx_count;
++};
++
++struct mcp25xxfd_priv {
++	struct can_priv	   can;
++	struct net_device *net;
++	struct spi_device *spi;
++	struct regulator *power;
++	struct regulator *transceiver;
++	struct clk *clk;
++
++	struct mutex clk_user_lock; /* lock for enabling/disabling the clock */
++	int clk_user_mask;
++#define MCP25XXFD_CLK_USER_CAN BIT(0)
++#define MCP25XXFD_CLK_USER_GPIO0 BIT(1)
++#define MCP25XXFD_CLK_USER_GPIO1 BIT(2)
++
++	struct dentry *debugfs_dir;
++
++#ifdef CONFIG_GPIOLIB
++	struct gpio_chip gpio;
++#endif
++
++	/* the actual model of the mcp25xxfd */
++	enum mcp25xxfd_model model;
++
++	struct {
++		/* clock configuration */
++		bool clock_pll;
++		bool clock_div2;
++		int  clock_odiv;
++
++		/* GPIO configuration */
++		bool gpio_opendrain;
++	} config;
++
++	/* the distinct spi_speeds to use for spi communication */
++	u32 spi_setup_speed_hz;
++	u32 spi_speed_hz;
++
++	/* fifo info */
++	struct {
++		/* define payload size and mode */
++		int payload_size;
++		u32 payload_mode;
++
++		/* TEF addresses - start, end and current */
++		u32 tef_fifos;
++		u32 tef_address_start;
++		u32 tef_address_end;
++		u32 tef_address;
++
++		/* address in mcp25xxfd-Fifo RAM of each fifo */
++		u32 fifo_address[32];
++
++		/* infos on tx-fifos */
++		u32 tx_fifos;
++		u32 tx_fifo_start;
++		u32 tx_fifo_mask; /* bitmask of which fifo is a tx fifo */
++		u32 tx_submitted_mask;
++		u32 tx_pending_mask;
++		u32 tx_pending_mask_in_irq;
++		u32 tx_processed_mask;
++
++		/* info on rx_fifos */
++		u32 rx_fifos;
++		u32 rx_fifo_depth;
++		u32 rx_fifo_start;
++		u32 rx_fifo_mask;  /* bitmask of which fifo is a rx fifo */
++
++		/* memory image of FIFO RAM on mcp25xxfd */
++		u8 fifo_data[MCP25XXFD_BUFFER_TXRX_SIZE];
++
++	} fifos;
++
++	/* structure with active fifos that need to get fed to the system */
++	struct mcp25xxfd_read_fifo_info queued_fifos;
++
++	/* statistics */
++	struct {
++		/* number of calls to the irq handler */
++		u64 irq_calls;
++		/* number of loops inside the irq handler */
++		u64 irq_loops;
++
++		/* interrupt handler state and statistics */
++		u32 irq_state;
++#define IRQ_STATE_NEVER_RUN 0
++#define IRQ_STATE_RUNNING 1
++#define IRQ_STATE_HANDLED 2
++		/* stats on number of rx overflows */
++		u64 rx_overflow;
++		/* statistics of FIFO usage */
++		u64 fifo_usage[32];
++
++		/* message abort counter */
++		u64 rx_mab;
++		u64 tx_mab;
++
++		/* message counter fd */
++		u64 rx_fd_count;
++		u64 tx_fd_count;
++
++		/* message counter fd bit rate switch */
++		u64 rx_brs_count;
++		u64 tx_brs_count;
++
++		/* interrupt counter */
++		u64 int_ivm_count;
++		u64 int_wake_count;
++		u64 int_cerr_count;
++		u64 int_serr_count;
++		u64 int_rxov_count;
++		u64 int_txat_count;
++		u64 int_spicrc_count;
++		u64 int_ecc_count;
++		u64 int_tef_count;
++		u64 int_mod_count;
++		u64 int_tbc_count;
++		u64 int_rx_count;
++		u64 int_tx_count;
++
++		/* dlc statistics */
++		u64 rx_dlc_usage[16];
++		u64 tx_dlc_usage[16];
++	} stats;
++
++	/* the current status of the mcp25xxfd */
++	struct {
++		u32 intf;
++		/* ASSERT(CAN_INT + 4 == CAN_RXIF) */
++		u32 rxif;
++		/* ASSERT(CAN_RXIF + 4 == CAN_TXIF) */
++		u32 txif;
++		/* ASSERT(CAN_TXIF + 4 == CAN_RXOVIF) */
++		u32 rxovif;
++		/* ASSERT(CAN_RXOVIF + 4 == CAN_TXATIF) */
++		u32 txatif;
++		/* ASSERT(CAN_TXATIF + 4 == CAN_TXREQ) */
++		u32 txreq;
++		/* ASSERT(CAN_TXREQ + 4 == CAN_TREC) */
++		u32 trec;
++		/* ASSERT(CAN_TREC + 4 == CAN_BDIAG0) */
++		u32 bdiag0;
++		/* ASSERT(CAN_BDIAG0 + 4 == CAN_BDIAG1) */
++		u32 bdiag1;
++	} status;
++
++	/* configuration registers */
++	struct {
++		u32 osc;
++		u32 ecccon;
++		u32 con;
++		u32 iocon;
++		u32 tdc;
++		u32 tscon;
++		u32 tefcon;
++		u32 nbtcfg;
++		u32 dbtcfg;
++	} regs;
++
++	/* interrupt handler signaling */
++	int force_quit;
++	int after_suspend;
++#define AFTER_SUSPEND_UP 1
++#define AFTER_SUSPEND_DOWN 2
++#define AFTER_SUSPEND_POWER 4
++#define AFTER_SUSPEND_RESTART 8
++	int restart_tx;
++
++	/* interrupt flags during irq handling */
++	u32 bdiag1_clear_mask;
++	u32 bdiag1_clear_value;
++
++	/* composit error id and dataduring irq handling */
++	u32 can_err_id;
++	u32 can_err_data[8];
++
++	/* the current mode */
++	u32 active_can_mode;
++	u32 new_state;
++
++	/* status of the tx_queue enabled/disabled */
++	u32 tx_queue_status;
++#define TX_QUEUE_STATUS_INIT		0
++#define TX_QUEUE_STATUS_RUNNING		1
++#define TX_QUEUE_STATUS_NEEDS_START	2
++#define TX_QUEUE_STATUS_STOPPED		3
++
++	/* spi-tx/rx buffers for efficient transfers
++	 * used during setup and irq
++	 */
++	struct mutex spi_rxtx_lock;
++	u8 spi_tx[MCP25XXFD_BUFFER_TXRX_SIZE];
++	u8 spi_rx[MCP25XXFD_BUFFER_TXRX_SIZE];
++
++	/* structure for transmit fifo spi_messages */
++	struct mcp25xxfd_trigger_tx_message *spi_transmit_fifos;
++};
++
++/* module parameters */
++bool use_bulk_release_fifos;
++module_param(use_bulk_release_fifos, bool, 0664);
++MODULE_PARM_DESC(use_bulk_release_fifos,
++		 "Use code that favours longer spi transfers over multiple transfers");
++bool use_complete_fdfifo_read;
++module_param(use_complete_fdfifo_read, bool, 0664);
++MODULE_PARM_DESC(use_complete_fdfifo_read,
++		 "Use code that favours longer spi transfers over multiple transfers for fd can");
++unsigned int tx_fifos;
++module_param(tx_fifos, uint, 0664);
++MODULE_PARM_DESC(tx_fifos,
++		 "Number of tx-fifos to configure\n");
++unsigned int bw_sharing_log2bits;
++module_param(bw_sharing_log2bits, uint, 0664);
++MODULE_PARM_DESC(bw_sharing_log2bits,
++		 "Delay between 2 transmissions in number of arbitration bit times\n");
++bool three_shot;
++module_param(three_shot, bool, 0664);
++MODULE_PARM_DESC(three_shot,
++		 "Use 3 shots when one-shot is requested");
++
++/* spi sync helper */
++
++/* wrapper arround spi_sync, that sets speed_hz */
++static int mcp25xxfd_sync_transfer(struct spi_device *spi,
++				   struct spi_transfer *xfer,
++				   unsigned int xfers,
++				   int speed_hz)
++{
++	int i;
++
++	for (i = 0; i < xfers; i++)
++		xfer[i].speed_hz = speed_hz;
++
++	return spi_sync_transfer(spi, xfer, xfers);
++}
++
++/* an optimization of spi_write_then_read that merges the transfers */
++static int mcp25xxfd_write_then_read(struct spi_device *spi,
++				     const void *tx_buf,
++				     unsigned int tx_len,
++				     void *rx_buf,
++				     unsigned int rx_len,
++				     int speed_hz)
++{
++	struct mcp25xxfd_priv *priv = spi_get_drvdata(spi);
++	struct spi_transfer xfer[2];
++	u8 single_reg_data_tx[6];
++	u8 single_reg_data_rx[6];
++	int ret;
++
++	memset(xfer, 0, sizeof(xfer));
++
++	/* when using a halfduplex controller or to big for buffer */
++	if ((spi->master->flags & SPI_MASTER_HALF_DUPLEX) ||
++	    (tx_len + rx_len > sizeof(priv->spi_tx))) {
++		xfer[0].tx_buf = tx_buf;
++		xfer[0].len = tx_len;
++
++		xfer[1].rx_buf = rx_buf;
++		xfer[1].len = rx_len;
++
++		return mcp25xxfd_sync_transfer(spi, xfer, 2, speed_hz);
++	}
++
++	/* full duplex optimization */
++	xfer[0].len = tx_len + rx_len;
++	if (xfer[0].len > sizeof(single_reg_data_tx)) {
++		mutex_lock(&priv->spi_rxtx_lock);
++		xfer[0].tx_buf = priv->spi_tx;
++		xfer[0].rx_buf = priv->spi_rx;
++	} else {
++		xfer[0].tx_buf = single_reg_data_tx;
++		xfer[0].rx_buf = single_reg_data_rx;
++	}
++
++	/* copy and clean */
++	memcpy((u8 *)xfer[0].tx_buf, tx_buf, tx_len);
++	memset((u8 *)xfer[0].tx_buf + tx_len, 0, rx_len);
++
++	ret = mcp25xxfd_sync_transfer(spi, xfer, 1, speed_hz);
++	if (!ret)
++		memcpy(rx_buf, xfer[0].rx_buf + tx_len, rx_len);
++
++	if (xfer[0].len > sizeof(single_reg_data_tx))
++		mutex_unlock(&priv->spi_rxtx_lock);
++
++	return ret;
++}
++
++/* simple spi_write wrapper with speed_hz */
++static int mcp25xxfd_write(struct spi_device *spi,
++			   const void *tx_buf,
++			   unsigned int tx_len,
++			   int speed_hz)
++{
++	struct spi_transfer xfer;
++
++	memset(&xfer, 0, sizeof(xfer));
++	xfer.tx_buf = tx_buf;
++	xfer.len = tx_len;
++
++	return mcp25xxfd_sync_transfer(spi, &xfer, 1, speed_hz);
++}
++
++/* spi_sync wrapper similar to spi_write_then_read that optimizes transfers */
++static int mcp25xxfd_write_then_write(struct spi_device *spi,
++				      const void *tx_buf,
++				      unsigned int tx_len,
++				      const void *tx2_buf,
++				      unsigned int tx2_len,
++				      int speed_hz)
++{
++	struct mcp25xxfd_priv *priv = spi_get_drvdata(spi);
++	struct spi_transfer xfer;
++	u8 single_reg_data[6];
++	int ret;
++
++	if (tx_len + tx2_len > MCP25XXFD_BUFFER_TXRX_SIZE)
++		return -EINVAL;
++
++	memset(&xfer, 0, sizeof(xfer));
++
++	xfer.len = tx_len + tx2_len;
++	if (xfer.len > sizeof(single_reg_data)) {
++		mutex_lock(&priv->spi_rxtx_lock);
++		xfer.tx_buf = priv->spi_tx;
++	} else {
++		xfer.tx_buf = single_reg_data;
++	}
++
++	memcpy((u8 *)xfer.tx_buf, tx_buf, tx_len);
++	memcpy((u8 *)xfer.tx_buf + tx_len, tx2_buf, tx2_len);
++
++	ret = mcp25xxfd_sync_transfer(spi, &xfer, 1, speed_hz);
++
++	if (xfer.len > sizeof(single_reg_data))
++		mutex_unlock(&priv->spi_rxtx_lock);
++
++	return ret;
++}
++
++/* mcp25xxfd spi command/protocol helper */
++
++static void mcp25xxfd_calc_cmd_addr(u16 cmd, u16 addr, u8 *data)
++{
++	cmd = cmd | (addr & ADDRESS_MASK);
++
++	data[0] = (cmd >> 8) & 0xff;
++	data[1] = (cmd >> 0) & 0xff;
++}
++
++static int mcp25xxfd_cmd_reset(struct spi_device *spi, u32 speed_hz)
++{
++	u8 cmd[2];
++
++	mcp25xxfd_calc_cmd_addr(INSTRUCTION_RESET, 0, cmd);
++
++	/* write the reset command */
++	return mcp25xxfd_write(spi, cmd, 2, speed_hz);
++}
++
++/* read multiple bytes, transform some registers */
++static int mcp25xxfd_cmd_readn(struct spi_device *spi, u32 reg,
++			       void *data, int n, u32 speed_hz)
++{
++	u8 cmd[2];
++	int ret;
++
++	mcp25xxfd_calc_cmd_addr(INSTRUCTION_READ, reg, cmd);
++
++	ret = mcp25xxfd_write_then_read(spi, &cmd, 2, data, n, speed_hz);
++	if (ret)
++		return ret;
++
++	return 0;
++}
++
++static int mcp25xxfd_convert_to_cpu(u32 *data, int n)
++{
++	int i;
++
++	for (i = 0; i < n; i++)
++		data[i] = le32_to_cpu(data[i]);
++
++	return 0;
++}
++
++static int mcp25xxfd_first_byte(u32 mask)
++{
++	return (mask & 0x0000ffff) ?
++		((mask & 0x000000ff) ? 0 : 1) :
++		((mask & 0x00ff0000) ? 2 : 3);
++}
++
++static int mcp25xxfd_last_byte(u32 mask)
++{
++	return (mask & 0xffff0000) ?
++		((mask & 0xff000000) ? 3 : 2) :
++		((mask & 0x0000ff00) ? 1 : 0);
++}
++
++/* read a register, but we are only interrested in a few bytes */
++static int mcp25xxfd_cmd_read_mask(struct spi_device *spi, u32 reg,
++				   u32 *data, u32 mask, u32 speed_hz)
++{
++	int first_byte, last_byte, len_byte;
++	int ret;
++
++	/* check that at least one bit is set */
++	if (!mask)
++		return -EINVAL;
++
++	/* calculate first and last byte used */
++	first_byte = mcp25xxfd_first_byte(mask);
++	last_byte = mcp25xxfd_last_byte(mask);
++	len_byte = last_byte - first_byte + 1;
++
++	/* do a partial read */
++	*data = 0;
++	ret = mcp25xxfd_cmd_readn(spi, reg + first_byte,
++				  ((void *)data + first_byte), len_byte,
++				  speed_hz);
++	if (ret)
++		return ret;
++
++	return mcp25xxfd_convert_to_cpu(data, 1);
++}
++
++static int mcp25xxfd_cmd_read(struct spi_device *spi, u32 reg, u32 *data,
++			      u32 speed_hz)
++{
++	return mcp25xxfd_cmd_read_mask(spi, reg, data, -1, speed_hz);
++}
++
++/* read a register, but we are only interrested in a few bytes */
++static int mcp25xxfd_cmd_write_mask(struct spi_device *spi, u32 reg,
++				    u32 data, u32 mask, u32 speed_hz)
++{
++	int first_byte, last_byte, len_byte;
++	u8 cmd[2];
++
++	/* check that at least one bit is set */
++	if (!mask)
++		return -EINVAL;
++
++	/* calculate first and last byte used */
++	first_byte = mcp25xxfd_first_byte(mask);
++	last_byte = mcp25xxfd_last_byte(mask);
++	len_byte = last_byte - first_byte + 1;
++
++	/* prepare buffer */
++	mcp25xxfd_calc_cmd_addr(INSTRUCTION_WRITE, reg + first_byte, cmd);
++	data = cpu_to_le32(data);
++
++	return mcp25xxfd_write_then_write(spi,
++					  cmd, sizeof(cmd),
++					  ((void *)&data + first_byte),
++					  len_byte,
++					  speed_hz);
++}
++
++static int mcp25xxfd_cmd_write(struct spi_device *spi, u32 reg, u32 data,
++			       u32 speed_hz)
++{
++	return mcp25xxfd_cmd_write_mask(spi, reg, data, -1, speed_hz);
++}
++
++static int mcp25xxfd_cmd_writen(struct spi_device *spi, u32 reg,
++				void *data, int n, u32 speed_hz)
++{
++	u8 cmd[2];
++	int ret;
++
++	mcp25xxfd_calc_cmd_addr(INSTRUCTION_WRITE, reg, cmd);
++
++	ret = mcp25xxfd_write_then_write(spi, &cmd, 2, data, n, speed_hz);
++	if (ret)
++		return ret;
++
++	return 0;
++}
++
++static int mcp25xxfd_clean_sram(struct spi_device *spi, u32 speed_hz)
++{
++	u8 buffer[256];
++	int i;
++	int ret;
++
++	memset(buffer, 0, sizeof(buffer));
++
++	for (i = 0; i < FIFO_DATA_SIZE; i += sizeof(buffer)) {
++		ret = mcp25xxfd_cmd_writen(spi, FIFO_DATA(i),
++					   buffer, sizeof(buffer),
++					   speed_hz);
++		if (ret)
++			return ret;
++	}
++
++	return 0;
++}
++
++/* mcp25xxfd opmode helper functions */
++
++static int mcp25xxfd_get_opmode(struct spi_device *spi,
++				int *mode,
++				int speed_hz)
++{
++	struct mcp25xxfd_priv *priv = spi_get_drvdata(spi);
++	int ret;
++
++	/* read the mode */
++	ret = mcp25xxfd_cmd_read_mask(spi,
++				      CAN_CON,
++				      &priv->regs.con,
++				      CAN_CON_OPMOD_MASK,
++				      speed_hz);
++	if (ret)
++		return ret;
++	/* calculate the mode */
++	*mode = (priv->regs.con & CAN_CON_OPMOD_MASK) >>
++		CAN_CON_OPMOD_SHIFT;
++
++	/* and assign to active mode as well */
++	priv->active_can_mode = *mode;
++
++	return 0;
++}
++
++static int mcp25xxfd_set_opmode(struct spi_device *spi, int mode,
++				int speed_hz)
++{
++	struct mcp25xxfd_priv *priv = spi_get_drvdata(spi);
++	u32 val = priv->regs.con & ~CAN_CON_REQOP_MASK;
++
++	/* regs.con also contains the effective register */
++	priv->regs.con = val |
++		(mode << CAN_CON_REQOP_SHIFT) |
++		(mode << CAN_CON_OPMOD_SHIFT);
++	priv->active_can_mode = mode;
++
++	/* if the opmode is sleep then the oscilator will be disabled
++	 * and also not ready
++	 */
++	if (mode == CAN_CON_MODE_SLEEP) {
++		priv->regs.osc &= ~(MCP25XXFD_OSC_OSCRDY |
++				    MCP25XXFD_OSC_PLLRDY |
++				    MCP25XXFD_OSC_SCLKRDY);
++		priv->regs.osc |= MCP25XXFD_OSC_OSCDIS;
++	}
++
++	/* but only write the relevant section */
++	return mcp25xxfd_cmd_write_mask(spi, CAN_CON,
++					priv->regs.con,
++					CAN_CON_REQOP_MASK,
++					speed_hz);
++}
++
++static int mcp25xxfd_set_normal_opmode(struct spi_device *spi)
++{
++	struct mcp25xxfd_priv *priv = spi_get_drvdata(spi);
++	int mode;
++
++	if (priv->can.ctrlmode & CAN_CTRLMODE_LOOPBACK)
++		mode = CAN_CON_MODE_EXTERNAL_LOOPBACK;
++	else if (priv->can.ctrlmode & CAN_CTRLMODE_LISTENONLY)
++		mode = CAN_CON_MODE_LISTENONLY;
++	else if (priv->can.ctrlmode & CAN_CTRLMODE_FD)
++		mode = CAN_CON_MODE_MIXED;
++	else
++		mode = CAN_CON_MODE_CAN2_0;
++
++	return mcp25xxfd_set_opmode(spi, mode, priv->spi_setup_speed_hz);
++}
++
++/* clock helper */
++static int mcp25xxfd_wake_from_sleep(struct spi_device *spi)
++{
++	struct mcp25xxfd_priv *priv = spi_get_drvdata(spi);
++	u32 waitfor = MCP25XXFD_OSC_OSCRDY;
++	u32 mask = waitfor | MCP25XXFD_OSC_OSCDIS;
++	unsigned long timeout;
++	int ret;
++
++	/* write clock with OSCDIS cleared*/
++	priv->regs.osc &= ~MCP25XXFD_OSC_OSCDIS;
++	ret = mcp25xxfd_cmd_write(spi, MCP25XXFD_OSC,
++				  priv->regs.osc,
++				  priv->spi_setup_speed_hz);
++	if (ret)
++		return ret;
++
++	/* wait for synced pll/osc/sclk */
++	timeout = jiffies + MCP25XXFD_OSC_POLLING_JIFFIES;
++	while (time_before_eq(jiffies, timeout)) {
++		ret = mcp25xxfd_cmd_read(spi, MCP25XXFD_OSC,
++					 &priv->regs.osc,
++					 priv->spi_setup_speed_hz);
++		if (ret)
++			return ret;
++		if ((priv->regs.osc & mask) == waitfor) {
++			priv->active_can_mode = CAN_CON_MODE_CONFIG;
++			return 0;
++		}
++		/* wait some time */
++		mdelay(100);
++	}
++
++	dev_err(&spi->dev,
++		"Clock did not enable within the timeout period\n");
++	return -ETIMEDOUT;
++}
++
++static int mcp25xxfd_hw_check_clock(struct spi_device *spi)
++{
++	struct mcp25xxfd_priv *priv = spi_get_drvdata(spi);
++	u32 val;
++	int ret;
++
++	/* read the osc register and check if it matches
++	 * what we have on record
++	 */
++	ret = mcp25xxfd_cmd_read(spi, MCP25XXFD_OSC,
++				 &val,
++				 priv->spi_setup_speed_hz);
++	if (ret)
++		return ret;
++
++	if (val == priv->regs.osc)
++		return 0;
++
++	/* ignore all those ready bits on second try */
++	if ((val & 0xff) == (priv->regs.osc & 0xff)) {
++		dev_info(&spi->dev,
++			 "The oscillator register value %08x does not match what we expect: %08x - it is still reasonable, but please investigate\n",
++			val, priv->regs.osc);
++		return 0;
++	}
++
++	dev_err(&spi->dev,
++		"The oscillator register value %08x does not match what we expect: %08x\n",
++		val, priv->regs.osc);
++
++	return -ENODEV;
++}
++
++static int mcp25xxfd_start_clock(struct spi_device *spi, int requestor_mask)
++{
++	struct mcp25xxfd_priv *priv = spi_get_drvdata(spi);
++	int ret = 0;
++
++	mutex_lock(&priv->clk_user_lock);
++
++	priv->clk_user_mask |= requestor_mask;
++
++	if (priv->clk_user_mask != requestor_mask)
++		goto out;
++
++	/* check that the controller clock register
++	 * is what it is supposed to be
++	 */
++	ret = mcp25xxfd_hw_check_clock(spi);
++	if (ret) {
++		dev_err(&spi->dev,
++			"Controller clock register in unexpected state");
++		goto out;
++	}
++
++	/* and we start the clock */
++	if (!IS_ERR(priv->clk))
++		ret = clk_prepare_enable(priv->clk);
++
++	/* we wake from sleep */
++	if (priv->active_can_mode == CAN_CON_MODE_SLEEP)
++		ret = mcp25xxfd_wake_from_sleep(spi);
++
++out:
++	mutex_unlock(&priv->clk_user_lock);
++
++	return ret;
++}
++
++static int mcp25xxfd_stop_clock(struct spi_device *spi, int requestor_mask)
++{
++	struct mcp25xxfd_priv *priv = spi_get_drvdata(spi);
++
++	mutex_lock(&priv->clk_user_lock);
++
++	priv->clk_user_mask &= ~requestor_mask;
++
++	if (!priv->clk_user_mask)
++		goto out;
++
++	/* put us into sleep mode */
++	mcp25xxfd_set_opmode(spi, CAN_CON_MODE_SLEEP,
++			     priv->spi_setup_speed_hz);
++
++	/* and we stop the clock */
++	if (!IS_ERR(priv->clk))
++		clk_disable_unprepare(priv->clk);
++
++out:
++	mutex_unlock(&priv->clk_user_lock);
++
++	return 0;
++}
++
++/* mcp25xxfd GPIO helper functions */
++#ifdef CONFIG_GPIOLIB
++
++enum mcp25xxfd_gpio_pins {
++	MCP25XXFD_GPIO_GPIO0 = 0,
++	MCP25XXFD_GPIO_GPIO1 = 1,
++};
++
++static int mcp25xxfd_gpio_request(struct gpio_chip *chip,
++				  unsigned int offset)
++{
++	struct mcp25xxfd_priv *priv = gpiochip_get_data(chip);
++	int clock_requestor = offset ?
++		MCP25XXFD_CLK_USER_GPIO1 : MCP25XXFD_CLK_USER_GPIO0;
++
++	/* only handle gpio 0/1 */
++	if (offset > 1)
++		return -EINVAL;
++
++	mcp25xxfd_start_clock(priv->spi, clock_requestor);
++
++	return 0;
++}
++
++static void mcp25xxfd_gpio_free(struct gpio_chip *chip,
++				unsigned int offset)
++{
++	struct mcp25xxfd_priv *priv = gpiochip_get_data(chip);
++	int clock_requestor = offset ?
++		MCP25XXFD_CLK_USER_GPIO1 : MCP25XXFD_CLK_USER_GPIO0;
++
++	/* only handle gpio 0/1 */
++	if (offset > 1)
++		return;
++
++	mcp25xxfd_stop_clock(priv->spi, clock_requestor);
++}
++
++static int mcp25xxfd_gpio_get(struct gpio_chip *chip, unsigned int offset)
++{
++	struct mcp25xxfd_priv *priv = gpiochip_get_data(chip);
++	u32 mask = (offset) ? MCP25XXFD_IOCON_GPIO1 : MCP25XXFD_IOCON_GPIO0;
++	int ret;
++
++	/* only handle gpio 0/1 */
++	if (offset > 1)
++		return -EINVAL;
++
++	/* read the relevant gpio Latch */
++	ret = mcp25xxfd_cmd_read_mask(priv->spi, MCP25XXFD_IOCON,
++				      &priv->regs.iocon, mask,
++				      priv->spi_setup_speed_hz);
++	if (ret)
++		return ret;
++
++	/* return the match */
++	return priv->regs.iocon & mask;
++}
++
++static void mcp25xxfd_gpio_set(struct gpio_chip *chip, unsigned int offset,
++			       int value)
++{
++	struct mcp25xxfd_priv *priv = gpiochip_get_data(chip);
++	u32 mask = (offset) ? MCP25XXFD_IOCON_LAT1 : MCP25XXFD_IOCON_LAT0;
++
++	/* only handle gpio 0/1 */
++	if (offset > 1)
++		return;
++
++	/* update in memory representation with the corresponding value */
++	if (value)
++		priv->regs.iocon |= mask;
++	else
++		priv->regs.iocon &= ~mask;
++
++	mcp25xxfd_cmd_write_mask(priv->spi, MCP25XXFD_IOCON,
++				 priv->regs.iocon, mask,
++				 priv->spi_setup_speed_hz);
++}
++
++static int mcp25xxfd_gpio_direction_input(struct gpio_chip *chip,
++					  unsigned int offset)
++{
++	struct mcp25xxfd_priv *priv = gpiochip_get_data(chip);
++	u32 mask_tri = (offset) ?
++		MCP25XXFD_IOCON_TRIS1 : MCP25XXFD_IOCON_TRIS0;
++	u32 mask_stby = (offset) ?
++		0 : MCP25XXFD_IOCON_XSTBYEN;
++	u32 mask_pm = (offset) ?
++		MCP25XXFD_IOCON_PM1 : MCP25XXFD_IOCON_PM0;
++
++	/* only handle gpio 0/1 */
++	if (offset > 1)
++		return -EINVAL;
++
++	/* set the mask */
++	priv->regs.iocon |= mask_tri | mask_pm;
++
++	/* clear stby */
++	priv->regs.iocon &= ~mask_stby;
++
++	return mcp25xxfd_cmd_write_mask(priv->spi, MCP25XXFD_IOCON,
++					priv->regs.iocon,
++					mask_tri | mask_stby | mask_pm,
++					priv->spi_setup_speed_hz);
++}
++
++static int mcp25xxfd_gpio_direction_output(struct gpio_chip *chip,
++					   unsigned int offset, int value)
++{
++	struct mcp25xxfd_priv *priv = gpiochip_get_data(chip);
++	u32 mask_tri = (offset) ?
++		MCP25XXFD_IOCON_TRIS1 : MCP25XXFD_IOCON_TRIS0;
++	u32 mask_lat = (offset) ?
++		MCP25XXFD_IOCON_LAT1 : MCP25XXFD_IOCON_LAT0;
++	u32 mask_pm = (offset) ?
++		MCP25XXFD_IOCON_PM1 : MCP25XXFD_IOCON_PM0;
++	u32 mask_stby = (offset) ?
++		0 : MCP25XXFD_IOCON_XSTBYEN;
++
++	/* only handle gpio 0/1 */
++	if (offset > 1)
++		return -EINVAL;
++
++	/* clear the tristate bit and also clear stby */
++	priv->regs.iocon &= ~(mask_tri | mask_stby);
++
++	/* set GPIO mode */
++	priv->regs.iocon |= mask_pm;
++
++	/* set the value */
++	if (value)
++		priv->regs.iocon |= mask_lat;
++	else
++		priv->regs.iocon &= ~mask_lat;
++
++	return mcp25xxfd_cmd_write_mask(priv->spi, MCP25XXFD_IOCON,
++					priv->regs.iocon,
++					mask_tri | mask_lat |
++					mask_pm | mask_stby,
++					priv->spi_setup_speed_hz);
++}
++
++static int mcp25xxfd_gpio_setup(struct spi_device *spi)
++{
++	struct mcp25xxfd_priv *priv = spi_get_drvdata(spi);
++
++	/* gpiochip only handles GPIO0 and GPIO1 */
++	priv->gpio.owner		= THIS_MODULE;
++	priv->gpio.parent		= &spi->dev;
++	priv->gpio.label		= dev_name(&spi->dev);
++	priv->gpio.direction_input	= mcp25xxfd_gpio_direction_input;
++	priv->gpio.get			= mcp25xxfd_gpio_get;
++	priv->gpio.direction_output	= mcp25xxfd_gpio_direction_output;
++	priv->gpio.set			= mcp25xxfd_gpio_set;
++	priv->gpio.request		= mcp25xxfd_gpio_request;
++	priv->gpio.free			= mcp25xxfd_gpio_free;
++	priv->gpio.base			= -1;
++	priv->gpio.ngpio		= 2;
++	priv->gpio.can_sleep		= 1;
++
++	return devm_gpiochip_add_data(&spi->dev, &priv->gpio, priv);
++}
++
++#else
++
++static int mcp25xxfd_gpio_setup(struct spi_device *spi)
++{
++	return 0;
++}
++
++#endif
++
++/* ideally these would be defined in uapi/linux/can.h */
++#define CAN_EFF_SID_SHIFT		(CAN_EFF_ID_BITS - CAN_SFF_ID_BITS)
++#define CAN_EFF_SID_BITS		CAN_SFF_ID_BITS
++#define CAN_EFF_SID_MASK				      \
++	GENMASK(CAN_EFF_SID_SHIFT + CAN_EFF_SID_BITS - 1,     \
++		CAN_EFF_SID_SHIFT)
++#define CAN_EFF_EID_SHIFT		0
++#define CAN_EFF_EID_BITS		CAN_EFF_SID_SHIFT
++#define CAN_EFF_EID_MASK				      \
++	GENMASK(CAN_EFF_EID_SHIFT + CAN_EFF_EID_BITS - 1,     \
++		CAN_EFF_EID_SHIFT)
++
++static void mcp25xxfd_canid_to_mcpid(u32 can_id, u32 *id, u32 *flags)
++{
++	if (can_id & CAN_EFF_FLAG) {
++		int sid = (can_id & CAN_EFF_SID_MASK) >> CAN_EFF_SID_SHIFT;
++		int eid = (can_id & CAN_EFF_EID_MASK) >> CAN_EFF_EID_SHIFT;
++		*id = (eid << CAN_OBJ_ID_EID_SHIFT) |
++			(sid << CAN_OBJ_ID_SID_SHIFT);
++		*flags = CAN_OBJ_FLAGS_IDE;
++	} else {
++		*id = can_id & CAN_SFF_MASK;
++		*flags = 0;
++	}
++
++	*flags |= (can_id & CAN_RTR_FLAG) ? CAN_OBJ_FLAGS_RTR : 0;
++}
++
++static void mcp25xxfd_mcpid_to_canid(u32 mcpid, u32 mcpflags, u32 *id)
++{
++	u32 sid = (mcpid & CAN_OBJ_ID_SID_MASK) >> CAN_OBJ_ID_SID_SHIFT;
++	u32 eid = (mcpid & CAN_OBJ_ID_EID_MASK) >> CAN_OBJ_ID_EID_SHIFT;
++
++	if (mcpflags & CAN_OBJ_FLAGS_IDE) {
++		*id = (eid << CAN_EFF_EID_SHIFT) |
++			(sid << CAN_EFF_SID_SHIFT) |
++			CAN_EFF_FLAG;
++	} else {
++		*id = sid;
++	}
++
++	*id |= (mcpflags & CAN_OBJ_FLAGS_RTR) ? CAN_RTR_FLAG : 0;
++}
++
++static void __mcp25xxfd_stop_queue(struct net_device *net,
++				   unsigned int id)
++{
++	struct mcp25xxfd_priv *priv = netdev_priv(net);
++
++	if (priv->tx_queue_status >= TX_QUEUE_STATUS_STOPPED)
++		dev_warn(&priv->spi->dev,
++			 "tx-queue is already stopped by: %i\n",
++			 priv->tx_queue_status);
++
++	priv->tx_queue_status = id ? id : TX_QUEUE_STATUS_STOPPED;
++	netif_stop_queue(priv->net);
++}
++
++/* helper to identify who is stopping the queue by line number */
++#define mcp25xxfd_stop_queue(spi) \
++	__mcp25xxfd_stop_queue(spi, __LINE__)
++
++static void mcp25xxfd_wake_queue(struct spi_device *spi)
++{
++	struct mcp25xxfd_priv *priv = spi_get_drvdata(spi);
++
++	/* nothing should be left pending /in flight now... */
++	priv->fifos.tx_pending_mask = 0;
++	priv->fifos.tx_submitted_mask = 0;
++	priv->fifos.tx_processed_mask = 0;
++	priv->tx_queue_status = TX_QUEUE_STATUS_RUNNING;
++
++	/* wake queue now */
++	netif_wake_queue(priv->net);
++}
++
++/* CAN transmit related*/
++
++static void mcp25xxfd_mark_tx_pending(void *context)
++{
++	struct mcp25xxfd_trigger_tx_message *txm = context;
++	struct spi_device *spi = txm->msg.spi;
++	struct mcp25xxfd_priv *priv = spi_get_drvdata(spi);
++
++	/* only here or in the irq handler this value is changed,
++	 * so there is no race condition and it does not require locking
++	 * serialization happens via spi_pump_message
++	 */
++	priv->fifos.tx_pending_mask |= BIT(txm->fifo);
++}
++
++static int mcp25xxfd_fill_spi_transmit_fifos(struct mcp25xxfd_priv *priv)
++{
++	struct mcp25xxfd_trigger_tx_message *txm;
++	int i, fifo;
++	const u32 trigger = CAN_FIFOCON_TXREQ | CAN_FIFOCON_UINC;
++	const int first_byte = mcp25xxfd_first_byte(trigger);
++	u32 fifo_address;
++
++	priv->spi_transmit_fifos = kcalloc(priv->fifos.tx_fifos,
++					   sizeof(*priv->spi_transmit_fifos),
++					   GFP_KERNEL | GFP_DMA);
++	if (!priv->spi_transmit_fifos)
++		return -ENOMEM;
++
++	for (i = 0; i < priv->fifos.tx_fifos; i++) {
++		fifo = priv->fifos.tx_fifo_start + i;
++		txm = &priv->spi_transmit_fifos[i];
++		fifo_address = priv->fifos.fifo_address[fifo];
++		/* prepare the message */
++		spi_message_init(&txm->msg);
++		txm->msg.complete = mcp25xxfd_mark_tx_pending;
++		txm->msg.context = txm;
++		txm->fifo = fifo;
++		/* the payload itself */
++		txm->fill_xfer.speed_hz = priv->spi_speed_hz;
++		txm->fill_xfer.tx_buf = txm->fill_cmd;
++		txm->fill_xfer.len = 2;
++		txm->fill_xfer.cs_change = true;
++		mcp25xxfd_calc_cmd_addr(INSTRUCTION_WRITE,
++					FIFO_DATA(fifo_address),
++					txm->fill_cmd);
++		spi_message_add_tail(&txm->fill_xfer, &txm->msg);
++		/* the trigger command */
++		txm->trigger_xfer.speed_hz = priv->spi_speed_hz;
++		txm->trigger_xfer.tx_buf = txm->trigger_cmd;
++		txm->trigger_xfer.len = 3;
++		mcp25xxfd_calc_cmd_addr(INSTRUCTION_WRITE,
++					CAN_FIFOCON(fifo) + first_byte,
++					txm->trigger_cmd);
++		txm->trigger_data = trigger >> (8 * first_byte);
++		spi_message_add_tail(&txm->trigger_xfer, &txm->msg);
++	}
++
++	return 0;
++}
++
++static int mcp25xxfd_transmit_message_common(struct spi_device *spi,
++					     int fifo,
++					     struct mcp25xxfd_obj_tx *obj,
++					     int len,
++					     u8 *data)
++{
++	struct mcp25xxfd_priv *priv = spi_get_drvdata(spi);
++	struct mcp25xxfd_trigger_tx_message *txm =
++		&priv->spi_transmit_fifos[fifo - priv->fifos.tx_fifo_start];
++	int ret;
++
++	/* add fifo as seq */
++	obj->header.flags |= fifo << CAN_OBJ_FLAGS_SEQ_SHIFT;
++
++	/* transform to le32 */
++	mcp25xxfd_obj_to_le(&obj->header);
++
++	/* fill in details */
++	memcpy(txm->fill_obj, obj, sizeof(struct mcp25xxfd_obj_tx));
++	memset(txm->fill_data, 0, priv->fifos.payload_size);
++	memcpy(txm->fill_data, data, len);
++
++	/* transfers to FIFO RAM has to be multiple of 4 */
++	txm->fill_xfer.len =
++		2 + sizeof(struct mcp25xxfd_obj_tx) + ALIGN(len, 4);
++
++	/* and transmit asyncroniously */
++	ret = spi_async(spi, &txm->msg);
++	if (ret)
++		return NETDEV_TX_BUSY;
++
++	return NETDEV_TX_OK;
++}
++
++static int mcp25xxfd_transmit_fdmessage(struct spi_device *spi, int fifo,
++					struct canfd_frame *frame)
++{
++	struct mcp25xxfd_priv *priv = spi_get_drvdata(spi);
++	struct mcp25xxfd_obj_tx obj;
++	int dlc = can_len2dlc(frame->len);
++	u32 flags;
++
++	frame->len = can_dlc2len(dlc);
++
++	mcp25xxfd_canid_to_mcpid(frame->can_id, &obj.header.id, &flags);
++
++	flags |= dlc << CAN_OBJ_FLAGS_DLC_SHIFT;
++	flags |= (frame->can_id & CAN_EFF_FLAG) ? CAN_OBJ_FLAGS_IDE : 0;
++	flags |= (frame->can_id & CAN_RTR_FLAG) ? CAN_OBJ_FLAGS_RTR : 0;
++	if (frame->flags & CANFD_BRS) {
++		flags |= CAN_OBJ_FLAGS_BRS;
++		priv->stats.tx_brs_count++;
++	}
++	flags |= (frame->flags & CANFD_ESI) ? CAN_OBJ_FLAGS_ESI : 0;
++	flags |= CAN_OBJ_FLAGS_FDF;
++
++	priv->stats.tx_fd_count++;
++	priv->stats.tx_dlc_usage[dlc]++;
++
++	obj.header.flags = flags;
++
++	return mcp25xxfd_transmit_message_common(spi, fifo, &obj,
++						 frame->len, frame->data);
++}
++
++static int mcp25xxfd_transmit_message(struct spi_device *spi, int fifo,
++				      struct can_frame *frame)
++{
++	struct mcp25xxfd_priv *priv = spi_get_drvdata(spi);
++	struct mcp25xxfd_obj_tx obj;
++	u32 flags;
++
++	if (frame->can_dlc > 8)
++		frame->can_dlc = 8;
++
++	priv->stats.tx_dlc_usage[frame->can_dlc]++;
++
++	mcp25xxfd_canid_to_mcpid(frame->can_id, &obj.header.id, &flags);
++
++	flags |= frame->can_dlc << CAN_OBJ_FLAGS_DLC_SHIFT;
++	flags |= (frame->can_id & CAN_EFF_FLAG) ? CAN_OBJ_FLAGS_IDE : 0;
++	flags |= (frame->can_id & CAN_RTR_FLAG) ? CAN_OBJ_FLAGS_RTR : 0;
++
++	obj.header.flags = flags;
++
++	return mcp25xxfd_transmit_message_common(spi, fifo, &obj,
++						 frame->can_dlc, frame->data);
++}
++
++static bool mcp25xxfd_is_last_txfifo(struct spi_device *spi,
++				     int fifo)
++{
++	struct mcp25xxfd_priv *priv = spi_get_drvdata(spi);
++
++	return (fifo ==
++		(priv->fifos.tx_fifo_start + priv->fifos.tx_fifos - 1));
++}
++
++static netdev_tx_t mcp25xxfd_start_xmit(struct sk_buff *skb,
++					struct net_device *net)
++{
++	struct mcp25xxfd_priv *priv = netdev_priv(net);
++	struct spi_device *spi = priv->spi;
++	u32 pending_mask;
++	int fifo;
++	int ret;
++
++	if (can_dropped_invalid_skb(net, skb))
++		return NETDEV_TX_OK;
++
++	if (priv->can.state == CAN_STATE_BUS_OFF) {
++		mcp25xxfd_stop_queue(priv->net);
++		return NETDEV_TX_BUSY;
++	}
++
++	/* get effective mask */
++	pending_mask = priv->fifos.tx_pending_mask |
++		priv->fifos.tx_submitted_mask;
++
++	/* decide on fifo to assign */
++	if (pending_mask)
++		fifo = fls(pending_mask);
++	else
++		fifo = priv->fifos.tx_fifo_start;
++
++	/* handle error - this should not happen... */
++	if (fifo >= priv->fifos.tx_fifo_start + priv->fifos.tx_fifos) {
++		dev_err(&spi->dev,
++			"reached tx-fifo %i, which is not valid\n",
++			fifo);
++		return NETDEV_TX_BUSY;
++	}
++
++	/* if we are the last one, then stop the queue */
++	if (mcp25xxfd_is_last_txfifo(spi, fifo))
++		mcp25xxfd_stop_queue(priv->net);
++
++	/* mark as submitted */
++	priv->fifos.tx_submitted_mask |= BIT(fifo);
++	priv->stats.fifo_usage[fifo]++;
++
++	/* now process it for real */
++	if (can_is_canfd_skb(skb))
++		ret = mcp25xxfd_transmit_fdmessage(spi, fifo,
++						   (struct canfd_frame *)
++						   skb->data);
++	else
++		ret = mcp25xxfd_transmit_message(spi, fifo,
++						 (struct can_frame *)
++						 skb->data);
++
++	/* keep it for reference until the message really got transmitted */
++	if (ret == NETDEV_TX_OK)
++		can_put_echo_skb(skb, priv->net, fifo);
++
++	return ret;
++}
++
++/* CAN RX Related */
++
++static int mcp25xxfd_can_transform_rx_fd(struct spi_device *spi,
++					 struct mcp25xxfd_obj_rx *rx)
++{
++	struct mcp25xxfd_priv *priv = spi_get_drvdata(spi);
++	struct canfd_frame *frame;
++	struct sk_buff *skb;
++	u32 flags = rx->header.flags;
++	int dlc;
++
++	/* allocate the skb buffer */
++	skb = alloc_canfd_skb(priv->net, &frame);
++	if (!skb) {
++		dev_err(&spi->dev, "cannot allocate RX skb\n");
++		priv->net->stats.rx_dropped++;
++		return -ENOMEM;
++	}
++
++	mcp25xxfd_mcpid_to_canid(rx->header.id, flags, &frame->can_id);
++	frame->flags |= (flags & CAN_OBJ_FLAGS_BRS) ? CANFD_BRS : 0;
++	frame->flags |= (flags & CAN_OBJ_FLAGS_ESI) ? CANFD_ESI : 0;
++
++	dlc = (flags & CAN_OBJ_FLAGS_DLC_MASK) >> CAN_OBJ_FLAGS_DLC_SHIFT;
++	frame->len = can_dlc2len(dlc);
++
++	memcpy(frame->data, rx->data, frame->len);
++
++	priv->stats.rx_fd_count++;
++	priv->net->stats.rx_packets++;
++	priv->net->stats.rx_bytes += frame->len;
++	if (rx->header.flags & CAN_OBJ_FLAGS_BRS)
++		priv->stats.rx_brs_count++;
++	priv->stats.rx_dlc_usage[dlc]++;
++
++	can_led_event(priv->net, CAN_LED_EVENT_RX);
++
++	netif_rx_ni(skb);
++
++	return 0;
++}
++
++static int mcp25xxfd_can_transform_rx_normal(struct spi_device *spi,
++					     struct mcp25xxfd_obj_rx *rx)
++{
++	struct mcp25xxfd_priv *priv = spi_get_drvdata(spi);
++	struct sk_buff *skb;
++	struct can_frame *frame;
++	u32 flags = rx->header.flags;
++	int len;
++	int dlc;
++
++	/* allocate the skb buffer */
++	skb = alloc_can_skb(priv->net, &frame);
++	if (!skb) {
++		dev_err(&spi->dev, "cannot allocate RX skb\n");
++		priv->net->stats.rx_dropped++;
++		return -ENOMEM;
++	}
++
++	mcp25xxfd_mcpid_to_canid(rx->header.id, flags, &frame->can_id);
++
++	dlc = (flags & CAN_OBJ_FLAGS_DLC_MASK) >> CAN_OBJ_FLAGS_DLC_SHIFT;
++	frame->can_dlc = dlc;
++
++	len = can_dlc2len(frame->can_dlc);
++
++	memcpy(frame->data, rx->data, len);
++
++	priv->net->stats.rx_packets++;
++	priv->net->stats.rx_bytes += len;
++	priv->stats.rx_dlc_usage[dlc]++;
++
++	can_led_event(priv->net, CAN_LED_EVENT_RX);
++
++	netif_rx_ni(skb);
++
++	return 0;
++}
++
++static int mcp25xxfd_process_queued_rx(struct spi_device *spi,
++				       struct mcp25xxfd_obj_ts *obj)
++{
++	struct mcp25xxfd_obj_rx *rx = container_of(obj,
++						   struct mcp25xxfd_obj_rx,
++						   header);
++
++	if (obj->flags & CAN_OBJ_FLAGS_FDF)
++		return mcp25xxfd_can_transform_rx_fd(spi, rx);
++	else
++		return mcp25xxfd_can_transform_rx_normal(spi, rx);
++}
++
++static int mcp25xxfd_normal_release_fifos(struct spi_device *spi,
++					  int start, int end)
++{
++	struct mcp25xxfd_priv *priv = spi_get_drvdata(spi);
++	int ret;
++
++	/* release each fifo in a separate transfer */
++	for (; start < end ; start++) {
++		ret = mcp25xxfd_cmd_write_mask(spi, CAN_FIFOCON(start),
++					       CAN_FIFOCON_UINC,
++					       CAN_FIFOCON_UINC,
++					       priv->spi_speed_hz);
++		if (ret)
++			return ret;
++	}
++
++	return 0;
++}
++
++/* unfortunately the CAN_FIFOCON are not directly consecutive
++ * so the optimization of "clearing all in one spi_transfer"
++ * would produce an overhead of 11 unnecessary bytes/fifo
++ * - transferring 14 (2 cmd + 12 data) bytes
++ * instead of just 3 (2 + 1).
++ * On some slower systems this may still be beneficial,
++ * but it is not good enough for the generic case.
++ * On a Raspberry Pi CM the timings for clearing 3 fifos
++ * (at 12.5MHz SPI clock speed) are:
++ * * normal:
++ *   * 3 spi transfers
++ *   * 9 bytes total
++ *   * 36.74us from first CS low to last CS high
++ *   * individual CS: 9.14us, 5.74us and 5.16us
++ *   * 77.02us from CS up of fifo transfer to last release CS up
++ * * bulk:
++ *   * 1 spi transfer
++ *   * 27 bytes total
++ *   * 29.06us CS Low
++ *   * 78.28us from CS up of fifo transfer to last release CS up
++ * this obviously varies with SPI_clock speed
++ * - the slower the clock the less efficient the optimization.
++ * similarly the faster the CPU (and bigger the code cache) the
++ * less effcient the optimization - the above case is border line.
++ */
++
++#define FIFOCON_SPACING (CAN_FIFOCON(1) - CAN_FIFOCON(0))
++#define FIFOCON_SPACINGW (FIFOCON_SPACING / sizeof(u32))
++
++static int mcp25xxfd_bulk_release_fifos(struct spi_device *spi,
++					int start, int end)
++{
++	struct mcp25xxfd_priv *priv = spi_get_drvdata(spi);
++	int i;
++	int ret;
++
++	/* calculate start address and length */
++	int fifos = end - start;
++	int first_byte = mcp25xxfd_first_byte(CAN_FIFOCON_UINC);
++	int addr = CAN_FIFOCON(start);
++	int len = 1 + (fifos - 1) * FIFOCON_SPACING;
++
++	/* the worsted case buffer */
++	u32 buf[32 * FIFOCON_SPACINGW], base;
++
++	base = (priv->fifos.payload_mode << CAN_FIFOCON_PLSIZE_SHIFT) |
++		((priv->fifos.rx_fifo_depth - 1) << CAN_FIFOCON_FSIZE_SHIFT) |
++		CAN_FIFOCON_RXTSEN | /* RX timestamps */
++		CAN_FIFOCON_UINC |
++		CAN_FIFOCON_TFERFFIE | /* FIFO Full */
++		CAN_FIFOCON_TFHRFHIE | /* FIFO Half Full*/
++		CAN_FIFOCON_TFNRFNIE; /* FIFO not empty */
++
++	memset(buf, 0, sizeof(buf));
++	for (i = 0; i < end - start ; i++) {
++		if (i == priv->fifos.rx_fifos - 1)
++			base |= CAN_FIFOCON_RXOVIE;
++		buf[FIFOCON_SPACINGW * i] = cpu_to_le32(base);
++	}
++
++	ret = mcp25xxfd_cmd_writen(spi, addr + first_byte,
++				   (u8 *)buf + first_byte,
++				   len,
++				   priv->spi_speed_hz);
++	if (ret)
++		return ret;
++
++	return 0;
++}
++
++/* queued FIFO handling for release to system */
++
++static void mcp25xxfd_clear_queued_fifos(struct spi_device *spi)
++{
++	struct mcp25xxfd_priv *priv = spi_get_drvdata(spi);
++
++	/* prepare rfi - mostly used for sorting */
++	priv->queued_fifos.rx_count = 0;
++}
++
++static void mcp25xxfd_addto_queued_fifos(struct spi_device *spi,
++					 struct mcp25xxfd_obj_ts *obj)
++{
++	struct mcp25xxfd_priv *priv = spi_get_drvdata(spi);
++	struct mcp25xxfd_read_fifo_info *rfi = &priv->queued_fifos;
++
++	/* timestamps must ignore the highest byte, so we shift it,
++	 * so that it still compares correctly
++	 */
++	obj->ts <<= 8;
++
++	/* add pointer to queued array-list */
++	rfi->rxb[rfi->rx_count] = obj;
++	rfi->rx_count++;
++}
++
++static int mcp25xxfd_process_queued_tef(struct spi_device *spi,
++					struct mcp25xxfd_obj_ts *obj)
++{
++	struct mcp25xxfd_priv *priv = spi_get_drvdata(spi);
++	struct mcp25xxfd_obj_tef *tef = container_of(obj,
++						     struct mcp25xxfd_obj_tef,
++						     header);
++	int dlc = (obj->flags & CAN_OBJ_FLAGS_DLC_MASK)
++		>> CAN_OBJ_FLAGS_DLC_SHIFT;
++	int fifo = (tef->header.flags & CAN_OBJ_FLAGS_SEQ_MASK) >>
++		CAN_OBJ_FLAGS_SEQ_SHIFT;
++
++	/* update counters */
++	priv->net->stats.tx_packets++;
++	priv->net->stats.tx_bytes += can_dlc2len(dlc);
++	if (obj->flags & CAN_OBJ_FLAGS_FDF)
++		priv->stats.tx_fd_count++;
++	if (obj->flags & CAN_OBJ_FLAGS_BRS)
++		priv->stats.tx_brs_count++;
++	priv->stats.tx_dlc_usage[dlc]++;
++
++	/* release it */
++	can_get_echo_skb(priv->net, fifo);
++
++	can_led_event(priv->net, CAN_LED_EVENT_TX);
++
++	return 0;
++}
++
++static int mcp25xxfd_compare_obj_ts(const void *a, const void *b)
++{
++	const struct mcp25xxfd_obj_ts * const *rxa = a;
++	const struct mcp25xxfd_obj_ts * const *rxb = b;
++	/* using signed here to handle rollover correctly */
++	s32 ats = (*rxa)->ts;
++	s32 bts = (*rxb)->ts;
++
++	if (ats < bts)
++		return -1;
++	if (ats > bts)
++		return 1;
++	return 0;
++}
++
++static int mcp25xxfd_process_queued_fifos(struct spi_device *spi)
++{
++	struct mcp25xxfd_priv *priv = spi_get_drvdata(spi);
++	struct mcp25xxfd_read_fifo_info *rfi = &priv->queued_fifos;
++	int i;
++	int ret;
++
++	/* sort the fifos (rx and TEF) by receive timestamp */
++	sort(rfi->rxb, rfi->rx_count, sizeof(struct mcp25xxfd_obj_ts *),
++	     mcp25xxfd_compare_obj_ts, NULL);
++
++	/* process the recived fifos */
++	for (i = 0; i < rfi->rx_count ; i++) {
++		if (rfi->rxb[i]->flags & CAN_OBJ_FLAGS_CUSTOM_ISTEF)
++			ret = mcp25xxfd_process_queued_tef(spi, rfi->rxb[i]);
++		else
++			ret = mcp25xxfd_process_queued_rx(spi, rfi->rxb[i]);
++		if (ret)
++			return ret;
++	}
++
++	/* clear queued fifos */
++	mcp25xxfd_clear_queued_fifos(spi);
++
++	return 0;
++}
++
++static int mcp25xxfd_transform_rx(struct spi_device *spi,
++				  struct mcp25xxfd_obj_rx *rx)
++{
++	int dlc;
++
++	/* transform the data to system byte order */
++	mcp25xxfd_obj_ts_from_le(&rx->header);
++
++	/* add the object to the list */
++	mcp25xxfd_addto_queued_fifos(spi, &rx->header);
++
++	/* calc length and return it */
++	dlc = (rx->header.flags & CAN_OBJ_FLAGS_DLC_MASK)
++		>> CAN_OBJ_FLAGS_DLC_SHIFT;
++	return can_dlc2len(dlc);
++}
++
++/* read_fifo implementations
++ *
++ * read_fifos is a simple implementation, that:
++ *   * loops all fifos
++ *     * read header + some data-bytes (8)
++ *     * read rest of data-bytes bytes
++ *     * release fifo
++ *   for 3 can frames dlc<=8 to read here we have:
++ *     * 6 spi transfers
++ *     * 75 bytes (= 3 * (2 + 12 + 8) bytes + 3 * 3 bytes)
++ *   for 3 canfd frames dlc>8 to read here we have:
++ *     * 9 spi transfers
++ *     * 81 (= 3 * (2 + 12 + 8 + 2) bytes + 3 * 3 bytes) + 3 * extra payload
++ *     this only transfers the required size of bytes on the spi bus.
++ *
++ * bulk_read_fifos is an optimization that is most practical for
++ * Can2.0 busses, but may also be practical for CanFD busses that
++ * have a high average payload data size.
++ *
++ * It will read all of the fifo data in a single spi_transfer:
++ *   * read all fifos in one go (as long as these are ajacent to each other)
++ *   * loop all fifos
++ *     * release fifo
++ *   for 3 can2.0 frames to read here we have:
++ *     * 4 spi transfers
++ *     * 71 bytes (= 2 + 3 * (12 + 8) bytes + 3 * 3 bytes)
++ *   for 3 canfd frames to read here we have:
++ *     * 4 spi transfers
++ *     * 230 bytes (= 2 + 3 * (12 + 64) bytes)
++ *     obviously this reads way too many bytes for framesizes <=32 bytes,
++ *     but it avoids the overhead on the CPU side and may even trigger
++ *     DMA transfers due to the high byte count, which release CPU cycles.
++ *
++ * This optimization will also be efficient for cases where a high
++ * percentage of canFD frames has a dlc-size > 8.
++ * This mode is used for Can2.0 configured busses.
++ *
++ * For now this option can get forced for CanFD via a module parameter.
++ * In the future there may be some heuristics that could trigger a usage
++ * of this mode as well in some circumstances.
++ *
++ * Note: there is a second optimization for release fifo as well,
++ *       but it is not as efficient as this optimization for the
++ *       non-CanFD case - see mcp25xxfd_bulk_release_fifos
++ */
++
++static int mcp25xxfd_read_fifos(struct spi_device *spi)
++{
++	struct mcp25xxfd_priv *priv = spi_get_drvdata(spi);
++	int fifo_header_size = sizeof(struct mcp25xxfd_obj_rx);
++	int fifo_min_payload_size = 8;
++	int fifo_min_size = fifo_header_size + fifo_min_payload_size;
++	int fifo_max_payload_size =
++		((priv->can.ctrlmode & CAN_CTRLMODE_FD) ? 64 : 8);
++	u32 mask = priv->status.rxif;
++	struct mcp25xxfd_obj_rx *rx;
++	int i, len;
++	int ret;
++	u32 fifo_address;
++	u8 *data;
++
++	/* read all the "open" segments in big chunks */
++	for (i = priv->fifos.rx_fifo_start + priv->fifos.rx_fifos - 1;
++	     i >= priv->fifos.rx_fifo_start;
++	     i--) {
++		if (!(mask & BIT(i)))
++			continue;
++		/* the fifo to fill */
++		rx = (struct mcp25xxfd_obj_rx *)
++			(priv->fifos.fifo_data + priv->fifos.fifo_address[i]);
++		/* read the minimal payload */
++		fifo_address = priv->fifos.fifo_address[i];
++		ret = mcp25xxfd_cmd_readn(spi,
++					  FIFO_DATA(fifo_address),
++					  rx,
++					  fifo_min_size,
++					  priv->spi_speed_hz);
++		if (ret)
++			return ret;
++		/* process fifo stats and get length */
++		len = min_t(int, mcp25xxfd_transform_rx(spi, rx),
++			    fifo_max_payload_size);
++
++		/* read extra payload if needed */
++		if (len > fifo_min_payload_size) {
++			data = &rx->data[fifo_min_payload_size];
++			ret = mcp25xxfd_cmd_readn(spi,
++						  FIFO_DATA(fifo_address +
++							    fifo_min_size),
++						  data,
++						  len - fifo_min_payload_size,
++						  priv->spi_speed_hz);
++			if (ret)
++				return ret;
++		}
++		/* release fifo */
++		ret = mcp25xxfd_normal_release_fifos(spi, i, i + 1);
++		if (ret)
++			return ret;
++		/* increment fifo_usage */
++		priv->stats.fifo_usage[i]++;
++	}
++
++	return 0;
++}
++
++static int mcp25xxfd_bulk_read_fifo_range(struct spi_device *spi,
++					  int start, int end)
++{
++	struct mcp25xxfd_priv *priv = spi_get_drvdata(spi);
++	const int fifo_header_size = sizeof(struct mcp25xxfd_obj_rx);
++	const int fifo_max_payload_size = priv->fifos.payload_size;
++	const int fifo_max_size = fifo_header_size + fifo_max_payload_size;
++	struct mcp25xxfd_obj_rx *rx;
++	int i;
++	int ret;
++
++	/* now we got start and end, so read the range */
++	ret = mcp25xxfd_cmd_readn(spi,
++				  FIFO_DATA(priv->fifos.fifo_address[start]),
++				  priv->fifos.fifo_data +
++				  priv->fifos.fifo_address[start],
++				  (end - start) * fifo_max_size,
++				  priv->spi_speed_hz);
++	if (ret)
++		return ret;
++
++	/* clear all the fifos in range */
++	if (use_bulk_release_fifos)
++		ret = mcp25xxfd_bulk_release_fifos(spi, start, end);
++	else
++		ret = mcp25xxfd_normal_release_fifos(spi, start, end);
++	if (ret)
++		return ret;
++
++	/* preprocess data */
++	for (i = start; i < end ; i++) {
++		/* store the fifo to process */
++		rx = (struct mcp25xxfd_obj_rx *)
++			(priv->fifos.fifo_data + priv->fifos.fifo_address[i]);
++		/* process fifo stats */
++		mcp25xxfd_transform_rx(spi, rx);
++		/* increment usage */
++		priv->stats.fifo_usage[i]++;
++	}
++
++	return 0;
++}
++
++static int mcp25xxfd_bulk_read_fifos(struct spi_device *spi)
++{
++	struct mcp25xxfd_priv *priv = spi_get_drvdata(spi);
++	u32 mask = priv->status.rxif;
++	int i, start, end;
++	int ret;
++
++	/* find blocks of set bits top down */
++	for (i = priv->fifos.rx_fifo_start + priv->fifos.rx_fifos - 1;
++	     mask && (i >= priv->fifos.rx_fifo_start);
++	     i--) {
++		/* if the bit is 0 then continue loop to find a 1 */
++		if ((mask & BIT(i)) == 0)
++			continue;
++
++		/* so we found a non-0 bit - this is start and end */
++		start = i;
++		end = i;
++
++		/* find the first bit set */
++		for (; mask & BIT(i); i--) {
++			mask &= ~BIT(i);
++			start = i;
++		}
++
++		/* now process that range */
++		ret = mcp25xxfd_bulk_read_fifo_range(spi, start, end + 1);
++		if (ret)
++			return ret;
++	}
++
++	return 0;
++}
++
++static int mcp25xxfd_can_ist_handle_rxif(struct spi_device *spi)
++{
++	struct mcp25xxfd_priv *priv = spi_get_drvdata(spi);
++	u32 mask = priv->status.rxif;
++	int ret;
++
++	if (!mask)
++		return 0;
++
++	/* read all the fifos - for non-fd case use bulk read optimization */
++	if (((priv->can.ctrlmode & CAN_CTRLMODE_FD) == 0) ||
++	    use_complete_fdfifo_read)
++		ret = mcp25xxfd_bulk_read_fifos(spi);
++	else
++		ret = mcp25xxfd_read_fifos(spi);
++
++	return 0;
++}
++
++static void mcp25xxfd_mark_tx_processed(struct spi_device *spi,
++					int fifo)
++{
++	struct mcp25xxfd_priv *priv = spi_get_drvdata(spi);
++
++	/* set mask */
++	priv->fifos.tx_processed_mask |= BIT(fifo);
++
++	/* check if we should reenable the TX-queue */
++	if (mcp25xxfd_is_last_txfifo(spi, fifo))
++		priv->tx_queue_status = TX_QUEUE_STATUS_NEEDS_START;
++}
++
++static int mcp25xxfd_can_ist_handle_tefif_handle_single(struct spi_device *spi)
++{
++	struct mcp25xxfd_priv *priv = spi_get_drvdata(spi);
++	struct mcp25xxfd_obj_tef *tef;
++	int fifo;
++	int ret;
++
++	/* calc address in address space */
++	tef = (struct mcp25xxfd_obj_tef *)(priv->fifos.fifo_data +
++					   priv->fifos.tef_address);
++
++	/* read all the object data */
++	ret = mcp25xxfd_cmd_readn(spi,
++				  FIFO_DATA(priv->fifos.tef_address),
++				  tef,
++				  /* we do not read the last byte of the ts
++				   * to avoid MAB issiues
++				   */
++				  sizeof(*tef) - 1,
++				  priv->spi_speed_hz);
++	/* increment the counter to read next */
++	ret = mcp25xxfd_cmd_write_mask(spi,
++				       CAN_TEFCON,
++				       CAN_TEFCON_UINC,
++				       CAN_TEFCON_UINC,
++				       priv->spi_speed_hz);
++
++	/* transform the data to system byte order */
++	mcp25xxfd_obj_ts_from_le(&tef->header);
++
++	fifo = (tef->header.flags & CAN_OBJ_FLAGS_SEQ_MASK) >>
++		CAN_OBJ_FLAGS_SEQ_SHIFT;
++
++	/* submit to queue */
++	tef->header.flags |= CAN_OBJ_FLAGS_CUSTOM_ISTEF;
++	mcp25xxfd_addto_queued_fifos(spi, &tef->header);
++
++	/* increment tef_address with rollover */
++	priv->fifos.tef_address += sizeof(*tef);
++	if (priv->fifos.tef_address > priv->fifos.tef_address_end)
++		priv->fifos.tef_address =
++			priv->fifos.tef_address_start;
++
++	/* and mark as processed right now */
++	mcp25xxfd_mark_tx_processed(spi, fifo);
++
++	return 0;
++}
++
++static int mcp25xxfd_can_ist_handle_tefif_conservative(struct spi_device *spi)
++{
++	struct mcp25xxfd_priv *priv = spi_get_drvdata(spi);
++	u32 val[2];
++	int ret;
++
++	while (1) {
++		/* get the current TEFSTA and TEFUA */
++		ret = mcp25xxfd_cmd_readn(priv->spi,
++					  CAN_TEFSTA,
++					  val,
++					  8,
++					  priv->spi_speed_hz);
++		if (ret)
++			return ret;
++		mcp25xxfd_convert_to_cpu(val, 2);
++
++		/* check for interrupt flags */
++		if (!(val[0] & CAN_TEFSTA_TEFNEIF))
++			return 0;
++
++		if (priv->fifos.tef_address != val[1]) {
++			dev_err(&spi->dev,
++				"TEF Address mismatch - read: %04x calculated: %04x\n",
++				val[1], priv->fifos.tef_address);
++			priv->fifos.tef_address = val[1];
++		}
++
++		ret = mcp25xxfd_can_ist_handle_tefif_handle_single(spi);
++		if (ret)
++			return ret;
++	}
++
++	return 0;
++}
++
++static int mcp25xxfd_can_ist_handle_tefif_count(struct spi_device *spi,
++						int count)
++{
++	int i;
++	int ret;
++
++	/* now clear TEF for each */
++	/* TODO: optimize for BULK reads, as we (hopefully) know COUNT */
++	for (i = 0; i < count; i++) {
++		/* handle a single TEF */
++		ret = mcp25xxfd_can_ist_handle_tefif_handle_single(spi);
++		if (ret)
++			return ret;
++	}
++
++	return 0;
++}
++
++static int mcp25xxfd_can_ist_handle_tefif(struct spi_device *spi)
++{
++	struct mcp25xxfd_priv *priv = spi_get_drvdata(spi);
++	u32 pending = priv->fifos.tx_pending_mask_in_irq &
++		(~priv->fifos.tx_processed_mask);
++	int count;
++
++	/* calculate the number of fifos that have been processed */
++	count = hweight_long(pending);
++	count -= hweight_long(priv->status.txreq & pending);
++
++	/* in case of unexpected results handle "safely" */
++	if (count <= 0)
++		return mcp25xxfd_can_ist_handle_tefif_conservative(spi);
++
++	return mcp25xxfd_can_ist_handle_tefif_count(spi, count);
++}
++
++static int mcp25xxfd_can_ist_handle_txatif_fifo(struct spi_device *spi,
++						int fifo)
++{
++	struct mcp25xxfd_priv *priv = spi_get_drvdata(spi);
++	u32 val;
++	int ret;
++
++	/* read fifo status */
++	ret = mcp25xxfd_cmd_read(spi,
++				 CAN_FIFOSTA(fifo),
++				 &val,
++				 priv->spi_speed_hz);
++	if (ret)
++		return ret;
++
++	/* clear the relevant interrupt flags */
++	ret = mcp25xxfd_cmd_write_mask(spi,
++				       CAN_FIFOSTA(fifo),
++				       0,
++				       CAN_FIFOSTA_TXABT |
++				       CAN_FIFOSTA_TXLARB |
++				       CAN_FIFOSTA_TXERR |
++				       CAN_FIFOSTA_TXATIF,
++				       priv->spi_speed_hz);
++
++	/* for specific cases we could trigger a retransmit
++	 * instead of an abort.
++	 */
++
++	/* and we release it from the echo_skb buffer
++	 * NOTE: this is one place where packet delivery will not
++	 * be ordered, as we do not have any timing information
++	 * when this occurred
++	 */
++	can_get_echo_skb(priv->net, fifo);
++
++	/* but we need to run a bit of cleanup */
++	priv->status.txif &= ~BIT(fifo);
++	priv->net->stats.tx_aborted_errors++;
++
++	/* mark the fifo as processed */
++	 mcp25xxfd_mark_tx_processed(spi, fifo);
++
++	/* handle all the known cases accordingly - ignoring FIFO full */
++	val &= CAN_FIFOSTA_TXABT |
++		CAN_FIFOSTA_TXLARB |
++		CAN_FIFOSTA_TXERR;
++	switch (val) {
++	case CAN_FIFOSTA_TXERR:
++		break;
++	default:
++		dev_warn_ratelimited(&spi->dev,
++				     "Unknown TX-Fifo abort condition: %08x - stopping tx-queue\n",
++				     val);
++		break;
++	}
++
++	return 0;
++}
++
++static int mcp25xxfd_can_ist_handle_txatif(struct spi_device *spi)
++{
++	struct mcp25xxfd_priv *priv = spi_get_drvdata(spi);
++	int i, fifo;
++	int ret;
++
++	/* process all the fifos with that flag set */
++	for (i = 0, fifo = priv->fifos.tx_fifo_start;
++	    i < priv->fifos.tx_fifos; i++, fifo++) {
++		if (priv->status.txatif & BIT(fifo)) {
++			ret = mcp25xxfd_can_ist_handle_txatif_fifo(spi, fifo);
++			if (ret)
++				return ret;
++		}
++	}
++
++	return 0;
++}
++
++static void mcp25xxfd_error_skb(struct net_device *net)
++{
++	struct mcp25xxfd_priv *priv = netdev_priv(net);
++	struct sk_buff *skb;
++	struct can_frame *frame;
++
++	skb = alloc_can_err_skb(net, &frame);
++	if (skb) {
++		frame->can_id = priv->can_err_id;
++		memcpy(frame->data, priv->can_err_data, 8);
++		netif_rx_ni(skb);
++	} else {
++		netdev_err(net, "cannot allocate error skb\n");
++	}
++}
++
++static int mcp25xxfd_can_ist_handle_rxovif(struct spi_device *spi)
++{
++	struct mcp25xxfd_priv *priv = spi_get_drvdata(spi);
++	u32 mask = priv->status.rxovif;
++	int i;
++	int ret;
++
++	/* clear all fifos that have an overflow bit set */
++	for (i = 0; i < 32; i++) {
++		if (mask & BIT(i)) {
++			ret = mcp25xxfd_cmd_write_mask(spi,
++						       CAN_FIFOSTA(i),
++						       0,
++						       CAN_FIFOSTA_RXOVIF,
++						       priv->spi_speed_hz);
++			if (ret)
++				return ret;
++			/* update statistics */
++			priv->net->stats.rx_over_errors++;
++			priv->net->stats.rx_errors++;
++			priv->stats.rx_overflow++;
++			priv->can_err_id |= CAN_ERR_CRTL;
++			priv->can_err_data[1] |= CAN_ERR_CRTL_RX_OVERFLOW;
++		}
++	}
++
++	return 0;
++}
++
++static int mcp25xxfd_can_ist_handle_modif(struct spi_device *spi)
++{
++	struct mcp25xxfd_priv *priv = spi_get_drvdata(spi);
++	int omode = priv->active_can_mode;
++	int mode;
++	int ret;
++
++	/* Note that this irq does not get triggered in all situations
++	 * for example SERRIF will move to RESTICTED or LISTENONLY
++	 * but MODIF will not be raised!
++	 */
++
++	/* get the mode */
++	ret = mcp25xxfd_get_opmode(spi, &mode, priv->spi_speed_hz);
++	if (ret)
++		return ret;
++
++	/* if we are restricted, then return to "normal" mode */
++	if (mode == CAN_CON_MODE_RESTRICTED)
++		return mcp25xxfd_set_normal_opmode(spi);
++
++	/* the controller itself will transition to sleep, so we ignore it */
++	if (mode == CAN_CON_MODE_SLEEP)
++		return 0;
++
++	/* switches to the same mode as before are also ignored
++	 * - this typically happens if the driver is shortly
++	 *   switching to a different mode and then returning to the
++	 *   original mode
++	 */
++	if (mode == omode)
++		return 0;
++
++	/* these we need to handle correctly, so warn and give context */
++	dev_warn(&spi->dev,
++		 "Controller unexpectedly switched from mode %s(%u) to %s(%u)\n",
++		 mcp25xxfd_mode_names[omode], omode,
++		 mcp25xxfd_mode_names[mode], mode);
++
++	return 0;
++}
++
++static int mcp25xxfd_can_ist_handle_cerrif(struct spi_device *spi)
++{
++	struct mcp25xxfd_priv *priv = spi_get_drvdata(spi);
++
++	/* in principle we could also delay reading bdiag registers
++	 * until we get here - it would add some extra delay in the
++	 * error case, but be slightly faster in the "normal" case.
++	 * slightly faster would be saving 8 bytes of spi transfer.
++	 */
++
++	dev_err_ratelimited(&spi->dev, "CAN Bus error\n");
++	priv->can_err_id |= CAN_ERR_BUSERROR;
++
++	if (priv->status.bdiag1 &
++	    (CAN_BDIAG1_DBIT0ERR | CAN_BDIAG1_NBIT0ERR)) {
++		priv->can_err_id |= CAN_ERR_BUSERROR;
++		priv->can_err_data[2] |= CAN_ERR_PROT_BIT0;
++		priv->bdiag1_clear_mask |= CAN_BDIAG1_DBIT0ERR |
++			CAN_BDIAG1_NBIT0ERR;
++	}
++	if (priv->status.bdiag1 &
++	    (CAN_BDIAG1_DBIT1ERR | CAN_BDIAG1_NBIT1ERR)) {
++		priv->can_err_id |= CAN_ERR_BUSERROR;
++		priv->can_err_data[2] |= CAN_ERR_PROT_BIT1;
++		priv->bdiag1_clear_mask |= CAN_BDIAG1_DBIT1ERR |
++			CAN_BDIAG1_NBIT1ERR;
++	}
++	if (priv->status.bdiag1 &
++	    (CAN_BDIAG1_DSTUFERR | CAN_BDIAG1_NSTUFERR)) {
++		priv->can_err_id |= CAN_ERR_BUSERROR;
++		priv->can_err_data[2] |= CAN_ERR_PROT_STUFF;
++		priv->bdiag1_clear_mask |= CAN_BDIAG1_DSTUFERR |
++			CAN_BDIAG1_NSTUFERR;
++	}
++	if (priv->status.bdiag1 &
++	    (CAN_BDIAG1_DFORMERR | CAN_BDIAG1_NFORMERR)) {
++		priv->can_err_id |= CAN_ERR_BUSERROR;
++		priv->can_err_data[2] |= CAN_ERR_PROT_FORM;
++		priv->bdiag1_clear_mask |= CAN_BDIAG1_DFORMERR |
++			CAN_BDIAG1_NFORMERR;
++	}
++	if (priv->status.bdiag1 & CAN_BDIAG1_NACKERR) {
++		priv->can_err_id |= CAN_ERR_ACK;
++		priv->bdiag1_clear_mask |= CAN_BDIAG1_NACKERR;
++	}
++
++	return 0;
++}
++
++static int mcp25xxfd_can_ist_handle_eccif(struct spi_device *spi)
++{
++	struct mcp25xxfd_priv *priv = spi_get_drvdata(spi);
++	int ret;
++	u32 val;
++	u32 addr;
++
++	priv->can_err_id |= CAN_ERR_CRTL;
++	priv->can_err_data[1] |= CAN_ERR_CRTL_UNSPEC;
++
++	/* read ECC status register */
++	ret = mcp25xxfd_cmd_read(spi, MCP25XXFD_ECCSTAT, &val,
++				 priv->spi_speed_hz);
++	if (ret)
++		return ret;
++
++	addr = (val & MCP25XXFD_ECCSTAT_ERRADDR_MASK) >>
++		MCP25XXFD_ECCSTAT_ERRADDR_SHIFT;
++
++	dev_err_ratelimited(&spi->dev,
++			    "ECC %s bit error at %03x\n",
++			    (val & MCP25XXFD_ECCSTAT_DEDIF) ?
++			    "double" : "single",
++			    addr);
++
++	return mcp25xxfd_cmd_write(spi, MCP25XXFD_ECCSTAT, 0,
++				 priv->spi_speed_hz);
++}
++
++static int mcp25xxfd_can_ist_handle_serrif_txmab(struct spi_device *spi)
++{
++	struct mcp25xxfd_priv *priv = spi_get_drvdata(spi);
++
++	priv->net->stats.tx_fifo_errors++;
++	priv->net->stats.tx_errors++;
++	priv->stats.tx_mab++;
++
++	return 0;
++}
++
++static int mcp25xxfd_can_ist_handle_serrif_rxmab(struct spi_device *spi)
++{
++	struct mcp25xxfd_priv *priv = spi_get_drvdata(spi);
++
++	priv->net->stats.rx_dropped++;
++	priv->net->stats.rx_errors++;
++	priv->stats.rx_mab++;
++
++	return 0;
++}
++
++static int mcp25xxfd_can_ist_handle_serrif(struct spi_device *spi)
++{
++	struct mcp25xxfd_priv *priv = spi_get_drvdata(spi);
++	u32 clear;
++	int ret;
++
++	/* clear some interrupts immediately,
++	 * so that we get notified if they happen again
++	 */
++	clear = CAN_INT_SERRIF | CAN_INT_MODIF | CAN_INT_IVMIF;
++	ret = mcp25xxfd_cmd_write_mask(spi, CAN_INT,
++				       priv->status.intf & (~clear),
++				       clear,
++				       priv->spi_speed_hz);
++	if (ret)
++		return ret;
++
++	/* Errors here are:
++	 * * Bus Bandwidth Error: when a RX Message Assembly Buffer
++	 *   is still full when the next message has already arrived
++	 *   the recived message shall be ignored
++	 * * TX MAB Underflow: when a TX Message is invalid
++	 *   due to ECC errors or TXMAB underflow
++	 *   in this situatioon the system will transition to
++	 *   Restricted or Listen Only mode
++	 */
++
++	priv->can_err_id |= CAN_ERR_CRTL;
++	priv->can_err_data[1] |= CAN_ERR_CRTL_UNSPEC;
++
++	/* a mode change + invalid message would indicate
++	 * TX MAB Underflow
++	 */
++	if ((priv->status.intf & CAN_INT_MODIF) &&
++	    (priv->status.intf & CAN_INT_IVMIF)) {
++		return mcp25xxfd_can_ist_handle_serrif_txmab(spi);
++	}
++
++	/* for RX there is only the RXIF an indicator
++	 * - surprizingly RX-MAB does not change mode or anything
++	 */
++	if (priv->status.intf & CAN_INT_RXIF)
++		return mcp25xxfd_can_ist_handle_serrif_rxmab(spi);
++
++	/* the final case */
++	dev_warn_ratelimited(&spi->dev,
++			     "unidentified system error - intf =  %08x\n",
++			     priv->status.intf);
++
++	return 0;
++}
++
++static int mcp25xxfd_can_ist_handle_ivmif(struct spi_device *spi)
++{
++	struct mcp25xxfd_priv *priv = spi_get_drvdata(spi);
++
++	/* if we have a systemerror as well, then ignore it */
++	if (priv->status.intf & CAN_INT_SERRIF)
++		return 0;
++
++	/* otherwise it is an RX issue, so account for it here */
++	priv->can_err_id |= CAN_ERR_PROT;
++	priv->can_err_data[2] |= CAN_ERR_PROT_FORM;
++	priv->net->stats.rx_frame_errors++;
++	priv->net->stats.rx_errors++;
++
++	return 0;
++}
++
++static int mcp25xxfd_disable_interrupts(struct spi_device *spi,
++					u32 speed_hz)
++{
++	struct mcp25xxfd_priv *priv = spi_get_drvdata(spi);
++
++	priv->status.intf = 0;
++	return mcp25xxfd_cmd_write(spi, CAN_INT, 0, speed_hz);
++}
++
++static int mcp25xxfd_enable_interrupts(struct spi_device *spi,
++				       u32 speed_hz)
++{
++	struct mcp25xxfd_priv *priv = spi_get_drvdata(spi);
++
++	priv->status.intf = CAN_INT_TEFIE |
++		CAN_INT_RXIE |
++		CAN_INT_MODIE |
++		CAN_INT_SERRIE |
++		CAN_INT_IVMIE |
++		CAN_INT_CERRIE |
++		CAN_INT_RXOVIE |
++		CAN_INT_ECCIE;
++	return mcp25xxfd_cmd_write(spi, CAN_INT,
++				   priv->status.intf,
++				   speed_hz);
++}
++
++static int mcp25xxfd_hw_wake(struct spi_device *spi)
++{
++	return mcp25xxfd_start_clock(spi, MCP25XXFD_CLK_USER_CAN);
++}
++
++static void mcp25xxfd_hw_sleep(struct spi_device *spi)
++{
++	struct mcp25xxfd_priv *priv = spi_get_drvdata(spi);
++
++	/* disable interrupts */
++	mcp25xxfd_disable_interrupts(spi, priv->spi_setup_speed_hz);
++
++	/* stop the clocks */
++	mcp25xxfd_stop_clock(spi, MCP25XXFD_CLK_USER_CAN);
++}
++
++static int mcp25xxfd_can_ist_handle_status(struct spi_device *spi)
++{
++	struct mcp25xxfd_priv *priv = spi_get_drvdata(spi);
++	const u32 clear_irq = CAN_INT_TBCIF |
++		CAN_INT_MODIF |
++		CAN_INT_SERRIF |
++		CAN_INT_CERRIF |
++		CAN_INT_WAKIF |
++		CAN_INT_IVMIF;
++	int ret;
++
++	/* clear all the interrupts asap */
++	ret = mcp25xxfd_cmd_write_mask(spi, CAN_INT,
++				       priv->status.intf & (~clear_irq),
++				       clear_irq,
++				       priv->spi_speed_hz);
++	if (ret)
++		return ret;
++
++	/* interrupt clearing info */
++	priv->bdiag1_clear_value = 0;
++	priv->bdiag1_clear_mask = 0;
++	priv->can_err_id = 0;
++	memset(priv->can_err_data, 0, 8);
++
++	/* state changes */
++	priv->new_state = priv->can.state;
++
++	/* clear queued fifos */
++	mcp25xxfd_clear_queued_fifos(spi);
++
++	/* system error interrupt needs to get handled first
++	 * to get us out of restricted mode
++	 */
++	if (priv->status.intf & CAN_INT_SERRIF) {
++		priv->stats.int_serr_count++;
++		ret = mcp25xxfd_can_ist_handle_serrif(spi);
++		if (ret)
++			return ret;
++	}
++
++	/* mode change interrupt */
++	if (priv->status.intf & CAN_INT_MODIF) {
++		priv->stats.int_mod_count++;
++		ret = mcp25xxfd_can_ist_handle_modif(spi);
++		if (ret)
++			return ret;
++	}
++
++	/* handle the rx */
++	if (priv->status.intf & CAN_INT_RXIF) {
++		priv->stats.int_rx_count++;
++		ret = mcp25xxfd_can_ist_handle_rxif(spi);
++		if (ret)
++			return ret;
++	}
++
++	/* handle aborted TX FIFOs */
++	if (priv->status.txatif) {
++		priv->stats.int_txat_count++;
++		ret = mcp25xxfd_can_ist_handle_txatif(spi);
++		if (ret)
++			return ret;
++	}
++
++	/* handle the tef */
++	if (priv->status.intf & CAN_INT_TEFIF) {
++		priv->stats.int_tef_count++;
++		ret = mcp25xxfd_can_ist_handle_tefif(spi);
++		if (ret)
++			return ret;
++	}
++
++	/* process the queued fifos */
++	ret = mcp25xxfd_process_queued_fifos(spi);
++
++	/* handle error interrupt flags */
++	if (priv->status.rxovif) {
++		priv->stats.int_rxov_count++;
++		ret = mcp25xxfd_can_ist_handle_rxovif(spi);
++		if (ret)
++			return ret;
++	}
++
++	/* sram ECC error interrupt */
++	if (priv->status.intf & CAN_INT_ECCIF) {
++		priv->stats.int_ecc_count++;
++		ret = mcp25xxfd_can_ist_handle_eccif(spi);
++		if (ret)
++			return ret;
++	}
++
++	/* message format interrupt */
++	if (priv->status.intf & CAN_INT_IVMIF) {
++		priv->stats.int_ivm_count++;
++		ret = mcp25xxfd_can_ist_handle_ivmif(spi);
++		if (ret)
++			return ret;
++	}
++
++	/* handle bus errors in more detail */
++	if (priv->status.intf & CAN_INT_CERRIF) {
++		priv->stats.int_cerr_count++;
++		ret = mcp25xxfd_can_ist_handle_cerrif(spi);
++		if (ret)
++			return ret;
++	}
++
++	/* Error counter handling */
++	if (priv->status.trec & CAN_TREC_TXWARN) {
++		priv->new_state = CAN_STATE_ERROR_WARNING;
++		priv->can_err_id |= CAN_ERR_CRTL;
++		priv->can_err_data[1] |= CAN_ERR_CRTL_TX_WARNING;
++	}
++	if (priv->status.trec & CAN_TREC_RXWARN) {
++		priv->new_state = CAN_STATE_ERROR_WARNING;
++		priv->can_err_id |= CAN_ERR_CRTL;
++		priv->can_err_data[1] |= CAN_ERR_CRTL_RX_WARNING;
++	}
++	if (priv->status.trec & CAN_TREC_TXBP) {
++		priv->new_state = CAN_STATE_ERROR_PASSIVE;
++		priv->can_err_id |= CAN_ERR_CRTL;
++		priv->can_err_data[1] |= CAN_ERR_CRTL_TX_PASSIVE;
++	}
++	if (priv->status.trec & CAN_TREC_RXBP) {
++		priv->new_state = CAN_STATE_ERROR_PASSIVE;
++		priv->can_err_id |= CAN_ERR_CRTL;
++		priv->can_err_data[1] |= CAN_ERR_CRTL_RX_PASSIVE;
++	}
++	if (priv->status.trec & CAN_TREC_TXBO) {
++		priv->new_state = CAN_STATE_BUS_OFF;
++		priv->can_err_id |= CAN_ERR_BUSOFF;
++	}
++
++	/* based on the last state state check the new state */
++	switch (priv->can.state) {
++	case CAN_STATE_ERROR_ACTIVE:
++		if (priv->new_state >= CAN_STATE_ERROR_WARNING &&
++		    priv->new_state <= CAN_STATE_BUS_OFF)
++			priv->can.can_stats.error_warning++;
++		/* fallthrough */
++	case CAN_STATE_ERROR_WARNING:
++		if (priv->new_state >= CAN_STATE_ERROR_PASSIVE &&
++		    priv->new_state <= CAN_STATE_BUS_OFF)
++			priv->can.can_stats.error_passive++;
++		break;
++	default:
++		break;
++	}
++	priv->can.state = priv->new_state;
++
++	/* and send error packet */
++	if (priv->can_err_id)
++		mcp25xxfd_error_skb(priv->net);
++
++	/* handle BUS OFF */
++	if (priv->can.state == CAN_STATE_BUS_OFF) {
++		if (priv->can.restart_ms == 0) {
++			mcp25xxfd_stop_queue(priv->net);
++			priv->force_quit = 1;
++			priv->can.can_stats.bus_off++;
++			can_bus_off(priv->net);
++			mcp25xxfd_hw_sleep(spi);
++		}
++	} else {
++		/* restart the tx queue if needed */
++		if (priv->fifos.tx_processed_mask == priv->fifos.tx_fifo_mask)
++			mcp25xxfd_wake_queue(spi);
++	}
++
++	/* clear bdiag flags */
++	if (priv->bdiag1_clear_mask) {
++		ret = mcp25xxfd_cmd_write_mask(spi,
++					       CAN_BDIAG1,
++					       priv->bdiag1_clear_value,
++					       priv->bdiag1_clear_mask,
++					       priv->spi_speed_hz);
++		if (ret)
++			return ret;
++	}
++
++	return 0;
++}
++
++static irqreturn_t mcp25xxfd_can_ist(int irq, void *dev_id)
++{
++	struct mcp25xxfd_priv *priv = dev_id;
++	struct spi_device *spi = priv->spi;
++	int ret;
++
++	priv->stats.irq_calls++;
++	priv->stats.irq_state = IRQ_STATE_RUNNING;
++
++	while (!priv->force_quit) {
++		/* count irq loops */
++		priv->stats.irq_loops++;
++
++		/* copy pending to in_irq - any
++		 * updates that happen asyncronously
++		 * are not taken into account here
++		 */
++		priv->fifos.tx_pending_mask_in_irq =
++			priv->fifos.tx_pending_mask;
++
++		/* read interrupt status flags */
++		ret = mcp25xxfd_cmd_readn(spi, CAN_INT,
++					  &priv->status,
++					  sizeof(priv->status),
++					  priv->spi_speed_hz);
++		if (ret)
++			return ret;
++
++		/* only act if the mask is applied */
++		if ((priv->status.intf &
++		     (priv->status.intf >> CAN_INT_IE_SHIFT)) == 0)
++			break;
++
++		/* handle the status */
++		ret = mcp25xxfd_can_ist_handle_status(spi);
++		if (ret)
++			return ret;
++	}
++
++	return IRQ_HANDLED;
++}
++
++static int mcp25xxfd_get_berr_counter(const struct net_device *net,
++				      struct can_berr_counter *bec)
++{
++	struct mcp25xxfd_priv *priv = netdev_priv(net);
++
++	bec->txerr = (priv->status.trec & CAN_TREC_TEC_MASK) >>
++		CAN_TREC_TEC_SHIFT;
++	bec->rxerr = (priv->status.trec & CAN_TREC_REC_MASK) >>
++		CAN_TREC_REC_SHIFT;
++
++	return 0;
++}
++
++static int mcp25xxfd_power_enable(struct regulator *reg, int enable)
++{
++	if (IS_ERR_OR_NULL(reg))
++		return 0;
++
++	if (enable)
++		return regulator_enable(reg);
++	else
++		return regulator_disable(reg);
++}
++
++static int mcp25xxfd_do_set_mode(struct net_device *net, enum can_mode mode)
++{
++	switch (mode) {
++	case CAN_MODE_START:
++		break;
++	default:
++		return -EOPNOTSUPP;
++	}
++
++	return 0;
++}
++
++static int mcp25xxfd_do_set_nominal_bittiming(struct net_device *net)
++{
++	struct mcp25xxfd_priv *priv = netdev_priv(net);
++	struct can_bittiming *bt = &priv->can.bittiming;
++	struct spi_device *spi = priv->spi;
++
++	int sjw = bt->sjw;
++	int pseg2 = bt->phase_seg2;
++	int pseg1 = bt->phase_seg1;
++	int propseg = bt->prop_seg;
++	int brp = bt->brp;
++
++	int tseg1 = propseg + pseg1;
++	int tseg2 = pseg2;
++
++	/* calculate nominal bit timing */
++	priv->regs.nbtcfg = ((sjw - 1) << CAN_NBTCFG_SJW_SHIFT) |
++		((tseg2 - 1) << CAN_NBTCFG_TSEG2_SHIFT) |
++		((tseg1 - 1) << CAN_NBTCFG_TSEG1_SHIFT) |
++		((brp - 1) << CAN_NBTCFG_BRP_SHIFT);
++
++	return mcp25xxfd_cmd_write(spi, CAN_NBTCFG,
++				   priv->regs.nbtcfg,
++				   priv->spi_setup_speed_hz);
++}
++
++static int mcp25xxfd_do_set_data_bittiming(struct net_device *net)
++{
++	struct mcp25xxfd_priv *priv = netdev_priv(net);
++	struct can_bittiming *bt = &priv->can.data_bittiming;
++	struct spi_device *spi = priv->spi;
++
++	int sjw = bt->sjw;
++	int pseg2 = bt->phase_seg2;
++	int pseg1 = bt->phase_seg1;
++	int propseg = bt->prop_seg;
++	int brp = bt->brp;
++
++	int tseg1 = propseg + pseg1;
++	int tseg2 = pseg2;
++
++	int ret;
++
++	/* set up Transmitter delay compensation */
++	if (!priv->regs.tdc)
++		priv->regs.tdc = CAN_TDC_EDGFLTEN |
++			(CAN_TDC_TDCMOD_AUTO << CAN_TDC_TDCMOD_SHIFT);
++	ret = mcp25xxfd_cmd_write(spi, CAN_TDC, priv->regs.tdc,
++				  priv->spi_setup_speed_hz);
++	if (ret)
++		return ret;
++
++	/* calculate nominal bit timing */
++	priv->regs.dbtcfg = ((sjw - 1) << CAN_DBTCFG_SJW_SHIFT) |
++		((tseg2 - 1) << CAN_DBTCFG_TSEG2_SHIFT) |
++		((tseg1 - 1) << CAN_DBTCFG_TSEG1_SHIFT) |
++		((brp - 1) << CAN_DBTCFG_BRP_SHIFT);
++
++	return mcp25xxfd_cmd_write(spi, CAN_DBTCFG,
++				   priv->regs.dbtcfg,
++				   priv->spi_setup_speed_hz);
++}
++
++static int mcp25xxfd_hw_probe(struct spi_device *spi)
++{
++	struct mcp25xxfd_priv *priv = spi_get_drvdata(spi);
++	int ret;
++
++	/* Wait for oscillator startup timer after power up */
++	mdelay(MCP25XXFD_OST_DELAY_MS);
++
++	/* send a "blind" reset, hoping we are in Config mode */
++	mcp25xxfd_cmd_reset(spi, priv->spi_setup_speed_hz);
++
++	/* Wait for oscillator startup again */
++	mdelay(MCP25XXFD_OST_DELAY_MS);
++
++	/* check clock register that the clock is ready or disabled */
++	ret = mcp25xxfd_cmd_read(spi, MCP25XXFD_OSC,
++				 &priv->regs.osc,
++				 priv->spi_setup_speed_hz);
++	if (ret)
++		return ret;
++
++	/* there can only be one... */
++	switch (priv->regs.osc &
++		(MCP25XXFD_OSC_OSCRDY | MCP25XXFD_OSC_OSCDIS)) {
++	case MCP25XXFD_OSC_OSCRDY: /* either the clock is ready */
++		break;
++	case MCP25XXFD_OSC_OSCDIS: /* or the clock is disabled */
++		/* wakeup sleeping system */
++		ret = mcp25xxfd_wake_from_sleep(spi);
++		if (ret)
++			return ret;
++		/* send a reset, hoping we are now in Config mode */
++		mcp25xxfd_cmd_reset(spi, priv->spi_setup_speed_hz);
++
++		/* Wait for oscillator startup again */
++		mdelay(MCP25XXFD_OST_DELAY_MS);
++		break;
++	default:
++		/* otherwise there is no valid device (or in strange state)
++		 *
++		 * if PLL is enabled but not ready, then there may be
++		 * something "fishy"
++		 * this happened during driver development
++		 * (enabling pll, when when on wrong clock), so best warn
++		 * about such a possibility
++		 */
++		if ((priv->regs.osc &
++		     (MCP25XXFD_OSC_PLLEN | MCP25XXFD_OSC_PLLRDY))
++		    == MCP25XXFD_OSC_PLLEN)
++			dev_err(&spi->dev,
++				"mcp25xxfd may be in a strange state - a power disconnect may be required\n");
++
++		return -ENODEV;
++	}
++
++	/* check if we are in config mode already*/
++
++	/* read CON register and match */
++	ret = mcp25xxfd_cmd_read(spi, CAN_CON,
++				 &priv->regs.con,
++				 priv->spi_setup_speed_hz);
++	if (ret)
++		return ret;
++
++	/* apply mask and check */
++	if ((priv->regs.con & CAN_CON_DEFAULT_MASK) == CAN_CON_DEFAULT) {
++		priv->active_can_mode = CAN_CON_MODE_CONFIG;
++		return 0;
++	}
++
++	/* as per datasheet a reset only works in Config Mode
++	 * so as we have in principle no knowledge of the current
++	 * mode that the controller is in we have no safe way
++	 * to detect the device correctly
++	 * hence we need to "blindly" put the controller into
++	 * config mode.
++	 * on the "save" side, the OSC reg has to be valid already,
++	 * so there is a chance we got the controller...
++	 */
++
++	/* blindly force it into config mode */
++	priv->regs.con = CAN_CON_DEFAULT;
++	priv->active_can_mode = CAN_CON_MODE_CONFIG;
++	ret = mcp25xxfd_cmd_write(spi, CAN_CON, CAN_CON_DEFAULT,
++				  priv->spi_setup_speed_hz);
++	if (ret)
++		return ret;
++
++	/* delay some time */
++	mdelay(MCP25XXFD_OST_DELAY_MS);
++
++	/* reset can controller */
++	mcp25xxfd_cmd_reset(spi, priv->spi_setup_speed_hz);
++
++	/* delay some time */
++	mdelay(MCP25XXFD_OST_DELAY_MS);
++
++	/* read CON register and match a final time */
++	ret = mcp25xxfd_cmd_read(spi, CAN_CON,
++				 &priv->regs.con,
++				 priv->spi_setup_speed_hz);
++	if (ret)
++		return ret;
++
++	/* apply mask and check */
++	if ((priv->regs.con & CAN_CON_DEFAULT_MASK) != CAN_CON_DEFAULT)
++		return -ENODEV;
++
++	/* just in case: disable interrupts on controller */
++	return mcp25xxfd_disable_interrupts(spi,
++					    priv->spi_setup_speed_hz);
++}
++
++static int mcp25xxfd_setup_osc(struct spi_device *spi)
++{
++	struct mcp25xxfd_priv *priv = spi_get_drvdata(spi);
++	int val = ((priv->config.clock_pll) ? MCP25XXFD_OSC_PLLEN : 0)
++		| ((priv->config.clock_div2) ? MCP25XXFD_OSC_SCLKDIV : 0);
++	int waitfor = ((priv->config.clock_pll) ? MCP25XXFD_OSC_PLLRDY : 0)
++		| ((priv->config.clock_div2) ? MCP25XXFD_OSC_SCLKRDY : 0)
++		| MCP25XXFD_OSC_OSCRDY;
++	int ret;
++	unsigned long timeout;
++
++	/* manage clock_out divider */
++	switch (priv->config.clock_odiv) {
++	case 10:
++		val |= (MCP25XXFD_OSC_CLKODIV_10)
++			<< MCP25XXFD_OSC_CLKODIV_SHIFT;
++		break;
++	case 4:
++		val |= (MCP25XXFD_OSC_CLKODIV_4)
++			<< MCP25XXFD_OSC_CLKODIV_SHIFT;
++		break;
++	case 2:
++		val |= (MCP25XXFD_OSC_CLKODIV_2)
++			<< MCP25XXFD_OSC_CLKODIV_SHIFT;
++		break;
++	case 1:
++		val |= (MCP25XXFD_OSC_CLKODIV_1)
++			<< MCP25XXFD_OSC_CLKODIV_SHIFT;
++		break;
++	case 0:
++		/* this means implicitly SOF output */
++		val |= (MCP25XXFD_OSC_CLKODIV_10)
++			<< MCP25XXFD_OSC_CLKODIV_SHIFT;
++		break;
++	default:
++		dev_err(&spi->dev,
++			"Unsupported output clock divider %i\n",
++			priv->config.clock_odiv);
++		return -EINVAL;
++	}
++
++	/* write clock */
++	ret = mcp25xxfd_cmd_write(spi, MCP25XXFD_OSC, val,
++				  priv->spi_setup_speed_hz);
++	if (ret)
++		return ret;
++
++	/* wait for synced pll/osc/sclk */
++	timeout = jiffies + MCP25XXFD_OSC_POLLING_JIFFIES;
++	while (time_before_eq(jiffies, timeout)) {
++		ret = mcp25xxfd_cmd_read(spi, MCP25XXFD_OSC,
++					 &priv->regs.osc,
++					 priv->spi_setup_speed_hz);
++		if (ret)
++			return ret;
++		if ((priv->regs.osc & waitfor) == waitfor)
++			return 0;
++	}
++
++	dev_err(&spi->dev,
++		"Clock did not lock within the timeout period\n");
++
++	/* we timed out */
++	return -ENODEV;
++}
++
++static int mcp25xxfd_setup_fifo(struct net_device *net,
++				struct mcp25xxfd_priv *priv,
++				struct spi_device *spi)
++{
++	u32 val, available_memory, tx_memory_used;
++	int ret;
++	int i, fifo;
++
++	/* clear all filter */
++	for (i = 0; i < 32; i++) {
++		ret = mcp25xxfd_cmd_write(spi, CAN_FLTOBJ(i), 0,
++					  priv->spi_setup_speed_hz);
++		if (ret)
++			return ret;
++		ret = mcp25xxfd_cmd_write(spi, CAN_FLTMASK(i), 0,
++					  priv->spi_setup_speed_hz);
++		if (ret)
++			return ret;
++		ret = mcp25xxfd_cmd_write_mask(spi, CAN_FLTCON(i), 0,
++					       CAN_FILCON_MASK(i),
++					       priv->spi_setup_speed_hz);
++		if (ret)
++			return ret;
++	}
++
++	/* decide on TEF, tx and rx FIFOS */
++	switch (net->mtu) {
++	case CAN_MTU:
++		/* note: if we have INT1 connected to a GPIO
++		 * then we could handle this differently and more
++		 * efficiently
++		 */
++
++		/* mtu is 8 */
++		priv->fifos.payload_size = 8;
++		priv->fifos.payload_mode = CAN_TXQCON_PLSIZE_8;
++
++		/* 7 tx fifos starting at fifo 1 */
++		priv->fifos.tx_fifos = 7;
++
++		/* 24 rx fifos with 1 buffers/fifo */
++		priv->fifos.rx_fifo_depth = 1;
++
++		break;
++	case CANFD_MTU:
++		/* wish there was a way to have hw filters
++		 * that can separate based on length ...
++		 */
++		/* MTU is 64 */
++		priv->fifos.payload_size = 64;
++		priv->fifos.payload_mode = CAN_TXQCON_PLSIZE_64;
++
++		/* 7 tx fifos */
++		priv->fifos.tx_fifos = 7;
++
++		/* 19 rx fifos with 1 buffer/fifo */
++		priv->fifos.rx_fifo_depth = 1;
++
++		break;
++	default:
++		return -EINVAL;
++	}
++
++	/* if defined as a module modify the number of tx_fifos */
++	if (tx_fifos) {
++		dev_info(&spi->dev,
++			 "Using %i tx-fifos as per module parameter\n",
++			 tx_fifos);
++		priv->fifos.tx_fifos = tx_fifos;
++	}
++
++	/* check range - we need 1 RX-fifo and one tef-fifo, hence 30 */
++	if (priv->fifos.tx_fifos > 30) {
++		dev_err(&spi->dev,
++			"There is an absolute maximum of 30 tx-fifos\n");
++		return -EINVAL;
++	}
++
++	tx_memory_used = priv->fifos.tx_fifos *
++		(sizeof(struct mcp25xxfd_obj_tef) +
++		 sizeof(struct mcp25xxfd_obj_tx) +
++		 priv->fifos.payload_size);
++	/* check that we are not exceeding memory limits with 1 RX buffer */
++	if (tx_memory_used + (sizeof(struct mcp25xxfd_obj_rx) +
++		   priv->fifos.payload_size) > MCP25XXFD_BUFFER_TXRX_SIZE) {
++		dev_err(&spi->dev,
++			"Configured %i tx-fifos exceeds available memory already\n",
++			priv->fifos.tx_fifos);
++		return -EINVAL;
++	}
++
++	/* calculate possible amount of RX fifos */
++	available_memory = MCP25XXFD_BUFFER_TXRX_SIZE - tx_memory_used;
++
++	priv->fifos.rx_fifos = available_memory /
++		(sizeof(struct mcp25xxfd_obj_rx) +
++		 priv->fifos.payload_size) /
++		priv->fifos.rx_fifo_depth;
++
++	/* we only support 31 FIFOS in total (TEF = FIFO0),
++	 * so modify rx accordingly
++	 */
++	if (priv->fifos.tx_fifos + priv->fifos.rx_fifos > 31)
++		priv->fifos.rx_fifos = 31 - priv->fifos.tx_fifos;
++
++	/* calculate effective memory used */
++	available_memory -= priv->fifos.rx_fifos *
++		(sizeof(struct mcp25xxfd_obj_rx) +
++		 priv->fifos.payload_size) *
++		priv->fifos.rx_fifo_depth;
++
++	/* calcluate tef size */
++	priv->fifos.tef_fifos = priv->fifos.tx_fifos;
++	fifo = available_memory / sizeof(struct mcp25xxfd_obj_tef);
++	if (fifo > 0) {
++		priv->fifos.tef_fifos += fifo;
++		if (priv->fifos.tef_fifos > 32)
++			priv->fifos.tef_fifos = 32;
++	}
++
++	/* calculate rx/tx fifo start */
++	priv->fifos.rx_fifo_start = 1;
++	priv->fifos.tx_fifo_start =
++		priv->fifos.rx_fifo_start + priv->fifos.rx_fifos;
++
++	/* set up TEF SIZE to the number of tx_fifos and IRQ */
++	priv->regs.tefcon = CAN_TEFCON_FRESET |
++		CAN_TEFCON_TEFNEIE |
++		CAN_TEFCON_TEFTSEN |
++		((priv->fifos.tef_fifos - 1) << CAN_TEFCON_FSIZE_SHIFT);
++
++	ret = mcp25xxfd_cmd_write(spi, CAN_TEFCON,
++				  priv->regs.tefcon,
++				  priv->spi_setup_speed_hz);
++	if (ret)
++		return ret;
++
++	/* set up tx fifos */
++	val = CAN_FIFOCON_TXEN |
++		CAN_FIFOCON_TXATIE | /* show up txatie flags in txatif reg */
++		CAN_FIFOCON_FRESET | /* reset FIFO */
++		(priv->fifos.payload_mode << CAN_FIFOCON_PLSIZE_SHIFT) |
++		(0 << CAN_FIFOCON_FSIZE_SHIFT); /* 1 FIFO only */
++
++	if (priv->can.ctrlmode & CAN_CTRLMODE_ONE_SHOT)
++		if (three_shot)
++			val |= CAN_FIFOCON_TXAT_THREE_SHOT <<
++				CAN_FIFOCON_TXAT_SHIFT;
++		else
++			val |= CAN_FIFOCON_TXAT_ONE_SHOT <<
++				CAN_FIFOCON_TXAT_SHIFT;
++	else
++		val |= CAN_FIFOCON_TXAT_UNLIMITED <<
++			CAN_FIFOCON_TXAT_SHIFT;
++
++	for (i = 0; i < priv->fifos.tx_fifos; i++) {
++		fifo = priv->fifos.tx_fifo_start + i;
++		ret = mcp25xxfd_cmd_write(spi, CAN_FIFOCON(fifo),
++					  /* the prioriy needs to be inverted
++					   * we need to run from lowest to
++					   * highest to avoid MAB errors
++					   */
++					  val | ((31 - fifo) <<
++						 CAN_FIFOCON_TXPRI_SHIFT),
++					  priv->spi_setup_speed_hz);
++		if (ret)
++			return ret;
++		priv->fifos.tx_fifo_mask |= BIT(fifo);
++	}
++
++	/* now set up RX FIFO */
++	for (i = 0,
++	     fifo = priv->fifos.rx_fifo_start + priv->fifos.rx_fifos - 1;
++	     i < priv->fifos.rx_fifos; i++, fifo--) {
++		/* prepare the fifo itself */
++		ret = mcp25xxfd_cmd_write(spi, CAN_FIFOCON(fifo),
++					  (priv->fifos.payload_mode <<
++					   CAN_FIFOCON_PLSIZE_SHIFT) |
++					  ((priv->fifos.rx_fifo_depth - 1) <<
++					   CAN_FIFOCON_FSIZE_SHIFT) |
++					  /* RX timestamps: */
++					  CAN_FIFOCON_RXTSEN |
++					  /* reset FIFO: */
++					  CAN_FIFOCON_FRESET |
++					  /* FIFO Full: */
++					  CAN_FIFOCON_TFERFFIE |
++					  /* FIFO Half Full: */
++					  CAN_FIFOCON_TFHRFHIE |
++					  /* FIFO not empty: */
++					  CAN_FIFOCON_TFNRFNIE |
++					  /* on last fifo add overflow flag: */
++					  ((i == priv->fifos.rx_fifos - 1) ?
++					   CAN_FIFOCON_RXOVIE : 0),
++					  priv->spi_setup_speed_hz);
++		if (ret)
++			return ret;
++		/* prepare the rx filter config: filter i directs to fifo
++		 * FLTMSK and FLTOBJ are 0 already, so they match everything
++		 */
++		ret = mcp25xxfd_cmd_write_mask(spi, CAN_FLTCON(i),
++					       CAN_FIFOCON_FLTEN(i) |
++					       (fifo << CAN_FILCON_SHIFT(i)),
++					       CAN_FIFOCON_FLTEN(i) |
++					       CAN_FILCON_MASK(i),
++					       priv->spi_setup_speed_hz);
++		if (ret)
++			return ret;
++
++		priv->fifos.rx_fifo_mask |= BIT(fifo);
++	}
++
++	/* we need to move out of CONFIG mode shortly to get the addresses */
++	ret = mcp25xxfd_set_opmode(spi, CAN_CON_MODE_INTERNAL_LOOPBACK,
++				   priv->spi_setup_speed_hz);
++	if (ret)
++		return ret;
++
++	/* for the TEF fifo */
++	ret = mcp25xxfd_cmd_read(spi, CAN_TEFUA, &val,
++				 priv->spi_setup_speed_hz);
++	if (ret)
++		return ret;
++	priv->fifos.tef_address = val;
++	priv->fifos.tef_address_start = val;
++	priv->fifos.tef_address_end = priv->fifos.tef_address_start +
++		priv->fifos.tef_fifos * sizeof(struct mcp25xxfd_obj_tef) -
++		1;
++
++	/* get all the relevant addresses for the transmit fifos */
++	for (i = 0; i < priv->fifos.tx_fifos; i++) {
++		fifo = priv->fifos.tx_fifo_start + i;
++		ret = mcp25xxfd_cmd_read(spi, CAN_FIFOUA(fifo),
++					 &val, priv->spi_setup_speed_hz);
++		if (ret)
++			return ret;
++		priv->fifos.fifo_address[fifo] = val;
++	}
++
++	/* and prepare the spi_messages */
++	ret = mcp25xxfd_fill_spi_transmit_fifos(priv);
++	if (ret)
++		return ret;
++
++	/* get all the relevant addresses for the rx fifos */
++	for (i = 0; i < priv->fifos.rx_fifos; i++) {
++		fifo = priv->fifos.rx_fifo_start + i;
++		ret = mcp25xxfd_cmd_read(spi, CAN_FIFOUA(fifo),
++					 &val, priv->spi_setup_speed_hz);
++		if (ret)
++			return ret;
++	       priv->fifos.fifo_address[fifo] = val;
++	}
++
++	/* now get back into config mode */
++	ret = mcp25xxfd_set_opmode(spi, CAN_CON_MODE_CONFIG,
++				   priv->spi_setup_speed_hz);
++	if (ret)
++		return ret;
++
++	return 0;
++}
++
++static int mcp25xxfd_setup(struct net_device *net,
++			   struct mcp25xxfd_priv *priv,
++			   struct spi_device *spi)
++{
++	int ret;
++
++	/* set up pll/clock if required */
++	ret = mcp25xxfd_setup_osc(spi);
++	if (ret)
++		return ret;
++
++	/* set up RAM ECC */
++	priv->regs.ecccon = MCP25XXFD_ECCCON_ECCEN |
++		MCP25XXFD_ECCCON_SECIE |
++		MCP25XXFD_ECCCON_DEDIE;
++	ret = mcp25xxfd_cmd_write(spi, MCP25XXFD_ECCCON,
++				  priv->regs.ecccon,
++				  priv->spi_setup_speed_hz);
++	if (ret)
++		return ret;
++
++	/* clean SRAM now that we have ECC enabled
++	 * only this case it is clear that all RAM cels have
++	 * valid ECC bits
++	 */
++	ret = mcp25xxfd_clean_sram(spi, priv->spi_setup_speed_hz);
++	if (ret)
++		return ret;
++
++	/* time stamp control register - 1ns resolution, but disabled */
++	ret = mcp25xxfd_cmd_write(spi, CAN_TBC, 0,
++				  priv->spi_setup_speed_hz);
++	if (ret)
++		return ret;
++	priv->regs.tscon = CAN_TSCON_TBCEN |
++		((priv->can.clock.freq / 1000000)
++		 << CAN_TSCON_TBCPRE_SHIFT);
++	ret = mcp25xxfd_cmd_write(spi, CAN_TSCON,
++				  priv->regs.tscon,
++				  priv->spi_setup_speed_hz);
++	if (ret)
++		return ret;
++
++	/* setup value of con_register */
++	priv->regs.con = CAN_CON_STEF /* enable TEF */;
++
++	/* transmission bandwidth sharing bits */
++	if (bw_sharing_log2bits > 12)
++		bw_sharing_log2bits = 12;
++	priv->regs.con |= bw_sharing_log2bits << CAN_CON_TXBWS_SHIFT;
++	/* non iso FD mode */
++	if (!(priv->can.ctrlmode & CAN_CTRLMODE_FD_NON_ISO))
++		priv->regs.con |= CAN_CON_ISOCRCEN;
++	/* one shot */
++	if (priv->can.ctrlmode & CAN_CTRLMODE_ONE_SHOT)
++		priv->regs.con |= CAN_CON_RTXAT;
++
++	/* and put us into default mode = CONFIG */
++	priv->regs.con |= (CAN_CON_MODE_CONFIG << CAN_CON_REQOP_SHIFT) |
++		(CAN_CON_MODE_CONFIG << CAN_CON_OPMOD_SHIFT);
++	/* apply it now - later we will only switch opsmodes... */
++	ret = mcp25xxfd_cmd_write(spi, CAN_CON,
++				  priv->regs.con,
++				  priv->spi_setup_speed_hz);
++
++	/* setup fifos - this also puts the system into sleep mode */
++	return mcp25xxfd_setup_fifo(net, priv, spi);
++}
++
++static int mcp25xxfd_open(struct net_device *net)
++{
++	struct mcp25xxfd_priv *priv = netdev_priv(net);
++	struct spi_device *spi = priv->spi;
++	int ret;
++
++	ret = open_candev(net);
++	if (ret) {
++		dev_err(&spi->dev, "unable to set initial baudrate!\n");
++		return ret;
++	}
++
++	mcp25xxfd_power_enable(priv->transceiver, 1);
++
++	priv->force_quit = 0;
++
++	/* clear those statistics */
++	memset(&priv->stats, 0, sizeof(priv->stats));
++
++	ret = request_threaded_irq(spi->irq, NULL,
++				   mcp25xxfd_can_ist,
++				   IRQF_ONESHOT | IRQF_TRIGGER_LOW,
++				   DEVICE_NAME, priv);
++	if (ret) {
++		dev_err(&spi->dev, "failed to acquire irq %d - %i\n",
++			spi->irq, ret);
++		mcp25xxfd_power_enable(priv->transceiver, 0);
++		close_candev(net);
++		return ret;
++	}
++
++	/* wake from sleep if necessary */
++	ret = mcp25xxfd_hw_wake(spi);
++	if (ret)
++		goto open_clean;
++
++	ret = mcp25xxfd_setup(net, priv, spi);
++	if (ret)
++		goto open_clean;
++
++	mcp25xxfd_do_set_nominal_bittiming(net);
++	mcp25xxfd_do_set_data_bittiming(net);
++
++	ret = mcp25xxfd_set_normal_opmode(spi);
++	if (ret)
++		goto open_clean;
++	/* setting up default state */
++	priv->can.state = CAN_STATE_ERROR_ACTIVE;
++
++	/* only now enable the interrupt on the controller */
++	ret =  mcp25xxfd_enable_interrupts(spi,
++					   priv->spi_setup_speed_hz);
++	if (ret)
++		goto open_clean;
++
++	can_led_event(net, CAN_LED_EVENT_OPEN);
++
++	priv->tx_queue_status = TX_QUEUE_STATUS_RUNNING;
++	netif_wake_queue(net);
++
++	return 0;
++
++open_clean:
++	mcp25xxfd_disable_interrupts(spi, priv->spi_setup_speed_hz);
++	free_irq(spi->irq, priv);
++	mcp25xxfd_hw_sleep(spi);
++	mcp25xxfd_power_enable(priv->transceiver, 0);
++	close_candev(net);
++
++	return ret;
++}
++
++static void mcp25xxfd_clean(struct net_device *net)
++{
++	struct mcp25xxfd_priv *priv = netdev_priv(net);
++	int i;
++
++	for (i = 0; i < priv->fifos.tx_fifos; i++) {
++		if (priv->fifos.tx_pending_mask & BIT(i)) {
++			can_free_echo_skb(priv->net, 0);
++			priv->net->stats.tx_errors++;
++		}
++	}
++
++	priv->fifos.tx_pending_mask = 0;
++}
++
++static int mcp25xxfd_stop(struct net_device *net)
++{
++	struct mcp25xxfd_priv *priv = netdev_priv(net);
++	struct spi_device *spi = priv->spi;
++
++	close_candev(net);
++
++	kfree(priv->spi_transmit_fifos);
++	priv->spi_transmit_fifos = NULL;
++
++	priv->force_quit = 1;
++	free_irq(spi->irq, priv);
++
++	/* Disable and clear pending interrupts */
++	mcp25xxfd_disable_interrupts(spi, priv->spi_setup_speed_hz);
++
++	mcp25xxfd_clean(net);
++
++	mcp25xxfd_hw_sleep(spi);
++
++	mcp25xxfd_power_enable(priv->transceiver, 0);
++
++	priv->can.state = CAN_STATE_STOPPED;
++
++	can_led_event(net, CAN_LED_EVENT_STOP);
++
++	return 0;
++}
++
++static const struct net_device_ops mcp25xxfd_netdev_ops = {
++	.ndo_open = mcp25xxfd_open,
++	.ndo_stop = mcp25xxfd_stop,
++	.ndo_start_xmit = mcp25xxfd_start_xmit,
++	.ndo_change_mtu = can_change_mtu,
++};
++
++static const struct of_device_id mcp25xxfd_of_match[] = {
++	{
++		.compatible	= "microchip,mcp2517fd",
++		.data		= (void *)CAN_MCP2517FD,
++	},
++	{ }
++};
++MODULE_DEVICE_TABLE(of, mcp25xxfd_of_match);
++
++static const struct spi_device_id mcp25xxfd_id_table[] = {
++	{
++		.name		= "mcp2517fd",
++		.driver_data	= (kernel_ulong_t)CAN_MCP2517FD,
++	},
++	{ }
++};
++MODULE_DEVICE_TABLE(spi, mcp25xxfd_id_table);
++
++static int mcp25xxfd_dump_regs(struct seq_file *file, void *offset)
++{
++	struct spi_device *spi = file->private;
++	struct mcp25xxfd_priv *priv = spi_get_drvdata(spi);
++	u32 data[CAN_TXQUA - CAN_CON + 4];
++	int i;
++	int count;
++	int ret;
++
++	count = (CAN_TXQUA - CAN_CON) / 4 + 1;
++	ret = mcp25xxfd_cmd_readn(spi, CAN_CON, data, 4 * count,
++				  priv->spi_setup_speed_hz);
++	if (ret)
++		return ret;
++
++	mcp25xxfd_convert_to_cpu((u32 *)data, 4 * count);
++
++	for (i = 0; i < count; i++) {
++		seq_printf(file, "Reg 0x%03x = 0x%08x\n",
++			   CAN_CON + 4 * i,
++			   ((u32 *)data)[i]);
++	}
++
++	count = (MCP25XXFD_ECCSTAT - MCP25XXFD_OSC) / 4 + 1;
++	ret = mcp25xxfd_cmd_readn(spi, MCP25XXFD_OSC, data, 4 * count,
++				  priv->spi_setup_speed_hz);
++	if (ret)
++		return ret;
++	mcp25xxfd_convert_to_cpu((u32 *)data, 4 * count);
++
++	for (i = 0; i < count; i++) {
++		seq_printf(file, "Reg 0x%03x = 0x%08x\n",
++			   MCP25XXFD_OSC + 4 * i,
++			   ((u32 *)data)[i]);
++	}
++
++	return 0;
++}
++
++#if defined(CONFIG_DEBUG_FS)
++static void mcp25xxfd_debugfs_add(struct mcp25xxfd_priv *priv)
++{
++	struct dentry *root, *fifousage, *fifoaddr, *rx, *tx, *status,
++		*regs, *stats, *rxdlc, *txdlc;
++	char name[32];
++	int i;
++
++	/* create the net device name */
++	snprintf(name, sizeof(name), DEVICE_NAME "-%s", priv->net->name);
++	priv->debugfs_dir = debugfs_create_dir(name, NULL);
++	root = priv->debugfs_dir;
++
++	rx = debugfs_create_dir("rx", root);
++	tx = debugfs_create_dir("tx", root);
++	fifoaddr = debugfs_create_dir("fifo_address", root);
++	status = debugfs_create_dir("status", root);
++	regs = debugfs_create_dir("regs", root);
++	stats = debugfs_create_dir("stats", root);
++	fifousage = debugfs_create_dir("fifo_usage", stats);
++	rxdlc = debugfs_create_dir("rx_dlc_usage", stats);
++	txdlc = debugfs_create_dir("tx_dlc_usage", stats);
++
++	/* add spi speed info */
++	debugfs_create_u32("spi_setup_speed_hz", 0444, root,
++			   &priv->spi_setup_speed_hz);
++	debugfs_create_u32("spi_speed_hz", 0444, root,
++			   &priv->spi_speed_hz);
++
++	/* add irq state info */
++	debugfs_create_u32("irq_state", 0444, root, &priv->stats.irq_state);
++
++	/* for the clock user mask */
++	debugfs_create_u32("clk_user_mask", 0444, root, &priv->clk_user_mask);
++
++	/* add fd statistics */
++	debugfs_create_u64("rx_fd_frames", 0444, stats,
++			   &priv->stats.rx_fd_count);
++	debugfs_create_u64("tx_fd_frames", 0444, stats,
++			   &priv->stats.tx_fd_count);
++	debugfs_create_u64("rx_brs_frames", 0444, stats,
++			   &priv->stats.rx_brs_count);
++	debugfs_create_u64("tx_brs_frames", 0444, stats,
++			   &priv->stats.tx_brs_count);
++
++	/* export the status structure */
++	debugfs_create_x32("intf", 0444, status, &priv->status.intf);
++	debugfs_create_x32("rx_if", 0444, status, &priv->status.rxif);
++	debugfs_create_x32("tx_if", 0444, status, &priv->status.txif);
++	debugfs_create_x32("rx_ovif", 0444, status, &priv->status.rxovif);
++	debugfs_create_x32("tx_atif", 0444, status, &priv->status.txatif);
++	debugfs_create_x32("tx_req", 0444, status, &priv->status.txreq);
++	debugfs_create_x32("trec", 0444, status, &priv->status.trec);
++	debugfs_create_x32("bdiag0", 0444, status, &priv->status.bdiag0);
++	debugfs_create_x32("bdiag1", 0444, status, &priv->status.bdiag1);
++
++	/* some configuration registers */
++	debugfs_create_x32("con", 0444, regs, &priv->regs.con);
++	debugfs_create_x32("ecccon", 0444, regs, &priv->regs.ecccon);
++	debugfs_create_x32("osc", 0444, regs, &priv->regs.osc);
++	debugfs_create_x32("iocon", 0444, regs, &priv->regs.iocon);
++	debugfs_create_x32("tdc", 0774, regs, &priv->regs.tdc);
++	debugfs_create_x32("tscon", 0444, regs, &priv->regs.tscon);
++	debugfs_create_x32("nbtcfg", 0444, regs, &priv->regs.nbtcfg);
++	debugfs_create_x32("dbtcfg", 0444, regs, &priv->regs.dbtcfg);
++
++	/* information on fifos */
++	debugfs_create_u32("fifo_start", 0444, rx,
++			   &priv->fifos.rx_fifo_start);
++	debugfs_create_u32("fifo_count", 0444, rx,
++			   &priv->fifos.rx_fifos);
++	debugfs_create_x32("fifo_mask", 0444, rx,
++			   &priv->fifos.rx_fifo_mask);
++	debugfs_create_u64("rx_overflow", 0444, rx,
++			   &priv->stats.rx_overflow);
++	debugfs_create_u64("rx_mab", 0444, stats,
++			   &priv->stats.rx_mab);
++
++	debugfs_create_u32("fifo_start", 0444, tx,
++			   &priv->fifos.tx_fifo_start);
++	debugfs_create_u32("fifo_count", 0444, tx,
++			   &priv->fifos.tx_fifos);
++	debugfs_create_x32("fifo_mask", 0444, tx,
++			   &priv->fifos.tx_fifo_mask);
++	debugfs_create_x32("fifo_pending", 0444, tx,
++			   &priv->fifos.tx_pending_mask);
++	debugfs_create_x32("fifo_submitted", 0444, tx,
++			   &priv->fifos.tx_submitted_mask);
++	debugfs_create_x32("fifo_processed", 0444, tx,
++			   &priv->fifos.tx_processed_mask);
++	debugfs_create_u32("queue_status", 0444, tx,
++			   &priv->tx_queue_status);
++	debugfs_create_u64("tx_mab", 0444, stats,
++			   &priv->stats.tx_mab);
++
++	debugfs_create_u32("tef_count", 0444, tx,
++			   &priv->fifos.tef_fifos);
++
++	debugfs_create_u32("fifo_max_payload_size", 0444, root,
++			   &priv->fifos.payload_size);
++
++	/* interrupt statistics */
++	debugfs_create_u64("int", 0444, stats,
++			   &priv->stats.irq_calls);
++	debugfs_create_u64("int_loops", 0444, stats,
++			   &priv->stats.irq_loops);
++	debugfs_create_u64("int_ivm", 0444, stats,
++			   &priv->stats.int_ivm_count);
++	debugfs_create_u64("int_wake", 0444, stats,
++			   &priv->stats.int_wake_count);
++	debugfs_create_u64("int_cerr", 0444, stats,
++			   &priv->stats.int_cerr_count);
++	debugfs_create_u64("int_serr", 0444, stats,
++			   &priv->stats.int_serr_count);
++	debugfs_create_u64("int_rxov", 0444, stats,
++			   &priv->stats.int_rxov_count);
++	debugfs_create_u64("int_txat", 0444, stats,
++			   &priv->stats.int_txat_count);
++	debugfs_create_u64("int_spicrc", 0444, stats,
++			   &priv->stats.int_spicrc_count);
++	debugfs_create_u64("int_ecc", 0444, stats,
++			   &priv->stats.int_ecc_count);
++	debugfs_create_u64("int_tef", 0444, stats,
++			   &priv->stats.int_tef_count);
++	debugfs_create_u64("int_mod", 0444, stats,
++			   &priv->stats.int_mod_count);
++	debugfs_create_u64("int_tbc", 0444, stats,
++			   &priv->stats.int_tbc_count);
++	debugfs_create_u64("int_rx", 0444, stats,
++			   &priv->stats.int_rx_count);
++	debugfs_create_u64("int_tx", 0444, stats,
++			   &priv->stats.int_tx_count);
++
++	/* dlc statistics */
++	for (i = 0; i < 16; i++) {
++		snprintf(name, sizeof(name), "%02i", i);
++		debugfs_create_u64(name, 0444, rxdlc,
++				   &priv->stats.rx_dlc_usage[i]);
++		debugfs_create_u64(name, 0444, txdlc,
++				   &priv->stats.tx_dlc_usage[i]);
++	}
++
++	/* statistics on fifo buffer usage and address */
++	for (i = 1; i < 32; i++) {
++		snprintf(name, sizeof(name), "%02i", i);
++		debugfs_create_u64(name, 0444, fifousage,
++				   &priv->stats.fifo_usage[i]);
++		debugfs_create_u32(name, 0444, fifoaddr,
++				   &priv->fifos.fifo_address[i]);
++	}
++
++	/* dump the controller registers themselves */
++	debugfs_create_devm_seqfile(&priv->spi->dev, "reg_dump",
++				    root, mcp25xxfd_dump_regs);
++}
++
++static void mcp25xxfd_debugfs_remove(struct mcp25xxfd_priv *priv)
++{
++	debugfs_remove_recursive(priv->debugfs_dir);
++}
++
++#else
++static void mcp25xxfd_debugfs_add(struct mcp25xxfd_priv *priv)
++{
++	return 0;
++}
++
++static void mcp25xxfd_debugfs_remove(struct mcp25xxfd_priv *priv)
++{
++}
++#endif
++
++#ifdef CONFIG_OF_DYNAMIC
++int mcp25xxfd_of_parse(struct mcp25xxfd_priv *priv)
++{
++	struct spi_device *spi = priv->spi;
++	const struct device_node *np = spi->dev.of_node;
++	u32 val;
++	int ret;
++
++	priv->config.clock_div2 =
++		of_property_read_bool(np, "microchip,clock-div2");
++
++	ret = of_property_read_u32_index(np, "microchip,clock-out-div",
++					 0, &val);
++	if (!ret) {
++		switch (val) {
++		case 0:
++		case 1:
++		case 2:
++		case 4:
++		case 10:
++			priv->config.clock_odiv = val;
++			break;
++		default:
++			dev_err(&spi->dev,
++				"Invalid value in device tree for microchip,clock_out_div: %u - valid values: 0, 1, 2, 4, 10\n",
++				val);
++			return -EINVAL;
++		}
++	}
++
++	priv->config.gpio_opendrain =
++		of_property_read_bool(np, "microchip,gpio-open-drain");
++
++	return 0;
++}
++#else
++int mcp25xxfd_of_parse(struct mcp25xxfd_priv *priv)
++{
++	return 0;
++}
++#endif
++
++static int mcp25xxfd_can_probe(struct spi_device *spi)
++{
++	const struct of_device_id *of_id =
++		of_match_device(mcp25xxfd_of_match, &spi->dev);
++	struct net_device *net;
++	struct mcp25xxfd_priv *priv;
++	struct clk *clk;
++	int ret, freq;
++
++	/* as irq_create_fwspec_mapping() can return 0, check for it */
++	if (spi->irq <= 0) {
++		dev_err(&spi->dev, "no valid irq line defined: irq = %i\n",
++			spi->irq);
++		return -EINVAL;
++	}
++
++	clk = devm_clk_get(&spi->dev, NULL);
++	if (IS_ERR(clk))
++		return PTR_ERR(clk);
++
++	freq = clk_get_rate(clk);
++	if (freq < MCP25XXFD_MIN_CLOCK_FREQUENCY ||
++	    freq > MCP25XXFD_MAX_CLOCK_FREQUENCY) {
++		dev_err(&spi->dev,
++			"Clock frequency %i is not in range [%i:%i]\n",
++			freq,
++			MCP25XXFD_MIN_CLOCK_FREQUENCY,
++			MCP25XXFD_MAX_CLOCK_FREQUENCY);
++		return -ERANGE;
++	}
++
++	/* Allocate can/net device */
++	net = alloc_candev(sizeof(*priv), TX_ECHO_SKB_MAX);
++	if (!net)
++		return -ENOMEM;
++
++	net->netdev_ops = &mcp25xxfd_netdev_ops;
++	net->flags |= IFF_ECHO;
++
++	priv = netdev_priv(net);
++	priv->can.bittiming_const = &mcp25xxfd_nominal_bittiming_const;
++	priv->can.do_set_bittiming = &mcp25xxfd_do_set_nominal_bittiming;
++	priv->can.data_bittiming_const = &mcp25xxfd_data_bittiming_const;
++	priv->can.do_set_data_bittiming = &mcp25xxfd_do_set_data_bittiming;
++	priv->can.do_set_mode = mcp25xxfd_do_set_mode;
++	priv->can.do_get_berr_counter = mcp25xxfd_get_berr_counter;
++
++	priv->can.ctrlmode_supported =
++		CAN_CTRLMODE_FD |
++		CAN_CTRLMODE_LOOPBACK |
++		CAN_CTRLMODE_LISTENONLY |
++		CAN_CTRLMODE_BERR_REPORTING |
++		CAN_CTRLMODE_FD_NON_ISO |
++		CAN_CTRLMODE_ONE_SHOT;
++
++	if (of_id)
++		priv->model = (enum mcp25xxfd_model)of_id->data;
++	else
++		priv->model = spi_get_device_id(spi)->driver_data;
++
++	spi_set_drvdata(spi, priv);
++	priv->spi = spi;
++	priv->net = net;
++	priv->clk = clk;
++
++	priv->clk_user_mask = MCP25XXFD_CLK_USER_CAN;
++
++	mutex_init(&priv->clk_user_lock);
++	mutex_init(&priv->spi_rxtx_lock);
++
++	/* enable the clock and mark as enabled */
++	priv->clk_user_mask = MCP25XXFD_CLK_USER_CAN;
++	ret = clk_prepare_enable(clk);
++	if (ret)
++		goto out_free;
++
++	/* Setup GPIO controller */
++	ret = mcp25xxfd_gpio_setup(spi);
++	if (ret)
++		goto out_clk;
++
++	/* all by default as push/pull */
++	priv->config.gpio_opendrain = false;
++
++	/* do not use the SCK clock divider of 2 */
++	priv->config.clock_div2 = false;
++
++	/* clock output is divided by 10 */
++	priv->config.clock_odiv = 10;
++
++	/* as a first guess we assume we are in CAN_CON_MODE_SLEEP
++	 * this is how we leave the controller when removing ourselves
++	 */
++	priv->active_can_mode = CAN_CON_MODE_SLEEP;
++
++	/* if we have a clock that is smaller then 4MHz, then enable the pll */
++	priv->config.clock_pll =
++		(freq <= MCP25XXFD_AUTO_PLL_MAX_CLOCK_FREQUENCY);
++
++	/* check in device tree for overrrides */
++	ret = mcp25xxfd_of_parse(priv);
++	if (ret)
++		return ret;
++
++	/* decide on real can clock rate */
++	priv->can.clock.freq = freq;
++	if (priv->config.clock_pll) {
++		priv->can.clock.freq *= MCP25XXFD_PLL_MULTIPLIER;
++		if (priv->can.clock.freq > MCP25XXFD_MAX_CLOCK_FREQUENCY) {
++			dev_err(&spi->dev,
++				"PLL clock frequency %i would exceed limit\n",
++				priv->can.clock.freq
++				);
++			return -EINVAL;
++		}
++	}
++	if (priv->config.clock_div2)
++		priv->can.clock.freq /= MCP25XXFD_SCLK_DIVIDER;
++
++	/* calclculate the clock frequencies to use */
++	priv->spi_setup_speed_hz = freq / 2;
++	priv->spi_speed_hz = priv->can.clock.freq / 2;
++	if (priv->config.clock_div2) {
++		priv->spi_setup_speed_hz /= MCP25XXFD_SCLK_DIVIDER;
++		priv->spi_speed_hz /= MCP25XXFD_SCLK_DIVIDER;
++	}
++
++	if (spi->max_speed_hz) {
++		priv->spi_setup_speed_hz = min_t(int,
++						 priv->spi_setup_speed_hz,
++						 spi->max_speed_hz);
++		priv->spi_speed_hz = min_t(int,
++					   priv->spi_speed_hz,
++					   spi->max_speed_hz);
++	}
++
++	/* Configure the SPI bus */
++	spi->bits_per_word = 8;
++	ret = spi_setup(spi);
++	if (ret)
++		goto out_clk;
++
++#if 0 //lm removed
++	priv->power = devm_regulator_get_optional(&spi->dev, "vdd");
++	priv->transceiver = devm_regulator_get_optional(&spi->dev, "xceiver");
++	if ((PTR_ERR(priv->power) == -EPROBE_DEFER) ||
++	    (PTR_ERR(priv->transceiver) == -EPROBE_DEFER)) {
++		ret = -EPROBE_DEFER;
++		goto out_clk;
++	}
++#endif
++	ret = mcp25xxfd_power_enable(priv->power, 1);
++	if (ret)
++		goto out_clk;
++
++	SET_NETDEV_DEV(net, &spi->dev);
++
++	ret = mcp25xxfd_hw_probe(spi);
++	/* on error retry a second time */
++	if (ret == -ENODEV) {
++		ret = mcp25xxfd_hw_probe(spi);
++		printk("mcp2517 retry a second time!\n");
++                ret = mcp25xxfd_hw_probe(spi);
++               if (ret == -ENODEV) {
++                       printk("mcp2517 retry the 3 time!\n");
++                       msleep(10);
++                       ret = mcp25xxfd_hw_probe(spi);
++                       if (ret == -ENODEV) {
++                       printk("mcp2517 retry the 4 time!\n");
++                       msleep(10);
++                       ret = mcp25xxfd_hw_probe(spi);
++                       }
++               }		
++		if (!ret)
++			dev_info(&spi->dev,
++				 "found device only during retry\n");
++	}
++	if (ret) {
++		if (ret == -ENODEV)
++			dev_err(&spi->dev,
++				"Cannot initialize MCP%x. Wrong wiring?\n",
++				priv->model);
++		goto error_probe;
++	}
++
++	/* setting up GPIO+INT as PUSHPULL , TXCAN PUSH/PULL, no Standby */
++	priv->regs.iocon = 0;
++
++	/* SOF/CLOCKOUT pin 3 */
++	if (priv->config.clock_odiv < 1)
++		priv->regs.iocon |= MCP25XXFD_IOCON_SOF;
++
++	/* INT/GPIO (probably also clockout) as open drain */
++	if (priv->config.gpio_opendrain)
++		priv->regs.iocon |= MCP25XXFD_IOCON_INTOD;
++
++	ret = mcp25xxfd_cmd_write(spi, MCP25XXFD_IOCON, priv->regs.iocon,
++				  priv->spi_setup_speed_hz);
++	if (ret)
++		return ret;
++
++	/* and put controller to sleep */
++	mcp25xxfd_hw_sleep(spi);
++
++	ret = register_candev(net);
++	if (ret)
++		goto error_probe;
++
++	/* register debugfs */
++	mcp25xxfd_debugfs_add(priv);
++
++	devm_can_led_init(net);
++
++	netdev_info(net, "MCP%x successfully initialized.\n", priv->model);
++	return 0;
++
++error_probe:
++	mcp25xxfd_power_enable(priv->power, 0);
++
++out_clk:
++	mcp25xxfd_stop_clock(spi, MCP25XXFD_CLK_USER_CAN);
++
++out_free:
++	free_candev(net);
++	dev_err(&spi->dev, "Probe failed, err=%d\n", -ret);
++	return ret;
++}
++
++static int mcp25xxfd_can_remove(struct spi_device *spi)
++{
++	struct mcp25xxfd_priv *priv = spi_get_drvdata(spi);
++	struct net_device *net = priv->net;
++
++	mcp25xxfd_debugfs_remove(priv);
++
++	unregister_candev(net);
++
++	mcp25xxfd_power_enable(priv->power, 0);
++
++	if (!IS_ERR(priv->clk))
++		clk_disable_unprepare(priv->clk);
++
++	free_candev(net);
++
++	return 0;
++}
++
++static int __maybe_unused mcp25xxfd_can_suspend(struct device *dev)
++{
++	struct spi_device *spi = to_spi_device(dev);
++	struct mcp25xxfd_priv *priv = spi_get_drvdata(spi);
++	struct net_device *net = priv->net;
++
++	priv->force_quit = 1;
++	disable_irq(spi->irq);
++
++	if (netif_running(net)) {
++		netif_device_detach(net);
++
++		mcp25xxfd_hw_sleep(spi);
++		mcp25xxfd_power_enable(priv->transceiver, 0);
++		priv->after_suspend = AFTER_SUSPEND_UP;
++	} else {
++		priv->after_suspend = AFTER_SUSPEND_DOWN;
++	}
++
++	if (!IS_ERR_OR_NULL(priv->power)) {
++		regulator_disable(priv->power);
++		priv->after_suspend |= AFTER_SUSPEND_POWER;
++	}
++
++	return 0;
++}
++
++static int __maybe_unused mcp25xxfd_can_resume(struct device *dev)
++{
++	struct spi_device *spi = to_spi_device(dev);
++	struct mcp25xxfd_priv *priv = spi_get_drvdata(spi);
++
++	if (priv->after_suspend & AFTER_SUSPEND_POWER)
++		mcp25xxfd_power_enable(priv->power, 1);
++
++	if (priv->after_suspend & AFTER_SUSPEND_UP)
++		mcp25xxfd_power_enable(priv->transceiver, 1);
++	else
++		priv->after_suspend = 0;
++
++	priv->force_quit = 0;
++
++	enable_irq(spi->irq);
++
++	return 0;
++}
++
++static SIMPLE_DEV_PM_OPS(mcp25xxfd_can_pm_ops, mcp25xxfd_can_suspend,
++	mcp25xxfd_can_resume);
++
++static struct spi_driver mcp25xxfd_can_driver = {
++	.driver = {
++		.name = DEVICE_NAME,
++		.of_match_table = mcp25xxfd_of_match,
++		.pm = &mcp25xxfd_can_pm_ops,
++	},
++	.id_table = mcp25xxfd_id_table,
++	.probe = mcp25xxfd_can_probe,
++	.remove = mcp25xxfd_can_remove,
++};
++module_spi_driver(mcp25xxfd_can_driver);
++
++MODULE_AUTHOR("Martin Sperl <kernel@xxxxxxxxxxxxxxxx>");
++MODULE_DESCRIPTION("Microchip 25XXFD CAN driver");
++MODULE_LICENSE("GPL v2");
+-- 
+2.7.4
+
diff --git a/layers/meta-balena-nanopc-t4/recipes-kernel/linux/files/4.4.185/0004-Added-LT9611-driver-support-for-LEC-PX30-A2.patch b/layers/meta-balena-nanopc-t4/recipes-kernel/linux/files/4.4.185/0004-Added-LT9611-driver-support-for-LEC-PX30-A2.patch
new file mode 100644
index 000000000..e010a7dae
--- /dev/null
+++ b/layers/meta-balena-nanopc-t4/recipes-kernel/linux/files/4.4.185/0004-Added-LT9611-driver-support-for-LEC-PX30-A2.patch
@@ -0,0 +1,1027 @@
+From 9ae6662b0318130c9ecb9b223ecf473e6f335d7d Mon Sep 17 00:00:00 2001
+From: Dineshkumar V <dineshkumar.varadarajan@adlinktech.com>
+Date: Wed, 19 Feb 2020 16:43:36 +0530
+Subject: [PATCH 4/4] Added LT9611 driver support for LEC-PX30-A2
+
+---
+ drivers/gpu/drm/bridge/Kconfig      |   7 +
+ drivers/gpu/drm/bridge/Makefile     |   2 +-
+ drivers/gpu/drm/bridge/lt9611-i2c.c | 976 ++++++++++++++++++++++++++++++++++++
+ 3 files changed, 984 insertions(+), 1 deletion(-)
+ create mode 100644 drivers/gpu/drm/bridge/lt9611-i2c.c
+
+diff --git a/drivers/gpu/drm/bridge/Kconfig b/drivers/gpu/drm/bridge/Kconfig
+index cbb2138..e4a8f47 100644
+--- a/drivers/gpu/drm/bridge/Kconfig
++++ b/drivers/gpu/drm/bridge/Kconfig
+@@ -48,6 +48,13 @@ config DRM_LONTIUM_LT8912
+ 	help
+ 	  Lontium LT8912 MIPI-DSI to LVDS and HDMI/MHL bridge chip driver.
+ 
++config DRM_LONTIUM_LT9611_I2C
++	tristate "Lontium LT9611 MIPI-DSI to HDMI/MHL bridge with i2c"
++	depends on OF
++	select DRM_KMS_HELPER
++	select REGMAP_I2C
++	help
++	  Lontium LT9611 MIPI-DSI to HDMI/MHL bridge chip driver with i2c.
+ config DRM_CHIPONE_ICN6211
+ 	tristate "Chipone ICN6211 MIPI-DSI to RGB bridge"
+ 	depends on OF
+diff --git a/drivers/gpu/drm/bridge/Makefile b/drivers/gpu/drm/bridge/Makefile
+index 19db905..effac4a 100644
+--- a/drivers/gpu/drm/bridge/Makefile
++++ b/drivers/gpu/drm/bridge/Makefile
+@@ -6,6 +6,6 @@ obj-$(CONFIG_DRM_RK1000) += rk1000.o
+ obj-$(CONFIG_DRM_DUMB_VGA_DAC) += dumb-vga-dac.o
+ obj-$(CONFIG_DRM_LONTIUM_LT8912) += lt8912.o
+ obj-$(CONFIG_DRM_CHIPONE_ICN6211) += icn6211.o
+-
++obj-$(CONFIG_DRM_LONTIUM_LT9611_I2C) += lt9611-i2c.o
+ obj-y += analogix/
+ obj-y += synopsys/
+diff --git a/drivers/gpu/drm/bridge/lt9611-i2c.c b/drivers/gpu/drm/bridge/lt9611-i2c.c
+new file mode 100644
+index 0000000..cdf763d
+--- /dev/null
++++ b/drivers/gpu/drm/bridge/lt9611-i2c.c
+@@ -0,0 +1,976 @@
++/* Copyright (c) 2017, The Linux Foundation. All rights reserved.
++ *
++ * This program is free software; you can redistribute it and/or modify
++ * it under the terms of the GNU General Public License version 2 and
++ * only version 2 as published by the Free Software Foundation.
++ *
++ * This program is distributed in the hope that it will be useful,
++ * but WITHOUT ANY WARRANTY; without even the implied warranty of
++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
++ * GNU General Public License for more details. *
++ */
++
++
++/*************************** 
++*driver ic: LT9611 
++*version: lt9611_driver_v1.4
++*release date: 20180816
++1. implement the adjustment of hdmi sync polarity. 
++2. implement pattern picture output.
++3. Add 1280x1024, 1024x768.
++
++****************************/
++
++#include <linux/types.h>
++# include <linux/kernel.h>
++# include <linux/module.h>
++# include <linux/init.h>
++# include <linux/device.h>
++# include <linux/platform_device.h>
++# include <linux/fs.h>
++# include <linux/delay.h>
++# include <linux/i2c.h>
++# include <linux/gpio.h>
++# include <linux/interrupt.h>
++# include <linux/of_gpio.h>
++# include <linux/of_irq.h>
++# include <linux/pm.h>
++# include <linux/pm_runtime.h>
++# include <linux/regulator/consumer.h>
++#include <linux/regmap.h>
++#include <linux/of_platform.h>
++#include <linux/kobject.h>
++
++#define DBUG 1
++
++#ifdef DBUG
++#define DEBUG  printk
++#else
++#define DEBUG(fmt, args...)
++#endif
++
++#define STRING_OFF         "off"
++#define STRING_ON          "on"
++
++#define single_port_mipi  1
++#define dual_port_mipi    2
++
++//Do not support 3lane
++#define lane_cnt_1   1
++#define lane_cnt_2   2  
++#define lane_cnt_4   0
++
++#define audio_i2s     0
++#define audio_spdif   1
++
++#define lt9611_dsi           0
++#define lt9611_csi           1
++
++#define Non_Burst_Mode_with_Sync_Events 0x00
++#define Non_Burst_Mode_with_Sync_Pulses 0x01
++#define Burst_Mode                      0x02
++
++#define ac_mode     0
++#define dc_mode     1
++
++#define hdcp_diable 0
++#define hdcp_enable 1
++
++
++#define  Output_RGB888           0
++#define	Output_YCbCr444          1
++#define	Output_YCbCr422_16BIT    2
++#define	Output_YCbCr422_20BIT    3
++#define	Output_YCbCr422_24BIT    4
++
++#define Video_Output_Mode  Output_RGB888
++
++enum video_format
++{
++ video_640x480_60Hz_vic1,       //vic 1
++ video_720x480_60Hz_vic3,       //vic 2
++ video_1280x720_60Hz_vic4,      //vic 3
++ video_1920x1080_60Hz_vic16,    //vic 4
++ 
++ video_1920x1080i_60Hz_169=5,  //vic 5
++ video_720x480i_60Hz_43=6,     //vic 6
++ video_720x480i_60Hz_169=7,    //vic 7
++ video_720x240P_60Hz_43=8,     //vic 8
++ video_720x240P_60Hz_169=9,    //vic 9
++ video_1920x1080_30Hz_vic, 
++ video_1280x720_30Hz_vic,
++ 
++ video_3840x2160_30Hz_vic,
++ video_3840x1080_60Hz_vic,
++ video_1024x600_60Hz_vic,
++ video_none
++};
++
++struct video_timing{
++int hfp;
++int hs;
++int hbp;
++int hact;
++int htotal;
++int vfp;
++int vs;
++int vbp;
++int vact;
++int vtotal;
++int pclk_khz;
++};
++
++struct lontium_ic_mode{
++int mipi_port_cnt; //1 or 2
++int mipi_lane_cnt; //1 or 2 or 4
++bool mipi_mode;   //dsi or csi
++int video_mode;    //Non-Burst Mode with Sync Pulses; Non-Burst Mode with Sync Events
++bool audio_out;   //i2s or spdif
++bool hdmi_coupling_mode;//ac_mode or dc_mode
++bool hdcp_encryption; //hdcp_enable or hdcp_diable
++};
++
++
++
++struct lontium_ic_mode lt9611_mode= {
++dual_port_mipi, //mipi_port_cnt; //single_port_mipi or dual_port_mipi
++//dual_port_mipi, //mipi_port_cnt; //single_port_mipi or dual_port_mipi
++lane_cnt_4,       //mipi_lane_cnt; //1 or 2 or 4
++lt9611_dsi,              //mipi_mode;     //lt9611_dsi or lt9611_csi
++Non_Burst_Mode_with_Sync_Events,
++audio_i2s,       //audio_out      //audio_i2s or audio_spdif
++//dc_mode,       //hdmi_coupling_mode;//ac_mode or dc_mode
++ac_mode,         //hdmi_coupling_mode;//ac_mode or dc_mode
++hdcp_enable      //hdcp_encryption //hdcp_enable or hdcp_diable
++};
++												// hfp, hs, hbp,hact,htotal,vfp, vs, vbp,vact,vtotal, pclk_khz
++struct video_timing video_640x480_60Hz     ={ 8, 96,  40, 640,   800, 33,  2,  10, 480,   525,  25000};
++struct video_timing video_720x480_60Hz     ={16, 62,  60, 720,   858,  9,  6,  30, 480,   525,  27000};
++struct video_timing video_1280x720_60Hz    ={110,40, 220,1280,  1650,  5,  5,  20, 720,   750,  49500};
++struct video_timing video_1280x720_30Hz    ={110,40, 220,1280,  1650,  5,  5,  20, 720,   750,  37125};
++struct video_timing video_1920x1080_30Hz   ={88, 44, 148,1920,  2200,  4,  5,  36, 1080, 1125,  74250};
++struct video_timing video_1920x1080_60Hz   ={88, 44, 148,1920,  2200,  4,  5,  36, 1080, 1125, 148500};
++struct video_timing video_3840x1080_60Hz   ={176,88, 296,3840,  4400,  4,  5,  36, 1080, 1125, 297000};
++struct video_timing video_3840x2160_30Hz   ={176,88, 296,3840,  4400,  8,  10, 72, 2160, 2250, 297000};
++struct video_timing video_1024x600_60Hz   ={60,60, 100,1024,  1154,  2,  5, 10, 600, 617, 34000};
++
++struct video_timing *video;
++
++struct lt9611 {
++
++	struct gpio_desc *reset_n;
++    struct regmap *regmap;
++	struct video_timing *video;
++	int mipi_lane_cnt;
++	bool is_dual;
++	bool audio_status;
++	int  hfp;
++	int hs_width;
++	int hbp;
++	int h_act;
++	int h_tal;
++	int vfp;
++	int vs_width;
++	int vbp;
++	int v_act;
++	int v_tal;
++	int mipi_video_format;
++	enum video_format video_format;
++	int hdmi_vic;
++	int hdmi_y;    //0x00:RGB, 0x01:YCbCr422 0x02:YCbCr 444
++    u8 sink_edid[256];
++	
++};
++
++static void lt9611_power_on(struct lt9611 *lt9611)
++{
++	DEBUG("ADLINK lt9611_power_on\n");
++	gpiod_direction_output(lt9611->reset_n, 0);
++	msleep(20);
++	gpiod_direction_output(lt9611->reset_n, 1);
++	msleep(20);
++	gpiod_direction_output(lt9611->reset_n, 0);
++	msleep(20);
++}
++
++static void lt9611_chip_id(struct lt9611 *lt9611)
++{
++   int rev[16];
++   regmap_write(lt9611->regmap, 0xff, 0x80);
++   regmap_write(lt9611->regmap, 0xee, 0x01);
++   regmap_read(lt9611->regmap, 0x00, &rev[0]);
++   regmap_read(lt9611->regmap, 0x01, &rev[1]);
++   regmap_read(lt9611->regmap, 0x02, &rev[2]);
++   DEBUG("ADLINK %s: lt9611 chip id: 0x%x 0x%x 0x%x\n", __func__, rev[0],rev[1],rev[2]);
++
++}
++
++static void lt9611_system_init(struct lt9611 *lt9611)
++{
++    DEBUG("ADLINK %s: lt9611 system init\n", __func__);
++	regmap_write(lt9611->regmap, 0xFF, 0x82);
++	regmap_write(lt9611->regmap, 0x51, 0x01);
++		//Timer for Frequency meter
++	regmap_write(lt9611->regmap, 0xFF, 0x82);
++	regmap_write(lt9611->regmap, 0x1b, 0x69); //Timer 2
++	regmap_write(lt9611->regmap, 0x1c, 0x78);
++	regmap_write(lt9611->regmap, 0xcb, 0x69); //Timer 1
++	regmap_write(lt9611->regmap, 0xcc, 0x78);
++
++	regmap_write(lt9611->regmap, 0xff, 0x80); 
++	regmap_write(lt9611->regmap, 0x04, 0xf0);
++	regmap_write(lt9611->regmap, 0x06, 0xf0);
++	regmap_write(lt9611->regmap, 0x0a, 0x80);
++	regmap_write(lt9611->regmap, 0x0b, 0x40);
++	regmap_write(lt9611->regmap, 0x0d, 0xef);
++	regmap_write(lt9611->regmap, 0x11, 0xfa);
++	
++}
++
++void lt9611_hdmi_out_disable(struct lt9611 *lt9611) //dsren
++{
++	regmap_write(lt9611->regmap, 0xff,0x81);
++	regmap_write(lt9611->regmap, 0x30,0x00); /* Txphy PD */
++	regmap_write(lt9611->regmap, 0x23,0x80); /* Txpll PD */ 
++}
++
++static void lt9611_mipi_input_analog(struct lt9611 *lt9611)//xuxi
++{
++	DEBUG("ADLINK %s\n",__func__);
++	//mipi mode
++	regmap_write(lt9611->regmap, 0xff, 0x81);
++	regmap_write(lt9611->regmap, 0x06, 0x40); //port A rx current
++	regmap_write(lt9611->regmap, 0x0a, 0xfe); //port A ldo voltage set
++	regmap_write(lt9611->regmap, 0x0b, 0xbf); //enable port A lprx
++	regmap_write(lt9611->regmap, 0x11, 0x40); //port B rx current
++	regmap_write(lt9611->regmap, 0x15, 0xfe); //port B ldo voltage set
++	regmap_write(lt9611->regmap, 0x16, 0xbf); //enable port B lprx
++	
++	regmap_write(lt9611->regmap, 0x1c, 0x03); //PortA clk lane no-LP mode.
++	regmap_write(lt9611->regmap, 0x20, 0x03); //PortB clk lane no-LP mode.
++}
++
++static void lt9611_mipi_input_digtal(struct lt9611 *lt9611) //weiguo
++{
++	DEBUG("ADLINK %s \n",__func__);
++	regmap_write(lt9611->regmap, 0xff, 0x82); 
++	regmap_write(lt9611->regmap, 0x4f, 0x80);    //[7] = Select ad_txpll_d_clk.
++	regmap_write(lt9611->regmap, 0x50, 0x10);
++	
++	regmap_write(lt9611->regmap, 0xff, 0x83); 
++	regmap_write(lt9611->regmap, 0x00, lt9611->mipi_lane_cnt); 
++	regmap_write(lt9611->regmap, 0x02, 0x0a); //settle
++	regmap_write(lt9611->regmap, 0x06, 0x0a); //settle
++
++	if(0) //dual_port_mipi
++	{
++	  DEBUG("ADLINK %s dual port mipi \n",__func__);	
++	  regmap_write(lt9611->regmap, 0x0a, 0x03); //1=dual_lr, 0=dual_en
++    }
++	else               //single_port_mipi       
++	{
++	  DEBUG("ADLINK %s single port mipi \n",__func__);
++	  regmap_write(lt9611->regmap, 0x0a, 0x00); //1=dual_lr, 0=dual_en	
++	}
++}
++
++static int lt9611_htotal_sysclk(struct lt9611 *lt9611)
++{
++	int  reg, temp;
++	regmap_write(lt9611->regmap, 0xff, 0x82);
++	regmap_read(lt9611->regmap, 0x86, &reg);
++	regmap_read(lt9611->regmap, 0x87, &temp);
++	reg = reg*256+temp;
++	DEBUG("ADLINK %s: lt9611 htotal sysclk: %d\n", __func__, reg);
++	return reg;
++}
++
++static void lt9611_video_check(struct lt9611 *lt9611) //dsren
++{
++  	int htotal_sysclk;
++	int temp,temp_l;
++	regmap_write(lt9611->regmap, 0xff, 0x82); // top video check module
++
++	regmap_read(lt9611->regmap, 0x82, &(lt9611->v_act));
++    regmap_read(lt9611->regmap, 0x83, &temp);
++	lt9611->v_act = ((lt9611->v_act)<<8) + temp;
++    
++	regmap_read(lt9611->regmap, 0x6c, &(lt9611->v_tal));
++    regmap_read(lt9611->regmap, 0x6d, &temp);
++    lt9611->v_tal = ((lt9611->v_tal)<<8) + temp;
++
++
++	regmap_write(lt9611->regmap, 0xff, 0x83);
++
++	regmap_read(lt9611->regmap, 0x82, &(lt9611->h_act));
++    regmap_read(lt9611->regmap, 0x83, &temp);
++	lt9611->h_act = ((lt9611->h_act)<<8) + temp;
++	lt9611->h_act = (lt9611->h_act/3);
++	
++	//if(lt9611.mipi_port_cnt==dual_port_mipi)
++	if(lt9611->is_dual) 
++	{
++		regmap_read(lt9611->regmap, 0x86, &temp);
++		regmap_read(lt9611->regmap, 0x87, &temp_l);
++	    temp = (temp<<8)+temp_l;
++		temp = (temp/3);
++		lt9611->h_act = lt9611->h_act+temp;
++	
++	}
++	regmap_read(lt9611->regmap, 0x88, &(lt9611->mipi_video_format));
++	htotal_sysclk = lt9611_htotal_sysclk(lt9611);
++printk("--YYS---111 \n");
++	if((lt9611->h_act==video_640x480_60Hz.hact)&&
++		 (lt9611->h_act == video_640x480_60Hz.vact)&&
++		 (lt9611->v_tal==video_640x480_60Hz.vtotal)){
++
++			DEBUG("ADLINK %s: Video_Check = video_640x480_60Hz\n", __func__);
++			lt9611->video_format = video_640x480_60Hz_vic1;
++			lt9611->hdmi_vic=1;
++			lt9611->video = &video_640x480_60Hz;
++
++			
++	}	
++	else if((lt9611->h_act == video_720x480_60Hz.hact)&&
++		 (lt9611->v_act == video_720x480_60Hz.vact)&&
++		 (lt9611->v_tal == video_720x480_60Hz.vtotal)){
++
++			DEBUG("ADLINK %s: Video_Check = video_720x480_60Hz\n", __func__);
++			lt9611->video_format = video_720x480_60Hz_vic3;
++			lt9611->video = &video_720x480_60Hz;
++			lt9611->hdmi_vic = 3;
++	}	
++	
++	else if((lt9611->h_act == video_1280x720_60Hz.hact)&&
++		 (lt9611->v_act == video_1280x720_60Hz.vact)&&
++		 (lt9611->v_tal == video_1280x720_60Hz.vtotal)){
++
++			DEBUG("ADLINK %s: Video_Check = video_1280x720_60Hz\n", __func__);
++			lt9611->video_format = video_1280x720_60Hz_vic4;
++			lt9611->video = &video_1280x720_60Hz;
++			lt9611->hdmi_vic = 4;
++	}
++	else if((lt9611->h_act == video_1920x1080_60Hz.hact)&&
++		 (lt9611->v_act == video_1920x1080_60Hz.vact)){
++
++			if(htotal_sysclk > 500){
++	
++			    DEBUG("ADLINK %s: Video_Check = video_1920x1080_30Hz\n", __func__);
++				lt9611->video_format = video_1920x1080_30Hz_vic;
++				lt9611->video = &video_1920x1080_30Hz;
++				lt9611->hdmi_vic = 34;
++		    }
++			else{
++			
++			    DEBUG("ADLINK %s: Video_Check = video_1920x1080_60Hz\n", __func__);
++				lt9611->video_format = video_1920x1080_60Hz_vic16;
++				lt9611->video = &video_1920x1080_60Hz;
++				lt9611->hdmi_vic = 16;
++		    }
++    }else if((lt9611->h_act == video_3840x2160_30Hz.hact)&&
++		 (lt9611->v_act == video_3840x2160_30Hz.vact)){
++
++			DEBUG("ADLINK %s: Video_Check = video_3840x2160_30Hz\n", __func__);
++			lt9611->video_format = video_3840x2160_30Hz_vic;
++			lt9611->video = &video_3840x2160_30Hz;
++			lt9611->hdmi_vic = 95;
++
++    }else if((lt9611->h_act == video_3840x1080_60Hz.hact)&&
++		 (lt9611->v_act == video_3840x1080_60Hz.vact)){
++			
++			DEBUG("ADLINK %s: Video_Check = video_3840x1080_60Hz\n", __func__);
++			lt9611->video_format = video_3840x1080_60Hz_vic;
++			lt9611->video = &video_3840x1080_60Hz;
++			lt9611->hdmi_vic = 0;
++
++	}else if((lt9611->h_act == video_1024x600_60Hz.hact)&&
++		 (lt9611->v_act == video_1024x600_60Hz.vact)){
++			
++			DEBUG("ADLINK %s: Video_Check = video_1024x600_60Hz\n", __func__);
++			lt9611->video_format = video_1024x600_60Hz_vic;
++			lt9611->video = &video_1024x600_60Hz;
++			lt9611->hdmi_vic = 0;
++	}		
++	else{//YYS
++
++			lt9611->video_format = video_1280x720_60Hz_vic4;
++			lt9611->video = &video_1280x720_60Hz;
++			lt9611->hdmi_vic = 4;
++
++         		lt9611->video_format = video_1920x1080_30Hz_vic;
++			lt9611->video = &video_1920x1080_30Hz;
++			lt9611->hdmi_vic = 34;
++
++			DEBUG("ADLINK %s:Video_Check = unknown video format\n", __func__);
++	}	
++
++
++}
++
++static void lt9611_frequency_meter_byte_clk(struct lt9611 *lt9611)
++{
++	int temp;
++	int reg = 0x00;
++	
++	/* port A byte clk meter */
++	regmap_write(lt9611->regmap, 0xff, 0x82);
++	regmap_write(lt9611->regmap, 0xff, 0x83);//PortA
++	msleep(50);
++	regmap_read(lt9611->regmap, 0xcd, &temp);
++	if((temp&0x60) == 0x60) /* clk stable */
++	{
++		reg = (temp&0x0f) * 65536;
++		regmap_read(lt9611->regmap, 0xce, &temp);
++		reg = reg + temp*256;
++		regmap_read(lt9611->regmap, 0xcf, &temp);
++		reg = reg + temp;
++		DEBUG("ADLINK %s:port A byte clk = %d\n", __func__, reg);
++
++	}
++	else /* clk unstable */
++	  	DEBUG("ADLINK %s:port A byte clk unstable\n", __func__);
++	
++	/* port B byte clk meter */
++	regmap_write(lt9611->regmap, 0xff, 0x82);
++	regmap_write(lt9611->regmap, 0xc7, 0x04);//PortA
++	msleep(50);
++	regmap_read(lt9611->regmap, 0xcd, &temp);
++
++	if((temp&0x60) == 0x60) /* clk stable */
++	{
++		reg = (temp&0x0f) * 65536;
++		regmap_read(lt9611->regmap, 0xce, &temp);
++		reg =reg + temp*256;
++		regmap_read(lt9611->regmap, 0xcf, &temp);
++		reg = reg + temp;
++
++		DEBUG("ADLINK %s:port B byte clk = %d\n", __func__, reg);
++
++	}
++	else /* clk unstable */
++	  	DEBUG("ADLINK %s:port B byte clk unstable\n", __func__);
++}
++
++static void lt9611_mipi_video_timing(struct lt9611 *lt9611) //weiguo
++{
++	struct video_timing *video_format = lt9611->video;
++	regmap_write(lt9611->regmap, 0xff, 0x83);
++	regmap_write(lt9611->regmap, 0x0d, (video_format->vtotal/256));
++	regmap_write(lt9611->regmap, 0x0e, (video_format->vtotal%256));//vtotal
++	regmap_write(lt9611->regmap, 0x0f, (video_format->vact/256));
++	regmap_write(lt9611->regmap, 0x10, (video_format->vact%256));  //vactive
++	regmap_write(lt9611->regmap, 0x11, (video_format->htotal/256));
++	regmap_write(lt9611->regmap, 0x12, (video_format->htotal%256));//htotal
++	regmap_write(lt9611->regmap, 0x13, (video_format->hact/256));
++	regmap_write(lt9611->regmap, 0x14, (video_format->hact%256)); //hactive
++	regmap_write(lt9611->regmap, 0x15, (video_format->vs%256));   //vsa
++	regmap_write(lt9611->regmap, 0x16, (video_format->hs%256));   //hsa
++	regmap_write(lt9611->regmap, 0x17, (video_format->vfp%256));  //vfp
++	regmap_write(lt9611->regmap, 0x18, ((video_format->vs+video_format->vbp)%256));  //vss
++	regmap_write(lt9611->regmap, 0x19, (video_format->hfp%256));  //hfp
++	regmap_write(lt9611->regmap, 0x1a, ((video_format->hs+video_format->hbp)/256));
++	regmap_write(lt9611->regmap, 0x1b, ((video_format->hs+video_format->hbp)%256));  //hss
++
++}
++
++static void lt9611_mipi_pcr(struct lt9611 *lt9611) //weiguo
++{
++	regmap_write(lt9611->regmap, 0xff, 0x83); 
++	regmap_write(lt9611->regmap, 0x0b, 0x01); //vsync read delay(reference value)
++	regmap_write(lt9611->regmap, 0x0c, 0x10); //
++	
++	regmap_write(lt9611->regmap, 0x48, 0x00); //de mode delay
++	regmap_write(lt9611->regmap, 0x49, 0x81); //=1/4 hact
++	
++	/* stage 1 */
++	regmap_write(lt9611->regmap, 0x21, 0x4a); //bit[3:0] step[11:8]
++	//regmap_write(lt9611->regmap,0x22,0x40);//step[7:0]
++	
++	regmap_write(lt9611->regmap, 0x24, 0x71); //bit[7:4]v/h/de mode; line for clk stb[11:8]
++	regmap_write(lt9611->regmap, 0x25, 0x50); //line for clk stb[7:0]
++	
++	regmap_write(lt9611->regmap, 0x2a, 0x02); //clk stable in
++	
++	/* stage 2 */
++	regmap_write(lt9611->regmap, 0x4a, 0x40); //offset //0x10
++	regmap_write(lt9611->regmap, 0x1d, 0x80); //PCR de mode step setting.
++	//regmap_write(lt9611->regmap,0x23,0x01); //
++	
++	/* MK limit */
++	regmap_write(lt9611->regmap, 0x2d, 0x38); //M up limit
++	regmap_write(lt9611->regmap, 0x31, 0x08); //M down limit
++	
++	switch(lt9611->video_format)
++	{
++		case video_3840x1080_60Hz_vic:
++		case video_3840x2160_30Hz_vic:
++		
++	       regmap_write(lt9611->regmap, 0x0b, 0x03); //vsync mode
++	       regmap_write(lt9611->regmap, 0x0c, 0xd0); //=1/4 hact
++	
++	       regmap_write(lt9611->regmap, 0x48, 0x03); //de mode delay
++	       regmap_write(lt9611->regmap, 0x49, 0xe0); //
++		
++	       regmap_write(lt9611->regmap, 0x24, 0x72);  //bit[7:4]v/h/de mode; line for clk stb[11:8]
++           regmap_write(lt9611->regmap, 0x25, 0x00);  //line for clk stb[7:0]
++	
++	       regmap_write(lt9611->regmap, 0x2a, 0x01);  //clk stable in
++		
++	       regmap_write(lt9611->regmap, 0x4a, 0x10); //offset
++	       regmap_write(lt9611->regmap, 0x1d, 0x10); //PCR de mode step setting.
++		
++	       regmap_write(lt9611->regmap, 0x26, 0x37);
++		   break;
++		
++		case video_1920x1080_60Hz_vic16:
++		    regmap_write(lt9611->regmap, 0x26, 0x37);
++		    break;
++		
++		case video_1920x1080_30Hz_vic:
++		
++		   regmap_write(lt9611->regmap, 0x26, 0x1c);
++		   break;
++		
++		case video_1280x720_60Hz_vic4:
++		case video_1280x720_30Hz_vic:
++		   regmap_write(lt9611->regmap, 0x26, 0x1c);
++		   break;
++	
++		case video_1024x600_60Hz_vic:
++		   regmap_write(lt9611->regmap, 0x24, 0x70); //bit[7:4]v/h/de mode; line for clk stb[11:8]
++		   regmap_write(lt9611->regmap, 0x25, 0x80); //line for clk stb[7:0]
++		
++		   regmap_write(lt9611->regmap, 0x2a, 0x10); //clk stable in
++		
++	    	/* stage 2 */
++		   //regmap_write(lt9611->regmap,0x23,0x04); //pcr h mode step
++		   //regmap_write(lt9611->regmap,0x4a,0x10); //offset //0x10
++		   regmap_write(lt9611->regmap, 0x1d, 0xf0); //PCR de mode step setting.
++		
++		   regmap_write(lt9611->regmap,0x26,0x19); //pcr_m 
++
++		   break;
++		
++		case video_720x480_60Hz_vic3:
++		case video_640x480_60Hz_vic1:
++		
++		  regmap_write(lt9611->regmap, 0x26, 0x14);
++		  break;
++		
++		default: break;
++	}
++
++	lt9611_mipi_video_timing(lt9611);
++
++    regmap_write(lt9611->regmap, 0xff, 0x80);
++	regmap_write(lt9611->regmap, 0x11, 0x5a); //Pcr reset
++	regmap_write(lt9611->regmap, 0x11, 0xfa);
++		
++}
++
++static void lt9611_pll(struct lt9611 *lt9611) //zhangzhichun
++{
++	int pclk;
++	int pll_lock_flag;
++	int i;
++	struct video_timing *video_format = lt9611->video;
++	pclk = video_format->pclk_khz;
++	DEBUG("ADLINK %s:set rx pll = %d\n", __func__, pclk);
++	
++	regmap_write(lt9611->regmap, 0xff, 0x81);
++	regmap_write(lt9611->regmap, 0x23, 0x40);
++	regmap_write(lt9611->regmap, 0x24, 0x64);
++	regmap_write(lt9611->regmap, 0x25, 0x80); //pre-divider
++	regmap_write(lt9611->regmap, 0x26, 0x55);
++	regmap_write(lt9611->regmap, 0x2c, 0x37);
++	
++	regmap_write(lt9611->regmap, 0x2f, 0x01);
++	regmap_write(lt9611->regmap, 0x26, 0x55);
++	regmap_write(lt9611->regmap, 0x27, 0x66);
++	regmap_write(lt9611->regmap, 0x28, 0x88);
++	
++	if(pclk > 150000)
++	  regmap_write(lt9611->regmap, 0x2d, 0x88);
++	else if(pclk > 70000)
++		regmap_write(lt9611->regmap, 0x2d, 0x99);
++	else
++		regmap_write(lt9611->regmap, 0x2d, 0xaa); //0xaa
++		
++	pclk = pclk / 2;
++	regmap_write(lt9611->regmap, 0xff, 0x82);     //13.5M
++	regmap_write(lt9611->regmap, 0xe3, pclk/65536);
++	pclk = pclk % 65536;
++	regmap_write(lt9611->regmap, 0xe4, pclk/256);
++	regmap_write(lt9611->regmap, 0xe5, pclk%256);
++	
++	regmap_write(lt9611->regmap, 0xde, 0x20);
++	regmap_write(lt9611->regmap, 0xde, 0xe0);
++		
++	regmap_write(lt9611->regmap, 0xff, 0x80);
++	regmap_write(lt9611->regmap, 0x11, 0x5a); /* Pcr clk reset */
++	regmap_write(lt9611->regmap, 0x11, 0xfa);
++	regmap_write(lt9611->regmap, 0x18, 0xdc); /* pll analog reset */
++	regmap_write(lt9611->regmap, 0x18, 0xfc);
++	regmap_write(lt9611->regmap, 0x16, 0xf1);
++	regmap_write(lt9611->regmap, 0x16, 0xf3);
++   
++	/* pll lock status */
++	for(i = 0; i < 6 ; i++)
++	{   
++			regmap_write(lt9611->regmap, 0xff, 0x80);	
++			regmap_write(lt9611->regmap, 0x16, 0xe3); /* pll lock logic reset */
++			regmap_write(lt9611->regmap, 0x16, 0xf3);
++			regmap_write(lt9611->regmap, 0xff, 0x82);
++			regmap_read(lt9611->regmap, 0x15, &pll_lock_flag);
++			if(pll_lock_flag & 0x80)
++			{
++				DEBUG("ADLINK %s:HDMI pll locked\n", __func__);
++				break;
++			}
++			else
++			{
++			    regmap_write(lt9611->regmap, 0xff, 0x80);
++				regmap_write(lt9611->regmap, 0x11, 0x5a); /* Pcr clk reset */
++	            regmap_write(lt9611->regmap, 0x11, 0xfa);
++				regmap_write(lt9611->regmap, 0x18, 0xdc); /* pll analog reset */
++			    regmap_write(lt9611->regmap, 0x18, 0xfc);
++				regmap_write(lt9611->regmap, 0x16, 0xf1); /* pll cal reset*/
++		        regmap_write(lt9611->regmap,0x16, 0xf3);
++				DEBUG(" ADLINK  %sHDMI pll unlocked, reset pll\n", __func__);
++			}
++	}
++}
++
++static void lt9611_audio_init(struct lt9611 *lt9611) //sujin
++{
++	#if 1
++	if(lt9611_mode.audio_out==audio_i2s)
++	{
++		DEBUG("%s:Audio inut = I2S 2ch\n", __func__);
++		regmap_write(lt9611->regmap, 0xff, 0x82);
++		regmap_write(lt9611->regmap, 0xd6, 0x8c);
++		regmap_write(lt9611->regmap, 0xd7, 0x04); //sync polarity
++		
++		regmap_write(lt9611->regmap, 0xff, 0x84);
++		regmap_write(lt9611->regmap, 0x06, 0x08);
++		regmap_write(lt9611->regmap, 0x07, 0x10);
++		
++		regmap_write(lt9611->regmap, 0x34, 0xd4); //CTS_N
++		lt9611->audio_status = 1;  
++	}
++	
++	if(lt9611_mode.audio_out==audio_spdif)
++	{
++		DEBUG("%s:Audio inut = SPDIF\n", __func__);
++		regmap_write(lt9611->regmap, 0xff, 0x82);
++		regmap_write(lt9611->regmap, 0xd6, 0x8c);
++		regmap_write(lt9611->regmap, 0xd7, 0x04); //sync polarity
++		
++		regmap_write(lt9611->regmap, 0xff, 0x84);
++		regmap_write(lt9611->regmap, 0x06, 0x0c);
++		regmap_write(lt9611->regmap, 0x07, 0x10);
++	
++		regmap_write(lt9611->regmap, 0x34, 0xd4); //CTS_N
++	}
++	#endif
++}
++
++
++static void lt9611_csc(struct lt9611 *lt9611) //dsren
++{
++	#if (Video_Output_Mode == Output_RGB888)
++	{
++		lt9611->hdmi_y=0;
++		regmap_write(lt9611->regmap,0xff,0x82);
++		regmap_write(lt9611->regmap,0xb9,0x00); //No csc
++	}
++	#elif (Video_Output_Mode == Output_YCbCr444)
++	{
++		 lt9611->hdmi_y=1;
++		 regmap_write(lt9611->regmap,0xb9,0x00); //RGB to YCbCr
++	}
++	#elif (Video_Output_Mode == Output_YCbCr22)
++	{
++		 lt9611->hdmi_y=2;
++		 regmap_write(lt9611->regmap,0xb9,0x00); //RGB to YCbCr
++	}
++	#endif
++}
++
++static void lt9611_hdcp_init(struct lt9611 *lt9611) //luodexing
++{
++	regmap_write(lt9611->regmap,0xff,0x85); 
++	regmap_write(lt9611->regmap,0x07,0x1f);
++	regmap_write(lt9611->regmap,0x13,0xfe);// [7]=force_hpd, [6]=force_rsen, [5]=vsync_pol, [4]=hsync_pol,
++	                              // [3]=hdmi_mode, [2]=no_accs_when_rdy, [1]=skip_wt_hdmi
++	regmap_write(lt9611->regmap,0x17,0x0f);// [7]=ri_short_read, [3]=sync_pol_mode, [2]=srm_chk_done, 
++	                              // [1]=bksv_srm_pass, [0]=ksv_list_vld
++	regmap_write(lt9611->regmap,0x15,0x05);
++	//regmap_write(lt9611->regmap,0x15,0x65);// [7]=key_ddc_st_sel, [6]=tx_hdcp_en,[5]=tx_auth_en, [4]=tx_re_auth
++}
++
++static void lt9611_hdmi_tx_digital(struct lt9611 *lt9611) //dsren
++{
++	  //AVI
++		regmap_write(lt9611->regmap,0xff,0x84);
++		regmap_write(lt9611->regmap,0x43,0x56-lt9611->hdmi_vic-((lt9611->hdmi_y<<5)+0x10));   //AVI_PB0
++		regmap_write(lt9611->regmap,0x44,(lt9611->hdmi_y<<5)+0x10); //AVI_PB1
++		regmap_write(lt9611->regmap,0x47,lt9611->hdmi_vic); //AVI_PB1
++}
++
++static void lt9611_hdmi_tx_phy(struct lt9611 *lt9611) //xyji
++{
++	regmap_write(lt9611->regmap,0xff,0x81);
++	regmap_write(lt9611->regmap,0x30,0x6a);
++	if(lt9611_mode.hdmi_coupling_mode==ac_mode)
++	{
++		regmap_write(lt9611->regmap,0x31,0x73); //DC: 0x44, AC:0x73
++    }
++	else //lt9611.hdmi_coupling_mode==dc_mode
++	{
++		regmap_write(lt9611->regmap,0x31,0x44);
++	}
++		regmap_write(lt9611->regmap,0x32,0x4a);
++		regmap_write(lt9611->regmap,0x33,0x0b);
++		regmap_write(lt9611->regmap,0x34,0x00);
++		regmap_write(lt9611->regmap,0x35,0x00);
++		regmap_write(lt9611->regmap,0x36,0x00);
++		regmap_write(lt9611->regmap,0x37,0x44);
++		regmap_write(lt9611->regmap,0x3f,0x0f);
++		regmap_write(lt9611->regmap,0x40,0xa0);
++		regmap_write(lt9611->regmap,0x41,0xa0);
++		regmap_write(lt9611->regmap,0x42,0xa0);
++		regmap_write(lt9611->regmap,0x43,0xa0);
++		regmap_write(lt9611->regmap,0x44,0x0a);
++}
++
++void lt9611_hdmi_out_enable(struct lt9611 *lt9611) //dsren
++{
++	regmap_write(lt9611->regmap,0xff,0x81);
++	regmap_write(lt9611->regmap,0x23,0x40);
++	
++	regmap_write(lt9611->regmap,0xff,0x82);
++	regmap_write(lt9611->regmap,0xde,0x20);
++	regmap_write(lt9611->regmap,0xde,0xe0);
++		
++	regmap_write(lt9611->regmap,0xff,0x80); 
++	regmap_write(lt9611->regmap,0x18,0xdc); /* txpll sw rst */
++	regmap_write(lt9611->regmap,0x18,0xfc);
++	regmap_write(lt9611->regmap,0x16,0xf1); /* txpll calibration rest */ 
++	regmap_write(lt9611->regmap,0x16,0xf3);
++	
++	regmap_write(lt9611->regmap,0x11,0x5a); //Pcr reset
++	regmap_write(lt9611->regmap,0x11,0xfa);
++	
++	regmap_write(lt9611->regmap,0xff,0x81);
++	regmap_write(lt9611->regmap,0x30,0xea);
++}
++
++static void lt9611_hdcp_enable(struct lt9611 *lt9611) //luodexing
++{
++#if 0
++	regmap_write(lt9611->regmap,0xff,0x80); 
++	regmap_write(lt9611->regmap,0x14,0x7f);
++    regmap_write(lt9611->regmap,0x14,0xff); 	
++	regmap_write(lt9611->regmap,0xff,0x85); 
++	regmap_write(lt9611->regmap,0x15,0x01); //disable HDCP
++	regmap_write(lt9611->regmap,0x15,0x71); //enable HDCP
++	regmap_write(lt9611->regmap,0x15,0x65); //enable HDCP
++#endif
++}
++
++static void lt9611_audio_enable(struct lt9611 *lt9611) //luodexing
++{
++	regmap_write(lt9611->regmap,0xff,0x84); 
++	regmap_write(lt9611->regmap,0x06,0x08);
++}
++
++static void lt9611_audio_disable(struct lt9611 *lt9611) //luodexing
++{
++	regmap_write(lt9611->regmap,0xff,0x84); 
++	regmap_write(lt9611->regmap,0x06,0x00);
++}
++
++static const struct regmap_config lt9611_regmap_config = {
++	.reg_bits = 8,
++	.val_bits = 8,
++	.max_register = 0xff,
++};
++
++
++static ssize_t audio_show(struct device *dev, struct device_attribute *attr, char *buf)
++{
++	char *s= buf;
++    int len;
++	struct lt9611 *lt9611 = dev_get_drvdata(dev);
++	if(lt9611->audio_status){
++		s += sprintf(s, "%s\n", STRING_ON);
++	}else{
++        s += sprintf(s,"%s\n", STRING_OFF);
++	}
++
++	if (s != buf)
++   	{
++		*(s-1) = '\n';
++    }
++    
++    len = (s - buf);
++
++	return len;
++}
++ 
++static ssize_t audio_store(struct device *dev, struct device_attribute *attr, const char *buf, size_t count)
++{
++	char *p;
++	int len;
++	struct lt9611 *lt9611 = dev_get_drvdata(dev);
++    p = memchr(buf, '\n', count);
++	len = p ? p - buf : count;   
++
++	 if(!strncmp(buf, STRING_ON, len ))
++    {
++        lt9611->audio_status = 1;
++		lt9611_audio_enable(lt9611);
++    }
++    else if(!strncmp(buf, STRING_OFF, len ))
++    {
++        lt9611->audio_status = 0;
++		lt9611_audio_disable(lt9611);
++    }
++
++	return count;
++}
++static DEVICE_ATTR(audio, 0664, audio_show, audio_store);
++
++static int lt9611_bridge_suspend(struct device *dev)
++{
++	struct lt9611 *lt9611 = dev_get_drvdata(dev);
++	lt9611_hdmi_out_disable(lt9611);
++	return 0;
++}
++
++static int lt9611_bridge_resume(struct device *dev)
++{
++	struct lt9611 *lt9611 = dev_get_drvdata(dev);
++	lt9611_pll(lt9611);
++	lt9611_mipi_pcr(lt9611);
++	lt9611_hdmi_tx_digital(lt9611);	
++	lt9611_hdmi_out_enable(lt9611);
++	return 0;
++}
++
++static SIMPLE_DEV_PM_OPS(lt9611_bridge_pm_ops,
++			 lt9611_bridge_suspend,
++			 lt9611_bridge_resume);
++
++static int lt9611_probe(struct i2c_client *client, const struct i2c_device_id *id)
++{
++	struct device *dev = &client->dev;
++    int ret;
++    struct lt9611 *lt9611;
++
++   // if(1) return 0;
++
++    printk("ADLINK ,LT9611 DRIVER \n");	
++	lt9611 = devm_kzalloc(dev, sizeof(*lt9611), GFP_KERNEL);
++	if (!lt9611){
++		dev_err(dev, "failed to alloc memory\n");
++		printk("ADLINK :%s failed to alloc memory \n",__func__);
++		return -ENOMEM;
++	}
++	dev_set_drvdata(dev, lt9611);
++
++	
++	lt9611->reset_n = devm_gpiod_get(dev, "reset", GPIOD_ASIS);
++	if (IS_ERR(lt9611->reset_n)) {
++		ret = PTR_ERR(lt9611->reset_n);
++                printk("ADLINK :%s failed to request reset GPIO \n",__func__);
++
++		dev_err(dev, "failed to request reset GPIO: %d\n", ret);
++		return ret;
++	}
++
++	lt9611->regmap = devm_regmap_init_i2c(client, &lt9611_regmap_config);
++	if (IS_ERR(lt9611->regmap)) {
++		dev_err(dev, "failed to allocate register map\n");
++
++                printk("ADLINK :%s failed to allocate register map \n",__func__);
++
++		return PTR_ERR(lt9611->regmap);
++	}
++
++    ret = device_create_file(dev, &dev_attr_audio);
++	if(ret < 0){
++		dev_err(dev, "failed to create attribute file\n");
++                printk("ADLINK :%s failed to create attribute \n",__func__);
++
++		return ret;
++	}
++ 
++	lt9611_power_on(lt9611);
++	lt9611_hdcp_enable(lt9611); //dummy
++    lt9611_chip_id(lt9611);
++	lt9611_system_init(lt9611);
++	lt9611_mipi_input_analog(lt9611);
++	lt9611_mipi_input_digtal(lt9611);
++	msleep(1000);
++	lt9611_video_check(lt9611);
++    lt9611_frequency_meter_byte_clk(lt9611);
++	lt9611_mipi_pcr(lt9611);
++	lt9611_pll(lt9611);
++	lt9611_audio_init(lt9611);
++	lt9611_csc(lt9611);
++	lt9611_hdcp_init(lt9611);
++	lt9611_hdmi_tx_digital(lt9611);
++	lt9611_hdmi_tx_phy(lt9611);
++	lt9611_hdmi_out_enable(lt9611);
++    return 0;
++}
++static int lt9611_remove(struct i2c_client *client)
++{
++	return 0;
++}
++
++static struct i2c_device_id lt9611_id[] = {
++	{ "lt9611", 0 },
++	{}
++};
++
++static const struct of_device_id lt9611_match_table[] = {
++	{ .compatible = "firefly, lt9611" },
++	{}
++};
++
++MODULE_DEVICE_TABLE(of, lt9611_match_table);
++
++static struct i2c_driver lt9611_driver = {
++	.driver			= {
++		.name		= "lt9611",
++		.owner		= THIS_MODULE,
++		.of_match_table = lt9611_match_table,
++		.pm		= &lt9611_bridge_pm_ops,
++	},
++    .probe			= lt9611_probe,
++	.remove			= lt9611_remove,
++	.id_table  = lt9611_id,
++
++};
++
++static int __init lt9611_init(void)
++{
++	return i2c_add_driver(&lt9611_driver);
++}
++
++static void __exit lt9611_exit(void)
++{
++	i2c_del_driver(&lt9611_driver);
++}
++
++module_init(lt9611_init);
++module_exit(lt9611_exit);
++
++
++MODULE_AUTHOR("xhguo@lontium.com");
++MODULE_DESCRIPTION("Lontium bridge IC LT9611 that convert mipi to hdmi)");
++MODULE_LICENSE("GPL");
++
+-- 
+2.7.4
+
diff --git a/layers/meta-balena-nanopc-t4/recipes-kernel/linux/files/4.4.185/0005-Modified-compatible-property-as-per-target-kernel-dt.patch b/layers/meta-balena-nanopc-t4/recipes-kernel/linux/files/4.4.185/0005-Modified-compatible-property-as-per-target-kernel-dt.patch
new file mode 100644
index 000000000..d5a3c4470
--- /dev/null
+++ b/layers/meta-balena-nanopc-t4/recipes-kernel/linux/files/4.4.185/0005-Modified-compatible-property-as-per-target-kernel-dt.patch
@@ -0,0 +1,40 @@
+From 73325c6a311a6e606714a48b2ca5615ea512254f Mon Sep 17 00:00:00 2001
+From: Dineshkumar V <dineshkumar.varadarajan@adlinktech.com>
+Date: Thu, 5 Dec 2019 21:45:51 +0530
+Subject: [PATCH 5/5] Modified compatible property as per target kernel dts
+ file
+
+---
+ drivers/clk/rockchip/clk-px30.c    | 2 +-
+ drivers/cpufreq/rockchip-cpufreq.c | 2 +-
+ 2 files changed, 2 insertions(+), 2 deletions(-)
+
+diff --git a/drivers/clk/rockchip/clk-px30.c b/drivers/clk/rockchip/clk-px30.c
+index 56e78c2..96690f1 100644
+--- a/drivers/clk/rockchip/clk-px30.c
++++ b/drivers/clk/rockchip/clk-px30.c
+@@ -1068,7 +1068,7 @@ static void __init px30_clk_init(struct device_node *np)
+ 				   PX30_GRF_SOC_STATUS0);
+ 	rockchip_clk_register_branches(ctx, px30_clk_branches,
+ 				       ARRAY_SIZE(px30_clk_branches));
+-	if (of_machine_is_compatible("rockchip,px30"))
++	if (of_machine_is_compatible("adlink,lec-px30"))
+ 		rockchip_clk_register_branches(ctx, px30_gpu_src_clk,
+ 				       ARRAY_SIZE(px30_gpu_src_clk));
+ 	else
+diff --git a/drivers/cpufreq/rockchip-cpufreq.c b/drivers/cpufreq/rockchip-cpufreq.c
+index c206b7c..ccb38ab 100644
+--- a/drivers/cpufreq/rockchip-cpufreq.c
++++ b/drivers/cpufreq/rockchip-cpufreq.c
+@@ -164,7 +164,7 @@ out:
+ }
+ static const struct of_device_id rockchip_cpufreq_of_match[] = {
+ 	{
+-		.compatible = "rockchip,px30",
++		.compatible = "adlink,lec-px30",
+ 		.data = (void *)&px30_get_soc_info,
+ 	},
+ 	{
+-- 
+2.7.4
+
diff --git a/layers/meta-balena-nanopc-t4/recipes-kernel/linux/files/4.4.185/0006-Added-Sx150x-gpio-expander-suppport-for-LEC-PX30-A2.patch b/layers/meta-balena-nanopc-t4/recipes-kernel/linux/files/4.4.185/0006-Added-Sx150x-gpio-expander-suppport-for-LEC-PX30-A2.patch
new file mode 100644
index 000000000..fbc80f9cb
--- /dev/null
+++ b/layers/meta-balena-nanopc-t4/recipes-kernel/linux/files/4.4.185/0006-Added-Sx150x-gpio-expander-suppport-for-LEC-PX30-A2.patch
@@ -0,0 +1,289 @@
+From 1044a22daf998d8ba03001906ecd54cfb223ba35 Mon Sep 17 00:00:00 2001
+From: Dineshkumar V <dineshkumar.varadarajan@adlinktech.com>
+Date: Wed, 19 Feb 2020 16:10:40 +0530
+Subject: [PATCH 6/6] Added Sx150x gpio expander suppport for LEC-PX30-A2
+
+---
+ drivers/gpio/gpio-sx150x.c | 242 ++++++++++++++++++++++++++++++++++++++++++++-
+ 1 file changed, 240 insertions(+), 2 deletions(-)
+
+diff --git a/drivers/gpio/gpio-sx150x.c b/drivers/gpio/gpio-sx150x.c
+index c014515..1011aa5 100644
+--- a/drivers/gpio/gpio-sx150x.c
++++ b/drivers/gpio/gpio-sx150x.c
+@@ -620,6 +620,224 @@ static int sx150x_install_irq_chip(struct sx150x_chip *chip,
+ 
+ 	return err;
+ }
++static struct sx150x_platform_data *of_sx150x_get_platdata(
++                                        struct i2c_client *client)
++{
++        int rc, gpio;
++        struct sx150x_platform_data *pdata;
++        struct device_node *np;
++	u32 value;
++        if (!client->dev.of_node)
++                return NULL;
++        np = client->dev.of_node;
++        pdata = devm_kzalloc(&client->dev, sizeof(*pdata), GFP_KERNEL);
++        if (!pdata)
++                return ERR_PTR(-ENOMEM);
++        gpio = of_get_named_gpio(np, "int-gpios", 0);
++        if (gpio_is_valid(gpio)) {
++                rc = devm_gpio_request_one(&client->dev, gpio,
++                        GPIOF_DIR_IN, "sx150x_interrupt");
++                if (rc)
++                        return ERR_PTR(rc);
++        }
++        pdata->irq_summary = irq_of_parse_and_map(np, 0);
++        if (!pdata->irq_summary)
++                return ERR_PTR(-EPROBE_DEFER);
++        pdata->oscio_is_gpo = of_property_read_bool(np, "oscio_is_gpo");
++        pdata->reset_during_probe =of_property_read_bool(np, "reset_during_probe");
++        rc = of_property_read_u32(np, "pullup_ena",&value);
++        if (rc)
++                pdata->io_pullup_ena = 0;
++	else
++		pdata->io_pullup_ena = value&0xffff;
++        rc = of_property_read_u32(np, "pulldn_ena",&value);
++        if (rc)
++                pdata->io_pulldn_ena = 0;
++	else
++		pdata->io_pulldn_ena = value&0xffff;
++        rc = of_property_read_u32(np, "open_drain_ena",&value);
++        if (rc)
++                pdata->io_open_drain_ena = 0;
++	else
++		pdata->io_pulldn_ena = value&0xffff;
++        rc = of_property_read_u32(np, "polarity",&value);
++        if (rc)
++                pdata->io_polarity = 0;
++	else
++		pdata->io_polarity = value&0xffff;
++	printk("io_pullup_ena=0x%x,io_pulldn_ena=0x%x,io_open_drain_ena=0x%x,pdata->io_polarity=0x%x\n",pdata->io_pullup_ena,pdata->io_pulldn_ena,pdata->io_open_drain_ena,pdata->io_polarity);
++        pdata->gpio_base = -1;
++        pdata->irq_base = 0;
++        return pdata;
++}
++//test pwd
++#if 0
++void init(struct i2c_client *client)
++{
++#define REG_MISC 0x1f
++#define REG_CLOCK 0x1e
++	sx150x_i2c_write(client,REG_MISC,16);
++	sx150x_i2c_write(client,REG_CLOCK,64);
++}
++#define 	REG_INPUT_DISABLE_B		0x00	//	RegInputDisableB Input buffer disable register _ I/O[15_8] (Bank B) 0000 0000
++#define 	REG_INPUT_DISABLE_A		0x01	//	RegInputDisableA Input buffer disable register _ I/O[7_0] (Bank A) 0000 0000
++#define 	REG_LONG_SLEW_B			0x02	//	RegLongSlewB Output buffer long slew register _ I/O[15_8] (Bank B) 0000 0000
++#define 	REG_LONG_SLEW_A			0x03	//	RegLongSlewA Output buffer long slew register _ I/O[7_0] (Bank A) 0000 0000
++#define 	REG_LOW_DRIVE_B			0x04	//	RegLowDriveB Output buffer low drive register _ I/O[15_8] (Bank B) 0000 0000
++#define 	REG_LOW_DRIVE_A			0x05	//	RegLowDriveA Output buffer low drive register _ I/O[7_0] (Bank A) 0000 0000
++#define 	REG_PULL_UP_B			0x06	//	RegPullUpB Pull_up register _ I/O[15_8] (Bank B) 0000 0000
++#define 	REG_PULL_UP_A			0x07	//	RegPullUpA Pull_up register _ I/O[7_0] (Bank A) 0000 0000
++#define 	REG_PULL_DOWN_B			0x08	//	RegPullDownB Pull_down register _ I/O[15_8] (Bank B) 0000 0000
++#define 	REG_PULL_DOWN_A			0x09	//	RegPullDownA Pull_down register _ I/O[7_0] (Bank A) 0000 0000
++#define 	REG_OPEN_DRAIN_B		0x0A	//	RegOpenDrainB Open drain register _ I/O[15_8] (Bank B) 0000 0000
++#define 	REG_OPEN_DRAIN_A		0x0B	//	RegOpenDrainA Open drain register _ I/O[7_0] (Bank A) 0000 0000
++#define 	REG_POLARITY_B			0x0C	//	RegPolarityB Polarity register _ I/O[15_8] (Bank B) 0000 0000
++#define 	REG_POLARITY_A			0x0D	//	RegPolarityA Polarity register _ I/O[7_0] (Bank A) 0000 0000
++#define 	REG_DIR_B				0x0E	//	RegDirB Direction register _ I/O[15_8] (Bank B) 1111 1111
++#define 	REG_DIR_A				0x0F	//	RegDirA Direction register _ I/O[7_0] (Bank A) 1111 1111
++#define 	REG_DATA_B				0x10	//	RegDataB Data register _ I/O[15_8] (Bank B) 1111 1111*
++#define 	REG_DATA_A				0x11	//	RegDataA Data register _ I/O[7_0] (Bank A) 1111 1111*
++#define 	REG_INTERRUPT_MASK_B	0x12	//	RegInterruptMaskB Interrupt mask register _ I/O[15_8] (Bank B) 1111 1111
++#define 	REG_INTERRUPT_MASK_A	0x13	//	RegInterruptMaskA Interrupt mask register _ I/O[7_0] (Bank A) 1111 1111
++#define 	REG_SENSE_HIGH_B		0x14	//	RegSenseHighB Sense register for I/O[15:12] 0000 0000
++#define 	REG_SENSE_LOW_B			0x15	//	RegSenseLowB Sense register for I/O[11:8] 0000 0000
++#define 	REG_SENSE_HIGH_A		0x16	//	RegSenseHighA Sense register for I/O[7:4] 0000 0000
++#define 	REG_SENSE_LOW_A			0x17	//	RegSenseLowA Sense register for I/O[3:0] 0000 0000
++#define 	REG_INTERRUPT_SOURCE_B	0x18	//	RegInterruptSourceB Interrupt source register _ I/O[15_8] (Bank B) 0000 0000
++#define 	REG_INTERRUPT_SOURCE_A	0x19	//	RegInterruptSourceA Interrupt source register _ I/O[7_0] (Bank A) 0000 0000
++#define 	REG_EVENT_STATUS_B		0x1A	//	RegEventStatusB Event status register _ I/O[15_8] (Bank B) 0000 0000
++#define 	REG_EVENT_STATUS_A		0x1B	//	RegEventStatusA Event status register _ I/O[7_0] (Bank A) 0000 0000
++#define 	REG_LEVEL_SHIFTER_1		0x1C	//	RegLevelShifter1 Level shifter register 0000 0000
++#define 	REG_LEVEL_SHIFTER_2		0x1D	//	RegLevelShifter2 Level shifter register 0000 0000
++#define 	REG_LED_DRIVER_ENABLE_B	0x20	//	RegLEDDriverEnableB LED driver enable register _ I/O[15_8] (Bank B) 0000 0000
++#define 	REG_LED_DRIVER_ENABLE_A	0x21	//	RegLEDDriverEnableA LED driver enable register _ I/O[7_0] (Bank A) 0000 0000
++#define 	REG_DEBOUNCE_CONFIG		0x22	//	RegDebounceConfig Debounce configuration register 0000 0000
++#define 	REG_DEBOUNCE_ENABLE_B	0x23	//	RegDebounceEnableB Debounce enable register _ I/O[15_8] (Bank B) 0000 0000
++#define 	REG_DEBOUNCE_ENABLE_A	0x24	//	RegDebounceEnableA Debounce enable register _ I/O[7_0] (Bank A) 0000 0000
++#define 	REG_KEY_CONFIG_1		0x25	//	RegKeyConfig1 Key scan configuration register 0000 0000
++#define 	REG_KEY_CONFIG_2		0x26	//	RegKeyConfig2 Key scan configuration register 0000 0000
++#define 	REG_KEY_DATA_1			0x27	//	RegKeyData1 Key value (column) 1111 1111
++#define 	REG_KEY_DATA_2			0x28	//	RegKeyData2 Key value (row) 1111 1111
++#define 	REG_T_ON_0				0x29	//	RegTOn0 ON time register for I/O[0] 0000 0000
++#define 	REG_I_ON_0				0x2A	//	RegIOn0 ON intensity register for I/O[0] 1111 1111
++#define 	REG_OFF_0				0x2B	//	RegOff0 OFF time/intensity register for I/O[0] 0000 0000
++#define 	REG_T_ON_1				0x2C	//	RegTOn1 ON time register for I/O[1] 0000 0000
++#define 	REG_I_ON_1				0x2D	//	RegIOn1 ON intensity register for I/O[1] 1111 1111
++#define 	REG_OFF_1				0x2E	//	RegOff1 OFF time/intensity register for I/O[1] 0000 0000
++#define 	REG_T_ON_2				0x2F	//	RegTOn2 ON time register for I/O[2] 0000 0000
++#define 	REG_I_ON_2				0x30	//	RegIOn2 ON intensity register for I/O[2] 1111 1111
++#define 	REG_OFF_2				0x31	//	RegOff2 OFF time/intensity register for I/O[2] 0000 0000
++#define 	REG_T_ON_3				0x32	//	RegTOn3 ON time register for I/O[3] 0000 0000
++#define 	REG_I_ON_3				0x33	//	RegIOn3 ON intensity register for I/O[3] 1111 1111
++#define 	REG_OFF_3				0x34	//	RegOff3 OFF time/intensity register for I/O[3] 0000 0000
++#define 	REG_T_ON_4				0x35	//	RegTOn4 ON time register for I/O[4] 0000 0000
++#define 	REG_I_ON_4				0x36	//	RegIOn4 ON intensity register for I/O[4] 1111 1111
++#define 	REG_OFF_4				0x37	//	RegOff4 OFF time/intensity register for I/O[4] 0000 0000
++#define 	REG_T_RISE_4			0x38	//	RegTRise4 Fade in register for I/O[4] 0000 0000
++#define 	REG_T_FALL_4			0x39	//	RegTFall4 Fade out register for I/O[4] 0000 0000
++#define 	REG_T_ON_5				0x3A	//	RegTOn5 ON time register for I/O[5] 0000 0000
++#define 	REG_I_ON_5				0x3B	//	RegIOn5 ON intensity register for I/O[5] 1111 1111
++#define 	REG_OFF_5				0x3C	//	RegOff5 OFF time/intensity register for I/O[5] 0000 0000
++#define 	REG_T_RISE_5			0x3D	//	RegTRise5 Fade in register for I/O[5] 0000 0000
++#define 	REG_T_FALL_5			0x3E	//	RegTFall5 Fade out register for I/O[5] 0000 0000
++#define 	REG_T_ON_6				0x3F	//	RegTOn6 ON time register for I/O[6] 0000 0000
++#define 	REG_I_ON_6				0x40	//	RegIOn6 ON intensity register for I/O[6] 1111 1111
++#define 	REG_OFF_6				0x41	//	RegOff6 OFF time/intensity register for I/O[6] 0000 0000
++#define 	REG_T_RISE_6			0x42	//	RegTRise6 Fade in register for I/O[6] 0000 0000
++#define 	REG_T_FALL_6			0x43	//	RegTFall6 Fade out register for I/O[6] 0000 0000
++#define 	REG_T_ON_7				0x44	//	RegTOn7 ON time register for I/O[7] 0000 0000
++#define 	REG_I_ON_7				0x45	//	RegIOn7 ON intensity register for I/O[7] 1111 1111
++#define 	REG_OFF_7				0x46	//	RegOff7 OFF time/intensity register for I/O[7] 0000 0000
++#define 	REG_T_RISE_7			0x47	//	RegTRise7 Fade in register for I/O[7] 0000 0000
++#define 	REG_T_FALL_7			0x48	//	RegTFall7 Fade out register for I/O[7] 0000 0000
++#define 	REG_T_ON_8				0x49	//	RegTOn8 ON time register for I/O[8] 0000 0000
++#define 	REG_I_ON_8				0x4A	//	RegIOn8 ON intensity register for I/O[8] 1111 1111
++#define 	REG_OFF_8				0x4B	//	RegOff8 OFF time/intensity register for I/O[8] 0000 0000
++#define 	REG_T_ON_9				0x4C	//	RegTOn9 ON time register for I/O[9] 0000 0000
++#define 	REG_I_ON_9				0x4D	//	RegIOn9 ON intensity register for I/O[9] 1111 1111
++#define 	REG_OFF_9				0x4E	//	RegOff9 OFF time/intensity register for I/O[9] 0000 0000
++#define 	REG_T_ON_10				0x4F	//	RegTOn10 ON time register for I/O[10] 0000 0000
++#define 	REG_I_ON_10				0x50	//	RegIOn10 ON intensity register for I/O[10] 1111 1111
++#define 	REG_OFF_10				0x51	//	RegOff10 OFF time/intensity register for I/O[10] 0000 0000
++#define 	REG_T_ON_11				0x52	//	RegTOn11 ON time register for I/O[11] 0000 0000
++#define 	REG_I_ON_11				0x53	//	RegIOn11 ON intensity register for I/O[11] 1111 1111
++#define 	REG_OFF_11				0x54	//	RegOff11 OFF time/intensity register for I/O[11] 0000 0000
++#define 	REG_T_ON_12				0x55	//	RegTOn12 ON time register for I/O[12] 0000 0000
++#define 	REG_I_ON_12				0x56	//	RegIOn12 ON intensity register for I/O[12] 1111 1111
++#define 	REG_OFF_12				0x57	//	RegOff12 OFF time/intensity register for I/O[12] 0000 0000
++#define 	REG_T_RISE_12			0x58	//	RegTRise12 Fade in register for I/O[12] 0000 0000
++#define 	REG_T_FALL_12			0x59	//	RegTFall12 Fade out register for I/O[12] 0000 0000
++#define 	REG_T_ON_13				0x5A	//	RegTOn13 ON time register for I/O[13] 0000 0000
++#define 	REG_I_ON_13				0x5B	//	RegIOn13 ON intensity register for I/O[13] 1111 1111
++#define 	REG_OFF_13				0x5C	//	RegOff13 OFF time/intensity register for I/O[13] 0000 0000
++#define 	REG_T_RISE_13			0x5D	//	RegTRise13 Fade in register for I/O[13] 0000 0000
++#define 	REG_T_FALL_13			0x5E	//	RegTFall13 Fade out register for I/O[13] 0000 0000
++#define 	REG_T_ON_14				0x5F	//	RegTOn14 ON time register for I/O[14] 0000 0000
++#define 	REG_I_ON_14				0x60	//	RegIOn14 ON intensity register for I/O[14] 1111 1111
++#define 	REG_OFF_14				0x61	//	RegOff14 OFF time/intensity register for I/O[14] 0000 0000
++#define 	REG_T_RISE_14			0x62	//	RegTRise14 Fade in register for I/O[14] 0000 0000
++#define 	REG_T_FALL_14			0x63	//	RegTFall14 Fade out register for I/O[14] 0000 0000
++#define 	REG_T_ON_15				0x64	//	RegTOn15 ON time register for I/O[15] 0000 0000
++#define 	REG_I_ON_15				0x65	//	RegIOn15 ON intensity register for I/O[15] 1111 1111
++#define 	REG_OFF_15				0x66	//	RegOff15 OFF time/intensity register for I/O[15] 0000 0000
++#define 	REG_T_RISE_15			0x67	//	RegTRise15 Fade in register for I/O[15] 0000 0000
++#define 	REG_T_FALL_15			0x68	//	RegTFall15 Fade out register for I/O[15] 0000 0000
++#define 	REG_HIGH_INPUT_B		0x69	//	RegHighInputB High input enable register _ I/O[15_8] (Bank B) 0000 0000
++#define 	REG_HIGH_INPUT_A		0x6A	//	RegHighInputA High input enable register _ I/O[7_0] (Bank A) 0000 0000
++#define 	REG_RESET				0x7D	//	RegReset Software reset register 0000 0000
++#define 	REG_TEST_1				0x7E	//	RegTest1 Test register 0000 0000
++#define 	REG_TEST_2				0x7F	//	RegTest2 Test register 0000 0000
++uint8_t REG_I_ON[16] = {REG_I_ON_0, REG_I_ON_1, REG_I_ON_2, REG_I_ON_3,
++					REG_I_ON_4, REG_I_ON_5, REG_I_ON_6, REG_I_ON_7,
++					REG_I_ON_8, REG_I_ON_9, REG_I_ON_10, REG_I_ON_11,
++					REG_I_ON_12, REG_I_ON_13, REG_I_ON_14, REG_I_ON_15};
++void  ledDriverInit(struct i2c_client *client, uint8_t pin)
++{
++	if(pin > 7)
++	{
++		uint8_t pinb = pin-8;
++		uint8_t temp;
++		sx150x_i2c_read(client,REG_INPUT_DISABLE_B,&temp);
++		temp |= (1<<pinb);
++		sx150x_i2c_write(client,REG_INPUT_DISABLE_B,temp);
++		sx150x_i2c_read(client,REG_PULL_UP_B,&temp);
++		temp &= ~(1<<pinb);
++		sx150x_i2c_write(client,REG_PULL_UP_B,temp);
++		sx150x_i2c_read(client,REG_DIR_B,&temp);
++                temp &= ~(1<<pinb);
++                sx150x_i2c_write(client,REG_DIR_B,temp);
++		sx150x_i2c_read(client,REG_LED_DRIVER_ENABLE_B,&temp);
++                temp |= (1<<pinb);
++                sx150x_i2c_write(client,REG_LED_DRIVER_ENABLE_B,temp);
++		sx150x_i2c_read(client,REG_DATA_B,&temp);
++                temp &= ~(1<<pinb);
++                sx150x_i2c_write(client,REG_DATA_B,temp);
++	}
++	else
++	{
++		uint8_t temp;
++                sx150x_i2c_read(client,REG_INPUT_DISABLE_A,&temp);
++                temp |= (1<<pin);
++                sx150x_i2c_write(client,REG_INPUT_DISABLE_A,temp);
++                sx150x_i2c_read(client,REG_PULL_UP_A,&temp);
++                temp &= ~(1<<pin);
++                sx150x_i2c_write(client,REG_PULL_UP_A,temp);
++                sx150x_i2c_read(client,REG_DIR_A,&temp);
++                temp &= ~(1<<pin);
++                sx150x_i2c_write(client,REG_DIR_A,temp);
++                sx150x_i2c_read(client,REG_LED_DRIVER_ENABLE_A,&temp);
++                temp |= (1<<pin);
++                sx150x_i2c_write(client,REG_LED_DRIVER_ENABLE_A,temp);
++                sx150x_i2c_read(client,REG_DATA_A,&temp);
++                temp &= ~(1<<pin);
++                sx150x_i2c_write(client,REG_DATA_A,temp);
++	}	
++}
++void  analogWrite(struct i2c_client *client,uint8_t pin,uint8_t cycle)
++{
++	sx150x_i2c_write(client,REG_I_ON[pin], cycle);
++}
++#endif
+ 
+ static int sx150x_probe(struct i2c_client *client,
+ 				const struct i2c_device_id *id)
+@@ -629,10 +847,15 @@ static int sx150x_probe(struct i2c_client *client,
+ 	struct sx150x_platform_data *pdata;
+ 	struct sx150x_chip *chip;
+ 	int rc;
+-
++	int irq;
+ 	pdata = dev_get_platdata(&client->dev);
++	if (!pdata) {
++                pdata = of_sx150x_get_platdata(client);
+ 	if (!pdata)
+ 		return -EINVAL;
++                else if (IS_ERR(pdata))
++                        return PTR_ERR(pdata);
++        }
+ 
+ 	if (!i2c_check_functionality(client->adapter, i2c_funcs))
+ 		return -ENOSYS;
+@@ -650,7 +873,7 @@ static int sx150x_probe(struct i2c_client *client,
+ 	rc = gpiochip_add(&chip->gpio_chip);
+ 	if (rc)
+ 		return rc;
+-
++	printk("pdata->irq_summary=%d\n",pdata->irq_summary);
+ 	if (pdata->irq_summary >= 0) {
+ 		rc = sx150x_install_irq_chip(chip,
+ 					pdata->irq_summary,
+@@ -661,6 +884,21 @@ static int sx150x_probe(struct i2c_client *client,
+ 
+ 	i2c_set_clientdata(client, chip);
+ 
++	gpio_direction_input(504);//pin 8
++	irq=gpio_to_irq(504);
++	printk("sx1509 irq=%d\n",irq);
++	enable_irq(irq);
++	printk("###########probe ok\n");
++#if 0
++	printk("sx150x test for pwm\n");
++	init(client);
++	for(i=0; i < 16; i++)
++	{
++		ledDriverInit(client,i);
++		analogWrite(client,i,127);
++	}
++	 printk("sx150xtest for pwm end\n");
++#endif
+ 	return 0;
+ probe_fail_post_gpiochip_add:
+ 	gpiochip_remove(&chip->gpio_chip);
+-- 
+2.7.4
+
diff --git a/layers/meta-balena-nanopc-t4/recipes-kernel/linux/files/4.4.185/0007-Added-SPI-chip-select-enable-disable-support-for-SPI.patch b/layers/meta-balena-nanopc-t4/recipes-kernel/linux/files/4.4.185/0007-Added-SPI-chip-select-enable-disable-support-for-SPI.patch
new file mode 100644
index 000000000..d7c8532ae
--- /dev/null
+++ b/layers/meta-balena-nanopc-t4/recipes-kernel/linux/files/4.4.185/0007-Added-SPI-chip-select-enable-disable-support-for-SPI.patch
@@ -0,0 +1,112 @@
+From 2ed09d2c6dabe7ae167b4e1fa585f5e1fbced5b2 Mon Sep 17 00:00:00 2001
+From: Dineshkumar V <dineshkumar.varadarajan@adlinktech.com>
+Date: Wed, 26 Feb 2020 18:45:49 +0530
+Subject: [PATCH 7/7] Added SPI chip select enable/disable support for SPI
+ Read/Write
+
+---
+ drivers/spi/spi-rockchip.c | 14 ++------------
+ drivers/spi/spi.c          | 18 ++++++++++++++++--
+ include/linux/spi/spi.h    |  1 +
+ 3 files changed, 19 insertions(+), 14 deletions(-)
+
+diff --git a/drivers/spi/spi-rockchip.c b/drivers/spi/spi-rockchip.c
+index a9a6339..7e44fcf 100644
+--- a/drivers/spi/spi-rockchip.c
++++ b/drivers/spi/spi-rockchip.c
+@@ -433,18 +433,9 @@ static void rockchip_spi_dma_txcb(void *data)
+ 	spin_unlock_irqrestore(&rs->lock, flags);
+ }
+ 
+-static u32 rockchip_spi_calc_burst_size(u32 data_len)
+-{
+-	u32 i;
+ 
+ 	/* burst size: 1, 2, 4, 8 */
+-	for (i = 1; i < 8; i <<= 1) {
+-		if (data_len & i)
+-			break;
+-	}
+ 
+-	return i;
+-}
+ 
+ static int rockchip_spi_prepare_dma(struct rockchip_spi *rs)
+ {
+@@ -465,7 +456,7 @@ static int rockchip_spi_prepare_dma(struct rockchip_spi *rs)
+ 		rxconf.direction = rs->dma_rx.direction;
+ 		rxconf.src_addr = rs->dma_rx.addr;
+ 		rxconf.src_addr_width = rs->n_bytes;
+-		rxconf.src_maxburst = rockchip_spi_calc_burst_size(rs->len / rs->n_bytes);
++		rxconf.src_maxburst = 1;
+ 		dmaengine_slave_config(rs->dma_rx.ch, &rxconf);
+ 
+ 		rxdesc = dmaengine_prep_slave_sg(
+@@ -598,8 +589,7 @@ static void rockchip_spi_config(struct rockchip_spi *rs)
+ 	writel_relaxed(rs->fifo_len / 2 - 1, rs->regs + ROCKCHIP_SPI_RXFTLR);
+ 
+ 	writel_relaxed(rs->fifo_len / 2 - 1, rs->regs + ROCKCHIP_SPI_DMATDLR);
+-	writel_relaxed(rockchip_spi_calc_burst_size(rs->len / rs->n_bytes) - 1,
+-		       rs->regs + ROCKCHIP_SPI_DMARDLR);
++	writel_relaxed(0, rs->regs + ROCKCHIP_SPI_DMARDLR);
+ 	writel_relaxed(dmacr, rs->regs + ROCKCHIP_SPI_DMACR);
+ 
+ 	spi_set_clk(rs, div);
+diff --git a/drivers/spi/spi.c b/drivers/spi/spi.c
+index c132c67..6b94ee4 100644
+--- a/drivers/spi/spi.c
++++ b/drivers/spi/spi.c
+@@ -673,6 +673,10 @@ static void spi_set_cs(struct spi_device *spi, bool enable)
+ 	if (spi->mode & SPI_CS_HIGH)
+ 		enable = !enable;
+ 
++	if(spi->spi_gpio_cs>0)
++	{
++		gpio_set_value(spi->spi_gpio_cs,!enable);
++	}
+ 	if (gpio_is_valid(spi->cs_gpio))
+ 		gpio_set_value(spi->cs_gpio, !enable);
+ 	else if (spi->master->set_cs)
+@@ -903,8 +907,6 @@ static int spi_map_msg(struct spi_master *master, struct spi_message *msg)
+ 		if (max_tx || max_rx) {
+ 			list_for_each_entry(xfer, &msg->transfers,
+ 					    transfer_list) {
+-				if (!xfer->len)
+-					continue;
+ 				if (!xfer->tx_buf)
+ 					xfer->tx_buf = master->dummy_tx;
+ 				if (!xfer->rx_buf)
+@@ -1521,6 +1523,18 @@ of_register_spi_device(struct spi_master *master, struct device_node *nc)
+ 	}
+ 	spi->max_speed_hz = value;
+ 
++	spi->spi_gpio_cs=of_get_named_gpio(nc,"spi-gpio-cs",0);
++	if(spi->spi_gpio_cs>0)
++	{
++		printk("spi->spi_gpio_cs=%d\n",spi->spi_gpio_cs);
++		rc = gpio_request(spi->spi_gpio_cs, "spi0_gpio_cs");
++       		if (rc != 0) {
++                	gpio_free(spi->spi_gpio_cs);
++                printk("gpio request spi_gpio_cs  failed\n");
++        	}
++        	else
++                    gpio_direction_output(spi->spi_gpio_cs, 1);
++        }	
+ 	/* Store a pointer to the node in the device structure */
+ 	of_node_get(nc);
+ 	spi->dev.of_node = nc;
+diff --git a/include/linux/spi/spi.h b/include/linux/spi/spi.h
+index cce80e6..e1b8c04 100644
+--- a/include/linux/spi/spi.h
++++ b/include/linux/spi/spi.h
+@@ -158,6 +158,7 @@ struct spi_device {
+ 	void			*controller_data;
+ 	char			modalias[SPI_NAME_SIZE];
+ 	int			cs_gpio;	/* chip select gpio */
++	int 			spi_gpio_cs;/*add by lm*/
+ 
+ 	/* the statistics */
+ 	struct spi_statistics	statistics;
+-- 
+2.7.4
+
diff --git a/layers/meta-balena-nanopc-t4/recipes-kernel/linux/files/4.4.185/0008-Modified-Boot-Arguments-to-mount-fileystem-from-SD-c.patch b/layers/meta-balena-nanopc-t4/recipes-kernel/linux/files/4.4.185/0008-Modified-Boot-Arguments-to-mount-fileystem-from-SD-c.patch
new file mode 100644
index 000000000..f057c7bee
--- /dev/null
+++ b/layers/meta-balena-nanopc-t4/recipes-kernel/linux/files/4.4.185/0008-Modified-Boot-Arguments-to-mount-fileystem-from-SD-c.patch
@@ -0,0 +1,25 @@
+From 981b285389321d180d4dad2e81cf34f513fa507e Mon Sep 17 00:00:00 2001
+From: Arun Kumar E V <dineshkumar.varadarajan@adlinktech.com>
+Date: Tue, 3 Mar 2020 15:21:29 +0530
+Subject: [PATCH 9/9] Modified Boot Arguments to mount fileystem from SD card
+
+---
+ arch/arm64/boot/dts/rockchip/rk3326-linux.dtsi | 2 +-
+ 1 file changed, 1 insertion(+), 1 deletion(-)
+
+diff --git a/arch/arm64/boot/dts/rockchip/rk3326-linux.dtsi b/arch/arm64/boot/dts/rockchip/rk3326-linux.dtsi
+index 9fbb720..4f2c272 100644
+--- a/arch/arm64/boot/dts/rockchip/rk3326-linux.dtsi
++++ b/arch/arm64/boot/dts/rockchip/rk3326-linux.dtsi
+@@ -45,7 +45,7 @@
+ 
+ 	chosen {
+  		//bootargs = "earlycon=uart8250,mmio32,0xff160000 swiotlb=1 console=ttyFIQ0 rw root=PARTUUID=614e0000-0000 rootwait";
+-		bootargs = "earlycon=uart8250,mmio32,0xff160000 swiotlb=1 console=ttyFIQ0 rw root=/dev/mmcblk1p4 rootwait";
++		bootargs = "earlycon=uart8250,mmio32,0xff160000 swiotlb=1 console=ttyFIQ0 rw root=/dev/mmcblk0p4 rootwait";
+ 	/*	 bootargs = "console=tty1 rw root=PARTUUID=614e0000-0000 rootwait";*/
+ 	};
+ 
+-- 
+2.7.4
+
diff --git a/layers/meta-balena-nanopc-t4/recipes-kernel/linux/files/4.4.185/adjust_wireless_firmware_path.patch b/layers/meta-balena-nanopc-t4/recipes-kernel/linux/files/4.4.185/adjust_wireless_firmware_path.patch
new file mode 100644
index 000000000..c9b6f9fcd
--- /dev/null
+++ b/layers/meta-balena-nanopc-t4/recipes-kernel/linux/files/4.4.185/adjust_wireless_firmware_path.patch
@@ -0,0 +1,24 @@
+Patch imported from https://github.com/armbian/build.git at revision c55f6ea8bc220bded6695fdae8b0c5bfa891b688
+
+Upstream-Status: Inappropriate [not author]
+Signed-off-by: Florin Sarbu <florin@balena.io>
+---
+ drivers/net/wireless/rockchip_wlan/rkwifi/rk_wifi_config.c | 2 +-
+ 1 file changed, 1 insertion(+), 1 deletion(-)
+
+diff --git a/drivers/net/wireless/rockchip_wlan/rkwifi/rk_wifi_config.c b/drivers/net/wireless/rockchip_wlan/rkwifi/rk_wifi_config.c
+index fa07a94..352ea75 100644
+--- a/drivers/net/wireless/rockchip_wlan/rkwifi/rk_wifi_config.c
++++ b/drivers/net/wireless/rockchip_wlan/rkwifi/rk_wifi_config.c
+@@ -18,7 +18,7 @@
+  */
+  
+ #define VENDOR_ETC_FIRMWARE "/vendor/etc/firmware/"
+-#define SYSTEM_ETC_FIRMWARE "/system/etc/firmware/"
++#define SYSTEM_ETC_FIRMWARE "/lib/firmware/rkwifi/"
+ char ANDROID_FW_PATH[64] = {0};
+ 
+ extern int get_wifi_chip_type(void);
+-- 
+2.7.4
+
diff --git a/layers/meta-balena-nanopc-t4/recipes-kernel/linux/files/4.4.185/defconfig b/layers/meta-balena-nanopc-t4/recipes-kernel/linux/files/4.4.185/defconfig
new file mode 100644
index 000000000..fbe7cebd8
--- /dev/null
+++ b/layers/meta-balena-nanopc-t4/recipes-kernel/linux/files/4.4.185/defconfig
@@ -0,0 +1,4411 @@
+#
+# Automatically generated file; DO NOT EDIT.
+# Linux/arm64 4.4.185 Kernel Configuration
+#
+CONFIG_ARM64=y
+CONFIG_64BIT=y
+CONFIG_ARCH_PHYS_ADDR_T_64BIT=y
+CONFIG_MMU=y
+CONFIG_ARCH_MMAP_RND_BITS_MIN=18
+CONFIG_ARCH_MMAP_RND_BITS_MAX=24
+CONFIG_ARCH_MMAP_RND_COMPAT_BITS_MIN=11
+CONFIG_ARCH_MMAP_RND_COMPAT_BITS_MAX=16
+CONFIG_ARM64_PAGE_SHIFT=12
+CONFIG_ARM64_CONT_SHIFT=4
+CONFIG_NO_IOPORT_MAP=y
+CONFIG_STACKTRACE_SUPPORT=y
+CONFIG_ILLEGAL_POINTER_VALUE=0xdead000000000000
+CONFIG_LOCKDEP_SUPPORT=y
+CONFIG_TRACE_IRQFLAGS_SUPPORT=y
+CONFIG_RWSEM_XCHGADD_ALGORITHM=y
+CONFIG_GENERIC_BUG=y
+CONFIG_GENERIC_BUG_RELATIVE_POINTERS=y
+CONFIG_GENERIC_HWEIGHT=y
+CONFIG_GENERIC_CSUM=y
+CONFIG_GENERIC_CALIBRATE_DELAY=y
+CONFIG_ZONE_DMA=y
+CONFIG_HAVE_GENERIC_RCU_GUP=y
+CONFIG_ARCH_DMA_ADDR_T_64BIT=y
+CONFIG_NEED_DMA_MAP_STATE=y
+CONFIG_NEED_SG_DMA_LENGTH=y
+CONFIG_SMP=y
+CONFIG_SWIOTLB=y
+CONFIG_IOMMU_HELPER=y
+CONFIG_KERNEL_MODE_NEON=y
+CONFIG_FIX_EARLYCON_MEM=y
+CONFIG_PGTABLE_LEVELS=3
+CONFIG_DEFCONFIG_LIST="/lib/modules/$UNAME_RELEASE/.config"
+CONFIG_IRQ_WORK=y
+CONFIG_BUILDTIME_EXTABLE_SORT=y
+CONFIG_THREAD_INFO_IN_TASK=y
+
+#
+# General setup
+#
+CONFIG_INIT_ENV_ARG_LIMIT=32
+CONFIG_CROSS_COMPILE=""
+# CONFIG_COMPILE_TEST is not set
+CONFIG_LOCALVERSION="-rockchip-standard"
+CONFIG_LOCALVERSION_AUTO=y
+CONFIG_DEFAULT_HOSTNAME="localhost"
+CONFIG_SWAP=y
+CONFIG_SYSVIPC=y
+CONFIG_SYSVIPC_SYSCTL=y
+# CONFIG_POSIX_MQUEUE is not set
+CONFIG_CROSS_MEMORY_ATTACH=y
+CONFIG_FHANDLE=y
+CONFIG_USELIB=y
+# CONFIG_AUDIT is not set
+CONFIG_HAVE_ARCH_AUDITSYSCALL=y
+
+#
+# IRQ subsystem
+#
+CONFIG_GENERIC_IRQ_PROBE=y
+CONFIG_GENERIC_IRQ_SHOW=y
+CONFIG_GENERIC_IRQ_SHOW_LEVEL=y
+CONFIG_GENERIC_IRQ_MIGRATION=y
+CONFIG_HARDIRQS_SW_RESEND=y
+CONFIG_GENERIC_IRQ_CHIP=y
+CONFIG_IRQ_DOMAIN=y
+CONFIG_IRQ_DOMAIN_HIERARCHY=y
+CONFIG_HANDLE_DOMAIN_IRQ=y
+# CONFIG_IRQ_DOMAIN_DEBUG is not set
+CONFIG_IRQ_FORCED_THREADING=y
+CONFIG_SPARSE_IRQ=y
+CONFIG_GENERIC_TIME_VSYSCALL=y
+CONFIG_GENERIC_CLOCKEVENTS=y
+CONFIG_ARCH_HAS_TICK_BROADCAST=y
+CONFIG_GENERIC_CLOCKEVENTS_BROADCAST=y
+
+#
+# Timers subsystem
+#
+CONFIG_TICK_ONESHOT=y
+CONFIG_NO_HZ_COMMON=y
+# CONFIG_HZ_PERIODIC is not set
+CONFIG_NO_HZ_IDLE=y
+# CONFIG_NO_HZ_FULL is not set
+CONFIG_NO_HZ=y
+CONFIG_HIGH_RES_TIMERS=y
+
+#
+# CPU/Task time and stats accounting
+#
+CONFIG_TICK_CPU_ACCOUNTING=y
+# CONFIG_VIRT_CPU_ACCOUNTING_GEN is not set
+# CONFIG_IRQ_TIME_ACCOUNTING is not set
+# CONFIG_SCHED_WALT is not set
+# CONFIG_BSD_PROCESS_ACCT is not set
+# CONFIG_TASKSTATS is not set
+
+#
+# RCU Subsystem
+#
+CONFIG_TREE_RCU=y
+# CONFIG_RCU_EXPERT is not set
+CONFIG_SRCU=y
+# CONFIG_TASKS_RCU is not set
+CONFIG_RCU_STALL_COMMON=y
+# CONFIG_TREE_RCU_TRACE is not set
+# CONFIG_RCU_EXPEDITE_BOOT is not set
+# CONFIG_BUILD_BIN2C is not set
+# CONFIG_IKCONFIG is not set
+CONFIG_LOG_BUF_SHIFT=18
+CONFIG_LOG_CPU_MAX_BUF_SHIFT=12
+CONFIG_GENERIC_SCHED_CLOCK=y
+CONFIG_CGROUPS=y
+# CONFIG_CGROUP_DEBUG is not set
+CONFIG_CGROUP_FREEZER=y
+# CONFIG_CGROUP_PIDS is not set
+CONFIG_CGROUP_DEVICE=y
+CONFIG_CPUSETS=y
+CONFIG_PROC_PID_CPUSET=y
+CONFIG_CGROUP_CPUACCT=y
+# CONFIG_MEMCG is not set
+# CONFIG_CGROUP_PERF is not set
+CONFIG_CGROUP_SCHED=y
+CONFIG_FAIR_GROUP_SCHED=y
+CONFIG_CFS_BANDWIDTH=y
+# CONFIG_RT_GROUP_SCHED is not set
+# CONFIG_BLK_CGROUP is not set
+# CONFIG_CHECKPOINT_RESTORE is not set
+CONFIG_NAMESPACES=y
+CONFIG_UTS_NS=y
+CONFIG_IPC_NS=y
+CONFIG_USER_NS=y
+CONFIG_PID_NS=y
+CONFIG_NET_NS=y
+# CONFIG_SCHED_AUTOGROUP is not set
+# CONFIG_SCHED_TUNE is not set
+CONFIG_DEFAULT_USE_ENERGY_AWARE=y
+# CONFIG_SYSFS_DEPRECATED is not set
+CONFIG_RELAY=y
+CONFIG_BLK_DEV_INITRD=y
+CONFIG_INITRAMFS_SOURCE=""
+CONFIG_RD_GZIP=y
+CONFIG_RD_BZIP2=y
+CONFIG_RD_LZMA=y
+CONFIG_RD_XZ=y
+CONFIG_RD_LZO=y
+CONFIG_RD_LZ4=y
+# CONFIG_INITRD_ASYNC is not set
+# CONFIG_CC_OPTIMIZE_FOR_PERFORMANCE is not set
+CONFIG_CC_OPTIMIZE_FOR_SIZE=y
+CONFIG_SYSCTL=y
+CONFIG_ANON_INODES=y
+CONFIG_HAVE_UID16=y
+CONFIG_SYSCTL_EXCEPTION_TRACE=y
+CONFIG_BPF=y
+CONFIG_EXPERT=y
+CONFIG_UID16=y
+CONFIG_MULTIUSER=y
+# CONFIG_SGETMASK_SYSCALL is not set
+CONFIG_SYSFS_SYSCALL=y
+# CONFIG_SYSCTL_SYSCALL is not set
+CONFIG_KALLSYMS=y
+# CONFIG_KALLSYMS_ALL is not set
+CONFIG_PRINTK=y
+CONFIG_BUG=y
+CONFIG_ELF_CORE=y
+CONFIG_BASE_FULL=y
+CONFIG_FUTEX=y
+CONFIG_EPOLL=y
+CONFIG_SIGNALFD=y
+CONFIG_TIMERFD=y
+CONFIG_EVENTFD=y
+# CONFIG_BPF_SYSCALL is not set
+CONFIG_SHMEM=y
+CONFIG_AIO=y
+CONFIG_ADVISE_SYSCALLS=y
+# CONFIG_USERFAULTFD is not set
+CONFIG_MEMBARRIER=y
+CONFIG_EMBEDDED=y
+CONFIG_HAVE_PERF_EVENTS=y
+CONFIG_PERF_USE_VMALLOC=y
+
+#
+# Kernel Performance Events And Counters
+#
+CONFIG_PERF_EVENTS=y
+# CONFIG_DEBUG_PERF_USE_VMALLOC is not set
+CONFIG_VM_EVENT_COUNTERS=y
+CONFIG_SLUB_DEBUG=y
+# CONFIG_COMPAT_BRK is not set
+# CONFIG_SLAB is not set
+CONFIG_SLUB=y
+# CONFIG_SLOB is not set
+CONFIG_SLUB_CPU_PARTIAL=y
+# CONFIG_SYSTEM_DATA_VERIFICATION is not set
+CONFIG_PROFILING=y
+CONFIG_TRACEPOINTS=y
+# CONFIG_KPROBES is not set
+# CONFIG_JUMP_LABEL is not set
+# CONFIG_UPROBES is not set
+# CONFIG_HAVE_64BIT_ALIGNED_ACCESS is not set
+CONFIG_HAVE_EFFICIENT_UNALIGNED_ACCESS=y
+CONFIG_HAVE_KPROBES=y
+CONFIG_HAVE_KRETPROBES=y
+CONFIG_HAVE_ARCH_TRACEHOOK=y
+CONFIG_HAVE_DMA_ATTRS=y
+CONFIG_HAVE_DMA_CONTIGUOUS=y
+CONFIG_GENERIC_SMP_IDLE_THREAD=y
+CONFIG_GENERIC_IDLE_POLL_SETUP=y
+CONFIG_HAVE_REGS_AND_STACK_ACCESS_API=y
+CONFIG_HAVE_CLK=y
+CONFIG_HAVE_DMA_API_DEBUG=y
+CONFIG_HAVE_HW_BREAKPOINT=y
+CONFIG_HAVE_PERF_REGS=y
+CONFIG_HAVE_PERF_USER_STACK_DUMP=y
+CONFIG_HAVE_ARCH_JUMP_LABEL=y
+CONFIG_HAVE_RCU_TABLE_FREE=y
+CONFIG_HAVE_ALIGNED_STRUCT_PAGE=y
+CONFIG_HAVE_CMPXCHG_LOCAL=y
+CONFIG_HAVE_CMPXCHG_DOUBLE=y
+CONFIG_ARCH_WANT_COMPAT_IPC_PARSE_VERSION=y
+CONFIG_HAVE_ARCH_SECCOMP_FILTER=y
+CONFIG_SECCOMP_FILTER=y
+CONFIG_HAVE_CC_STACKPROTECTOR=y
+# CONFIG_CC_STACKPROTECTOR is not set
+CONFIG_CC_STACKPROTECTOR_NONE=y
+# CONFIG_CC_STACKPROTECTOR_REGULAR is not set
+# CONFIG_CC_STACKPROTECTOR_STRONG is not set
+CONFIG_HAVE_CONTEXT_TRACKING=y
+CONFIG_HAVE_VIRT_CPU_ACCOUNTING_GEN=y
+CONFIG_HAVE_IRQ_TIME_ACCOUNTING=y
+CONFIG_HAVE_ARCH_TRANSPARENT_HUGEPAGE=y
+CONFIG_HAVE_ARCH_HUGE_VMAP=y
+CONFIG_MODULES_USE_ELF_RELA=y
+CONFIG_ARCH_HAS_ELF_RANDOMIZE=y
+CONFIG_HAVE_ARCH_MMAP_RND_BITS=y
+CONFIG_ARCH_MMAP_RND_BITS=18
+CONFIG_HAVE_ARCH_MMAP_RND_COMPAT_BITS=y
+CONFIG_ARCH_MMAP_RND_COMPAT_BITS=11
+CONFIG_CLONE_BACKWARDS=y
+CONFIG_OLD_SIGSUSPEND3=y
+CONFIG_COMPAT_OLD_SIGACTION=y
+
+#
+# GCOV-based kernel profiling
+#
+# CONFIG_GCOV_KERNEL is not set
+CONFIG_ARCH_HAS_GCOV_PROFILE_ALL=y
+CONFIG_HAVE_GENERIC_DMA_COHERENT=y
+CONFIG_SLABINFO=y
+CONFIG_RT_MUTEXES=y
+CONFIG_BASE_SMALL=0
+CONFIG_MODULES=y
+CONFIG_MODULE_FORCE_LOAD=y
+CONFIG_MODULE_UNLOAD=y
+CONFIG_MODULE_FORCE_UNLOAD=y
+# CONFIG_MODVERSIONS is not set
+# CONFIG_MODULE_SRCVERSION_ALL is not set
+# CONFIG_MODULE_SIG is not set
+# CONFIG_MODULE_COMPRESS is not set
+CONFIG_MODULES_TREE_LOOKUP=y
+CONFIG_BLOCK=y
+CONFIG_BLK_DEV_BSG=y
+# CONFIG_BLK_DEV_BSGLIB is not set
+# CONFIG_BLK_DEV_INTEGRITY is not set
+# CONFIG_BLK_CMDLINE_PARSER is not set
+
+#
+# Partition Types
+#
+CONFIG_PARTITION_ADVANCED=y
+# CONFIG_ACORN_PARTITION is not set
+# CONFIG_AIX_PARTITION is not set
+# CONFIG_OSF_PARTITION is not set
+# CONFIG_AMIGA_PARTITION is not set
+# CONFIG_ATARI_PARTITION is not set
+# CONFIG_MAC_PARTITION is not set
+CONFIG_MSDOS_PARTITION=y
+# CONFIG_BSD_DISKLABEL is not set
+# CONFIG_MINIX_SUBPARTITION is not set
+# CONFIG_SOLARIS_X86_PARTITION is not set
+# CONFIG_UNIXWARE_DISKLABEL is not set
+# CONFIG_LDM_PARTITION is not set
+# CONFIG_SGI_PARTITION is not set
+# CONFIG_ULTRIX_PARTITION is not set
+# CONFIG_SUN_PARTITION is not set
+# CONFIG_KARMA_PARTITION is not set
+CONFIG_EFI_PARTITION=y
+# CONFIG_SYSV68_PARTITION is not set
+CONFIG_RK_PARTITION=y
+# CONFIG_CMDLINE_PARTITION is not set
+CONFIG_BLOCK_COMPAT=y
+
+#
+# IO Schedulers
+#
+CONFIG_IOSCHED_NOOP=y
+CONFIG_IOSCHED_DEADLINE=y
+CONFIG_IOSCHED_CFQ=y
+# CONFIG_DEFAULT_DEADLINE is not set
+CONFIG_DEFAULT_CFQ=y
+# CONFIG_DEFAULT_NOOP is not set
+CONFIG_DEFAULT_IOSCHED="cfq"
+CONFIG_ASN1=y
+CONFIG_UNINLINE_SPIN_UNLOCK=y
+CONFIG_ARCH_SUPPORTS_ATOMIC_RMW=y
+CONFIG_MUTEX_SPIN_ON_OWNER=y
+CONFIG_RWSEM_SPIN_ON_OWNER=y
+CONFIG_LOCK_SPIN_ON_OWNER=y
+CONFIG_FREEZER=y
+
+#
+# Platform selection
+#
+# CONFIG_ARCH_BCM_IPROC is not set
+# CONFIG_ARCH_BERLIN is not set
+# CONFIG_ARCH_EXYNOS7 is not set
+# CONFIG_ARCH_LAYERSCAPE is not set
+# CONFIG_ARCH_HISI is not set
+# CONFIG_ARCH_MEDIATEK is not set
+# CONFIG_ARCH_QCOM is not set
+CONFIG_ARCH_ROCKCHIP=y
+# CONFIG_ARCH_SEATTLE is not set
+# CONFIG_ARCH_STRATIX10 is not set
+# CONFIG_ARCH_TEGRA is not set
+# CONFIG_ARCH_SPRD is not set
+# CONFIG_ARCH_THUNDER is not set
+# CONFIG_ARCH_VEXPRESS is not set
+# CONFIG_ARCH_XGENE is not set
+# CONFIG_ARCH_ZYNQMP is not set
+
+#
+# Bus support
+#
+# CONFIG_PCI is not set
+# CONFIG_PCI_DOMAINS is not set
+# CONFIG_PCI_DOMAINS_GENERIC is not set
+# CONFIG_PCI_SYSCALL is not set
+
+#
+# Kernel Features
+#
+
+#
+# ARM errata workarounds via the alternatives framework
+#
+# CONFIG_ARM64_ERRATUM_826319 is not set
+# CONFIG_ARM64_ERRATUM_827319 is not set
+# CONFIG_ARM64_ERRATUM_824069 is not set
+# CONFIG_ARM64_ERRATUM_819472 is not set
+# CONFIG_ARM64_ERRATUM_832075 is not set
+CONFIG_ARM64_ERRATUM_845719=y
+CONFIG_ARM64_ERRATUM_843419=y
+# CONFIG_ARM64_ERRATUM_1024718 is not set
+# CONFIG_CAVIUM_ERRATUM_22375 is not set
+# CONFIG_CAVIUM_ERRATUM_23154 is not set
+CONFIG_CAVIUM_ERRATUM_27456=y
+CONFIG_ARM64_4K_PAGES=y
+# CONFIG_ARM64_16K_PAGES is not set
+# CONFIG_ARM64_64K_PAGES is not set
+CONFIG_ARM64_VA_BITS_39=y
+# CONFIG_ARM64_VA_BITS_48 is not set
+CONFIG_ARM64_VA_BITS=39
+# CONFIG_CPU_BIG_ENDIAN is not set
+CONFIG_SCHED_MC=y
+# CONFIG_SCHED_SMT is not set
+CONFIG_NR_CPUS=8
+CONFIG_HOTPLUG_CPU=y
+# CONFIG_PREEMPT_NONE is not set
+CONFIG_PREEMPT_VOLUNTARY=y
+# CONFIG_PREEMPT is not set
+# CONFIG_HZ_100 is not set
+# CONFIG_HZ_250 is not set
+# CONFIG_HZ_300 is not set
+CONFIG_HZ_1000=y
+CONFIG_HZ=1000
+CONFIG_SCHED_HRTICK=y
+CONFIG_ARCH_SUPPORTS_DEBUG_PAGEALLOC=y
+CONFIG_ARCH_HAS_HOLES_MEMORYMODEL=y
+CONFIG_ARCH_SPARSEMEM_ENABLE=y
+CONFIG_ARCH_SPARSEMEM_DEFAULT=y
+CONFIG_ARCH_SELECT_MEMORY_MODEL=y
+CONFIG_HAVE_ARCH_PFN_VALID=y
+CONFIG_HW_PERF_EVENTS=y
+CONFIG_SYS_SUPPORTS_HUGETLBFS=y
+CONFIG_ARCH_WANT_HUGE_PMD_SHARE=y
+CONFIG_ARCH_HAS_CACHE_LINE_SIZE=y
+CONFIG_SELECT_MEMORY_MODEL=y
+CONFIG_SPARSEMEM_MANUAL=y
+CONFIG_SPARSEMEM=y
+CONFIG_HAVE_MEMORY_PRESENT=y
+CONFIG_SPARSEMEM_EXTREME=y
+CONFIG_SPARSEMEM_VMEMMAP_ENABLE=y
+CONFIG_SPARSEMEM_VMEMMAP=y
+CONFIG_HAVE_MEMBLOCK=y
+CONFIG_NO_BOOTMEM=y
+# CONFIG_HAVE_BOOTMEM_INFO_NODE is not set
+CONFIG_SPLIT_PTLOCK_CPUS=4
+# CONFIG_COMPACTION is not set
+CONFIG_PHYS_ADDR_T_64BIT=y
+CONFIG_ZONE_DMA_FLAG=1
+CONFIG_BOUNCE=y
+# CONFIG_KSM is not set
+CONFIG_DEFAULT_MMAP_MIN_ADDR=32768
+# CONFIG_TRANSPARENT_HUGEPAGE is not set
+# CONFIG_CLEANCACHE is not set
+# CONFIG_FRONTSWAP is not set
+# CONFIG_CMA is not set
+# CONFIG_ZPOOL is not set
+# CONFIG_ZBUD is not set
+CONFIG_ZSMALLOC=y
+# CONFIG_PGTABLE_MAPPING is not set
+# CONFIG_ZSMALLOC_STAT is not set
+CONFIG_GENERIC_EARLY_IOREMAP=y
+# CONFIG_IDLE_PAGE_TRACKING is not set
+CONFIG_FRAME_VECTOR=y
+CONFIG_SECCOMP=y
+# CONFIG_KEXEC is not set
+# CONFIG_CRASH_DUMP is not set
+# CONFIG_XEN is not set
+CONFIG_FORCE_MAX_ZONEORDER=11
+CONFIG_UNMAP_KERNEL_AT_EL0=y
+CONFIG_ARMV8_DEPRECATED=y
+CONFIG_SWP_EMULATION=y
+CONFIG_CP15_BARRIER_EMULATION=y
+CONFIG_SETEND_EMULATION=y
+# CONFIG_ARM64_SW_TTBR0_PAN is not set
+
+#
+# ARMv8.1 architectural features
+#
+CONFIG_ARM64_HW_AFDBM=y
+CONFIG_ARM64_PAN=y
+# CONFIG_ARM64_LSE_ATOMICS is not set
+CONFIG_ARM64_UAO=y
+CONFIG_ARM64_MODULE_CMODEL_LARGE=y
+# CONFIG_RANDOMIZE_BASE is not set
+
+#
+# Boot options
+#
+CONFIG_CMDLINE=""
+# CONFIG_EFI is not set
+# CONFIG_BUILD_ARM64_APPENDED_DTB_IMAGE is not set
+
+#
+# Userspace binary formats
+#
+CONFIG_BINFMT_ELF=y
+CONFIG_COMPAT_BINFMT_ELF=y
+CONFIG_CORE_DUMP_DEFAULT_ELF_HEADERS=y
+CONFIG_BINFMT_SCRIPT=y
+# CONFIG_HAVE_AOUT is not set
+# CONFIG_BINFMT_MISC is not set
+CONFIG_COREDUMP=y
+CONFIG_COMPAT=y
+CONFIG_SYSVIPC_COMPAT=y
+CONFIG_KEYS_COMPAT=y
+
+#
+# Power management options
+#
+CONFIG_SUSPEND=y
+CONFIG_SUSPEND_FREEZER=y
+# CONFIG_SUSPEND_SKIP_SYNC is not set
+CONFIG_HAS_WAKELOCK=y
+CONFIG_WAKELOCK=y
+# CONFIG_HIBERNATION is not set
+CONFIG_PM_SLEEP=y
+CONFIG_PM_SLEEP_SMP=y
+# CONFIG_PM_AUTOSLEEP is not set
+# CONFIG_PM_WAKELOCKS is not set
+CONFIG_PM=y
+CONFIG_PM_DEBUG=y
+CONFIG_PM_ADVANCED_DEBUG=y
+# CONFIG_PM_TEST_SUSPEND is not set
+CONFIG_PM_SLEEP_DEBUG=y
+CONFIG_PM_OPP=y
+CONFIG_PM_CLK=y
+CONFIG_PM_GENERIC_DOMAINS=y
+CONFIG_WQ_POWER_EFFICIENT_DEFAULT=y
+CONFIG_PM_GENERIC_DOMAINS_SLEEP=y
+CONFIG_PM_GENERIC_DOMAINS_OF=y
+CONFIG_CPU_PM=y
+CONFIG_ARCH_HIBERNATION_POSSIBLE=y
+CONFIG_ARCH_SUSPEND_POSSIBLE=y
+
+#
+# CPU Power Management
+#
+
+#
+# CPU Idle
+#
+CONFIG_CPU_IDLE=y
+CONFIG_CPU_IDLE_GOV_LADDER=y
+CONFIG_CPU_IDLE_GOV_MENU=y
+CONFIG_DT_IDLE_STATES=y
+
+#
+# ARM CPU Idle Drivers
+#
+CONFIG_ARM_CPUIDLE=y
+# CONFIG_ARCH_NEEDS_CPU_IDLE_COUPLED is not set
+
+#
+# CPU Frequency scaling
+#
+CONFIG_CPU_FREQ=y
+CONFIG_CPU_FREQ_GOV_COMMON=y
+CONFIG_CPU_FREQ_STAT=y
+# CONFIG_CPU_FREQ_STAT_DETAILS is not set
+CONFIG_CPU_FREQ_TIMES=y
+# CONFIG_CPU_FREQ_DEFAULT_GOV_PERFORMANCE is not set
+# CONFIG_CPU_FREQ_DEFAULT_GOV_POWERSAVE is not set
+# CONFIG_CPU_FREQ_DEFAULT_GOV_USERSPACE is not set
+# CONFIG_CPU_FREQ_DEFAULT_GOV_ONDEMAND is not set
+# CONFIG_CPU_FREQ_DEFAULT_GOV_CONSERVATIVE is not set
+CONFIG_CPU_FREQ_DEFAULT_GOV_INTERACTIVE=y
+# CONFIG_CPU_FREQ_DEFAULT_GOV_SCHEDUTIL is not set
+CONFIG_CPU_FREQ_GOV_PERFORMANCE=y
+CONFIG_CPU_FREQ_GOV_POWERSAVE=y
+CONFIG_CPU_FREQ_GOV_USERSPACE=y
+CONFIG_CPU_FREQ_GOV_ONDEMAND=y
+CONFIG_CPU_FREQ_GOV_INTERACTIVE=y
+CONFIG_CPU_FREQ_GOV_CONSERVATIVE=y
+# CONFIG_CPU_FREQ_GOV_SCHEDUTIL is not set
+
+#
+# CPU frequency scaling drivers
+#
+CONFIG_CPUFREQ_DT=y
+# CONFIG_ARM_BIG_LITTLE_CPUFREQ is not set
+# CONFIG_ARM_KIRKWOOD_CPUFREQ is not set
+CONFIG_ARM_ROCKCHIP_CPUFREQ=y
+CONFIG_NET=y
+CONFIG_COMPAT_NETLINK_MESSAGES=y
+
+#
+# Networking options
+#
+CONFIG_PACKET=y
+# CONFIG_PACKET_DIAG is not set
+CONFIG_UNIX=y
+# CONFIG_UNIX_DIAG is not set
+CONFIG_XFRM=y
+CONFIG_XFRM_ALGO=y
+CONFIG_XFRM_USER=y
+# CONFIG_XFRM_SUB_POLICY is not set
+# CONFIG_XFRM_MIGRATE is not set
+# CONFIG_XFRM_STATISTICS is not set
+CONFIG_NET_KEY=y
+# CONFIG_NET_KEY_MIGRATE is not set
+CONFIG_INET=y
+CONFIG_IP_MULTICAST=y
+CONFIG_IP_ADVANCED_ROUTER=y
+# CONFIG_IP_FIB_TRIE_STATS is not set
+# CONFIG_IP_MULTIPLE_TABLES is not set
+# CONFIG_IP_ROUTE_MULTIPATH is not set
+# CONFIG_IP_ROUTE_VERBOSE is not set
+# CONFIG_IP_PNP is not set
+# CONFIG_NET_IPIP is not set
+# CONFIG_NET_IPGRE_DEMUX is not set
+# CONFIG_NET_IP_TUNNEL is not set
+CONFIG_IP_MROUTE=y
+# CONFIG_IP_MROUTE_MULTIPLE_TABLES is not set
+# CONFIG_IP_PIMSM_V1 is not set
+# CONFIG_IP_PIMSM_V2 is not set
+CONFIG_SYN_COOKIES=y
+# CONFIG_NET_UDP_TUNNEL is not set
+# CONFIG_NET_FOU is not set
+# CONFIG_INET_AH is not set
+# CONFIG_INET_ESP is not set
+# CONFIG_INET_IPCOMP is not set
+# CONFIG_INET_XFRM_TUNNEL is not set
+# CONFIG_INET_TUNNEL is not set
+# CONFIG_INET_XFRM_MODE_TRANSPORT is not set
+# CONFIG_INET_XFRM_MODE_TUNNEL is not set
+# CONFIG_INET_XFRM_MODE_BEET is not set
+# CONFIG_INET_LRO is not set
+# CONFIG_INET_DIAG is not set
+# CONFIG_TCP_CONG_ADVANCED is not set
+CONFIG_TCP_CONG_CUBIC=y
+CONFIG_DEFAULT_TCP_CONG="cubic"
+# CONFIG_TCP_MD5SIG is not set
+CONFIG_IPV6=y
+# CONFIG_IPV6_ROUTER_PREF is not set
+# CONFIG_IPV6_OPTIMISTIC_DAD is not set
+# CONFIG_INET6_AH is not set
+# CONFIG_INET6_ESP is not set
+# CONFIG_INET6_IPCOMP is not set
+# CONFIG_IPV6_MIP6 is not set
+# CONFIG_IPV6_ILA is not set
+# CONFIG_INET6_XFRM_TUNNEL is not set
+# CONFIG_INET6_TUNNEL is not set
+# CONFIG_INET6_XFRM_MODE_TRANSPORT is not set
+# CONFIG_INET6_XFRM_MODE_TUNNEL is not set
+# CONFIG_INET6_XFRM_MODE_BEET is not set
+# CONFIG_INET6_XFRM_MODE_ROUTEOPTIMIZATION is not set
+# CONFIG_IPV6_SIT is not set
+# CONFIG_IPV6_TUNNEL is not set
+# CONFIG_IPV6_GRE is not set
+# CONFIG_IPV6_MULTIPLE_TABLES is not set
+# CONFIG_IPV6_MROUTE is not set
+# CONFIG_ANDROID_PARANOID_NETWORK is not set
+# CONFIG_NETWORK_SECMARK is not set
+CONFIG_NET_PTP_CLASSIFY=y
+# CONFIG_NETWORK_PHY_TIMESTAMPING is not set
+# CONFIG_NETFILTER is not set
+# CONFIG_IP_DCCP is not set
+# CONFIG_IP_SCTP is not set
+# CONFIG_RDS is not set
+# CONFIG_TIPC is not set
+# CONFIG_ATM is not set
+# CONFIG_L2TP is not set
+# CONFIG_BRIDGE is not set
+CONFIG_HAVE_NET_DSA=y
+# CONFIG_NET_DSA is not set
+# CONFIG_VLAN_8021Q is not set
+# CONFIG_DECNET is not set
+# CONFIG_LLC2 is not set
+# CONFIG_IPX is not set
+# CONFIG_ATALK is not set
+# CONFIG_X25 is not set
+# CONFIG_LAPB is not set
+# CONFIG_PHONET is not set
+# CONFIG_6LOWPAN is not set
+# CONFIG_IEEE802154 is not set
+# CONFIG_NET_SCHED is not set
+# CONFIG_DCB is not set
+CONFIG_DNS_RESOLVER=y
+# CONFIG_BATMAN_ADV is not set
+# CONFIG_OPENVSWITCH is not set
+# CONFIG_VSOCKETS is not set
+# CONFIG_NETLINK_DIAG is not set
+# CONFIG_MPLS is not set
+# CONFIG_HSR is not set
+# CONFIG_NET_SWITCHDEV is not set
+# CONFIG_NET_L3_MASTER_DEV is not set
+CONFIG_RPS=y
+CONFIG_RFS_ACCEL=y
+CONFIG_XPS=y
+# CONFIG_CGROUP_NET_PRIO is not set
+# CONFIG_CGROUP_NET_CLASSID is not set
+CONFIG_NET_RX_BUSY_POLL=y
+CONFIG_BQL=y
+# CONFIG_BPF_JIT is not set
+CONFIG_NET_FLOW_LIMIT=y
+
+#
+# Network testing
+#
+# CONFIG_NET_PKTGEN is not set
+# CONFIG_NET_DROP_MONITOR is not set
+# CONFIG_HAMRADIO is not set
+CONFIG_CAN=y
+CONFIG_CAN_RAW=y
+CONFIG_CAN_BCM=y
+CONFIG_CAN_GW=y
+
+#
+# CAN Device Drivers
+#
+# CONFIG_CAN_VCAN is not set
+# CONFIG_CAN_SLCAN is not set
+CONFIG_CAN_DEV=y
+CONFIG_CAN_CALC_BITTIMING=y
+# CONFIG_CAN_LEDS is not set
+# CONFIG_CAN_GRCAN is not set
+# CONFIG_CAN_XILINXCAN is not set
+# CONFIG_CAN_SJA1000 is not set
+# CONFIG_CAN_C_CAN is not set
+# CONFIG_CAN_M_CAN is not set
+# CONFIG_CAN_CC770 is not set
+
+#
+# CAN SPI interfaces
+#
+# CONFIG_CAN_MCP251X is not set
+CONFIG_CAN_MCP25XXFD=m
+
+#
+# CAN USB interfaces
+#
+# CONFIG_CAN_EMS_USB is not set
+# CONFIG_CAN_ESD_USB2 is not set
+# CONFIG_CAN_GS_USB is not set
+# CONFIG_CAN_KVASER_USB is not set
+# CONFIG_CAN_PEAK_USB is not set
+# CONFIG_CAN_8DEV_USB is not set
+# CONFIG_CAN_SOFTING is not set
+# CONFIG_CAN_DEBUG_DEVICES is not set
+# CONFIG_IRDA is not set
+CONFIG_BT=y
+CONFIG_BT_BREDR=y
+CONFIG_BT_RFCOMM=y
+# CONFIG_BT_RFCOMM_TTY is not set
+# CONFIG_BT_BNEP is not set
+CONFIG_BT_HIDP=y
+CONFIG_BT_HS=y
+CONFIG_BT_LE=y
+# CONFIG_BT_SELFTEST is not set
+CONFIG_BT_DEBUGFS=y
+
+#
+# Bluetooth device drivers
+#
+CONFIG_BT_INTEL=y
+CONFIG_BT_BCM=y
+CONFIG_BT_RTL=y
+# CONFIG_BT_RTKBTUSB is not set
+CONFIG_BT_HCIBTUSB=y
+CONFIG_BT_HCIBTUSB_BCM=y
+CONFIG_BT_HCIBTUSB_RTL=y
+# CONFIG_BT_HCIBTSDIO is not set
+CONFIG_BT_HCIUART=y
+CONFIG_BT_HCIUART_H4=y
+# CONFIG_BT_HCIUART_BCSP is not set
+CONFIG_BT_HCIUART_ATH3K=y
+CONFIG_BT_HCIUART_LL=y
+# CONFIG_BT_HCIUART_3WIRE is not set
+# CONFIG_BT_HCIUART_INTEL is not set
+# CONFIG_BT_HCIUART_BCM is not set
+# CONFIG_BT_HCIUART_QCA is not set
+# CONFIG_BT_HCIBCM203X is not set
+# CONFIG_BT_HCIBPA10X is not set
+CONFIG_BT_HCIBFUSB=y
+CONFIG_BT_HCIVHCI=y
+CONFIG_BT_MRVL=y
+CONFIG_BT_MRVL_SDIO=y
+# CONFIG_BT_ATH3K is not set
+# CONFIG_AF_RXRPC is not set
+CONFIG_WIRELESS=y
+CONFIG_WIRELESS_EXT=y
+CONFIG_WEXT_CORE=y
+CONFIG_WEXT_PROC=y
+CONFIG_WEXT_PRIV=y
+CONFIG_CFG80211=y
+CONFIG_NL80211_TESTMODE=y
+# CONFIG_CFG80211_DEVELOPER_WARNINGS is not set
+# CONFIG_CFG80211_REG_DEBUG is not set
+# CONFIG_CFG80211_CERTIFICATION_ONUS is not set
+CONFIG_CFG80211_DEFAULT_PS=y
+CONFIG_CFG80211_DEBUGFS=y
+# CONFIG_CFG80211_INTERNAL_REGDB is not set
+CONFIG_CFG80211_CRDA_SUPPORT=y
+CONFIG_CFG80211_WEXT=y
+# CONFIG_LIB80211 is not set
+CONFIG_MAC80211=y
+CONFIG_MAC80211_HAS_RC=y
+CONFIG_MAC80211_RC_MINSTREL=y
+CONFIG_MAC80211_RC_MINSTREL_HT=y
+# CONFIG_MAC80211_RC_MINSTREL_VHT is not set
+CONFIG_MAC80211_RC_DEFAULT_MINSTREL=y
+CONFIG_MAC80211_RC_DEFAULT="minstrel_ht"
+# CONFIG_MAC80211_MESH is not set
+CONFIG_MAC80211_LEDS=y
+CONFIG_MAC80211_DEBUGFS=y
+# CONFIG_MAC80211_MESSAGE_TRACING is not set
+CONFIG_MAC80211_DEBUG_MENU=y
+# CONFIG_MAC80211_NOINLINE is not set
+CONFIG_MAC80211_VERBOSE_DEBUG=y
+# CONFIG_MAC80211_MLME_DEBUG is not set
+# CONFIG_MAC80211_STA_DEBUG is not set
+# CONFIG_MAC80211_HT_DEBUG is not set
+# CONFIG_MAC80211_OCB_DEBUG is not set
+# CONFIG_MAC80211_IBSS_DEBUG is not set
+# CONFIG_MAC80211_PS_DEBUG is not set
+# CONFIG_MAC80211_TDLS_DEBUG is not set
+# CONFIG_MAC80211_DEBUG_COUNTERS is not set
+CONFIG_MAC80211_STA_HASH_MAX_SIZE=0
+# CONFIG_WIMAX is not set
+CONFIG_RFKILL=y
+CONFIG_RFKILL_PM=y
+CONFIG_RFKILL_LEDS=y
+# CONFIG_RFKILL_INPUT is not set
+# CONFIG_RFKILL_REGULATOR is not set
+# CONFIG_RFKILL_GPIO is not set
+# CONFIG_NET_9P is not set
+# CONFIG_CAIF is not set
+# CONFIG_CEPH_LIB is not set
+# CONFIG_NFC is not set
+# CONFIG_LWTUNNEL is not set
+# CONFIG_DST_CACHE is not set
+CONFIG_HAVE_BPF_JIT=y
+CONFIG_HAVE_EBPF_JIT=y
+
+#
+# Device Drivers
+#
+CONFIG_ARM_AMBA=y
+# CONFIG_TEGRA_AHB is not set
+
+#
+# Generic Driver Options
+#
+CONFIG_UEVENT_HELPER=y
+CONFIG_UEVENT_HELPER_PATH=""
+CONFIG_DEVTMPFS=y
+CONFIG_DEVTMPFS_MOUNT=y
+CONFIG_STANDALONE=y
+CONFIG_PREVENT_FIRMWARE_BUILD=y
+CONFIG_FW_LOADER=y
+CONFIG_FIRMWARE_IN_KERNEL=y
+CONFIG_EXTRA_FIRMWARE=""
+# CONFIG_FW_LOADER_USER_HELPER_FALLBACK is not set
+CONFIG_WANT_DEV_COREDUMP=y
+CONFIG_ALLOW_DEV_COREDUMP=y
+CONFIG_DEV_COREDUMP=y
+# CONFIG_DEBUG_DRIVER is not set
+CONFIG_DEBUG_DEVRES=y
+# CONFIG_SYS_HYPERVISOR is not set
+# CONFIG_GENERIC_CPU_DEVICES is not set
+CONFIG_GENERIC_CPU_AUTOPROBE=y
+CONFIG_REGMAP=y
+CONFIG_REGMAP_I2C=y
+CONFIG_REGMAP_SPI=y
+CONFIG_REGMAP_MMIO=y
+CONFIG_REGMAP_IRQ=y
+CONFIG_DMA_SHARED_BUFFER=y
+# CONFIG_FENCE_TRACE is not set
+
+#
+# Bus devices
+#
+# CONFIG_ARM_CCI400_PMU is not set
+# CONFIG_ARM_CCI500_PMU is not set
+# CONFIG_ARM_CCN is not set
+# CONFIG_VEXPRESS_CONFIG is not set
+CONFIG_CONNECTOR=y
+CONFIG_PROC_EVENTS=y
+# CONFIG_MTD is not set
+CONFIG_DTC=y
+CONFIG_OF=y
+# CONFIG_OF_UNITTEST is not set
+CONFIG_OF_FLATTREE=y
+CONFIG_OF_EARLY_FLATTREE=y
+CONFIG_OF_ADDRESS=y
+CONFIG_OF_IRQ=y
+CONFIG_OF_NET=y
+CONFIG_OF_MDIO=y
+CONFIG_OF_RESERVED_MEM=y
+# CONFIG_OF_OVERLAY is not set
+# CONFIG_PARPORT is not set
+CONFIG_BLK_DEV=y
+# CONFIG_BLK_DEV_NULL_BLK is not set
+CONFIG_ZRAM=y
+# CONFIG_ZRAM_WRITEBACK is not set
+# CONFIG_ZRAM_MEMORY_TRACKING is not set
+# CONFIG_BLK_DEV_COW_COMMON is not set
+CONFIG_BLK_DEV_LOOP=y
+CONFIG_BLK_DEV_LOOP_MIN_COUNT=8
+# CONFIG_BLK_DEV_CRYPTOLOOP is not set
+# CONFIG_BLK_DEV_DRBD is not set
+# CONFIG_BLK_DEV_NBD is not set
+CONFIG_BLK_DEV_RAM=y
+CONFIG_BLK_DEV_RAM_COUNT=1
+CONFIG_BLK_DEV_RAM_SIZE=4096
+# CONFIG_CDROM_PKTCDVD is not set
+# CONFIG_ATA_OVER_ETH is not set
+# CONFIG_BLK_DEV_RBD is not set
+
+#
+# Misc devices
+#
+# CONFIG_ROCKCHIP_SCR is not set
+# CONFIG_SENSORS_LIS3LV02D is not set
+# CONFIG_AD525X_DPOT is not set
+# CONFIG_DUMMY_IRQ is not set
+# CONFIG_ICS932S401 is not set
+# CONFIG_ENCLOSURE_SERVICES is not set
+# CONFIG_APDS9802ALS is not set
+# CONFIG_ISL29003 is not set
+# CONFIG_ISL29020 is not set
+# CONFIG_SENSORS_TSL2550 is not set
+# CONFIG_SENSORS_BH1780 is not set
+# CONFIG_SENSORS_BH1770 is not set
+# CONFIG_SENSORS_APDS990X is not set
+# CONFIG_HMC6352 is not set
+# CONFIG_DS1682 is not set
+# CONFIG_TI_DAC7512 is not set
+# CONFIG_BMP085_I2C is not set
+# CONFIG_BMP085_SPI is not set
+# CONFIG_USB_SWITCH_FSA9480 is not set
+# CONFIG_LATTICE_ECP3_CONFIG is not set
+# CONFIG_SRAM is not set
+# CONFIG_MEMORY_STATE_TIME is not set
+# CONFIG_USB_CAM_GPIO is not set
+# CONFIG_GPIO_DET is not set
+# CONFIG_C2PORT is not set
+
+#
+# EEPROM support
+#
+# CONFIG_EEPROM_AT24 is not set
+# CONFIG_EEPROM_AT25 is not set
+# CONFIG_EEPROM_LEGACY is not set
+# CONFIG_EEPROM_MAX6875 is not set
+# CONFIG_EEPROM_93CX6 is not set
+# CONFIG_EEPROM_93XX46 is not set
+
+#
+# Texas Instruments shared transport line discipline
+#
+# CONFIG_TI_ST is not set
+# CONFIG_SENSORS_LIS3_SPI is not set
+# CONFIG_SENSORS_LIS3_I2C is not set
+
+#
+# Altera FPGA firmware download module
+#
+# CONFIG_ALTERA_STAPL is not set
+
+#
+# Intel MIC Bus Driver
+#
+
+#
+# SCIF Bus Driver
+#
+
+#
+# Intel MIC Host Driver
+#
+
+#
+# Intel MIC Card Driver
+#
+
+#
+# SCIF Driver
+#
+
+#
+# Intel MIC Coprocessor State Management (COSM) Drivers
+#
+# CONFIG_ECHO is not set
+# CONFIG_CXL_BASE is not set
+# CONFIG_CXL_KERNEL_API is not set
+# CONFIG_CXL_EEH is not set
+
+#
+# SCSI device support
+#
+CONFIG_SCSI_MOD=y
+# CONFIG_RAID_ATTRS is not set
+CONFIG_SCSI=y
+CONFIG_SCSI_DMA=y
+# CONFIG_SCSI_NETLINK is not set
+# CONFIG_SCSI_MQ_DEFAULT is not set
+CONFIG_SCSI_PROC_FS=y
+
+#
+# SCSI support type (disk, tape, CD-ROM)
+#
+CONFIG_BLK_DEV_SD=y
+# CONFIG_CHR_DEV_ST is not set
+# CONFIG_CHR_DEV_OSST is not set
+CONFIG_BLK_DEV_SR=y
+# CONFIG_BLK_DEV_SR_VENDOR is not set
+# CONFIG_CHR_DEV_SG is not set
+# CONFIG_CHR_DEV_SCH is not set
+# CONFIG_SCSI_CONSTANTS is not set
+# CONFIG_SCSI_LOGGING is not set
+CONFIG_SCSI_SCAN_ASYNC=y
+
+#
+# SCSI Transports
+#
+CONFIG_SCSI_SPI_ATTRS=y
+# CONFIG_SCSI_FC_ATTRS is not set
+# CONFIG_SCSI_ISCSI_ATTRS is not set
+# CONFIG_SCSI_SAS_ATTRS is not set
+# CONFIG_SCSI_SAS_LIBSAS is not set
+# CONFIG_SCSI_SRP_ATTRS is not set
+CONFIG_SCSI_LOWLEVEL=y
+# CONFIG_ISCSI_TCP is not set
+# CONFIG_ISCSI_BOOT_SYSFS is not set
+# CONFIG_SCSI_UFSHCD is not set
+# CONFIG_SCSI_DEBUG is not set
+# CONFIG_SCSI_LOWLEVEL_PCMCIA is not set
+# CONFIG_SCSI_DH is not set
+# CONFIG_SCSI_OSD_INITIATOR is not set
+CONFIG_HAVE_PATA_PLATFORM=y
+# CONFIG_ATA is not set
+# CONFIG_MD is not set
+# CONFIG_TARGET_CORE is not set
+CONFIG_NETDEVICES=y
+CONFIG_MII=y
+CONFIG_NET_CORE=y
+# CONFIG_BONDING is not set
+# CONFIG_DUMMY is not set
+# CONFIG_EQUALIZER is not set
+# CONFIG_NET_TEAM is not set
+# CONFIG_MACVLAN is not set
+# CONFIG_IPVLAN is not set
+# CONFIG_VXLAN is not set
+# CONFIG_NETCONSOLE is not set
+# CONFIG_NETPOLL is not set
+# CONFIG_NET_POLL_CONTROLLER is not set
+# CONFIG_TUN is not set
+# CONFIG_TUN_VNET_CROSS_LE is not set
+# CONFIG_VETH is not set
+# CONFIG_NLMON is not set
+
+#
+# CAIF transport drivers
+#
+
+#
+# Distributed Switch Architecture drivers
+#
+# CONFIG_NET_DSA_MV88E6XXX is not set
+# CONFIG_NET_DSA_MV88E6XXX_NEED_PPU is not set
+CONFIG_ETHERNET=y
+# CONFIG_ALTERA_TSE is not set
+# CONFIG_NET_VENDOR_AMD is not set
+# CONFIG_NET_VENDOR_ARC is not set
+# CONFIG_NET_VENDOR_AURORA is not set
+# CONFIG_NET_CADENCE is not set
+# CONFIG_NET_VENDOR_BROADCOM is not set
+# CONFIG_DNET is not set
+# CONFIG_NET_VENDOR_EZCHIP is not set
+# CONFIG_NET_VENDOR_HISILICON is not set
+# CONFIG_NET_VENDOR_INTEL is not set
+# CONFIG_NET_VENDOR_MARVELL is not set
+# CONFIG_NET_VENDOR_MICREL is not set
+# CONFIG_NET_VENDOR_MICROCHIP is not set
+# CONFIG_NET_VENDOR_NATSEMI is not set
+# CONFIG_ETHOC is not set
+# CONFIG_NET_VENDOR_QUALCOMM is not set
+# CONFIG_NET_VENDOR_RENESAS is not set
+# CONFIG_NET_VENDOR_ROCKER is not set
+# CONFIG_NET_VENDOR_SAMSUNG is not set
+# CONFIG_NET_VENDOR_SEEQ is not set
+# CONFIG_NET_VENDOR_SMSC is not set
+CONFIG_NET_VENDOR_SMSC9514=y
+CONFIG_SMSC9500=m
+CONFIG_SMSCUSBNET=m
+CONFIG_NET_VENDOR_STMICRO=y
+CONFIG_STMMAC_ETH=y
+CONFIG_STMMAC_PLATFORM=y
+# CONFIG_DWMAC_GENERIC is not set
+# CONFIG_DWMAC_IPQ806X is not set
+# CONFIG_DWMAC_LPC18XX is not set
+# CONFIG_DWMAC_MESON is not set
+CONFIG_DWMAC_ROCKCHIP=y
+# CONFIG_DWMAC_SOCFPGA is not set
+# CONFIG_DWMAC_STI is not set
+# CONFIG_DWMAC_SUNXI is not set
+# CONFIG_NET_VENDOR_SYNOPSYS is not set
+# CONFIG_NET_VENDOR_VIA is not set
+# CONFIG_NET_VENDOR_WIZNET is not set
+CONFIG_PHYLIB=y
+
+#
+# MII PHY device drivers
+#
+# CONFIG_AQUANTIA_PHY is not set
+# CONFIG_AT803X_PHY is not set
+# CONFIG_AMD_PHY is not set
+# CONFIG_MARVELL_PHY is not set
+# CONFIG_DAVICOM_PHY is not set
+# CONFIG_QSEMI_PHY is not set
+# CONFIG_LXT_PHY is not set
+# CONFIG_CICADA_PHY is not set
+# CONFIG_VITESSE_PHY is not set
+# CONFIG_TERANETICS_PHY is not set
+CONFIG_ROCKCHIP_PHY=y
+# CONFIG_SMSC_PHY is not set
+# CONFIG_BROADCOM_PHY is not set
+# CONFIG_BCM7XXX_PHY is not set
+# CONFIG_BCM87XX_PHY is not set
+# CONFIG_ICPLUS_PHY is not set
+# CONFIG_REALTEK_PHY is not set
+# CONFIG_NATIONAL_PHY is not set
+# CONFIG_STE10XP is not set
+# CONFIG_LSI_ET1011C_PHY is not set
+# CONFIG_MICREL_PHY is not set
+# CONFIG_DP83848_PHY is not set
+# CONFIG_DP83867_PHY is not set
+# CONFIG_MICROCHIP_PHY is not set
+# CONFIG_FIXED_PHY is not set
+# CONFIG_MDIO_BITBANG is not set
+# CONFIG_MDIO_OCTEON is not set
+# CONFIG_MDIO_BUS_MUX_GPIO is not set
+# CONFIG_MDIO_BUS_MUX_MMIOREG is not set
+# CONFIG_MDIO_BCM_UNIMAC is not set
+# CONFIG_MICREL_KS8995MA is not set
+# CONFIG_PPP is not set
+# CONFIG_SLIP is not set
+CONFIG_USB_NET_DRIVERS=y
+# CONFIG_USB_CATC is not set
+# CONFIG_USB_KAWETH is not set
+# CONFIG_USB_PEGASUS is not set
+CONFIG_USB_RTL8150=y
+CONFIG_USB_RTL8152=y
+# CONFIG_USB_LAN78XX is not set
+CONFIG_USB_USBNET=y
+CONFIG_USB_NET_AX8817X=y
+CONFIG_USB_NET_AX88179_178A=y
+CONFIG_USB_NET_CDCETHER=y
+# CONFIG_USB_NET_CDC_EEM is not set
+CONFIG_USB_NET_CDC_NCM=y
+# CONFIG_USB_NET_HUAWEI_CDC_NCM is not set
+CONFIG_USB_NET_CDC_MBIM=y
+# CONFIG_USB_NET_DM9601 is not set
+# CONFIG_USB_NET_SR9700 is not set
+# CONFIG_USB_NET_SR9800 is not set
+# CONFIG_USB_NET_SMSC75XX is not set
+CONFIG_USB_NET_SMSC95XX=y
+# CONFIG_USB_NET_GL620A is not set
+# CONFIG_USB_NET_NET1080 is not set
+# CONFIG_USB_NET_PLUSB is not set
+# CONFIG_USB_NET_MCS7830 is not set
+CONFIG_USB_NET_RNDIS_HOST=y
+# CONFIG_USB_NET_CDC_SUBSET is not set
+# CONFIG_USB_NET_ZAURUS is not set
+# CONFIG_USB_NET_CX82310_ETH is not set
+# CONFIG_USB_NET_KALMIA is not set
+# CONFIG_USB_NET_QMI_WWAN is not set
+# CONFIG_USB_HSO is not set
+# CONFIG_USB_NET_INT51X1 is not set
+# CONFIG_USB_IPHETH is not set
+# CONFIG_USB_SIERRA_NET is not set
+# CONFIG_USB_VL600 is not set
+# CONFIG_USB_NET_CH9200 is not set
+CONFIG_WLAN=y
+CONFIG_LIBERTAS_THINFIRM=y
+# CONFIG_LIBERTAS_THINFIRM_DEBUG is not set
+# CONFIG_LIBERTAS_THINFIRM_USB is not set
+# CONFIG_AT76C50X_USB is not set
+# CONFIG_USB_ZD1201 is not set
+CONFIG_USB_NET_RNDIS_WLAN=y
+# CONFIG_RTL8187 is not set
+# CONFIG_MAC80211_HWSIM is not set
+# CONFIG_VIRT_WIFI is not set
+# CONFIG_ATH_CARDS is not set
+# CONFIG_B43 is not set
+# CONFIG_B43LEGACY is not set
+# CONFIG_BRCMSMAC is not set
+# CONFIG_BRCMFMAC is not set
+# CONFIG_HOSTAP is not set
+# CONFIG_LIBERTAS is not set
+# CONFIG_P54_COMMON is not set
+# CONFIG_RT2X00 is not set
+# CONFIG_WL_MEDIATEK is not set
+CONFIG_RTL_CARDS=y
+# CONFIG_RTL8192CU is not set
+# CONFIG_RTL8XXXU is not set
+CONFIG_WL_ROCKCHIP=y
+CONFIG_WIFI_BUILD_MODULE=y
+# CONFIG_WIFI_LOAD_DRIVER_WHEN_KERNEL_BOOTUP is not set
+# CONFIG_WIFI_GENERATE_RANDOM_MAC_ADDR is not set
+CONFIG_AP6XXX=m
+# CONFIG_CYW_BCMDHD is not set
+CONFIG_RTL_WIRELESS_SOLUTION=y
+CONFIG_RTL8188EU=m
+# CONFIG_RTL8188FU is not set
+# CONFIG_RTL8189ES is not set
+# CONFIG_RTL8189FS is not set
+# CONFIG_RTL8723BS is not set
+CONFIG_RTL8723BU=y
+# CONFIG_RTL8723CS is not set
+# CONFIG_RTL8723DS is not set
+# CONFIG_MVL88W8977 is not set
+
+#
+# SouthSV 6XXX WLAN support
+#
+# CONFIG_SSV6051 is not set
+# CONFIG_WL_TI is not set
+# CONFIG_ZD1211RW is not set
+CONFIG_MWIFIEX=y
+CONFIG_MWIFIEX_SDIO=y
+# CONFIG_MWIFIEX_USB is not set
+# CONFIG_CW1200 is not set
+# CONFIG_RSI_91X is not set
+
+#
+# Enable WiMAX (Networking options) to see the WiMAX drivers
+#
+# CONFIG_WAN is not set
+# CONFIG_ISDN is not set
+# CONFIG_NVM is not set
+
+#
+# Input device support
+#
+CONFIG_INPUT=y
+CONFIG_INPUT_LEDS=y
+CONFIG_INPUT_FF_MEMLESS=y
+CONFIG_INPUT_POLLDEV=y
+# CONFIG_INPUT_SPARSEKMAP is not set
+CONFIG_INPUT_MATRIXKMAP=y
+
+#
+# Userland interfaces
+#
+# CONFIG_INPUT_MOUSEDEV is not set
+# CONFIG_INPUT_JOYDEV is not set
+CONFIG_INPUT_EVDEV=y
+# CONFIG_INPUT_EVBUG is not set
+# CONFIG_INPUT_KEYRESET is not set
+# CONFIG_INPUT_KEYCOMBO is not set
+
+#
+# Input Device Drivers
+#
+CONFIG_INPUT_KEYBOARD=y
+CONFIG_KEYBOARD_ADC=y
+# CONFIG_KEYBOARD_ADP5588 is not set
+# CONFIG_KEYBOARD_ADP5589 is not set
+# CONFIG_KEYBOARD_ATKBD is not set
+# CONFIG_KEYBOARD_QT1070 is not set
+# CONFIG_KEYBOARD_QT2160 is not set
+# CONFIG_KEYBOARD_LKKBD is not set
+CONFIG_KEYBOARD_GPIO=y
+CONFIG_KEYBOARD_GPIO_POLLED=y
+# CONFIG_KEYBOARD_TCA6416 is not set
+# CONFIG_KEYBOARD_TCA8418 is not set
+# CONFIG_KEYBOARD_MATRIX is not set
+# CONFIG_KEYBOARD_LM8323 is not set
+# CONFIG_KEYBOARD_LM8333 is not set
+# CONFIG_KEYBOARD_MAX7359 is not set
+# CONFIG_KEYBOARD_MCS is not set
+# CONFIG_KEYBOARD_MPR121 is not set
+# CONFIG_KEYBOARD_NEWTON is not set
+# CONFIG_KEYBOARD_OPENCORES is not set
+# CONFIG_KEYBOARD_SAMSUNG is not set
+# CONFIG_KEYBOARD_STOWAWAY is not set
+# CONFIG_KEYBOARD_SUNKBD is not set
+# CONFIG_KEYBOARD_OMAP4 is not set
+CONFIG_KEYBOARD_ROCKCHIP=y
+# CONFIG_KEYBOARD_XTKBD is not set
+# CONFIG_KEYBOARD_CAP11XX is not set
+# CONFIG_KEYBOARD_BCM is not set
+CONFIG_INPUT_MOUSE=y
+# CONFIG_MOUSE_PS2 is not set
+# CONFIG_MOUSE_SERIAL is not set
+# CONFIG_MOUSE_APPLETOUCH is not set
+# CONFIG_MOUSE_BCM5974 is not set
+CONFIG_MOUSE_CYAPA=y
+CONFIG_MOUSE_ELAN_I2C=y
+CONFIG_MOUSE_ELAN_I2C_I2C=y
+# CONFIG_MOUSE_ELAN_I2C_SMBUS is not set
+# CONFIG_MOUSE_VSXXXAA is not set
+# CONFIG_MOUSE_GPIO is not set
+# CONFIG_MOUSE_SYNAPTICS_I2C is not set
+# CONFIG_MOUSE_SYNAPTICS_USB is not set
+# CONFIG_INPUT_JOYSTICK is not set
+# CONFIG_INPUT_TABLET is not set
+CONFIG_INPUT_TOUCHSCREEN=y
+CONFIG_TOUCHSCREEN_PROPERTIES=y
+# CONFIG_TOUCHSCREEN_ADS7846 is not set
+# CONFIG_TOUCHSCREEN_AD7877 is not set
+# CONFIG_TOUCHSCREEN_AD7879 is not set
+# CONFIG_TOUCHSCREEN_AR1021_I2C is not set
+CONFIG_TOUCHSCREEN_ATMEL_MXT=y
+# CONFIG_TOUCHSCREEN_AUO_PIXCIR is not set
+# CONFIG_TOUCHSCREEN_BU21013 is not set
+# CONFIG_TOUCHSCREEN_CHIPONE_ICN8318 is not set
+# CONFIG_TOUCHSCREEN_CY8C40XX is not set
+# CONFIG_TOUCHSCREEN_CY8CTMG110 is not set
+# CONFIG_TOUCHSCREEN_CYTTSP_CORE is not set
+# CONFIG_TOUCHSCREEN_CYTTSP4_CORE is not set
+# CONFIG_TOUCHSCREEN_DYNAPRO is not set
+# CONFIG_TOUCHSCREEN_HAMPSHIRE is not set
+# CONFIG_TOUCHSCREEN_EETI is not set
+# CONFIG_TOUCHSCREEN_EGALAX is not set
+# CONFIG_TOUCHSCREEN_FT6236 is not set
+# CONFIG_TOUCHSCREEN_FUJITSU is not set
+# CONFIG_TOUCHSCREEN_GOODIX is not set
+# CONFIG_TOUCHSCREEN_GSLX680A is not set
+# CONFIG_TOUCHSCREEN_GSLX680_D708 is not set
+# CONFIG_TOUCHSCREEN_GSLX680_PAD is not set
+CONFIG_TOUCHSCREEN_GSLX680_VR=y
+# CONFIG_TOUCHSCREEN_GSLX680_FIREFLY is not set
+CONFIG_TOUCHSCREEN_GSL3673=y
+# CONFIG_TOUCHSCREEN_GSL3673_800X1280 is not set
+CONFIG_TOUCHSCREEN_GT9XX=y
+# CONFIG_TOUCHSCREEN_ILI210X is not set
+# CONFIG_TOUCHSCREEN_GUNZE is not set
+CONFIG_TOUCHSCREEN_ELAN=y
+# CONFIG_TOUCHSCREEN_ELO is not set
+# CONFIG_TOUCHSCREEN_WACOM_W8001 is not set
+# CONFIG_TOUCHSCREEN_WACOM_I2C is not set
+# CONFIG_TOUCHSCREEN_MAX11801 is not set
+# CONFIG_TOUCHSCREEN_MCS5000 is not set
+# CONFIG_TOUCHSCREEN_MMS114 is not set
+# CONFIG_TOUCHSCREEN_MTOUCH is not set
+# CONFIG_TOUCHSCREEN_IMX6UL_TSC is not set
+# CONFIG_TOUCHSCREEN_INEXIO is not set
+# CONFIG_TOUCHSCREEN_MK712 is not set
+# CONFIG_TOUCHSCREEN_PENMOUNT is not set
+# CONFIG_TOUCHSCREEN_EDT_FT5X06 is not set
+# CONFIG_TOUCHSCREEN_TOUCHRIGHT is not set
+# CONFIG_TOUCHSCREEN_TOUCHWIN is not set
+# CONFIG_TOUCHSCREEN_PIXCIR is not set
+# CONFIG_TOUCHSCREEN_WDT87XX_I2C is not set
+CONFIG_TOUCHSCREEN_USB_COMPOSITE=y
+CONFIG_TOUCHSCREEN_USB_EGALAX=y
+CONFIG_TOUCHSCREEN_USB_PANJIT=y
+CONFIG_TOUCHSCREEN_USB_3M=y
+CONFIG_TOUCHSCREEN_USB_ITM=y
+CONFIG_TOUCHSCREEN_USB_ETURBO=y
+CONFIG_TOUCHSCREEN_USB_GUNZE=y
+CONFIG_TOUCHSCREEN_USB_DMC_TSC10=y
+CONFIG_TOUCHSCREEN_USB_IRTOUCH=y
+CONFIG_TOUCHSCREEN_USB_IDEALTEK=y
+CONFIG_TOUCHSCREEN_USB_GENERAL_TOUCH=y
+CONFIG_TOUCHSCREEN_USB_GOTOP=y
+CONFIG_TOUCHSCREEN_USB_JASTEC=y
+CONFIG_TOUCHSCREEN_USB_ELO=y
+CONFIG_TOUCHSCREEN_USB_E2I=y
+CONFIG_TOUCHSCREEN_USB_ZYTRONIC=y
+CONFIG_TOUCHSCREEN_USB_ETT_TC45USB=y
+CONFIG_TOUCHSCREEN_USB_NEXIO=y
+CONFIG_TOUCHSCREEN_USB_EASYTOUCH=y
+# CONFIG_TOUCHSCREEN_TOUCHIT213 is not set
+# CONFIG_TOUCHSCREEN_TSC_SERIO is not set
+# CONFIG_TOUCHSCREEN_TSC2004 is not set
+# CONFIG_TOUCHSCREEN_TSC2005 is not set
+# CONFIG_TOUCHSCREEN_TSC2007 is not set
+# CONFIG_TOUCHSCREEN_ST1232 is not set
+# CONFIG_TOUCHSCREEN_SUR40 is not set
+# CONFIG_TOUCHSCREEN_SX8654 is not set
+# CONFIG_TOUCHSCREEN_TPS6507X is not set
+# CONFIG_TOUCHSCREEN_ZFORCE is not set
+# CONFIG_TOUCHSCREEN_ROHM_BU21023 is not set
+# CONFIG_TOUCHSCREEN_VTL_CT36X is not set
+CONFIG_TOUCHSCREEN_GT1X=y
+CONFIG_ROCKCHIP_REMOTECTL=y
+CONFIG_ROCKCHIP_REMOTECTL_PWM=y
+
+#
+# handle all sensors
+#
+# CONFIG_SENSOR_DEVICE is not set
+CONFIG_INPUT_MISC=y
+# CONFIG_INPUT_AD714X is not set
+# CONFIG_INPUT_BMA150 is not set
+# CONFIG_INPUT_E3X0_BUTTON is not set
+# CONFIG_INPUT_MMA8450 is not set
+# CONFIG_INPUT_MPU3050 is not set
+# CONFIG_INPUT_GP2A is not set
+# CONFIG_INPUT_GPIO_BEEPER is not set
+# CONFIG_INPUT_GPIO_TILT_POLLED is not set
+# CONFIG_INPUT_ATI_REMOTE2 is not set
+# CONFIG_INPUT_KEYCHORD is not set
+# CONFIG_INPUT_KEYSPAN_REMOTE is not set
+# CONFIG_INPUT_KXTJ9 is not set
+# CONFIG_INPUT_POWERMATE is not set
+# CONFIG_INPUT_YEALINK is not set
+# CONFIG_INPUT_CM109 is not set
+# CONFIG_INPUT_REGULATOR_HAPTIC is not set
+CONFIG_INPUT_RK8XX_PWRKEY=y
+CONFIG_INPUT_UINPUT=y
+CONFIG_INPUT_GPIO=y
+# CONFIG_INPUT_PCF8574 is not set
+# CONFIG_INPUT_PWM_BEEPER is not set
+# CONFIG_INPUT_GPIO_ROTARY_ENCODER is not set
+# CONFIG_INPUT_ADXL34X is not set
+# CONFIG_INPUT_IMS_PCU is not set
+# CONFIG_INPUT_CMA3000 is not set
+# CONFIG_INPUT_SOC_BUTTON_ARRAY is not set
+# CONFIG_INPUT_DRV260X_HAPTICS is not set
+# CONFIG_INPUT_DRV2665_HAPTICS is not set
+# CONFIG_INPUT_DRV2667_HAPTICS is not set
+
+#
+# Hardware I/O ports
+#
+# CONFIG_SERIO is not set
+# CONFIG_GAMEPORT is not set
+
+#
+# Character devices
+#
+CONFIG_TTY=y
+CONFIG_VT=y
+CONFIG_CONSOLE_TRANSLATIONS=y
+CONFIG_VT_CONSOLE=y
+CONFIG_VT_CONSOLE_SLEEP=y
+CONFIG_HW_CONSOLE=y
+CONFIG_VT_HW_CONSOLE_BINDING=y
+CONFIG_UNIX98_PTYS=y
+CONFIG_DEVPTS_MULTIPLE_INSTANCES=y
+# CONFIG_LEGACY_PTYS is not set
+# CONFIG_SERIAL_NONSTANDARD is not set
+# CONFIG_N_GSM is not set
+# CONFIG_TRACE_SINK is not set
+CONFIG_LDISC_AUTOLOAD=y
+CONFIG_DEVMEM=y
+# CONFIG_DEVKMEM is not set
+
+#
+# Serial drivers
+#
+CONFIG_SERIAL_EARLYCON=y
+CONFIG_SERIAL_8250=y
+CONFIG_SERIAL_8250_DEPRECATED_OPTIONS=y
+CONFIG_SERIAL_8250_CONSOLE=y
+CONFIG_SERIAL_8250_DMA=y
+CONFIG_SERIAL_8250_NR_UARTS=5
+CONFIG_SERIAL_8250_RUNTIME_UARTS=5
+# CONFIG_SERIAL_8250_EXTENDED is not set
+CONFIG_SERIAL_8250_FSL=y
+CONFIG_SERIAL_8250_DW=y
+# CONFIG_SERIAL_8250_RT288X is not set
+# CONFIG_SERIAL_8250_INGENIC is not set
+
+#
+# Non-8250 serial port support
+#
+# CONFIG_SERIAL_AMBA_PL010 is not set
+# CONFIG_SERIAL_AMBA_PL011 is not set
+# CONFIG_SERIAL_EARLYCON_ARM_SEMIHOST is not set
+# CONFIG_SERIAL_MAX3100 is not set
+# CONFIG_SERIAL_MAX310X is not set
+# CONFIG_SERIAL_UARTLITE is not set
+CONFIG_SERIAL_CORE=y
+CONFIG_SERIAL_CORE_CONSOLE=y
+CONFIG_SERIAL_OF_PLATFORM=y
+# CONFIG_SERIAL_SCCNXP is not set
+# CONFIG_SERIAL_SC16IS7XX is not set
+# CONFIG_SERIAL_ALTERA_JTAGUART is not set
+# CONFIG_SERIAL_ALTERA_UART is not set
+# CONFIG_SERIAL_IFX6X60 is not set
+# CONFIG_SERIAL_XILINX_PS_UART is not set
+# CONFIG_SERIAL_ARC is not set
+# CONFIG_SERIAL_FSL_LPUART is not set
+# CONFIG_SERIAL_CONEXANT_DIGICOLOR is not set
+# CONFIG_TTY_PRINTK is not set
+# CONFIG_HVC_DCC is not set
+# CONFIG_IPMI_HANDLER is not set
+CONFIG_HW_RANDOM=y
+# CONFIG_HW_RANDOM_TIMERIOMEM is not set
+CONFIG_HW_RANDOM_TPM=y
+CONFIG_HW_RANDOM_ROCKCHIP=y
+
+#
+# PCMCIA character devices
+#
+# CONFIG_RAW_DRIVER is not set
+CONFIG_TCG_TPM=y
+# CONFIG_TCG_TIS_I2C_ATMEL is not set
+CONFIG_TCG_TIS_I2C_INFINEON=y
+# CONFIG_TCG_TIS_I2C_NUVOTON is not set
+# CONFIG_TCG_TIS_ST33ZP24 is not set
+# CONFIG_XILLYBUS is not set
+
+#
+# I2C support
+#
+CONFIG_I2C=y
+CONFIG_I2C_BOARDINFO=y
+CONFIG_I2C_COMPAT=y
+CONFIG_I2C_CHARDEV=y
+CONFIG_I2C_MUX=y
+
+#
+# Multiplexer I2C Chip support
+#
+# CONFIG_I2C_ARB_GPIO_CHALLENGE is not set
+# CONFIG_I2C_MUX_GPIO is not set
+# CONFIG_I2C_MUX_PCA9541 is not set
+# CONFIG_I2C_MUX_PCA954x is not set
+# CONFIG_I2C_MUX_PINCTRL is not set
+# CONFIG_I2C_MUX_REG is not set
+CONFIG_I2C_HELPER_AUTO=y
+CONFIG_I2C_ALGOBIT=y
+
+#
+# I2C Hardware Bus support
+#
+
+#
+# I2C system bus drivers (mostly embedded / system-on-chip)
+#
+# CONFIG_I2C_CADENCE is not set
+# CONFIG_I2C_CBUS_GPIO is not set
+# CONFIG_I2C_DESIGNWARE_PLATFORM is not set
+# CONFIG_I2C_EMEV2 is not set
+# CONFIG_I2C_GPIO is not set
+# CONFIG_I2C_NOMADIK is not set
+# CONFIG_I2C_OCORES is not set
+# CONFIG_I2C_PCA_PLATFORM is not set
+# CONFIG_I2C_PXA_PCI is not set
+CONFIG_I2C_RK3X=y
+# CONFIG_I2C_SIMTEC is not set
+# CONFIG_I2C_XILINX is not set
+
+#
+# External I2C/SMBus adapter drivers
+#
+# CONFIG_I2C_DIOLAN_U2C is not set
+# CONFIG_I2C_PARPORT_LIGHT is not set
+# CONFIG_I2C_ROBOTFUZZ_OSIF is not set
+# CONFIG_I2C_TAOS_EVM is not set
+# CONFIG_I2C_TINY_USB is not set
+
+#
+# Other I2C/SMBus bus drivers
+#
+# CONFIG_I2C_STUB is not set
+# CONFIG_I2C_SLAVE is not set
+# CONFIG_I2C_DEBUG_CORE is not set
+# CONFIG_I2C_DEBUG_ALGO is not set
+# CONFIG_I2C_DEBUG_BUS is not set
+CONFIG_SPI=y
+# CONFIG_SPI_DEBUG is not set
+CONFIG_SPI_MASTER=y
+
+#
+# SPI Master Controller Drivers
+#
+# CONFIG_SPI_ALTERA is not set
+CONFIG_SPI_BITBANG=y
+# CONFIG_SPI_CADENCE is not set
+# CONFIG_SPI_GPIO is not set
+# CONFIG_SPI_FSL_SPI is not set
+# CONFIG_SPI_OC_TINY is not set
+# CONFIG_SPI_PL022 is not set
+# CONFIG_SPI_PXA2XX_PCI is not set
+CONFIG_SPI_ROCKCHIP=y
+# CONFIG_SPI_SC18IS602 is not set
+# CONFIG_SPI_XCOMM is not set
+# CONFIG_SPI_XILINX is not set
+# CONFIG_SPI_ZYNQMP_GQSPI is not set
+# CONFIG_SPI_DESIGNWARE is not set
+
+#
+# SPI Protocol Masters
+#
+CONFIG_SPI_SPIDEV=y
+# CONFIG_SPI_TLE62X0 is not set
+# CONFIG_SPMI is not set
+# CONFIG_HSI is not set
+
+#
+# PPS support
+#
+CONFIG_PPS=y
+# CONFIG_PPS_DEBUG is not set
+
+#
+# PPS clients support
+#
+# CONFIG_PPS_CLIENT_KTIMER is not set
+# CONFIG_PPS_CLIENT_LDISC is not set
+# CONFIG_PPS_CLIENT_GPIO is not set
+
+#
+# PPS generators support
+#
+
+#
+# PTP clock support
+#
+CONFIG_PTP_1588_CLOCK=y
+
+#
+# Enable PHYLIB and NETWORK_PHY_TIMESTAMPING to see the additional clocks.
+#
+CONFIG_PINCTRL=y
+
+#
+# Pin controllers
+#
+CONFIG_PINMUX=y
+CONFIG_PINCONF=y
+CONFIG_GENERIC_PINCONF=y
+# CONFIG_DEBUG_PINCTRL is not set
+# CONFIG_PINCTRL_AMD is not set
+CONFIG_PINCTRL_ROCKCHIP=y
+# CONFIG_PINCTRL_SINGLE is not set
+# CONFIG_PINCTRL_RK805 is not set
+CONFIG_ARCH_WANT_OPTIONAL_GPIOLIB=y
+CONFIG_ARCH_REQUIRE_GPIOLIB=y
+CONFIG_GPIOLIB=y
+CONFIG_GPIO_DEVRES=y
+CONFIG_OF_GPIO=y
+CONFIG_GPIOLIB_IRQCHIP=y
+CONFIG_DEBUG_GPIO=y
+CONFIG_GPIO_SYSFS=y
+CONFIG_GPIO_GENERIC=y
+
+#
+# Memory mapped GPIO drivers
+#
+# CONFIG_GPIO_74XX_MMIO is not set
+# CONFIG_GPIO_ALTERA is not set
+# CONFIG_GPIO_DWAPB is not set
+CONFIG_GPIO_GENERIC_PLATFORM=y
+# CONFIG_GPIO_GRGPIO is not set
+# CONFIG_GPIO_PL061 is not set
+# CONFIG_GPIO_SYSCON is not set
+# CONFIG_GPIO_XGENE is not set
+# CONFIG_GPIO_XILINX is not set
+# CONFIG_GPIO_ZX is not set
+
+#
+# I2C GPIO expanders
+#
+# CONFIG_GPIO_ADP5588 is not set
+# CONFIG_GPIO_ADNP is not set
+# CONFIG_GPIO_MAX7300 is not set
+# CONFIG_GPIO_MAX732X is not set
+# CONFIG_GPIO_PCA953X is not set
+# CONFIG_GPIO_PCF857X is not set
+CONFIG_GPIO_SX150X=y
+
+#
+# MFD GPIO expanders
+#
+CONFIG_GPIO_RK8XX=y
+
+#
+# SPI GPIO expanders
+#
+# CONFIG_GPIO_74X164 is not set
+# CONFIG_GPIO_MAX7301 is not set
+# CONFIG_GPIO_MC33880 is not set
+
+#
+# SPI or I2C GPIO expanders
+#
+# CONFIG_GPIO_MCP23S08 is not set
+
+#
+# USB GPIO expanders
+#
+# CONFIG_W1 is not set
+CONFIG_POWER_SUPPLY=y
+# CONFIG_POWER_SUPPLY_DEBUG is not set
+# CONFIG_PDA_POWER is not set
+# CONFIG_GENERIC_ADC_BATTERY is not set
+# CONFIG_TEST_POWER is not set
+# CONFIG_BATTERY_DS2780 is not set
+# CONFIG_BATTERY_DS2781 is not set
+# CONFIG_BATTERY_DS2782 is not set
+# CONFIG_BATTERY_SBS is not set
+# CONFIG_BATTERY_BQ27XXX is not set
+# CONFIG_BATTERY_MAX17040 is not set
+# CONFIG_BATTERY_MAX17042 is not set
+# CONFIG_CHARGER_MAX8903 is not set
+# CONFIG_CHARGER_LP8727 is not set
+CONFIG_CHARGER_GPIO=y
+# CONFIG_CHARGER_MANAGER is not set
+# CONFIG_CHARGER_BQ2415X is not set
+# CONFIG_CHARGER_BQ24190 is not set
+# CONFIG_CHARGER_BQ24257 is not set
+# CONFIG_CHARGER_BQ24735 is not set
+# CONFIG_CHARGER_BQ25700 is not set
+# CONFIG_CHARGER_BQ25890 is not set
+# CONFIG_CHARGER_SMB347 is not set
+# CONFIG_CHARGER_SY6982C is not set
+# CONFIG_CHARGER_UNIVERSAL is not set
+# CONFIG_BATTERY_GAUGE_LTC2941 is not set
+# CONFIG_BATTERY_EC is not set
+# CONFIG_BATTERY_CW2015 is not set
+# CONFIG_BATTERY_RK816 is not set
+CONFIG_BATTERY_RK817=y
+CONFIG_CHARGER_RK817=y
+# CONFIG_BATTERY_RK818 is not set
+# CONFIG_CHARGER_RK818 is not set
+# CONFIG_CHARGER_RT9455 is not set
+CONFIG_POWER_RESET=y
+CONFIG_POWER_RESET_GPIO=y
+CONFIG_POWER_RESET_GPIO_RESTART=y
+# CONFIG_POWER_RESET_LTC2952 is not set
+# CONFIG_POWER_RESET_RESTART is not set
+# CONFIG_POWER_RESET_XGENE is not set
+# CONFIG_POWER_RESET_SYSCON is not set
+# CONFIG_POWER_RESET_SYSCON_POWEROFF is not set
+CONFIG_REBOOT_MODE=y
+CONFIG_SYSCON_REBOOT_MODE=y
+CONFIG_POWER_AVS=y
+CONFIG_ROCKCHIP_IODOMAIN=y
+CONFIG_HWMON=y
+# CONFIG_HWMON_VID is not set
+# CONFIG_HWMON_DEBUG_CHIP is not set
+
+#
+# Native drivers
+#
+# CONFIG_SENSORS_AD7314 is not set
+# CONFIG_SENSORS_AD7414 is not set
+# CONFIG_SENSORS_AD7418 is not set
+# CONFIG_SENSORS_ADM1021 is not set
+# CONFIG_SENSORS_ADM1025 is not set
+# CONFIG_SENSORS_ADM1026 is not set
+# CONFIG_SENSORS_ADM1029 is not set
+# CONFIG_SENSORS_ADM1031 is not set
+# CONFIG_SENSORS_ADM9240 is not set
+# CONFIG_SENSORS_ADT7310 is not set
+# CONFIG_SENSORS_ADT7410 is not set
+# CONFIG_SENSORS_ADT7411 is not set
+# CONFIG_SENSORS_ADT7462 is not set
+# CONFIG_SENSORS_ADT7470 is not set
+# CONFIG_SENSORS_ADT7475 is not set
+# CONFIG_SENSORS_ASC7621 is not set
+# CONFIG_SENSORS_ATXP1 is not set
+# CONFIG_SENSORS_DS620 is not set
+# CONFIG_SENSORS_DS1621 is not set
+# CONFIG_SENSORS_F71805F is not set
+# CONFIG_SENSORS_F71882FG is not set
+# CONFIG_SENSORS_F75375S is not set
+# CONFIG_SENSORS_GL518SM is not set
+# CONFIG_SENSORS_GL520SM is not set
+# CONFIG_SENSORS_G760A is not set
+# CONFIG_SENSORS_G762 is not set
+# CONFIG_SENSORS_GPIO_FAN is not set
+# CONFIG_SENSORS_HIH6130 is not set
+# CONFIG_SENSORS_IIO_HWMON is not set
+# CONFIG_SENSORS_IT87 is not set
+# CONFIG_SENSORS_JC42 is not set
+# CONFIG_SENSORS_POWR1220 is not set
+# CONFIG_SENSORS_LINEAGE is not set
+# CONFIG_SENSORS_LTC2945 is not set
+# CONFIG_SENSORS_LTC4151 is not set
+# CONFIG_SENSORS_LTC4215 is not set
+# CONFIG_SENSORS_LTC4222 is not set
+# CONFIG_SENSORS_LTC4245 is not set
+# CONFIG_SENSORS_LTC4260 is not set
+# CONFIG_SENSORS_LTC4261 is not set
+# CONFIG_SENSORS_MAX1111 is not set
+# CONFIG_SENSORS_MAX16065 is not set
+# CONFIG_SENSORS_MAX1619 is not set
+# CONFIG_SENSORS_MAX1668 is not set
+# CONFIG_SENSORS_MAX197 is not set
+# CONFIG_SENSORS_MAX6639 is not set
+# CONFIG_SENSORS_MAX6642 is not set
+# CONFIG_SENSORS_MAX6650 is not set
+# CONFIG_SENSORS_MAX6697 is not set
+# CONFIG_SENSORS_MAX31790 is not set
+# CONFIG_SENSORS_HTU21 is not set
+# CONFIG_SENSORS_MCP3021 is not set
+# CONFIG_SENSORS_ADCXX is not set
+# CONFIG_SENSORS_LM63 is not set
+# CONFIG_SENSORS_LM70 is not set
+# CONFIG_SENSORS_LM73 is not set
+# CONFIG_SENSORS_LM75 is not set
+# CONFIG_SENSORS_LM77 is not set
+# CONFIG_SENSORS_LM78 is not set
+# CONFIG_SENSORS_LM80 is not set
+# CONFIG_SENSORS_LM83 is not set
+# CONFIG_SENSORS_LM85 is not set
+# CONFIG_SENSORS_LM87 is not set
+# CONFIG_SENSORS_LM90 is not set
+# CONFIG_SENSORS_LM92 is not set
+# CONFIG_SENSORS_LM93 is not set
+# CONFIG_SENSORS_LM95234 is not set
+# CONFIG_SENSORS_LM95241 is not set
+# CONFIG_SENSORS_LM95245 is not set
+# CONFIG_SENSORS_PC87360 is not set
+# CONFIG_SENSORS_PC87427 is not set
+# CONFIG_SENSORS_NTC_THERMISTOR is not set
+# CONFIG_SENSORS_NCT6683 is not set
+# CONFIG_SENSORS_NCT6775 is not set
+# CONFIG_SENSORS_NCT7802 is not set
+# CONFIG_SENSORS_NCT7904 is not set
+# CONFIG_SENSORS_PCF8591 is not set
+# CONFIG_PMBUS is not set
+# CONFIG_SENSORS_PWM_FAN is not set
+# CONFIG_SENSORS_SHT15 is not set
+# CONFIG_SENSORS_SHT21 is not set
+# CONFIG_SENSORS_SHTC1 is not set
+# CONFIG_SENSORS_DME1737 is not set
+# CONFIG_SENSORS_EMC1403 is not set
+# CONFIG_SENSORS_EMC2103 is not set
+# CONFIG_SENSORS_EMC6W201 is not set
+# CONFIG_SENSORS_SMSC47M1 is not set
+# CONFIG_SENSORS_SMSC47M192 is not set
+# CONFIG_SENSORS_SMSC47B397 is not set
+# CONFIG_SENSORS_SCH56XX_COMMON is not set
+# CONFIG_SENSORS_SCH5627 is not set
+# CONFIG_SENSORS_SCH5636 is not set
+# CONFIG_SENSORS_SMM665 is not set
+# CONFIG_SENSORS_ADC128D818 is not set
+CONFIG_SENSORS_ADS1015=y
+# CONFIG_SENSORS_ADS7828 is not set
+# CONFIG_SENSORS_ADS7871 is not set
+# CONFIG_SENSORS_AMC6821 is not set
+# CONFIG_SENSORS_INA209 is not set
+# CONFIG_SENSORS_INA2XX is not set
+# CONFIG_SENSORS_TC74 is not set
+# CONFIG_SENSORS_THMC50 is not set
+# CONFIG_SENSORS_TMP102 is not set
+# CONFIG_SENSORS_TMP103 is not set
+# CONFIG_SENSORS_TMP401 is not set
+# CONFIG_SENSORS_TMP421 is not set
+# CONFIG_SENSORS_VT1211 is not set
+# CONFIG_SENSORS_W83781D is not set
+# CONFIG_SENSORS_W83791D is not set
+# CONFIG_SENSORS_W83792D is not set
+# CONFIG_SENSORS_W83793 is not set
+# CONFIG_SENSORS_W83795 is not set
+# CONFIG_SENSORS_W83L785TS is not set
+# CONFIG_SENSORS_W83L786NG is not set
+# CONFIG_SENSORS_W83627HF is not set
+# CONFIG_SENSORS_W83627EHF is not set
+CONFIG_THERMAL=y
+CONFIG_THERMAL_HWMON=y
+CONFIG_THERMAL_OF=y
+CONFIG_THERMAL_WRITABLE_TRIPS=y
+# CONFIG_THERMAL_DEFAULT_GOV_STEP_WISE is not set
+# CONFIG_THERMAL_DEFAULT_GOV_FAIR_SHARE is not set
+# CONFIG_THERMAL_DEFAULT_GOV_USER_SPACE is not set
+CONFIG_THERMAL_DEFAULT_GOV_POWER_ALLOCATOR=y
+CONFIG_THERMAL_GOV_FAIR_SHARE=y
+CONFIG_THERMAL_GOV_STEP_WISE=y
+# CONFIG_THERMAL_GOV_BANG_BANG is not set
+# CONFIG_THERMAL_GOV_USER_SPACE is not set
+CONFIG_THERMAL_GOV_POWER_ALLOCATOR=y
+CONFIG_CPU_THERMAL=y
+# CONFIG_CLOCK_THERMAL is not set
+CONFIG_DEVFREQ_THERMAL=y
+# CONFIG_THERMAL_EMULATION is not set
+# CONFIG_IMX_THERMAL is not set
+CONFIG_ROCKCHIP_THERMAL=y
+# CONFIG_RK_VIRTUAL_THERMAL is not set
+# CONFIG_RK3368_THERMAL is not set
+CONFIG_WATCHDOG=y
+# CONFIG_WATCHDOG_CORE is not set
+# CONFIG_WATCHDOG_NOWAYOUT is not set
+
+#
+# Watchdog Device Drivers
+#
+# CONFIG_SOFT_WATCHDOG is not set
+# CONFIG_GPIO_WATCHDOG is not set
+# CONFIG_XILINX_WATCHDOG is not set
+# CONFIG_ARM_SP805_WATCHDOG is not set
+# CONFIG_CADENCE_WATCHDOG is not set
+CONFIG_DW_WATCHDOG=y
+# CONFIG_MAX63XX_WATCHDOG is not set
+# CONFIG_BCM7038_WDT is not set
+# CONFIG_MEN_A21_WDT is not set
+
+#
+# USB-based Watchdog Cards
+#
+# CONFIG_USBPCWATCHDOG is not set
+CONFIG_SSB_POSSIBLE=y
+
+#
+# Sonics Silicon Backplane
+#
+# CONFIG_SSB is not set
+CONFIG_BCMA_POSSIBLE=y
+
+#
+# Broadcom specific AMBA
+#
+# CONFIG_BCMA is not set
+
+#
+# Multifunction device drivers
+#
+CONFIG_MFD_CORE=y
+# CONFIG_MFD_AS3711 is not set
+# CONFIG_MFD_AS3722 is not set
+# CONFIG_PMIC_ADP5520 is not set
+# CONFIG_MFD_AAT2870_CORE is not set
+# CONFIG_MFD_ATMEL_FLEXCOM is not set
+# CONFIG_MFD_ATMEL_HLCDC is not set
+# CONFIG_MFD_BCM590XX is not set
+# CONFIG_MFD_AXP20X is not set
+# CONFIG_MFD_CROS_EC is not set
+# CONFIG_PMIC_DA903X is not set
+# CONFIG_MFD_DA9052_SPI is not set
+# CONFIG_MFD_DA9052_I2C is not set
+# CONFIG_MFD_DA9055 is not set
+# CONFIG_MFD_DA9062 is not set
+# CONFIG_MFD_DA9063 is not set
+# CONFIG_MFD_DA9150 is not set
+# CONFIG_MFD_DLN2 is not set
+# CONFIG_MFD_MC13XXX_SPI is not set
+# CONFIG_MFD_MC13XXX_I2C is not set
+# CONFIG_MFD_HI6421_PMIC is not set
+# CONFIG_HTC_PASIC3 is not set
+# CONFIG_HTC_I2CPLD is not set
+# CONFIG_INTEL_SOC_PMIC is not set
+# CONFIG_MFD_KEMPLD is not set
+# CONFIG_MFD_88PM800 is not set
+# CONFIG_MFD_88PM805 is not set
+# CONFIG_MFD_88PM860X is not set
+# CONFIG_MFD_MAX14577 is not set
+# CONFIG_MFD_MAX77686 is not set
+# CONFIG_MFD_MAX77693 is not set
+# CONFIG_MFD_MAX77843 is not set
+# CONFIG_MFD_MAX8907 is not set
+# CONFIG_MFD_MAX8925 is not set
+# CONFIG_MFD_MAX8997 is not set
+# CONFIG_MFD_MAX8998 is not set
+# CONFIG_MFD_MT6397 is not set
+# CONFIG_MFD_MENF21BMC is not set
+# CONFIG_EZX_PCAP is not set
+# CONFIG_MFD_VIPERBOARD is not set
+# CONFIG_MFD_RETU is not set
+# CONFIG_MFD_PCF50633 is not set
+# CONFIG_MFD_RT5033 is not set
+# CONFIG_MFD_RTSX_USB is not set
+# CONFIG_MFD_RC5T583 is not set
+# CONFIG_MFD_RK618 is not set
+CONFIG_MFD_RK808=y
+# CONFIG_MFD_RN5T618 is not set
+# CONFIG_MFD_SEC_CORE is not set
+# CONFIG_MFD_SI476X_CORE is not set
+# CONFIG_MFD_SM501 is not set
+# CONFIG_MFD_SKY81452 is not set
+# CONFIG_MFD_SMSC is not set
+# CONFIG_ABX500_CORE is not set
+# CONFIG_MFD_STMPE is not set
+CONFIG_MFD_SYSCON=y
+# CONFIG_MFD_TI_AM335X_TSCADC is not set
+# CONFIG_MFD_LP3943 is not set
+# CONFIG_MFD_LP8788 is not set
+# CONFIG_MFD_PALMAS is not set
+# CONFIG_TPS6105X is not set
+# CONFIG_TPS65010 is not set
+# CONFIG_TPS6507X is not set
+# CONFIG_MFD_TPS65090 is not set
+# CONFIG_MFD_TPS65217 is not set
+# CONFIG_MFD_TPS65218 is not set
+# CONFIG_MFD_TPS6586X is not set
+# CONFIG_MFD_TPS65910 is not set
+# CONFIG_MFD_TPS65912 is not set
+# CONFIG_MFD_TPS65912_I2C is not set
+# CONFIG_MFD_TPS65912_SPI is not set
+# CONFIG_MFD_TPS80031 is not set
+# CONFIG_TWL4030_CORE is not set
+# CONFIG_TWL6040_CORE is not set
+# CONFIG_MFD_WL1273_CORE is not set
+# CONFIG_MFD_LM3533 is not set
+# CONFIG_MFD_TC3589X is not set
+# CONFIG_MFD_TMIO is not set
+# CONFIG_MFD_ARIZONA_I2C is not set
+# CONFIG_MFD_ARIZONA_SPI is not set
+# CONFIG_MFD_WM8400 is not set
+# CONFIG_MFD_WM831X_I2C is not set
+# CONFIG_MFD_WM831X_SPI is not set
+# CONFIG_MFD_RK1000 is not set
+# CONFIG_MFD_WM8350_I2C is not set
+# CONFIG_MFD_WM8994 is not set
+CONFIG_FUSB_30X=y
+CONFIG_REGULATOR=y
+CONFIG_REGULATOR_DEBUG=y
+CONFIG_REGULATOR_FIXED_VOLTAGE=y
+# CONFIG_REGULATOR_VIRTUAL_CONSUMER is not set
+# CONFIG_REGULATOR_USERSPACE_CONSUMER is not set
+# CONFIG_REGULATOR_ACT8865 is not set
+# CONFIG_REGULATOR_AD5398 is not set
+# CONFIG_REGULATOR_ANATOP is not set
+# CONFIG_REGULATOR_DA9210 is not set
+# CONFIG_REGULATOR_DA9211 is not set
+CONFIG_REGULATOR_FAN53555=y
+CONFIG_REGULATOR_GPIO=y
+# CONFIG_REGULATOR_ISL9305 is not set
+# CONFIG_REGULATOR_ISL6271A is not set
+# CONFIG_REGULATOR_LP3971 is not set
+# CONFIG_REGULATOR_LP3972 is not set
+# CONFIG_REGULATOR_LP872X is not set
+# CONFIG_REGULATOR_LP8752 is not set
+# CONFIG_REGULATOR_LP8755 is not set
+# CONFIG_REGULATOR_LTC3589 is not set
+# CONFIG_REGULATOR_MAX1586 is not set
+# CONFIG_REGULATOR_MAX8649 is not set
+# CONFIG_REGULATOR_MAX8660 is not set
+# CONFIG_REGULATOR_MAX8952 is not set
+# CONFIG_REGULATOR_MAX8973 is not set
+# CONFIG_REGULATOR_MP8865 is not set
+# CONFIG_REGULATOR_MT6311 is not set
+# CONFIG_REGULATOR_PFUZE100 is not set
+CONFIG_REGULATOR_PWM=y
+CONFIG_REGULATOR_RK808=y
+CONFIG_REGULATOR_RK818=y
+# CONFIG_REGULATOR_SYR82X is not set
+# CONFIG_REGULATOR_TPS51632 is not set
+# CONFIG_REGULATOR_TPS549B22 is not set
+# CONFIG_REGULATOR_TPS62360 is not set
+# CONFIG_REGULATOR_TPS65023 is not set
+# CONFIG_REGULATOR_TPS6507X is not set
+# CONFIG_REGULATOR_TPS65132 is not set
+# CONFIG_REGULATOR_TPS6524X is not set
+# CONFIG_REGULATOR_XZ3216 is not set
+CONFIG_MEDIA_SUPPORT=y
+
+#
+# Multimedia core support
+#
+CONFIG_MEDIA_CAMERA_SUPPORT=y
+# CONFIG_MEDIA_ANALOG_TV_SUPPORT is not set
+# CONFIG_MEDIA_DIGITAL_TV_SUPPORT is not set
+# CONFIG_MEDIA_RADIO_SUPPORT is not set
+# CONFIG_MEDIA_SDR_SUPPORT is not set
+CONFIG_MEDIA_RC_SUPPORT=y
+# CONFIG_MEDIA_CEC_SUPPORT is not set
+CONFIG_MEDIA_CONTROLLER=y
+CONFIG_VIDEO_DEV=y
+CONFIG_VIDEO_V4L2_SUBDEV_API=y
+CONFIG_VIDEO_V4L2=y
+# CONFIG_VIDEO_ADV_DEBUG is not set
+# CONFIG_VIDEO_FIXED_MINOR_RANGES is not set
+CONFIG_V4L2_MEM2MEM_DEV=y
+CONFIG_V4L2_FWNODE=y
+CONFIG_VIDEOBUF_GEN=y
+CONFIG_VIDEOBUF2_CORE=y
+CONFIG_VIDEOBUF2_MEMOPS=y
+CONFIG_VIDEOBUF2_DMA_CONTIG=y
+CONFIG_VIDEOBUF2_VMALLOC=y
+CONFIG_VIDEOBUF2_DMA_SG=y
+# CONFIG_TTPCI_EEPROM is not set
+
+#
+# Media drivers
+#
+CONFIG_RC_CORE=y
+CONFIG_RC_MAP=y
+# CONFIG_LIRC is not set
+CONFIG_RC_DECODERS=y
+CONFIG_IR_NEC_DECODER=y
+# CONFIG_IR_RC5_DECODER is not set
+# CONFIG_IR_RC6_DECODER is not set
+# CONFIG_IR_JVC_DECODER is not set
+# CONFIG_IR_SONY_DECODER is not set
+# CONFIG_IR_SANYO_DECODER is not set
+# CONFIG_IR_SHARP_DECODER is not set
+# CONFIG_IR_MCE_KBD_DECODER is not set
+# CONFIG_IR_XMP_DECODER is not set
+# CONFIG_IR_IMON_DECODER is not set
+# CONFIG_RC_DEVICES is not set
+CONFIG_MEDIA_USB_SUPPORT=y
+
+#
+# Webcam devices
+#
+CONFIG_USB_VIDEO_CLASS=y
+# CONFIG_USB_VIDEO_CLASS_INPUT_EVDEV is not set
+# CONFIG_USB_GSPCA is not set
+# CONFIG_USB_PWC is not set
+# CONFIG_VIDEO_CPIA2 is not set
+# CONFIG_USB_ZR364XX is not set
+# CONFIG_USB_STKWEBCAM is not set
+# CONFIG_USB_S2255 is not set
+# CONFIG_VIDEO_USBTV is not set
+# CONFIG_NPU_USB_ACM is not set
+
+#
+# Webcam, TV (analog/digital) USB devices
+#
+# CONFIG_VIDEO_EM28XX is not set
+CONFIG_V4L_PLATFORM_DRIVERS=y
+CONFIG_SOC_CAMERA=y
+# CONFIG_SOC_CAMERA_PLATFORM is not set
+# CONFIG_VIDEO_XILINX is not set
+# CONFIG_VIDEO_RK_CIF_ISP10 is not set
+# CONFIG_VIDEO_ROCKCHIP_CIF is not set
+CONFIG_VIDEO_ROCKCHIP_ISP1=y
+CONFIG_V4L_MEM2MEM_DRIVERS=y
+# CONFIG_VIDEO_MEM2MEM_DEINTERLACE is not set
+# CONFIG_VIDEO_SH_VEU is not set
+CONFIG_VIDEO_ROCKCHIP_RGA=y
+# CONFIG_VIDEO_ROCKCHIP_VPU is not set
+# CONFIG_V4L_TEST_DRIVERS is not set
+# CONFIG_ROCKCHIP_TSP is not set
+
+#
+# Supported MMC/SDIO adapters
+#
+# CONFIG_CYPRESS_FIRMWARE is not set
+
+#
+# Media ancillary drivers (tuners, sensors, i2c, spi, frontends)
+#
+# CONFIG_MEDIA_SUBDRV_AUTOSELECT is not set
+# CONFIG_VIDEO_IR_I2C is not set
+
+#
+# I2C Encoders, decoders, sensors and other helper chips
+#
+
+#
+# Audio decoders, processors and mixers
+#
+# CONFIG_VIDEO_TVAUDIO is not set
+# CONFIG_VIDEO_TDA7432 is not set
+# CONFIG_VIDEO_TDA9840 is not set
+# CONFIG_VIDEO_TEA6415C is not set
+# CONFIG_VIDEO_TEA6420 is not set
+# CONFIG_VIDEO_MSP3400 is not set
+# CONFIG_VIDEO_CS5345 is not set
+# CONFIG_VIDEO_CS53L32A is not set
+# CONFIG_VIDEO_TLV320AIC23B is not set
+# CONFIG_VIDEO_UDA1342 is not set
+# CONFIG_VIDEO_WM8775 is not set
+# CONFIG_VIDEO_WM8739 is not set
+# CONFIG_VIDEO_VP27SMPX is not set
+# CONFIG_VIDEO_SONY_BTF_MPX is not set
+
+#
+# RDS decoders
+#
+# CONFIG_VIDEO_SAA6588 is not set
+
+#
+# Video decoders
+#
+# CONFIG_VIDEO_ADV7180 is not set
+# CONFIG_VIDEO_ADV7181D is not set
+# CONFIG_VIDEO_ADV7183 is not set
+# CONFIG_VIDEO_ADV7604 is not set
+# CONFIG_VIDEO_ADV7842 is not set
+# CONFIG_VIDEO_BT819 is not set
+# CONFIG_VIDEO_BT856 is not set
+# CONFIG_VIDEO_BT866 is not set
+# CONFIG_VIDEO_KS0127 is not set
+# CONFIG_VIDEO_ML86V7667 is not set
+# CONFIG_VIDEO_SAA7110 is not set
+# CONFIG_VIDEO_SAA711X is not set
+# CONFIG_VIDEO_TC35874X is not set
+# CONFIG_VIDEO_TVP514X is not set
+# CONFIG_VIDEO_TVP5150 is not set
+# CONFIG_VIDEO_TVP7002 is not set
+# CONFIG_VIDEO_TW2804 is not set
+# CONFIG_VIDEO_TW9903 is not set
+# CONFIG_VIDEO_TW9906 is not set
+# CONFIG_VIDEO_VPX3220 is not set
+
+#
+# Video and audio decoders
+#
+# CONFIG_VIDEO_SAA717X is not set
+# CONFIG_VIDEO_CX25840 is not set
+
+#
+# Video encoders
+#
+# CONFIG_VIDEO_SAA7127 is not set
+# CONFIG_VIDEO_SAA7185 is not set
+# CONFIG_VIDEO_ADV7170 is not set
+# CONFIG_VIDEO_ADV7175 is not set
+# CONFIG_VIDEO_ADV7343 is not set
+# CONFIG_VIDEO_ADV7393 is not set
+# CONFIG_VIDEO_ADV7511 is not set
+# CONFIG_VIDEO_AD9389B is not set
+# CONFIG_VIDEO_AK881X is not set
+# CONFIG_VIDEO_THS8200 is not set
+
+#
+# Camera sensor devices
+#
+# CONFIG_VIDEO_IMX219 is not set
+# CONFIG_VIDEO_IMX258 is not set
+# CONFIG_VIDEO_IMX317 is not set
+# CONFIG_VIDEO_IMX323 is not set
+# CONFIG_VIDEO_IMX327 is not set
+# CONFIG_VIDEO_VIRT_CAMERA is not set
+# CONFIG_VIDEO_OV2659 is not set
+# CONFIG_VIDEO_OV2680 is not set
+# CONFIG_VIDEO_OV2685 is not set
+# CONFIG_VIDEO_OV2718 is not set
+# CONFIG_VIDEO_OV2735 is not set
+# CONFIG_VIDEO_OV4689 is not set
+# CONFIG_VIDEO_OV5647 is not set
+# CONFIG_VIDEO_OV5648 is not set
+CONFIG_VIDEO_OV5695=y
+# CONFIG_VIDEO_OV7251 is not set
+# CONFIG_VIDEO_OV7640 is not set
+# CONFIG_VIDEO_OV7670 is not set
+# CONFIG_VIDEO_OV7725 is not set
+# CONFIG_VIDEO_OV7750 is not set
+# CONFIG_VIDEO_OV8858 is not set
+# CONFIG_VIDEO_OV9281 is not set
+# CONFIG_VIDEO_OV9650 is not set
+# CONFIG_VIDEO_OV13850 is not set
+# CONFIG_VIDEO_VS6624 is not set
+# CONFIG_VIDEO_MT9M032 is not set
+# CONFIG_VIDEO_MT9P031 is not set
+# CONFIG_VIDEO_MT9T001 is not set
+# CONFIG_VIDEO_MT9V011 is not set
+# CONFIG_VIDEO_MT9V032 is not set
+# CONFIG_VIDEO_AR0230 is not set
+# CONFIG_VIDEO_SR030PC30 is not set
+# CONFIG_VIDEO_NOON010PC30 is not set
+# CONFIG_VIDEO_M5MOLS is not set
+# CONFIG_VIDEO_S5K6AA is not set
+# CONFIG_VIDEO_S5K6A3 is not set
+# CONFIG_VIDEO_S5K4ECGX is not set
+# CONFIG_VIDEO_S5K5BAF is not set
+# CONFIG_VIDEO_SMIAPP is not set
+# CONFIG_VIDEO_S5C73M3 is not set
+# CONFIG_VIDEO_GC2155 is not set
+# CONFIG_VIDEO_GC0312 is not set
+# CONFIG_VIDEO_GC2145 is not set
+CONFIG_VIDEO_GC2355=y
+# CONFIG_VIDEO_GC2385 is not set
+# CONFIG_VIDEO_GC5025 is not set
+# CONFIG_VIDEO_GC8034 is not set
+CONFIG_VIDEO_SC031GS=y
+# CONFIG_VIDEO_SC132GS is not set
+# CONFIG_VIDEO_GC0329 is not set
+# CONFIG_VIDEO_GC2035 is not set
+# CONFIG_VIDEO_BF3925 is not set
+# CONFIG_VIDEO_JX_H65 is not set
+CONFIG_VIDEO_PREISP_DUMMY_SENSOR=y
+
+#
+# Flash devices
+#
+# CONFIG_VIDEO_ADP1653 is not set
+# CONFIG_VIDEO_AS3645A is not set
+# CONFIG_VIDEO_LM3560 is not set
+# CONFIG_VIDEO_LM3646 is not set
+# CONFIG_VIDEO_SGM3784 is not set
+
+#
+# Video improvement chips
+#
+# CONFIG_VIDEO_UPD64031A is not set
+# CONFIG_VIDEO_UPD64083 is not set
+
+#
+# Camera lens devices
+#
+# CONFIG_VIDEO_VM149C is not set
+# CONFIG_VIDEO_DW9714 is not set
+# CONFIG_VIDEO_FP5510 is not set
+
+#
+# Audio/Video compression chips
+#
+# CONFIG_VIDEO_SAA6752HS is not set
+
+#
+# Miscellaneous helper chips
+#
+# CONFIG_VIDEO_THS7303 is not set
+# CONFIG_VIDEO_M52790 is not set
+# CONFIG_VIDEO_NVP6324 is not set
+
+#
+# Sensors used on soc_camera driver
+#
+
+#
+# soc_camera sensor drivers
+#
+# CONFIG_SOC_CAMERA_IMX074 is not set
+# CONFIG_SOC_CAMERA_MT9M001 is not set
+# CONFIG_SOC_CAMERA_MT9M111 is not set
+# CONFIG_SOC_CAMERA_MT9T031 is not set
+# CONFIG_SOC_CAMERA_MT9T112 is not set
+# CONFIG_SOC_CAMERA_MT9V022 is not set
+# CONFIG_SOC_CAMERA_OV2640 is not set
+# CONFIG_SOC_CAMERA_OV5642 is not set
+# CONFIG_SOC_CAMERA_OV6650 is not set
+# CONFIG_SOC_CAMERA_OV772X is not set
+# CONFIG_SOC_CAMERA_OV9640 is not set
+# CONFIG_SOC_CAMERA_OV9740 is not set
+# CONFIG_SOC_CAMERA_RJ54N1 is not set
+# CONFIG_SOC_CAMERA_TW9910 is not set
+
+#
+# SPI helper chips
+#
+# CONFIG_VIDEO_GS1662 is not set
+CONFIG_VIDEO_ROCKCHIP_PREISP=y
+
+#
+# Customise DVB Frontends
+#
+# CONFIG_DVB_AU8522_V4L is not set
+# CONFIG_DVB_TUNER_DIB0070 is not set
+# CONFIG_DVB_TUNER_DIB0090 is not set
+
+#
+# Tools to develop new frontends
+#
+# CONFIG_DVB_DUMMY_FE is not set
+# CONFIG_CAMSYS_DRV is not set
+# CONFIG_ROCK_CHIP_SOC_CAMERA is not set
+
+#
+# Graphics support
+#
+CONFIG_DRM=y
+CONFIG_DRM_IGNORE_IOTCL_PERMIT=y
+CONFIG_DRM_MIPI_DSI=y
+CONFIG_DRM_KMS_HELPER=y
+CONFIG_DRM_KMS_FB_HELPER=y
+CONFIG_DRM_FBDEV_EMULATION=y
+CONFIG_DRM_LOAD_EDID_FIRMWARE=y
+# CONFIG_DRM_DP_CEC is not set
+# CONFIG_DRM_SCDC_HELPER is not set
+CONFIG_DRM_DMA_SYNC=y
+
+#
+# I2C encoder or helper chips
+#
+# CONFIG_DRM_I2C_ADV7511 is not set
+# CONFIG_DRM_I2C_CH7006 is not set
+# CONFIG_DRM_I2C_SIL164 is not set
+# CONFIG_DRM_I2C_NXP_TDA998X is not set
+# CONFIG_DRM_VGEM is not set
+CONFIG_DRM_ROCKCHIP=y
+# CONFIG_ROCKCHIP_DRM_DEBUG is not set
+# CONFIG_ROCKCHIP_DW_HDMI is not set
+CONFIG_ROCKCHIP_DW_MIPI_DSI=y
+# CONFIG_ROCKCHIP_MIPI_CSI_TX is not set
+CONFIG_ROCKCHIP_ANALOGIX_DP=y
+# CONFIG_ROCKCHIP_INNO_HDMI is not set
+CONFIG_ROCKCHIP_LVDS=y
+CONFIG_ROCKCHIP_DRM_TVE=y
+# CONFIG_ROCKCHIP_RGB is not set
+# CONFIG_ROCKCHIP_DRM_BACKLIGHT is not set
+# CONFIG_ROCKCHIP_RK3066_HDMI is not set
+# CONFIG_DRM_UDL is not set
+CONFIG_DRM_PANEL=y
+
+#
+# Display Panels
+#
+CONFIG_DRM_PANEL_SIMPLE=y
+# CONFIG_DRM_PANEL_SAMSUNG_LD9040 is not set
+# CONFIG_DRM_PANEL_LG_LG4573 is not set
+# CONFIG_DRM_PANEL_SAMSUNG_S6E8AA0 is not set
+# CONFIG_DRM_PANEL_SHARP_LQ101R1SX01 is not set
+CONFIG_DRM_BRIDGE=y
+
+#
+# Display Interface Bridges
+#
+# CONFIG_DRM_NXP_PTN3460 is not set
+# CONFIG_DRM_PARADE_PS8622 is not set
+# CONFIG_DRM_RK1000 is not set
+# CONFIG_DRM_DUMB_VGA_DAC is not set
+# CONFIG_DRM_LONTIUM_LT8912 is not set
+CONFIG_DRM_LONTIUM_LT9611_I2C=y
+# CONFIG_DRM_CHIPONE_ICN6211 is not set
+CONFIG_DRM_ANALOGIX_DP=y
+# CONFIG_DRM_ANALOGIX_ANX78XX is not set
+# CONFIG_DRM_ANALOGIX_ANX6345 is not set
+# CONFIG_POWERVR_ROGUE_M is not set
+# CONFIG_MALI400 is not set
+CONFIG_MALI_MIDGARD_FOR_ANDROID=y
+# CONFIG_MALI_MIDGARD_FOR_LINUX is not set
+# CONFIG_MALI_MIDGARD is not set
+# CONFIG_MALI_CORESTACK is not set
+CONFIG_MALI_PWRSOFT_765=y
+# CONFIG_MALI_KUTF is not set
+# CONFIG_MALI_BIFROST_FOR_ANDROID is not set
+CONFIG_MALI_BIFROST_FOR_LINUX=y
+CONFIG_MALI_BIFROST=y
+# CONFIG_MALI_BIFROST_GATOR_SUPPORT is not set
+# CONFIG_MALI_BIFROST_ENABLE_TRACE is not set
+CONFIG_MALI_BIFROST_DEVFREQ=y
+# CONFIG_MALI_BIFROST_DMA_FENCE is not set
+CONFIG_MALI_PLATFORM_NAME="rk"
+CONFIG_MALI_BIFROST_EXPERT=y
+# CONFIG_MALI_BIFROST_PRFCNT_SET_SECONDARY is not set
+CONFIG_MALI_BIFROST_DEBUG=y
+# CONFIG_MALI_BIFROST_NO_MALI is not set
+# CONFIG_MALI_BIFROST_TRACE_TIMELINE is not set
+# CONFIG_MALI_BIFROST_SYSTEM_TRACE is not set
+# CONFIG_MALI_JOB_DUMP is not set
+# CONFIG_MALI_2MB_ALLOC is not set
+
+#
+# Frame buffer Devices
+#
+CONFIG_FB=y
+# CONFIG_FIRMWARE_EDID is not set
+CONFIG_FB_CMDLINE=y
+# CONFIG_FB_DDC is not set
+# CONFIG_FB_BOOT_VESA_SUPPORT is not set
+CONFIG_FB_CFB_FILLRECT=y
+CONFIG_FB_CFB_COPYAREA=y
+CONFIG_FB_CFB_IMAGEBLIT=y
+# CONFIG_FB_CFB_REV_PIXELS_IN_BYTE is not set
+CONFIG_FB_SYS_FILLRECT=y
+CONFIG_FB_SYS_COPYAREA=y
+CONFIG_FB_SYS_IMAGEBLIT=y
+# CONFIG_FB_FOREIGN_ENDIAN is not set
+CONFIG_FB_SYS_FOPS=y
+# CONFIG_FB_SVGALIB is not set
+# CONFIG_FB_MACMODES is not set
+# CONFIG_FB_BACKLIGHT is not set
+# CONFIG_FB_MODE_HELPERS is not set
+# CONFIG_FB_TILEBLITTING is not set
+
+#
+# Frame buffer hardware drivers
+#
+# CONFIG_FB_ARMCLCD is not set
+# CONFIG_FB_UVESA is not set
+# CONFIG_FB_OPENCORES is not set
+# CONFIG_FB_S1D13XXX is not set
+# CONFIG_FB_SMSCUFX is not set
+# CONFIG_FB_UDL is not set
+# CONFIG_FB_IBM_GXT4500 is not set
+# CONFIG_FB_VIRTUAL is not set
+# CONFIG_FB_METRONOME is not set
+# CONFIG_FB_BROADSHEET is not set
+# CONFIG_FB_AUO_K190X is not set
+# CONFIG_FB_SIMPLE is not set
+# CONFIG_FB_SSD1307 is not set
+CONFIG_BACKLIGHT_LCD_SUPPORT=y
+# CONFIG_LCD_CLASS_DEVICE is not set
+CONFIG_BACKLIGHT_CLASS_DEVICE=y
+CONFIG_BACKLIGHT_GENERIC=y
+CONFIG_BACKLIGHT_PWM=y
+# CONFIG_BACKLIGHT_PM8941_WLED is not set
+# CONFIG_BACKLIGHT_ADP8860 is not set
+# CONFIG_BACKLIGHT_ADP8870 is not set
+# CONFIG_BACKLIGHT_LM3630A is not set
+# CONFIG_BACKLIGHT_LM3639 is not set
+# CONFIG_BACKLIGHT_LP855X is not set
+# CONFIG_BACKLIGHT_GPIO is not set
+# CONFIG_BACKLIGHT_LV5207LP is not set
+# CONFIG_BACKLIGHT_BD6107 is not set
+
+#
+# Rockchip Misc Video driver
+#
+# CONFIG_FB_ROCKCHIP is not set
+# CONFIG_LCDC_RK3368 is not set
+CONFIG_LCD_GENERAL=y
+# CONFIG_LCD_MIPI is not set
+# CONFIG_RK_TRSM is not set
+# CONFIG_RK_HDMI is not set
+
+#
+# RGA
+#
+# CONFIG_ROCKCHIP_RGA is not set
+
+#
+# RGA2
+#
+# CONFIG_ROCKCHIP_RGA2 is not set
+
+#
+# VCODEC
+#
+CONFIG_RK_VCODEC=y
+
+#
+# IEP
+#
+# CONFIG_IEP is not set
+# CONFIG_IEP_MMU is not set
+
+#
+# DP
+#
+
+#
+# ROCKCHIP_MPP
+#
+CONFIG_ROCKCHIP_MPP_SERVICE=y
+CONFIG_ROCKCHIP_MPP_DEVICE=y
+# CONFIG_VGASTATE is not set
+CONFIG_VIDEOMODE_HELPERS=y
+CONFIG_HDMI=y
+
+#
+# Console display driver support
+#
+CONFIG_DUMMY_CONSOLE=y
+CONFIG_DUMMY_CONSOLE_COLUMNS=80
+CONFIG_DUMMY_CONSOLE_ROWS=25
+CONFIG_FRAMEBUFFER_CONSOLE=y
+# CONFIG_LOGO is not set
+CONFIG_SOUND=y
+# CONFIG_SOUND_OSS_CORE is not set
+CONFIG_SND=y
+CONFIG_SND_TIMER=y
+CONFIG_SND_PCM=y
+CONFIG_SND_DMAENGINE_PCM=y
+CONFIG_SND_HWDEP=y
+CONFIG_SND_RAWMIDI=y
+CONFIG_SND_JACK=y
+CONFIG_SND_SEQUENCER=y
+CONFIG_SND_SEQ_DUMMY=y
+# CONFIG_SND_MIXER_OSS is not set
+# CONFIG_SND_PCM_OSS is not set
+CONFIG_SND_PCM_TIMER=y
+# CONFIG_SND_SEQUENCER_OSS is not set
+CONFIG_SND_HRTIMER=y
+CONFIG_SND_SEQ_HRTIMER_DEFAULT=y
+CONFIG_SND_DYNAMIC_MINORS=y
+CONFIG_SND_MAX_CARDS=32
+# CONFIG_SND_SUPPORT_OLD_API is not set
+CONFIG_SND_PROC_FS=y
+CONFIG_SND_VERBOSE_PROCFS=y
+# CONFIG_SND_VERBOSE_PRINTK is not set
+# CONFIG_SND_DEBUG is not set
+CONFIG_SND_RAWMIDI_SEQ=y
+# CONFIG_SND_OPL3_LIB_SEQ is not set
+# CONFIG_SND_OPL4_LIB_SEQ is not set
+# CONFIG_SND_SBAWE_SEQ is not set
+# CONFIG_SND_EMU10K1_SEQ is not set
+CONFIG_SND_DRIVERS=y
+# CONFIG_SND_DUMMY is not set
+# CONFIG_SND_ALOOP is not set
+# CONFIG_SND_VIRMIDI is not set
+# CONFIG_SND_MTPAV is not set
+# CONFIG_SND_SERIAL_U16550 is not set
+# CONFIG_SND_MPU401 is not set
+
+#
+# HD-Audio
+#
+CONFIG_SND_HDA_PREALLOC_SIZE=64
+# CONFIG_SND_SPI is not set
+CONFIG_SND_USB=y
+CONFIG_SND_USB_AUDIO=y
+# CONFIG_SND_USB_UA101 is not set
+# CONFIG_SND_USB_CAIAQ is not set
+# CONFIG_SND_USB_6FIRE is not set
+# CONFIG_SND_USB_HIFACE is not set
+# CONFIG_SND_BCD2000 is not set
+# CONFIG_SND_USB_POD is not set
+# CONFIG_SND_USB_PODHD is not set
+# CONFIG_SND_USB_TONEPORT is not set
+# CONFIG_SND_USB_VARIAX is not set
+CONFIG_SND_SOC=y
+CONFIG_SND_SOC_GENERIC_DMAENGINE_PCM=y
+# CONFIG_SND_ATMEL_SOC is not set
+# CONFIG_SND_DESIGNWARE_I2S is not set
+
+#
+# SoC Audio for Freescale CPUs
+#
+
+#
+# Common SoC Audio options for Freescale CPUs:
+#
+# CONFIG_SND_SOC_FSL_ASRC is not set
+# CONFIG_SND_SOC_FSL_SAI is not set
+# CONFIG_SND_SOC_FSL_SSI is not set
+# CONFIG_SND_SOC_FSL_SPDIF is not set
+# CONFIG_SND_SOC_FSL_ESAI is not set
+# CONFIG_SND_SOC_IMX_AUDMUX is not set
+CONFIG_SND_SOC_ROCKCHIP=y
+# CONFIG_SND_SOC_ROCKCHIP_FORCE_SRAM is not set
+CONFIG_SND_SOC_ROCKCHIP_I2S=y
+# CONFIG_SND_SOC_ROCKCHIP_I2S_TDM is not set
+# CONFIG_SND_SOC_ROCKCHIP_MULTI_DAIS is not set
+# CONFIG_SND_SOC_ROCKCHIP_PDM is not set
+# CONFIG_SND_SOC_ROCKCHIP_SPDIF is not set
+# CONFIG_SND_SOC_ROCKCHIP_SPDIFRX is not set
+# CONFIG_SND_SOC_ROCKCHIP_VAD is not set
+# CONFIG_SND_SOC_ROCKCHIP_DA7219 is not set
+# CONFIG_SND_SOC_ROCKCHIP_HDMI_ANALOG is not set
+# CONFIG_SND_SOC_ROCKCHIP_MAX98090 is not set
+# CONFIG_SND_SOC_ROCKCHIP_MULTICODECS is not set
+# CONFIG_SND_SOC_ROCKCHIP_RT5645 is not set
+# CONFIG_SND_SOC_ROCKCHIP_RT5651_TC358749 is not set
+# CONFIG_SND_SOC_ROCKCHIP_CDNDP is not set
+
+#
+# Allwinner SoC Audio support
+#
+# CONFIG_SND_SUN4I_CODEC is not set
+# CONFIG_SND_SOC_XTFPGA_I2S is not set
+CONFIG_SND_SOC_I2C_AND_SPI=y
+
+#
+# CODEC drivers
+#
+# CONFIG_SND_SOC_AC97_CODEC is not set
+# CONFIG_SND_SOC_ADAU1701 is not set
+# CONFIG_SND_SOC_AK4104 is not set
+# CONFIG_SND_SOC_AK4554 is not set
+# CONFIG_SND_SOC_AK4613 is not set
+# CONFIG_SND_SOC_AK4642 is not set
+# CONFIG_SND_SOC_AK5386 is not set
+# CONFIG_SND_SOC_ALC5623 is not set
+# CONFIG_SND_SOC_CS35L32 is not set
+# CONFIG_SND_SOC_CS42L51_I2C is not set
+# CONFIG_SND_SOC_CS42L52 is not set
+# CONFIG_SND_SOC_CS42L56 is not set
+# CONFIG_SND_SOC_CS42L73 is not set
+# CONFIG_SND_SOC_CS4265 is not set
+# CONFIG_SND_SOC_CS4270 is not set
+# CONFIG_SND_SOC_CS4271_I2C is not set
+# CONFIG_SND_SOC_CS4271_SPI is not set
+# CONFIG_SND_SOC_CS42XX8_I2C is not set
+# CONFIG_SND_SOC_CS4349 is not set
+# CONFIG_SND_SOC_CX2072X is not set
+# CONFIG_SND_SOC_CX20810 is not set
+# CONFIG_SND_SOC_DUMMY_CODEC is not set
+# CONFIG_SND_SOC_BT_SCO is not set
+# CONFIG_SND_SOC_ES8316 is not set
+# CONFIG_SND_SOC_ES8323 is not set
+# CONFIG_SND_SOC_ES8328 is not set
+# CONFIG_SND_SOC_ES8328_I2C is not set
+# CONFIG_SND_SOC_ES8396 is not set
+# CONFIG_SND_SOC_GTM601 is not set
+# CONFIG_SND_SOC_GVA_CODEC is not set
+# CONFIG_SND_SOC_FM1288 is not set
+# CONFIG_SND_SOC_PCM1681 is not set
+# CONFIG_SND_SOC_PCM1792A is not set
+# CONFIG_SND_SOC_PCM512x_I2C is not set
+# CONFIG_SND_SOC_PCM512x_SPI is not set
+# CONFIG_SND_SOC_RK312X is not set
+# CONFIG_SND_SOC_RK3228 is not set
+# CONFIG_SND_SOC_RK3308 is not set
+# CONFIG_SND_SOC_RK3328 is not set
+CONFIG_SND_SOC_RK817=y
+CONFIG_SND_SOC_RL6231=y
+# CONFIG_SND_SOC_RT5616 is not set
+# CONFIG_SND_SOC_RT5631 is not set
+CONFIG_SND_SOC_RT5640=y
+# CONFIG_SND_SOC_RT5651 is not set
+# CONFIG_SND_SOC_RT5677_SPI is not set
+# CONFIG_SND_SOC_SGTL5000 is not set
+# CONFIG_SND_SOC_SIRF_AUDIO_CODEC is not set
+# CONFIG_SND_SOC_SPDIF is not set
+# CONFIG_SND_SOC_SSM2602_SPI is not set
+# CONFIG_SND_SOC_SSM2602_I2C is not set
+# CONFIG_SND_SOC_SSM4567 is not set
+# CONFIG_SND_SOC_STA32X is not set
+# CONFIG_SND_SOC_STA350 is not set
+# CONFIG_SND_SOC_STI_SAS is not set
+# CONFIG_SND_SOC_TAS2552 is not set
+# CONFIG_SND_SOC_TAS5086 is not set
+# CONFIG_SND_SOC_TAS571X is not set
+# CONFIG_SND_SOC_TC358749X is not set
+# CONFIG_SND_SOC_TFA9879 is not set
+# CONFIG_SND_SOC_TLV320AIC23_I2C is not set
+# CONFIG_SND_SOC_TLV320AIC23_SPI is not set
+# CONFIG_SND_SOC_TLV320AIC31XX is not set
+# CONFIG_SND_SOC_TLV320AIC3X is not set
+# CONFIG_SND_SOC_TS3A227E is not set
+# CONFIG_SND_SOC_WM8510 is not set
+# CONFIG_SND_SOC_WM8523 is not set
+# CONFIG_SND_SOC_WM8580 is not set
+# CONFIG_SND_SOC_WM8711 is not set
+# CONFIG_SND_SOC_WM8728 is not set
+# CONFIG_SND_SOC_WM8731 is not set
+# CONFIG_SND_SOC_WM8737 is not set
+# CONFIG_SND_SOC_WM8741 is not set
+# CONFIG_SND_SOC_WM8750 is not set
+# CONFIG_SND_SOC_WM8753 is not set
+# CONFIG_SND_SOC_WM8770 is not set
+# CONFIG_SND_SOC_WM8776 is not set
+# CONFIG_SND_SOC_WM8804_I2C is not set
+# CONFIG_SND_SOC_WM8804_SPI is not set
+# CONFIG_SND_SOC_WM8903 is not set
+# CONFIG_SND_SOC_WM8962 is not set
+# CONFIG_SND_SOC_WM8978 is not set
+# CONFIG_SND_SOC_TPA6130A2 is not set
+CONFIG_SND_SIMPLE_CARD=y
+# CONFIG_SOUND_PRIME is not set
+
+#
+# HID support
+#
+CONFIG_HID=y
+CONFIG_HID_BATTERY_STRENGTH=y
+CONFIG_HIDRAW=y
+CONFIG_UHID=y
+CONFIG_HID_GENERIC=y
+
+#
+# Special HID drivers
+#
+# CONFIG_HID_A4TECH is not set
+# CONFIG_HID_ACRUX is not set
+# CONFIG_HID_APPLE is not set
+# CONFIG_HID_APPLEIR is not set
+# CONFIG_HID_AUREAL is not set
+# CONFIG_HID_BELKIN is not set
+# CONFIG_HID_BETOP_FF is not set
+# CONFIG_HID_CHERRY is not set
+# CONFIG_HID_CHICONY is not set
+# CONFIG_HID_CORSAIR is not set
+# CONFIG_HID_PRODIKEYS is not set
+# CONFIG_HID_CP2112 is not set
+# CONFIG_HID_CYPRESS is not set
+# CONFIG_HID_DRAGONRISE is not set
+# CONFIG_HID_EMS_FF is not set
+# CONFIG_HID_ELECOM is not set
+# CONFIG_HID_ELO is not set
+# CONFIG_HID_EZKEY is not set
+# CONFIG_HID_GEMBIRD is not set
+# CONFIG_HID_GFRM is not set
+# CONFIG_HID_HOLTEK is not set
+# CONFIG_HID_GT683R is not set
+# CONFIG_HID_KEYTOUCH is not set
+# CONFIG_HID_KYE is not set
+# CONFIG_HID_UCLOGIC is not set
+# CONFIG_HID_WALTOP is not set
+# CONFIG_HID_GYRATION is not set
+# CONFIG_HID_ICADE is not set
+# CONFIG_HID_TWINHAN is not set
+CONFIG_HID_KENSINGTON=y
+# CONFIG_HID_LCPOWER is not set
+# CONFIG_HID_LENOVO is not set
+# CONFIG_HID_LOGITECH is not set
+# CONFIG_HID_MAGICMOUSE is not set
+# CONFIG_HID_MICROSOFT is not set
+# CONFIG_HID_MONTEREY is not set
+CONFIG_HID_MULTITOUCH=y
+# CONFIG_HID_NTRIG is not set
+# CONFIG_HID_ORTEK is not set
+# CONFIG_HID_PANTHERLORD is not set
+# CONFIG_HID_PENMOUNT is not set
+# CONFIG_HID_PETALYNX is not set
+# CONFIG_HID_PICOLCD is not set
+# CONFIG_HID_PLANTRONICS is not set
+# CONFIG_HID_PRIMAX is not set
+# CONFIG_HID_ROCCAT is not set
+# CONFIG_HID_SAITEK is not set
+# CONFIG_HID_SAMSUNG is not set
+# CONFIG_HID_SONY is not set
+# CONFIG_HID_SPEEDLINK is not set
+# CONFIG_HID_STEELSERIES is not set
+# CONFIG_HID_SUNPLUS is not set
+# CONFIG_HID_RMI is not set
+# CONFIG_HID_GREENASIA is not set
+# CONFIG_HID_SMARTJOYPLUS is not set
+# CONFIG_HID_TIVO is not set
+# CONFIG_HID_TOPSEED is not set
+# CONFIG_HID_THINGM is not set
+# CONFIG_HID_THRUSTMASTER is not set
+# CONFIG_HID_WACOM is not set
+# CONFIG_HID_WIIMOTE is not set
+# CONFIG_HID_XINMO is not set
+# CONFIG_HID_ZEROPLUS is not set
+# CONFIG_HID_ZYDACRON is not set
+# CONFIG_HID_SENSOR_HUB is not set
+# CONFIG_HID_RKVR is not set
+# CONFIG_HID_ALPS is not set
+
+#
+# USB HID support
+#
+CONFIG_USB_HID=y
+# CONFIG_HID_PID is not set
+CONFIG_USB_HIDDEV=y
+
+#
+# I2C HID support
+#
+CONFIG_I2C_HID=y
+CONFIG_USB_OHCI_LITTLE_ENDIAN=y
+CONFIG_USB_SUPPORT=y
+CONFIG_USB_COMMON=y
+CONFIG_USB_ARCH_HAS_HCD=y
+CONFIG_USB=y
+CONFIG_USB_ANNOUNCE_NEW_DEVICES=y
+
+#
+# Miscellaneous USB options
+#
+# CONFIG_USB_DEFAULT_PERSIST is not set
+# CONFIG_USB_DYNAMIC_MINORS is not set
+CONFIG_USB_OTG=y
+# CONFIG_USB_OTG_WHITELIST is not set
+# CONFIG_USB_OTG_BLACKLIST_HUB is not set
+# CONFIG_USB_OTG_FSM is not set
+# CONFIG_USB_ULPI_BUS is not set
+CONFIG_USB_MON=y
+# CONFIG_USB_WUSB_CBAF is not set
+
+#
+# USB Host Controller Drivers
+#
+# CONFIG_USB_C67X00_HCD is not set
+# CONFIG_USB_XHCI_HCD is not set
+CONFIG_USB_EHCI_HCD=y
+CONFIG_USB_EHCI_ROOT_HUB_TT=y
+CONFIG_USB_EHCI_TT_NEWSCHED=y
+CONFIG_USB_EHCI_HCD_PLATFORM=y
+# CONFIG_USB_OXU210HP_HCD is not set
+# CONFIG_USB_ISP116X_HCD is not set
+# CONFIG_USB_ISP1362_HCD is not set
+# CONFIG_USB_FOTG210_HCD is not set
+# CONFIG_USB_MAX3421_HCD is not set
+CONFIG_USB_OHCI_HCD=y
+CONFIG_USB_OHCI_HCD_PLATFORM=y
+# CONFIG_USB_SL811_HCD is not set
+# CONFIG_USB_R8A66597_HCD is not set
+# CONFIG_USB_HCD_TEST_MODE is not set
+
+#
+# USB Device Class drivers
+#
+CONFIG_USB_ACM=y
+# CONFIG_USB_PRINTER is not set
+CONFIG_USB_WDM=y
+# CONFIG_USB_TMC is not set
+
+#
+# NOTE: USB_STORAGE depends on SCSI but BLK_DEV_SD may
+#
+
+#
+# also be needed; see USB_STORAGE Help for more info
+#
+CONFIG_USB_STORAGE=y
+# CONFIG_USB_STORAGE_DEBUG is not set
+# CONFIG_USB_STORAGE_REALTEK is not set
+# CONFIG_USB_STORAGE_DATAFAB is not set
+# CONFIG_USB_STORAGE_FREECOM is not set
+# CONFIG_USB_STORAGE_ISD200 is not set
+# CONFIG_USB_STORAGE_USBAT is not set
+# CONFIG_USB_STORAGE_SDDR09 is not set
+# CONFIG_USB_STORAGE_SDDR55 is not set
+# CONFIG_USB_STORAGE_JUMPSHOT is not set
+# CONFIG_USB_STORAGE_ALAUDA is not set
+# CONFIG_USB_STORAGE_ONETOUCH is not set
+# CONFIG_USB_STORAGE_KARMA is not set
+# CONFIG_USB_STORAGE_CYPRESS_ATACB is not set
+# CONFIG_USB_STORAGE_ENE_UB6250 is not set
+CONFIG_USB_UAS=y
+
+#
+# USB Imaging devices
+#
+# CONFIG_USB_MDC800 is not set
+# CONFIG_USB_MICROTEK is not set
+# CONFIG_USBIP_CORE is not set
+# CONFIG_USB_MUSB_HDRC is not set
+# CONFIG_USB_DWC3 is not set
+CONFIG_USB_DWC2=y
+# CONFIG_USB_DWC2_HOST is not set
+
+#
+# Gadget/Dual-role mode requires USB Gadget support to be enabled
+#
+# CONFIG_USB_DWC2_PERIPHERAL is not set
+CONFIG_USB_DWC2_DUAL_ROLE=y
+# CONFIG_USB_DWC2_DEBUG is not set
+# CONFIG_USB_DWC2_TRACK_MISSED_SOFS is not set
+# CONFIG_USB_CHIPIDEA is not set
+# CONFIG_USB_ISP1760 is not set
+
+#
+# USB port drivers
+#
+CONFIG_USB_SERIAL=y
+# CONFIG_USB_SERIAL_CONSOLE is not set
+CONFIG_USB_SERIAL_GENERIC=y
+# CONFIG_USB_SERIAL_SIMPLE is not set
+# CONFIG_USB_SERIAL_AIRCABLE is not set
+# CONFIG_USB_SERIAL_ARK3116 is not set
+# CONFIG_USB_SERIAL_BELKIN is not set
+# CONFIG_USB_SERIAL_CH341 is not set
+# CONFIG_USB_SERIAL_WHITEHEAT is not set
+# CONFIG_USB_SERIAL_DIGI_ACCELEPORT is not set
+CONFIG_USB_SERIAL_CP210X=y
+# CONFIG_USB_SERIAL_CYPRESS_M8 is not set
+# CONFIG_USB_SERIAL_EMPEG is not set
+CONFIG_USB_SERIAL_FTDI_SIO=y
+# CONFIG_USB_SERIAL_VISOR is not set
+# CONFIG_USB_SERIAL_IPAQ is not set
+# CONFIG_USB_SERIAL_IR is not set
+# CONFIG_USB_SERIAL_EDGEPORT is not set
+# CONFIG_USB_SERIAL_EDGEPORT_TI is not set
+# CONFIG_USB_SERIAL_F81232 is not set
+# CONFIG_USB_SERIAL_GARMIN is not set
+# CONFIG_USB_SERIAL_IPW is not set
+# CONFIG_USB_SERIAL_IUU is not set
+# CONFIG_USB_SERIAL_KEYSPAN_PDA is not set
+CONFIG_USB_SERIAL_KEYSPAN=y
+# CONFIG_USB_SERIAL_KEYSPAN_MPR is not set
+# CONFIG_USB_SERIAL_KEYSPAN_USA28 is not set
+# CONFIG_USB_SERIAL_KEYSPAN_USA28X is not set
+# CONFIG_USB_SERIAL_KEYSPAN_USA28XA is not set
+# CONFIG_USB_SERIAL_KEYSPAN_USA28XB is not set
+# CONFIG_USB_SERIAL_KEYSPAN_USA19 is not set
+# CONFIG_USB_SERIAL_KEYSPAN_USA18X is not set
+# CONFIG_USB_SERIAL_KEYSPAN_USA19W is not set
+# CONFIG_USB_SERIAL_KEYSPAN_USA19QW is not set
+# CONFIG_USB_SERIAL_KEYSPAN_USA19QI is not set
+# CONFIG_USB_SERIAL_KEYSPAN_USA49W is not set
+# CONFIG_USB_SERIAL_KEYSPAN_USA49WLC is not set
+# CONFIG_USB_SERIAL_KLSI is not set
+# CONFIG_USB_SERIAL_KOBIL_SCT is not set
+# CONFIG_USB_SERIAL_MCT_U232 is not set
+# CONFIG_USB_SERIAL_METRO is not set
+# CONFIG_USB_SERIAL_MOS7720 is not set
+# CONFIG_USB_SERIAL_MOS7840 is not set
+# CONFIG_USB_SERIAL_MXUPORT is not set
+# CONFIG_USB_SERIAL_NAVMAN is not set
+CONFIG_USB_SERIAL_PL2303=y
+CONFIG_USB_SERIAL_OTI6858=y
+# CONFIG_USB_SERIAL_QCAUX is not set
+CONFIG_USB_SERIAL_QUALCOMM=y
+# CONFIG_USB_SERIAL_SPCP8X5 is not set
+# CONFIG_USB_SERIAL_SAFE is not set
+CONFIG_USB_SERIAL_SIERRAWIRELESS=y
+# CONFIG_USB_SERIAL_SYMBOL is not set
+# CONFIG_USB_SERIAL_TI is not set
+# CONFIG_USB_SERIAL_CYBERJACK is not set
+# CONFIG_USB_SERIAL_XIRCOM is not set
+CONFIG_USB_SERIAL_WWAN=y
+CONFIG_USB_SERIAL_OPTION=y
+# CONFIG_USB_SERIAL_OMNINET is not set
+# CONFIG_USB_SERIAL_OPTICON is not set
+# CONFIG_USB_SERIAL_XSENS_MT is not set
+# CONFIG_USB_SERIAL_WISHBONE is not set
+# CONFIG_USB_SERIAL_SSU100 is not set
+# CONFIG_USB_SERIAL_QT2 is not set
+# CONFIG_USB_SERIAL_DEBUG is not set
+
+#
+# USB Miscellaneous drivers
+#
+# CONFIG_USB_EMI62 is not set
+# CONFIG_USB_EMI26 is not set
+# CONFIG_USB_ADUTUX is not set
+# CONFIG_USB_SEVSEG is not set
+# CONFIG_USB_RIO500 is not set
+# CONFIG_USB_LEGOTOWER is not set
+# CONFIG_USB_LCD is not set
+# CONFIG_USB_LED is not set
+# CONFIG_USB_CYPRESS_CY7C63 is not set
+# CONFIG_USB_CYTHERM is not set
+# CONFIG_USB_IDMOUSE is not set
+# CONFIG_USB_FTDI_ELAN is not set
+# CONFIG_USB_APPLEDISPLAY is not set
+# CONFIG_USB_SISUSBVGA is not set
+# CONFIG_USB_LD is not set
+# CONFIG_USB_TRANCEVIBRATOR is not set
+# CONFIG_USB_IOWARRIOR is not set
+# CONFIG_USB_TEST is not set
+# CONFIG_USB_EHSET_TEST_FIXTURE is not set
+# CONFIG_USB_ISIGHTFW is not set
+# CONFIG_USB_YUREX is not set
+CONFIG_USB_EZUSB_FX2=y
+# CONFIG_USB_HSIC_USB3503 is not set
+# CONFIG_USB_LINK_LAYER_TEST is not set
+# CONFIG_USB_CHAOSKEY is not set
+
+#
+# USB Physical Layer drivers
+#
+# CONFIG_USB_PHY is not set
+# CONFIG_USB_OTG_WAKELOCK is not set
+# CONFIG_NOP_USB_XCEIV is not set
+# CONFIG_USB_GPIO_VBUS is not set
+# CONFIG_USB_ISP1301 is not set
+# CONFIG_USB_ULPI is not set
+CONFIG_USB_GADGET=y
+# CONFIG_USB_GADGET_DEBUG is not set
+CONFIG_USB_GADGET_DEBUG_FILES=y
+# CONFIG_USB_GADGET_DEBUG_FS is not set
+CONFIG_USB_GADGET_VBUS_DRAW=500
+CONFIG_USB_GADGET_STORAGE_NUM_BUFFERS=2
+
+#
+# USB Peripheral Controller
+#
+# CONFIG_USB_FOTG210_UDC is not set
+# CONFIG_USB_GR_UDC is not set
+# CONFIG_USB_R8A66597 is not set
+# CONFIG_USB_PXA27X is not set
+# CONFIG_USB_MV_UDC is not set
+# CONFIG_USB_MV_U3D is not set
+# CONFIG_USB_M66592 is not set
+# CONFIG_USB_BDC_UDC is not set
+# CONFIG_USB_NET2272 is not set
+# CONFIG_USB_GADGET_XILINX is not set
+# CONFIG_USB_DUMMY_HCD is not set
+CONFIG_USB_LIBCOMPOSITE=y
+CONFIG_USB_F_ACM=y
+CONFIG_USB_U_SERIAL=y
+CONFIG_USB_F_SERIAL=y
+CONFIG_USB_F_OBEX=y
+# CONFIG_USB_CONFIGFS is not set
+# CONFIG_USB_ZERO is not set
+# CONFIG_USB_AUDIO is not set
+# CONFIG_USB_ETH is not set
+# CONFIG_USB_G_NCM is not set
+# CONFIG_USB_GADGETFS is not set
+# CONFIG_USB_FUNCTIONFS is not set
+# CONFIG_USB_MASS_STORAGE is not set
+CONFIG_USB_G_SERIAL=y
+# CONFIG_USB_MIDI_GADGET is not set
+# CONFIG_USB_G_PRINTER is not set
+# CONFIG_USB_CDC_COMPOSITE is not set
+# CONFIG_USB_G_ACM_MS is not set
+# CONFIG_USB_G_MULTI is not set
+# CONFIG_USB_G_HID is not set
+# CONFIG_USB_G_DBGP is not set
+# CONFIG_USB_G_WEBCAM is not set
+
+#
+# ROCKCHIP USB Support
+#
+# CONFIG_USB20_HOST is not set
+# CONFIG_USB20_OTG is not set
+# CONFIG_USB_LED_TRIG is not set
+# CONFIG_UWB is not set
+CONFIG_MMC=y
+# CONFIG_MMC_DEBUG is not set
+# CONFIG_MMC_EMBEDDED_SDIO is not set
+# CONFIG_MMC_PARANOID_SD_INIT is not set
+
+#
+# MMC/SD/SDIO Card Drivers
+#
+CONFIG_MMC_BLOCK=y
+CONFIG_MMC_BLOCK_MINORS=32
+CONFIG_MMC_BLOCK_BOUNCE=y
+# CONFIG_SDIO_UART is not set
+CONFIG_MMC_TEST=y
+# CONFIG_MMC_SIMULATE_MAX_SPEED is not set
+
+#
+# MMC/SD/SDIO Host Controller Drivers
+#
+# CONFIG_MMC_ARMMMCI is not set
+# CONFIG_MMC_SDHCI is not set
+# CONFIG_MMC_SPI is not set
+CONFIG_MMC_DW=y
+CONFIG_MMC_DW_PLTFM=y
+# CONFIG_MMC_DW_EXYNOS is not set
+# CONFIG_MMC_DW_K3 is not set
+CONFIG_MMC_DW_ROCKCHIP=y
+# CONFIG_MMC_VUB300 is not set
+# CONFIG_MMC_USHC is not set
+# CONFIG_MMC_USDHI6ROL0 is not set
+# CONFIG_MMC_MTK is not set
+# CONFIG_MEMSTICK is not set
+CONFIG_NEW_LEDS=y
+CONFIG_LEDS_CLASS=y
+# CONFIG_LEDS_CLASS_FLASH is not set
+
+#
+# LED drivers
+#
+# CONFIG_LEDS_BCM6328 is not set
+# CONFIG_LEDS_BCM6358 is not set
+# CONFIG_LEDS_LM3530 is not set
+# CONFIG_LEDS_LM3642 is not set
+# CONFIG_LEDS_PCA9532 is not set
+CONFIG_LEDS_GPIO=y
+# CONFIG_LEDS_LP3944 is not set
+# CONFIG_LEDS_LP5521 is not set
+# CONFIG_LEDS_LP5523 is not set
+# CONFIG_LEDS_LP5562 is not set
+# CONFIG_LEDS_LP8501 is not set
+# CONFIG_LEDS_LP8860 is not set
+# CONFIG_LEDS_PCA955X is not set
+# CONFIG_LEDS_PCA963X is not set
+# CONFIG_LEDS_DAC124S085 is not set
+# CONFIG_LEDS_PWM is not set
+# CONFIG_LEDS_REGULATOR is not set
+# CONFIG_LEDS_BD2802 is not set
+# CONFIG_LEDS_LT3593 is not set
+# CONFIG_LEDS_TCA6507 is not set
+# CONFIG_LEDS_TLC591XX is not set
+# CONFIG_LEDS_LM355x is not set
+CONFIG_LEDS_IS31FL32XX=y
+
+#
+# LED driver for blink(1) USB RGB LED is under Special HID drivers (HID_THINGM)
+#
+# CONFIG_LEDS_BLINKM is not set
+# CONFIG_LEDS_SYSCON is not set
+
+#
+# LED Triggers
+#
+CONFIG_LEDS_TRIGGERS=y
+# CONFIG_LEDS_TRIGGER_TIMER is not set
+# CONFIG_LEDS_TRIGGER_ONESHOT is not set
+# CONFIG_LEDS_TRIGGER_HEARTBEAT is not set
+# CONFIG_LEDS_TRIGGER_BACKLIGHT is not set
+# CONFIG_LEDS_TRIGGER_CPU is not set
+# CONFIG_LEDS_TRIGGER_GPIO is not set
+# CONFIG_LEDS_TRIGGER_DEFAULT_ON is not set
+
+#
+# iptables trigger is under Netfilter config (LED target)
+#
+# CONFIG_LEDS_TRIGGER_TRANSIENT is not set
+# CONFIG_LEDS_TRIGGER_CAMERA is not set
+# CONFIG_SWITCH is not set
+# CONFIG_ACCESSIBILITY is not set
+CONFIG_EDAC_SUPPORT=y
+# CONFIG_EDAC is not set
+CONFIG_RTC_LIB=y
+CONFIG_RTC_CLASS=y
+CONFIG_RTC_HCTOSYS=y
+CONFIG_RTC_HCTOSYS_DEVICE="rtc0"
+CONFIG_RTC_SYSTOHC=y
+CONFIG_RTC_SYSTOHC_DEVICE="rtc0"
+# CONFIG_RTC_DEBUG is not set
+
+#
+# RTC interfaces
+#
+CONFIG_RTC_INTF_SYSFS=y
+CONFIG_RTC_INTF_PROC=y
+CONFIG_RTC_INTF_DEV=y
+# CONFIG_RTC_INTF_DEV_UIE_EMUL is not set
+# CONFIG_RTC_DRV_TEST is not set
+
+#
+# I2C RTC drivers
+#
+# CONFIG_RTC_DRV_ABB5ZES3 is not set
+# CONFIG_RTC_DRV_ABX80X is not set
+# CONFIG_RTC_DRV_DS1307 is not set
+# CONFIG_RTC_DRV_DS1374 is not set
+# CONFIG_RTC_DRV_DS1672 is not set
+# CONFIG_RTC_DRV_DS3232 is not set
+# CONFIG_RTC_DRV_FAKE is not set
+# CONFIG_RTC_DRV_HYM8563 is not set
+# CONFIG_RTC_DRV_MAX6900 is not set
+CONFIG_RTC_DRV_RK808=y
+# CONFIG_RTC_DRV_RK_TIMER is not set
+# CONFIG_RTC_DRV_RS5C372 is not set
+# CONFIG_RTC_DRV_ISL1208 is not set
+# CONFIG_RTC_DRV_ISL12022 is not set
+# CONFIG_RTC_DRV_ISL12057 is not set
+# CONFIG_RTC_DRV_X1205 is not set
+# CONFIG_RTC_DRV_PCF2127 is not set
+# CONFIG_RTC_DRV_PCF8523 is not set
+# CONFIG_RTC_DRV_PCF8563 is not set
+# CONFIG_RTC_DRV_PCF85063 is not set
+# CONFIG_RTC_DRV_PCF8583 is not set
+# CONFIG_RTC_DRV_M41T80 is not set
+# CONFIG_RTC_DRV_BQ32K is not set
+# CONFIG_RTC_DRV_S35390A is not set
+# CONFIG_RTC_DRV_FM3130 is not set
+# CONFIG_RTC_DRV_RX8581 is not set
+# CONFIG_RTC_DRV_RX8025 is not set
+# CONFIG_RTC_DRV_EM3027 is not set
+# CONFIG_RTC_DRV_RV3029C2 is not set
+# CONFIG_RTC_DRV_RV8803 is not set
+
+#
+# SPI RTC drivers
+#
+# CONFIG_RTC_DRV_M41T93 is not set
+# CONFIG_RTC_DRV_M41T94 is not set
+# CONFIG_RTC_DRV_DS1305 is not set
+# CONFIG_RTC_DRV_DS1343 is not set
+# CONFIG_RTC_DRV_DS1347 is not set
+# CONFIG_RTC_DRV_DS1390 is not set
+# CONFIG_RTC_DRV_MAX6902 is not set
+# CONFIG_RTC_DRV_R9701 is not set
+# CONFIG_RTC_DRV_RS5C348 is not set
+# CONFIG_RTC_DRV_DS3234 is not set
+# CONFIG_RTC_DRV_PCF2123 is not set
+# CONFIG_RTC_DRV_RX4581 is not set
+# CONFIG_RTC_DRV_MCP795 is not set
+
+#
+# Platform RTC drivers
+#
+# CONFIG_RTC_DRV_DS1286 is not set
+# CONFIG_RTC_DRV_DS1511 is not set
+# CONFIG_RTC_DRV_DS1553 is not set
+# CONFIG_RTC_DRV_DS1685_FAMILY is not set
+# CONFIG_RTC_DRV_DS1742 is not set
+# CONFIG_RTC_DRV_DS2404 is not set
+# CONFIG_RTC_DRV_STK17TA8 is not set
+# CONFIG_RTC_DRV_M48T86 is not set
+# CONFIG_RTC_DRV_M48T35 is not set
+# CONFIG_RTC_DRV_M48T59 is not set
+# CONFIG_RTC_DRV_MSM6242 is not set
+# CONFIG_RTC_DRV_BQ4802 is not set
+# CONFIG_RTC_DRV_RP5C01 is not set
+# CONFIG_RTC_DRV_V3020 is not set
+# CONFIG_RTC_DRV_ZYNQMP is not set
+
+#
+# on-CPU RTC drivers
+#
+# CONFIG_RTC_DRV_PL030 is not set
+# CONFIG_RTC_DRV_PL031 is not set
+# CONFIG_RTC_DRV_SNVS is not set
+
+#
+# HID Sensor RTC drivers
+#
+# CONFIG_RTC_DRV_HID_SENSOR_TIME is not set
+CONFIG_DMADEVICES=y
+# CONFIG_DMADEVICES_DEBUG is not set
+
+#
+# DMA Devices
+#
+CONFIG_DMA_ENGINE=y
+CONFIG_DMA_OF=y
+# CONFIG_AMBA_PL08X is not set
+# CONFIG_FSL_EDMA is not set
+# CONFIG_INTEL_IDMA64 is not set
+CONFIG_PL330_DMA=y
+# CONFIG_DW_DMAC is not set
+
+#
+# DMA Clients
+#
+# CONFIG_ASYNC_TX_DMA is not set
+# CONFIG_DMATEST is not set
+# CONFIG_AUXDISPLAY is not set
+# CONFIG_UIO is not set
+# CONFIG_VFIO is not set
+# CONFIG_VIRT_DRIVERS is not set
+
+#
+# Virtio drivers
+#
+# CONFIG_VIRTIO_MMIO is not set
+
+#
+# Microsoft Hyper-V guest support
+#
+CONFIG_STAGING=y
+# CONFIG_PRISM2_USB is not set
+# CONFIG_COMEDI is not set
+# CONFIG_RTLLIB is not set
+# CONFIG_R8712U is not set
+# CONFIG_R8188EU is not set
+# CONFIG_R8723AU is not set
+# CONFIG_VT6656 is not set
+
+#
+# IIO staging drivers
+#
+
+#
+# Accelerometers
+#
+# CONFIG_ADIS16201 is not set
+# CONFIG_ADIS16203 is not set
+# CONFIG_ADIS16204 is not set
+# CONFIG_ADIS16209 is not set
+# CONFIG_ADIS16220 is not set
+# CONFIG_ADIS16240 is not set
+# CONFIG_LIS3L02DQ is not set
+# CONFIG_SCA3000 is not set
+
+#
+# Analog to digital converters
+#
+# CONFIG_AD7606 is not set
+# CONFIG_AD7780 is not set
+# CONFIG_AD7816 is not set
+# CONFIG_AD7192 is not set
+# CONFIG_AD7280 is not set
+
+#
+# Analog digital bi-direction converters
+#
+# CONFIG_ADT7316 is not set
+
+#
+# Capacitance to digital converters
+#
+# CONFIG_AD7150 is not set
+# CONFIG_AD7152 is not set
+# CONFIG_AD7746 is not set
+
+#
+# Direct Digital Synthesis
+#
+# CONFIG_AD9832 is not set
+# CONFIG_AD9834 is not set
+
+#
+# Digital gyroscope sensors
+#
+# CONFIG_ADIS16060 is not set
+
+#
+# Network Analyzer, Impedance Converters
+#
+# CONFIG_AD5933 is not set
+# CONFIG_INV_MPU_IIO is not set
+
+#
+# Light sensors
+#
+CONFIG_SENSORS_ISL29018=y
+# CONFIG_SENSORS_ISL29028 is not set
+CONFIG_TSL2583=y
+# CONFIG_TSL2x7x is not set
+
+#
+# Magnetometer sensors
+#
+# CONFIG_SENSORS_HMC5843_I2C is not set
+# CONFIG_SENSORS_HMC5843_SPI is not set
+
+#
+# Active energy metering IC
+#
+# CONFIG_ADE7753 is not set
+# CONFIG_ADE7754 is not set
+# CONFIG_ADE7758 is not set
+# CONFIG_ADE7759 is not set
+# CONFIG_ADE7854 is not set
+
+#
+# Resolver to digital converters
+#
+# CONFIG_AD2S90 is not set
+# CONFIG_AD2S1200 is not set
+# CONFIG_AD2S1210 is not set
+
+#
+# Triggers - standalone
+#
+# CONFIG_IIO_PERIODIC_RTC_TRIGGER is not set
+# CONFIG_IIO_SIMPLE_DUMMY is not set
+
+#
+# Speakup console speech
+#
+# CONFIG_SPEAKUP is not set
+# CONFIG_TOUCHSCREEN_SYNAPTICS_I2C_RMI4 is not set
+# CONFIG_STAGING_MEDIA is not set
+
+#
+# Android
+#
+# CONFIG_ASHMEM is not set
+# CONFIG_ANDROID_TIMED_OUTPUT is not set
+# CONFIG_ANDROID_LOW_MEMORY_KILLER is not set
+# CONFIG_SYNC is not set
+# CONFIG_ION is not set
+CONFIG_FIQ_DEBUGGER=y
+CONFIG_FIQ_DEBUGGER_NO_SLEEP=y
+# CONFIG_FIQ_DEBUGGER_WAKEUP_IRQ_ALWAYS_ON is not set
+CONFIG_FIQ_DEBUGGER_CONSOLE=y
+CONFIG_FIQ_DEBUGGER_CONSOLE_DEFAULT_ENABLE=y
+# CONFIG_FIQ_DEBUGGER_TRUST_ZONE is not set
+# CONFIG_FIQ_DEBUGGER_UART_OVERLAY is not set
+# CONFIG_FIQ_WATCHDOG is not set
+# CONFIG_RK_CONSOLE_THREAD is not set
+# CONFIG_STAGING_BOARD is not set
+# CONFIG_WIMAX_GDM72XX is not set
+# CONFIG_LTE_GDM724X is not set
+# CONFIG_LUSTRE_FS is not set
+# CONFIG_DGAP is not set
+# CONFIG_GS_FPGABOOT is not set
+# CONFIG_COMMON_CLK_XLNX_CLKWZRD is not set
+# CONFIG_FB_TFT is not set
+# CONFIG_FSL_MC_BUS is not set
+# CONFIG_WILC1000_DRIVER is not set
+# CONFIG_MOST is not set
+# CONFIG_POWERVR_ROGUE_N is not set
+# CONFIG_GOLDFISH is not set
+# CONFIG_CHROME_PLATFORMS is not set
+CONFIG_CLKDEV_LOOKUP=y
+CONFIG_HAVE_CLK_PREPARE=y
+CONFIG_COMMON_CLK=y
+
+#
+# Common Clock Framework
+#
+# CONFIG_COMMON_CLK_VERSATILE is not set
+CONFIG_COMMON_CLK_RK808=y
+# CONFIG_COMMON_CLK_SI5351 is not set
+# CONFIG_COMMON_CLK_SI514 is not set
+# CONFIG_COMMON_CLK_SI570 is not set
+# CONFIG_COMMON_CLK_CDCE925 is not set
+# CONFIG_CLK_QORIQ is not set
+# CONFIG_COMMON_CLK_XGENE is not set
+# CONFIG_COMMON_CLK_PWM is not set
+# CONFIG_COMMON_CLK_PXA is not set
+# CONFIG_COMMON_CLK_CDCE706 is not set
+
+#
+# Hardware Spinlock drivers
+#
+# CONFIG_HWSPINLOCK_ROCKCHIP is not set
+
+#
+# Clock Source drivers
+#
+CONFIG_CLKSRC_OF=y
+CONFIG_CLKSRC_PROBE=y
+CONFIG_ROCKCHIP_TIMER=y
+CONFIG_ARM_ARCH_TIMER=y
+CONFIG_ARM_ARCH_TIMER_EVTSTREAM=y
+# CONFIG_ARM_ARCH_TIMER_VCT_ACCESS is not set
+# CONFIG_ARM_TIMER_SP804 is not set
+# CONFIG_ATMEL_PIT is not set
+# CONFIG_SH_TIMER_CMT is not set
+# CONFIG_SH_TIMER_MTU2 is not set
+# CONFIG_SH_TIMER_TMU is not set
+# CONFIG_EM_TIMER_STI is not set
+# CONFIG_MAILBOX is not set
+CONFIG_IOMMU_API=y
+CONFIG_IOMMU_SUPPORT=y
+
+#
+# Generic IOMMU Pagetable Support
+#
+# CONFIG_IOMMU_IO_PGTABLE_LPAE is not set
+CONFIG_IOMMU_IOVA=y
+CONFIG_OF_IOMMU=y
+CONFIG_IOMMU_DMA=y
+CONFIG_ROCKCHIP_IOMMU=y
+# CONFIG_RK_IOMMU is not set
+# CONFIG_ARM_SMMU is not set
+
+#
+# Remoteproc drivers
+#
+# CONFIG_STE_MODEM_RPROC is not set
+
+#
+# Rpmsg drivers
+#
+
+#
+# SOC (System On Chip) specific Drivers
+#
+
+#
+# Rockchip CPU selection
+#
+CONFIG_CPU_PX30=y
+# CONFIG_CPU_RK1808 is not set
+# CONFIG_CPU_RK3308 is not set
+CONFIG_CPU_RK3328=y
+# CONFIG_CPU_RK3366 is not set
+CONFIG_CPU_RK3368=y
+CONFIG_CPU_RK3399=y
+CONFIG_ANDROID_VERSION=0x07010000
+CONFIG_ROCKCHIP_CPUINFO=y
+# CONFIG_ROCKCHIP_DEVICEINFO is not set
+CONFIG_ROCKCHIP_IPA=y
+CONFIG_ROCKCHIP_OPP=y
+# CONFIG_ROCKCHIP_PM_TEST is not set
+CONFIG_ROCKCHIP_GRF=y
+CONFIG_ROCKCHIP_PM_DOMAINS=y
+CONFIG_ROCKCHIP_PVTM=y
+CONFIG_ROCKCHIP_SUSPEND_MODE=y
+CONFIG_ROCKCHIP_SYSTEM_MONITOR=y
+# CONFIG_ROCKCHIP_VENDOR_STORAGE_UPDATE_LOADER is not set
+# CONFIG_SUNXI_SRAM is not set
+# CONFIG_SOC_TI is not set
+CONFIG_PM_DEVFREQ=y
+
+#
+# DEVFREQ Governors
+#
+CONFIG_DEVFREQ_GOV_SIMPLE_ONDEMAND=y
+CONFIG_DEVFREQ_GOV_PERFORMANCE=y
+CONFIG_DEVFREQ_GOV_POWERSAVE=y
+CONFIG_DEVFREQ_GOV_USERSPACE=y
+
+#
+# DEVFREQ Drivers
+#
+# CONFIG_ARM_ROCKCHIP_BUS_DEVFREQ is not set
+CONFIG_ARM_ROCKCHIP_DMC_DEVFREQ=y
+CONFIG_PM_DEVFREQ_EVENT=y
+CONFIG_DEVFREQ_EVENT_ROCKCHIP_DFI=y
+# CONFIG_DEVFREQ_EVENT_ROCKCHIP_NOCP is not set
+CONFIG_EXTCON=y
+
+#
+# Extcon Device Drivers
+#
+# CONFIG_EXTCON_ADC_JACK is not set
+# CONFIG_EXTCON_GPIO is not set
+# CONFIG_EXTCON_RT8973A is not set
+# CONFIG_EXTCON_SM5502 is not set
+# CONFIG_EXTCON_USB_GPIO is not set
+CONFIG_MEMORY=y
+# CONFIG_ARM_PL172_MPMC is not set
+CONFIG_IIO=y
+CONFIG_IIO_BUFFER=y
+# CONFIG_IIO_BUFFER_CB is not set
+CONFIG_IIO_KFIFO_BUF=y
+CONFIG_IIO_TRIGGER=y
+CONFIG_IIO_CONSUMERS_PER_TRIGGER=2
+
+#
+# Accelerometers
+#
+# CONFIG_BMA180 is not set
+# CONFIG_BMC150_ACCEL is not set
+# CONFIG_IIO_ST_ACCEL_3AXIS is not set
+# CONFIG_KXSD9 is not set
+# CONFIG_KXCJK1013 is not set
+# CONFIG_MMA8452 is not set
+# CONFIG_MMA9551 is not set
+# CONFIG_MMA9553 is not set
+# CONFIG_MXC4005 is not set
+# CONFIG_STK8312 is not set
+# CONFIG_STK8BA50 is not set
+
+#
+# Analog to digital converters
+#
+# CONFIG_AD7266 is not set
+# CONFIG_AD7291 is not set
+# CONFIG_AD7298 is not set
+# CONFIG_AD7476 is not set
+# CONFIG_AD7791 is not set
+# CONFIG_AD7793 is not set
+# CONFIG_AD7887 is not set
+# CONFIG_AD7923 is not set
+# CONFIG_AD799X is not set
+# CONFIG_CC10001_ADC is not set
+# CONFIG_GPIO_MUXADC is not set
+# CONFIG_HI8435 is not set
+# CONFIG_MAX1027 is not set
+# CONFIG_MAX1363 is not set
+# CONFIG_MCP320X is not set
+# CONFIG_MCP3422 is not set
+# CONFIG_NAU7802 is not set
+CONFIG_ROCKCHIP_SARADC=y
+# CONFIG_TI_ADC081C is not set
+# CONFIG_TI_ADC128S052 is not set
+# CONFIG_VF610_ADC is not set
+
+#
+# Amplifiers
+#
+# CONFIG_AD8366 is not set
+
+#
+# Chemical Sensors
+#
+# CONFIG_VZ89X is not set
+
+#
+# Hid Sensor IIO Common
+#
+
+#
+# SSP Sensor Common
+#
+# CONFIG_IIO_SSP_SENSORHUB is not set
+
+#
+# Digital to analog converters
+#
+# CONFIG_AD5064 is not set
+# CONFIG_AD5360 is not set
+# CONFIG_AD5380 is not set
+# CONFIG_AD5421 is not set
+# CONFIG_AD5446 is not set
+# CONFIG_AD5449 is not set
+# CONFIG_AD5504 is not set
+# CONFIG_AD5624R_SPI is not set
+# CONFIG_AD5686 is not set
+# CONFIG_AD5755 is not set
+# CONFIG_AD5764 is not set
+# CONFIG_AD5791 is not set
+# CONFIG_AD7303 is not set
+# CONFIG_M62332 is not set
+# CONFIG_MAX517 is not set
+# CONFIG_MAX5821 is not set
+# CONFIG_MCP4725 is not set
+# CONFIG_MCP4922 is not set
+
+#
+# Frequency Synthesizers DDS/PLL
+#
+
+#
+# Clock Generator/Distribution
+#
+# CONFIG_AD9523 is not set
+
+#
+# Phase-Locked Loop (PLL) frequency synthesizers
+#
+# CONFIG_ADF4350 is not set
+
+#
+# Digital gyroscope sensors
+#
+# CONFIG_ADIS16080 is not set
+# CONFIG_ADIS16130 is not set
+# CONFIG_ADIS16136 is not set
+# CONFIG_ADIS16260 is not set
+# CONFIG_ADXRS450 is not set
+# CONFIG_BMG160 is not set
+# CONFIG_IIO_ST_GYRO_3AXIS is not set
+# CONFIG_ITG3200 is not set
+
+#
+# Humidity sensors
+#
+# CONFIG_DHT11 is not set
+# CONFIG_HDC100X is not set
+# CONFIG_HTU21 is not set
+# CONFIG_SI7005 is not set
+# CONFIG_SI7020 is not set
+
+#
+# Inertial measurement units
+#
+# CONFIG_ADIS16400 is not set
+# CONFIG_ADIS16480 is not set
+# CONFIG_KMX61 is not set
+# CONFIG_INV_MPU6050_IIO is not set
+
+#
+# Light sensors
+#
+# CONFIG_ADJD_S311 is not set
+# CONFIG_AL3320A is not set
+# CONFIG_APDS9300 is not set
+# CONFIG_APDS9960 is not set
+# CONFIG_BH1750 is not set
+# CONFIG_CM32181 is not set
+# CONFIG_CM3232 is not set
+# CONFIG_CM3323 is not set
+# CONFIG_CM36651 is not set
+# CONFIG_GP2AP020A00F is not set
+# CONFIG_ISL29125 is not set
+# CONFIG_JSA1212 is not set
+# CONFIG_RPR0521 is not set
+# CONFIG_LTR501 is not set
+# CONFIG_OPT3001 is not set
+# CONFIG_PA12203001 is not set
+# CONFIG_STK3310 is not set
+# CONFIG_TCS3414 is not set
+# CONFIG_TCS3472 is not set
+CONFIG_SENSORS_TSL2563=y
+# CONFIG_TSL4531 is not set
+# CONFIG_US5182D is not set
+# CONFIG_VCNL4000 is not set
+# CONFIG_VL6180 is not set
+
+#
+# Magnetometer sensors
+#
+# CONFIG_AK8975 is not set
+# CONFIG_AK09911 is not set
+# CONFIG_BMC150_MAGN is not set
+# CONFIG_MAG3110 is not set
+# CONFIG_MMC35240 is not set
+# CONFIG_IIO_ST_MAGN_3AXIS is not set
+
+#
+# Inclinometer sensors
+#
+
+#
+# Triggers - standalone
+#
+# CONFIG_IIO_INTERRUPT_TRIGGER is not set
+CONFIG_IIO_SYSFS_TRIGGER=y
+
+#
+# Digital potentiometers
+#
+# CONFIG_MCP4531 is not set
+
+#
+# Pressure sensors
+#
+# CONFIG_BMP280 is not set
+# CONFIG_MPL115 is not set
+# CONFIG_MPL3115 is not set
+# CONFIG_MS5611 is not set
+# CONFIG_MS5637 is not set
+# CONFIG_IIO_ST_PRESS is not set
+# CONFIG_T5403 is not set
+
+#
+# Lightning sensors
+#
+# CONFIG_AS3935 is not set
+
+#
+# Proximity sensors
+#
+# CONFIG_LIDAR_LITE_V2 is not set
+# CONFIG_SRF04 is not set
+# CONFIG_SX9500 is not set
+
+#
+# Temperature sensors
+#
+# CONFIG_MLX90614 is not set
+# CONFIG_TMP006 is not set
+# CONFIG_TSYS01 is not set
+# CONFIG_TSYS02D is not set
+CONFIG_PWM=y
+CONFIG_PWM_SYSFS=y
+# CONFIG_PWM_FSL_FTM is not set
+# CONFIG_PWM_GPIO is not set
+# CONFIG_PWM_PCA9685 is not set
+CONFIG_PWM_ROCKCHIP=y
+# CONFIG_PWM_ROCKCHIP_I2S is not set
+CONFIG_IRQCHIP=y
+CONFIG_ARM_GIC=y
+CONFIG_ARM_GIC_V3=y
+CONFIG_PARTITION_PERCPU=y
+# CONFIG_IPACK_BUS is not set
+CONFIG_ARCH_HAS_RESET_CONTROLLER=y
+CONFIG_RESET_CONTROLLER=y
+# CONFIG_FMC is not set
+
+#
+# PHY Subsystem
+#
+CONFIG_GENERIC_PHY=y
+# CONFIG_PHY_PXA_28NM_HSIC is not set
+# CONFIG_PHY_PXA_28NM_USB2 is not set
+# CONFIG_BCM_KONA_USB2_PHY is not set
+# CONFIG_PHY_SAMSUNG_USB2 is not set
+# CONFIG_PHY_XGENE is not set
+# CONFIG_PHY_ROCKCHIP_USB is not set
+# CONFIG_PHY_ROCKCHIP_INNO_COMBPHY is not set
+CONFIG_PHY_ROCKCHIP_INNO_USB2=y
+# CONFIG_PHY_ROCKCHIP_INNO_USB3 is not set
+# CONFIG_PHY_ROCKCHIP_EMMC is not set
+# CONFIG_PHY_ROCKCHIP_DP is not set
+CONFIG_PHY_ROCKCHIP_MIPI_RX=y
+# CONFIG_PHY_ROCKCHIP_INNO_MIPI_DPHY is not set
+# CONFIG_PHY_ROCKCHIP_INNO_HDMI_PHY is not set
+# CONFIG_PHY_ROCKCHIP_INNO_VIDEO_PHY is not set
+CONFIG_PHY_ROCKCHIP_INNO_VIDEO_COMBO_PHY=y
+# CONFIG_PHY_ROCKCHIP_TYPEC is not set
+# CONFIG_PHY_ROCKCHIP_PCIE is not set
+# CONFIG_POWERCAP is not set
+# CONFIG_MCB is not set
+
+#
+# Performance monitor support
+#
+CONFIG_ARM_PMU=y
+CONFIG_RAS=y
+
+#
+# Android
+#
+CONFIG_ANDROID=y
+# CONFIG_ANDROID_BINDER_IPC is not set
+# CONFIG_LIBNVDIMM is not set
+CONFIG_NVMEM=y
+# CONFIG_ROCKCHIP_EFUSE is not set
+CONFIG_ROCKCHIP_OTP=y
+# CONFIG_STM is not set
+# CONFIG_INTEL_TH is not set
+
+#
+# FPGA Configuration Support
+#
+# CONFIG_FPGA is not set
+# CONFIG_TEE is not set
+# CONFIG_RK_FLASH is not set
+# CONFIG_RK_NAND is not set
+
+#
+# Headset device support
+#
+# CONFIG_RK_HEADSET is not set
+
+#
+# Firmware Drivers
+#
+CONFIG_ARM_PSCI_FW=y
+# CONFIG_FIRMWARE_MEMMAP is not set
+CONFIG_HAVE_ARM_SMCCC=y
+CONFIG_ROCKCHIP_SIP=y
+
+#
+# File systems
+#
+CONFIG_DCACHE_WORD_ACCESS=y
+# CONFIG_EXT2_FS is not set
+# CONFIG_EXT3_FS is not set
+CONFIG_EXT4_FS=y
+CONFIG_EXT4_USE_FOR_EXT2=y
+CONFIG_EXT4_FS_POSIX_ACL=y
+CONFIG_EXT4_FS_SECURITY=y
+# CONFIG_EXT4_ENCRYPTION is not set
+# CONFIG_EXT4_DEBUG is not set
+CONFIG_JBD2=y
+# CONFIG_JBD2_DEBUG is not set
+CONFIG_FS_MBCACHE=y
+# CONFIG_REISERFS_FS is not set
+# CONFIG_JFS_FS is not set
+CONFIG_XFS_FS=y
+# CONFIG_XFS_QUOTA is not set
+# CONFIG_XFS_POSIX_ACL is not set
+# CONFIG_XFS_RT is not set
+# CONFIG_XFS_WARN is not set
+# CONFIG_XFS_DEBUG is not set
+# CONFIG_GFS2_FS is not set
+# CONFIG_OCFS2_FS is not set
+# CONFIG_BTRFS_FS is not set
+# CONFIG_NILFS2_FS is not set
+# CONFIG_F2FS_FS is not set
+# CONFIG_FS_DAX is not set
+CONFIG_FS_POSIX_ACL=y
+CONFIG_EXPORTFS=y
+CONFIG_FILE_LOCKING=y
+# CONFIG_FS_ENCRYPTION is not set
+CONFIG_FSNOTIFY=y
+# CONFIG_DNOTIFY is not set
+CONFIG_INOTIFY_USER=y
+# CONFIG_FANOTIFY is not set
+# CONFIG_QUOTA is not set
+# CONFIG_QUOTACTL is not set
+# CONFIG_AUTOFS4_FS is not set
+CONFIG_FUSE_FS=y
+# CONFIG_CUSE is not set
+# CONFIG_OVERLAY_FS is not set
+
+#
+# Caches
+#
+# CONFIG_FSCACHE is not set
+
+#
+# CD-ROM/DVD Filesystems
+#
+CONFIG_ISO9660_FS=y
+CONFIG_JOLIET=y
+CONFIG_ZISOFS=y
+# CONFIG_UDF_FS is not set
+
+#
+# DOS/FAT/NT Filesystems
+#
+CONFIG_FAT_FS=y
+# CONFIG_MSDOS_FS is not set
+CONFIG_VFAT_FS=y
+CONFIG_FAT_DEFAULT_CODEPAGE=936
+CONFIG_FAT_DEFAULT_IOCHARSET="utf8"
+# CONFIG_NTFS_FS is not set
+
+#
+# Pseudo filesystems
+#
+CONFIG_PROC_FS=y
+# CONFIG_PROC_KCORE is not set
+CONFIG_PROC_SYSCTL=y
+CONFIG_PROC_PAGE_MONITOR=y
+# CONFIG_PROC_CHILDREN is not set
+CONFIG_PROC_UID=y
+CONFIG_KERNFS=y
+CONFIG_SYSFS=y
+CONFIG_TMPFS=y
+CONFIG_TMPFS_POSIX_ACL=y
+CONFIG_TMPFS_XATTR=y
+# CONFIG_HUGETLBFS is not set
+# CONFIG_HUGETLB_PAGE is not set
+CONFIG_CONFIGFS_FS=y
+CONFIG_MISC_FILESYSTEMS=y
+# CONFIG_ADFS_FS is not set
+# CONFIG_AFFS_FS is not set
+# CONFIG_ECRYPT_FS is not set
+# CONFIG_SDCARD_FS is not set
+# CONFIG_HFS_FS is not set
+# CONFIG_HFSPLUS_FS is not set
+# CONFIG_BEFS_FS is not set
+# CONFIG_BFS_FS is not set
+# CONFIG_EFS_FS is not set
+# CONFIG_LOGFS is not set
+# CONFIG_CRAMFS is not set
+CONFIG_SQUASHFS=y
+CONFIG_SQUASHFS_DECOMP_SINGLE=y
+# CONFIG_SQUASHFS_DECOMP_MULTI is not set
+# CONFIG_SQUASHFS_DECOMP_MULTI_PERCPU is not set
+# CONFIG_SQUASHFS_XATTR is not set
+CONFIG_SQUASHFS_ZLIB=y
+# CONFIG_SQUASHFS_LZ4 is not set
+# CONFIG_SQUASHFS_LZO is not set
+# CONFIG_SQUASHFS_XZ is not set
+# CONFIG_SQUASHFS_ZSTD is not set
+# CONFIG_SQUASHFS_4K_DEVBLK_SIZE is not set
+# CONFIG_SQUASHFS_EMBEDDED is not set
+CONFIG_SQUASHFS_FRAGMENT_CACHE_SIZE=3
+# CONFIG_VXFS_FS is not set
+# CONFIG_MINIX_FS is not set
+# CONFIG_OMFS_FS is not set
+# CONFIG_HPFS_FS is not set
+# CONFIG_QNX4FS_FS is not set
+# CONFIG_QNX6FS_FS is not set
+# CONFIG_ROMFS_FS is not set
+# CONFIG_PSTORE is not set
+# CONFIG_SYSV_FS is not set
+# CONFIG_UFS_FS is not set
+CONFIG_NETWORK_FILESYSTEMS=y
+CONFIG_NFS_FS=y
+CONFIG_NFS_V2=y
+CONFIG_NFS_V3=y
+CONFIG_NFS_V3_ACL=y
+CONFIG_NFS_V4=y
+CONFIG_NFS_SWAP=y
+# CONFIG_NFS_V4_1 is not set
+# CONFIG_NFS_USE_LEGACY_DNS is not set
+CONFIG_NFS_USE_KERNEL_DNS=y
+# CONFIG_NFSD is not set
+CONFIG_GRACE_PERIOD=y
+CONFIG_LOCKD=y
+CONFIG_LOCKD_V4=y
+CONFIG_NFS_ACL_SUPPORT=y
+CONFIG_NFS_COMMON=y
+CONFIG_SUNRPC=y
+CONFIG_SUNRPC_GSS=y
+CONFIG_SUNRPC_SWAP=y
+# CONFIG_SUNRPC_DEBUG is not set
+# CONFIG_CEPH_FS is not set
+# CONFIG_CIFS is not set
+# CONFIG_NCP_FS is not set
+# CONFIG_CODA_FS is not set
+# CONFIG_AFS_FS is not set
+CONFIG_NLS=y
+CONFIG_NLS_DEFAULT="utf8"
+CONFIG_NLS_CODEPAGE_437=y
+# CONFIG_NLS_CODEPAGE_737 is not set
+# CONFIG_NLS_CODEPAGE_775 is not set
+# CONFIG_NLS_CODEPAGE_850 is not set
+# CONFIG_NLS_CODEPAGE_852 is not set
+# CONFIG_NLS_CODEPAGE_855 is not set
+# CONFIG_NLS_CODEPAGE_857 is not set
+# CONFIG_NLS_CODEPAGE_860 is not set
+# CONFIG_NLS_CODEPAGE_861 is not set
+# CONFIG_NLS_CODEPAGE_862 is not set
+# CONFIG_NLS_CODEPAGE_863 is not set
+# CONFIG_NLS_CODEPAGE_864 is not set
+# CONFIG_NLS_CODEPAGE_865 is not set
+# CONFIG_NLS_CODEPAGE_866 is not set
+# CONFIG_NLS_CODEPAGE_869 is not set
+CONFIG_NLS_CODEPAGE_936=y
+# CONFIG_NLS_CODEPAGE_950 is not set
+# CONFIG_NLS_CODEPAGE_932 is not set
+# CONFIG_NLS_CODEPAGE_949 is not set
+# CONFIG_NLS_CODEPAGE_874 is not set
+# CONFIG_NLS_ISO8859_8 is not set
+# CONFIG_NLS_CODEPAGE_1250 is not set
+# CONFIG_NLS_CODEPAGE_1251 is not set
+CONFIG_NLS_ASCII=y
+CONFIG_NLS_ISO8859_1=y
+# CONFIG_NLS_ISO8859_2 is not set
+# CONFIG_NLS_ISO8859_3 is not set
+# CONFIG_NLS_ISO8859_4 is not set
+# CONFIG_NLS_ISO8859_5 is not set
+# CONFIG_NLS_ISO8859_6 is not set
+# CONFIG_NLS_ISO8859_7 is not set
+# CONFIG_NLS_ISO8859_9 is not set
+# CONFIG_NLS_ISO8859_13 is not set
+# CONFIG_NLS_ISO8859_14 is not set
+# CONFIG_NLS_ISO8859_15 is not set
+# CONFIG_NLS_KOI8_R is not set
+# CONFIG_NLS_KOI8_U is not set
+# CONFIG_NLS_MAC_ROMAN is not set
+# CONFIG_NLS_MAC_CELTIC is not set
+# CONFIG_NLS_MAC_CENTEURO is not set
+# CONFIG_NLS_MAC_CROATIAN is not set
+# CONFIG_NLS_MAC_CYRILLIC is not set
+# CONFIG_NLS_MAC_GAELIC is not set
+# CONFIG_NLS_MAC_GREEK is not set
+# CONFIG_NLS_MAC_ICELAND is not set
+# CONFIG_NLS_MAC_INUIT is not set
+# CONFIG_NLS_MAC_ROMANIAN is not set
+# CONFIG_NLS_MAC_TURKISH is not set
+CONFIG_NLS_UTF8=y
+# CONFIG_DLM is not set
+# CONFIG_VIRTUALIZATION is not set
+
+#
+# Kernel hacking
+#
+
+#
+# printk and dmesg options
+#
+CONFIG_PRINTK_TIME=y
+# CONFIG_PRINTK_PROCESS is not set
+CONFIG_MESSAGE_LOGLEVEL_DEFAULT=4
+# CONFIG_BOOT_PRINTK_DELAY is not set
+CONFIG_DYNAMIC_DEBUG=y
+
+#
+# Compile-time checks and compiler options
+#
+CONFIG_DEBUG_INFO=y
+# CONFIG_DEBUG_INFO_REDUCED is not set
+# CONFIG_DEBUG_INFO_SPLIT is not set
+# CONFIG_DEBUG_INFO_DWARF4 is not set
+# CONFIG_GDB_SCRIPTS is not set
+CONFIG_ENABLE_WARN_DEPRECATED=y
+CONFIG_ENABLE_MUST_CHECK=y
+CONFIG_FRAME_WARN=2048
+# CONFIG_STRIP_ASM_SYMS is not set
+# CONFIG_READABLE_ASM is not set
+# CONFIG_UNUSED_SYMBOLS is not set
+# CONFIG_PAGE_OWNER is not set
+CONFIG_DEBUG_FS=y
+# CONFIG_HEADERS_CHECK is not set
+# CONFIG_DEBUG_SECTION_MISMATCH is not set
+CONFIG_SECTION_MISMATCH_WARN_ONLY=y
+CONFIG_ARCH_WANT_FRAME_POINTERS=y
+CONFIG_FRAME_POINTER=y
+# CONFIG_DEBUG_FORCE_WEAK_PER_CPU is not set
+CONFIG_MAGIC_SYSRQ=y
+CONFIG_MAGIC_SYSRQ_DEFAULT_ENABLE=0
+CONFIG_DEBUG_KERNEL=y
+
+#
+# Memory Debugging
+#
+# CONFIG_PAGE_EXTENSION is not set
+# CONFIG_DEBUG_PAGEALLOC is not set
+# CONFIG_DEBUG_OBJECTS is not set
+# CONFIG_SLUB_DEBUG_ON is not set
+# CONFIG_SLUB_STATS is not set
+CONFIG_HAVE_DEBUG_KMEMLEAK=y
+# CONFIG_DEBUG_KMEMLEAK is not set
+# CONFIG_DEBUG_STACK_USAGE is not set
+# CONFIG_DEBUG_VM is not set
+# CONFIG_DEBUG_MEMORY_INIT is not set
+# CONFIG_DEBUG_PER_CPU_MAPS is not set
+CONFIG_HAVE_ARCH_KASAN=y
+# CONFIG_KASAN is not set
+# CONFIG_DEBUG_SHIRQ is not set
+
+#
+# Debug Lockups and Hangs
+#
+CONFIG_LOCKUP_DETECTOR=y
+CONFIG_HARDLOCKUP_DETECTOR_OTHER_CPU=y
+CONFIG_HARDLOCKUP_DETECTOR=y
+# CONFIG_BOOTPARAM_HARDLOCKUP_PANIC is not set
+CONFIG_BOOTPARAM_HARDLOCKUP_PANIC_VALUE=0
+CONFIG_BOOTPARAM_SOFTLOCKUP_PANIC=y
+CONFIG_BOOTPARAM_SOFTLOCKUP_PANIC_VALUE=1
+CONFIG_DETECT_HUNG_TASK=y
+CONFIG_DEFAULT_HUNG_TASK_TIMEOUT=120
+CONFIG_BOOTPARAM_HUNG_TASK_PANIC=y
+CONFIG_BOOTPARAM_HUNG_TASK_PANIC_VALUE=1
+# CONFIG_PANIC_ON_OOPS is not set
+CONFIG_PANIC_ON_OOPS_VALUE=0
+CONFIG_PANIC_TIMEOUT=0
+CONFIG_SCHED_DEBUG=y
+CONFIG_SCHED_INFO=y
+# CONFIG_PANIC_ON_RT_THROTTLING is not set
+CONFIG_SCHEDSTATS=y
+# CONFIG_SCHED_STACK_END_CHECK is not set
+# CONFIG_DEBUG_TIMEKEEPING is not set
+CONFIG_TIMER_STATS=y
+
+#
+# Lock Debugging (spinlocks, mutexes, etc...)
+#
+# CONFIG_DEBUG_RT_MUTEXES is not set
+CONFIG_DEBUG_SPINLOCK=y
+# CONFIG_DEBUG_MUTEXES is not set
+# CONFIG_DEBUG_WW_MUTEX_SLOWPATH is not set
+# CONFIG_DEBUG_LOCK_ALLOC is not set
+# CONFIG_PROVE_LOCKING is not set
+# CONFIG_LOCK_STAT is not set
+# CONFIG_DEBUG_ATOMIC_SLEEP is not set
+# CONFIG_DEBUG_LOCKING_API_SELFTESTS is not set
+# CONFIG_LOCK_TORTURE_TEST is not set
+CONFIG_STACKTRACE=y
+# CONFIG_DEBUG_KOBJECT is not set
+CONFIG_HAVE_DEBUG_BUGVERBOSE=y
+CONFIG_DEBUG_BUGVERBOSE=y
+# CONFIG_DEBUG_LIST is not set
+# CONFIG_DEBUG_PI_LIST is not set
+# CONFIG_DEBUG_SG is not set
+# CONFIG_DEBUG_NOTIFIERS is not set
+CONFIG_DEBUG_CREDENTIALS=y
+
+#
+# RCU Debugging
+#
+# CONFIG_PROVE_RCU is not set
+# CONFIG_SPARSE_RCU_POINTER is not set
+# CONFIG_TORTURE_TEST is not set
+# CONFIG_RCU_TORTURE_TEST is not set
+CONFIG_RCU_CPU_STALL_TIMEOUT=60
+# CONFIG_RCU_TRACE is not set
+# CONFIG_RCU_EQS_DEBUG is not set
+# CONFIG_DEBUG_BLOCK_EXT_DEVT is not set
+# CONFIG_NOTIFIER_ERROR_INJECTION is not set
+# CONFIG_FAULT_INJECTION is not set
+CONFIG_NOP_TRACER=y
+CONFIG_HAVE_FUNCTION_TRACER=y
+CONFIG_HAVE_FUNCTION_GRAPH_TRACER=y
+CONFIG_HAVE_DYNAMIC_FTRACE=y
+CONFIG_HAVE_FTRACE_MCOUNT_RECORD=y
+CONFIG_HAVE_SYSCALL_TRACEPOINTS=y
+CONFIG_HAVE_C_RECORDMCOUNT=y
+CONFIG_TRACE_CLOCK=y
+CONFIG_RING_BUFFER=y
+CONFIG_EVENT_TRACING=y
+CONFIG_GPU_TRACEPOINTS=y
+CONFIG_CONTEXT_SWITCH_TRACER=y
+CONFIG_TRACING=y
+CONFIG_GENERIC_TRACER=y
+CONFIG_TRACING_SUPPORT=y
+CONFIG_FTRACE=y
+CONFIG_FUNCTION_TRACER=y
+CONFIG_FUNCTION_GRAPH_TRACER=y
+# CONFIG_PREEMPTIRQ_EVENTS is not set
+# CONFIG_IRQSOFF_TRACER is not set
+# CONFIG_SCHED_TRACER is not set
+# CONFIG_FTRACE_SYSCALLS is not set
+# CONFIG_TRACER_SNAPSHOT is not set
+CONFIG_BRANCH_PROFILE_NONE=y
+# CONFIG_PROFILE_ANNOTATED_BRANCHES is not set
+# CONFIG_PROFILE_ALL_BRANCHES is not set
+# CONFIG_STACK_TRACER is not set
+CONFIG_BLK_DEV_IO_TRACE=y
+# CONFIG_PROBE_EVENTS is not set
+CONFIG_DYNAMIC_FTRACE=y
+# CONFIG_FUNCTION_PROFILER is not set
+CONFIG_FTRACE_MCOUNT_RECORD=y
+# CONFIG_FTRACE_STARTUP_TEST is not set
+# CONFIG_TRACEPOINT_BENCHMARK is not set
+# CONFIG_RING_BUFFER_BENCHMARK is not set
+# CONFIG_RING_BUFFER_STARTUP_TEST is not set
+# CONFIG_TRACE_ENUM_MAP_FILE is not set
+CONFIG_TRACING_EVENTS_GPIO=y
+
+#
+# Runtime Testing
+#
+CONFIG_LKDTM=y
+# CONFIG_TEST_LIST_SORT is not set
+# CONFIG_BACKTRACE_SELF_TEST is not set
+# CONFIG_RBTREE_TEST is not set
+# CONFIG_INTERVAL_TREE_TEST is not set
+# CONFIG_PERCPU_TEST is not set
+# CONFIG_ATOMIC64_SELFTEST is not set
+# CONFIG_TEST_HEXDUMP is not set
+# CONFIG_TEST_STRING_HELPERS is not set
+# CONFIG_TEST_KSTRTOX is not set
+# CONFIG_TEST_PRINTF is not set
+# CONFIG_TEST_RHASHTABLE is not set
+# CONFIG_DMA_API_DEBUG is not set
+# CONFIG_TEST_LKM is not set
+# CONFIG_TEST_USER_COPY is not set
+# CONFIG_TEST_BPF is not set
+# CONFIG_TEST_FIRMWARE is not set
+# CONFIG_TEST_UDELAY is not set
+# CONFIG_MEMTEST is not set
+# CONFIG_TEST_STATIC_KEYS is not set
+# CONFIG_BUG_ON_DATA_CORRUPTION is not set
+# CONFIG_SAMPLES is not set
+CONFIG_HAVE_ARCH_KGDB=y
+# CONFIG_KGDB is not set
+# CONFIG_ARM64_PTDUMP is not set
+CONFIG_STRICT_DEVMEM=y
+# CONFIG_PID_IN_CONTEXTIDR is not set
+# CONFIG_ARM64_RANDOMIZE_TEXT_OFFSET is not set
+CONFIG_DEBUG_SET_MODULE_RONX=y
+CONFIG_DEBUG_RODATA=y
+# CONFIG_DEBUG_ALIGN_RODATA is not set
+# CONFIG_CORESIGHT is not set
+
+#
+# Security options
+#
+CONFIG_KEYS=y
+# CONFIG_PERSISTENT_KEYRINGS is not set
+# CONFIG_BIG_KEYS is not set
+# CONFIG_TRUSTED_KEYS is not set
+# CONFIG_ENCRYPTED_KEYS is not set
+# CONFIG_SECURITY_DMESG_RESTRICT is not set
+# CONFIG_SECURITY_PERF_EVENTS_RESTRICT is not set
+# CONFIG_SECURITY is not set
+CONFIG_SECURITYFS=y
+CONFIG_HAVE_HARDENED_USERCOPY_ALLOCATOR=y
+CONFIG_HAVE_ARCH_HARDENED_USERCOPY=y
+# CONFIG_HARDENED_USERCOPY is not set
+# CONFIG_TEE_SUPPORT is not set
+CONFIG_DEFAULT_SECURITY_DAC=y
+CONFIG_DEFAULT_SECURITY=""
+CONFIG_CRYPTO=y
+
+#
+# Crypto core or helper
+#
+CONFIG_CRYPTO_ALGAPI=y
+CONFIG_CRYPTO_ALGAPI2=y
+CONFIG_CRYPTO_AEAD=y
+CONFIG_CRYPTO_AEAD2=y
+CONFIG_CRYPTO_BLKCIPHER=y
+CONFIG_CRYPTO_BLKCIPHER2=y
+CONFIG_CRYPTO_HASH=y
+CONFIG_CRYPTO_HASH2=y
+CONFIG_CRYPTO_RNG=y
+CONFIG_CRYPTO_RNG2=y
+CONFIG_CRYPTO_RNG_DEFAULT=y
+CONFIG_CRYPTO_PCOMP2=y
+CONFIG_CRYPTO_AKCIPHER2=y
+CONFIG_CRYPTO_AKCIPHER=y
+# CONFIG_CRYPTO_RSA is not set
+CONFIG_CRYPTO_MANAGER=y
+CONFIG_CRYPTO_MANAGER2=y
+# CONFIG_CRYPTO_USER is not set
+CONFIG_CRYPTO_MANAGER_DISABLE_TESTS=y
+CONFIG_CRYPTO_GF128MUL=y
+CONFIG_CRYPTO_NULL=y
+CONFIG_CRYPTO_NULL2=y
+# CONFIG_CRYPTO_PCRYPT is not set
+CONFIG_CRYPTO_WORKQUEUE=y
+CONFIG_CRYPTO_CRYPTD=y
+# CONFIG_CRYPTO_MCRYPTD is not set
+# CONFIG_CRYPTO_AUTHENC is not set
+# CONFIG_CRYPTO_TEST is not set
+CONFIG_CRYPTO_ABLK_HELPER=y
+
+#
+# Authenticated Encryption with Associated Data
+#
+CONFIG_CRYPTO_CCM=y
+CONFIG_CRYPTO_GCM=y
+# CONFIG_CRYPTO_CHACHA20POLY1305 is not set
+CONFIG_CRYPTO_SEQIV=y
+# CONFIG_CRYPTO_ECHAINIV is not set
+
+#
+# Block modes
+#
+# CONFIG_CRYPTO_CBC is not set
+# CONFIG_CRYPTO_HEH is not set
+CONFIG_CRYPTO_CTR=y
+# CONFIG_CRYPTO_CTS is not set
+CONFIG_CRYPTO_ECB=y
+# CONFIG_CRYPTO_LRW is not set
+# CONFIG_CRYPTO_PCBC is not set
+# CONFIG_CRYPTO_XTS is not set
+# CONFIG_CRYPTO_KEYWRAP is not set
+
+#
+# Hash modes
+#
+CONFIG_CRYPTO_CMAC=y
+CONFIG_CRYPTO_HMAC=y
+# CONFIG_CRYPTO_XCBC is not set
+# CONFIG_CRYPTO_VMAC is not set
+
+#
+# Digest
+#
+CONFIG_CRYPTO_CRC32C=y
+# CONFIG_CRYPTO_CRC32 is not set
+CONFIG_CRYPTO_CRCT10DIF=y
+CONFIG_CRYPTO_GHASH=y
+# CONFIG_CRYPTO_POLY1305 is not set
+# CONFIG_CRYPTO_MD4 is not set
+CONFIG_CRYPTO_MD5=y
+# CONFIG_CRYPTO_MICHAEL_MIC is not set
+# CONFIG_CRYPTO_RMD128 is not set
+# CONFIG_CRYPTO_RMD160 is not set
+# CONFIG_CRYPTO_RMD256 is not set
+# CONFIG_CRYPTO_RMD320 is not set
+CONFIG_CRYPTO_SHA1=y
+CONFIG_CRYPTO_SHA256=y
+CONFIG_CRYPTO_SHA512=y
+# CONFIG_CRYPTO_TGR192 is not set
+# CONFIG_CRYPTO_WP512 is not set
+
+#
+# Ciphers
+#
+CONFIG_CRYPTO_AES=y
+# CONFIG_CRYPTO_ANUBIS is not set
+CONFIG_CRYPTO_ARC4=y
+# CONFIG_CRYPTO_BLOWFISH is not set
+# CONFIG_CRYPTO_CAMELLIA is not set
+# CONFIG_CRYPTO_CAST5 is not set
+# CONFIG_CRYPTO_CAST6 is not set
+# CONFIG_CRYPTO_DES is not set
+# CONFIG_CRYPTO_FCRYPT is not set
+# CONFIG_CRYPTO_KHAZAD is not set
+# CONFIG_CRYPTO_SALSA20 is not set
+# CONFIG_CRYPTO_CHACHA20 is not set
+# CONFIG_CRYPTO_SEED is not set
+# CONFIG_CRYPTO_SERPENT is not set
+# CONFIG_CRYPTO_TEA is not set
+CONFIG_CRYPTO_TWOFISH=y
+CONFIG_CRYPTO_TWOFISH_COMMON=y
+
+#
+# Compression
+#
+# CONFIG_CRYPTO_DEFLATE is not set
+# CONFIG_CRYPTO_ZLIB is not set
+CONFIG_CRYPTO_LZO=y
+# CONFIG_CRYPTO_842 is not set
+# CONFIG_CRYPTO_LZ4 is not set
+# CONFIG_CRYPTO_LZ4HC is not set
+# CONFIG_CRYPTO_ZSTD is not set
+
+#
+# Random Number Generation
+#
+CONFIG_CRYPTO_ANSI_CPRNG=y
+CONFIG_CRYPTO_DRBG_MENU=y
+CONFIG_CRYPTO_DRBG_HMAC=y
+# CONFIG_CRYPTO_DRBG_HASH is not set
+# CONFIG_CRYPTO_DRBG_CTR is not set
+CONFIG_CRYPTO_DRBG=y
+CONFIG_CRYPTO_JITTERENTROPY=y
+CONFIG_CRYPTO_USER_API=y
+CONFIG_CRYPTO_USER_API_HASH=y
+CONFIG_CRYPTO_USER_API_SKCIPHER=y
+# CONFIG_CRYPTO_USER_API_RNG is not set
+# CONFIG_CRYPTO_USER_API_AEAD is not set
+CONFIG_CRYPTO_HASH_INFO=y
+CONFIG_CRYPTO_HW=y
+# CONFIG_CRYPTO_DEV_CCP is not set
+# CONFIG_CRYPTO_DEV_ROCKCHIP_V1 is not set
+# CONFIG_CRYPTO_DEV_ROCKCHIP_V2 is not set
+CONFIG_ASYMMETRIC_KEY_TYPE=y
+CONFIG_ASYMMETRIC_PUBLIC_KEY_SUBTYPE=y
+CONFIG_PUBLIC_KEY_ALGO_RSA=y
+CONFIG_X509_CERTIFICATE_PARSER=y
+CONFIG_PKCS7_MESSAGE_PARSER=y
+# CONFIG_PKCS7_TEST_KEY is not set
+# CONFIG_SIGNED_PE_FILE_VERIFICATION is not set
+
+#
+# Certificates for signature checking
+#
+CONFIG_SYSTEM_TRUSTED_KEYRING=y
+CONFIG_SYSTEM_TRUSTED_KEYS=""
+CONFIG_ARM64_CRYPTO=y
+CONFIG_CRYPTO_SHA1_ARM64_CE=y
+CONFIG_CRYPTO_SHA2_ARM64_CE=y
+CONFIG_CRYPTO_GHASH_ARM64_CE=y
+# CONFIG_CRYPTO_POLY_HASH_ARM64_CE is not set
+CONFIG_CRYPTO_AES_ARM64_CE=y
+CONFIG_CRYPTO_AES_ARM64_CE_CCM=y
+CONFIG_CRYPTO_AES_ARM64_CE_BLK=y
+# CONFIG_CRYPTO_AES_ARM64_NEON_BLK is not set
+# CONFIG_CRYPTO_CRC32_ARM64 is not set
+CONFIG_BINARY_PRINTF=y
+
+#
+# Library routines
+#
+CONFIG_BITREVERSE=y
+CONFIG_HAVE_ARCH_BITREVERSE=y
+CONFIG_RATIONAL=y
+CONFIG_GENERIC_STRNCPY_FROM_USER=y
+CONFIG_GENERIC_STRNLEN_USER=y
+CONFIG_GENERIC_NET_UTILS=y
+CONFIG_GENERIC_PCI_IOMAP=y
+CONFIG_GENERIC_IO=y
+CONFIG_ARCH_USE_CMPXCHG_LOCKREF=y
+CONFIG_CRC_CCITT=y
+CONFIG_CRC16=y
+CONFIG_CRC_T10DIF=y
+CONFIG_CRC_ITU_T=y
+CONFIG_CRC32=y
+# CONFIG_CRC32_SELFTEST is not set
+CONFIG_CRC32_SLICEBY8=y
+# CONFIG_CRC32_SLICEBY4 is not set
+# CONFIG_CRC32_SARWATE is not set
+# CONFIG_CRC32_BIT is not set
+CONFIG_CRC7=y
+CONFIG_LIBCRC32C=y
+# CONFIG_CRC8 is not set
+CONFIG_AUDIT_ARCH_COMPAT_GENERIC=y
+# CONFIG_RANDOM32_SELFTEST is not set
+CONFIG_ZLIB_INFLATE=y
+CONFIG_LZO_COMPRESS=y
+CONFIG_LZO_DECOMPRESS=y
+CONFIG_LZ4_DECOMPRESS=y
+CONFIG_XZ_DEC=y
+# CONFIG_XZ_DEC_X86 is not set
+# CONFIG_XZ_DEC_POWERPC is not set
+# CONFIG_XZ_DEC_IA64 is not set
+CONFIG_XZ_DEC_ARM=y
+CONFIG_XZ_DEC_ARMTHUMB=y
+# CONFIG_XZ_DEC_SPARC is not set
+CONFIG_XZ_DEC_BCJ=y
+# CONFIG_XZ_DEC_TEST is not set
+CONFIG_DECOMPRESS_GZIP=y
+CONFIG_DECOMPRESS_BZIP2=y
+CONFIG_DECOMPRESS_LZMA=y
+CONFIG_DECOMPRESS_XZ=y
+CONFIG_DECOMPRESS_LZO=y
+CONFIG_DECOMPRESS_LZ4=y
+CONFIG_GENERIC_ALLOCATOR=y
+CONFIG_ASSOCIATIVE_ARRAY=y
+CONFIG_HAS_IOMEM=y
+CONFIG_HAS_DMA=y
+CONFIG_CPU_RMAP=y
+CONFIG_DQL=y
+CONFIG_NLATTR=y
+CONFIG_ARCH_HAS_ATOMIC64_DEC_IF_POSITIVE=y
+CONFIG_CLZ_TAB=y
+# CONFIG_CORDIC is not set
+# CONFIG_DDR is not set
+CONFIG_MPILIB=y
+CONFIG_LIBFDT=y
+CONFIG_OID_REGISTRY=y
+# CONFIG_SG_SPLIT is not set
+CONFIG_ARCH_HAS_SG_CHAIN=y
diff --git a/layers/meta-balena-nanopc-t4/recipes-kernel/linux/linux-rockchip_%.bbappend b/layers/meta-balena-nanopc-t4/recipes-kernel/linux/linux-rockchip_%.bbappend
index e65b4cfea..e8fd580cd 100644
--- a/layers/meta-balena-nanopc-t4/recipes-kernel/linux/linux-rockchip_%.bbappend
+++ b/layers/meta-balena-nanopc-t4/recipes-kernel/linux/linux-rockchip_%.bbappend
@@ -1 +1,8 @@
-inherit kernel-resin
+inherit kernel-resin deploy
+
+# Fix module build on this 4.4 kernel
+RESIN_CONFIGS_append_lec-px30 = " ccstackprotector"
+RESIN_CONFIGS[ccstackprotector] = " \
+    CONFIG_CC_STACKPROTECTOR_NONE=y \
+    CONFIG_CC_STACKPROTECTOR_STRONG=n \
+"
diff --git a/layers/meta-balena-nanopc-t4/recipes-kernel/linux/linux-rockchip_4.4.185.bb b/layers/meta-balena-nanopc-t4/recipes-kernel/linux/linux-rockchip_4.4.185.bb
new file mode 100644
index 000000000..7f35dbc7b
--- /dev/null
+++ b/layers/meta-balena-nanopc-t4/recipes-kernel/linux/linux-rockchip_4.4.185.bb
@@ -0,0 +1,38 @@
+SUMMARY = "LEC-PX30 kernel"
+DESCRIPTION = "ADLINK iPi LEC-PX30 kernel"
+
+FILESEXTRAPATHS_prepend := "${THISDIR}/files/4.4.185:"
+
+LINUX_VERSION = "4.4.185"
+
+SRC_URI = " \
+    git://github.com/rockchip-linux/kernel.git;branch=develop-4.4 \
+    file://adjust_wireless_firmware_path.patch \
+"
+SRCREV = "e83084b53d4e02f5fd25aad25b42ffd3108c7f15"
+
+require recipes-kernel/linux/linux-yocto.inc
+
+PV = "${LINUX_VERSION}+git${SRCPV}"
+
+S = "${WORKDIR}/git"
+
+KCONFIG_MODE="--alldefconfig"
+
+COMPATIBLE_MACHINE = "(lec-px30)"
+
+SRC_URI += " \
+        file://defconfig \
+        file://0001-Device-tree-for-LEC-PX30-A2.patch \
+        file://0002-Added-ethernet-driver-support-for-LEC-PX30-A2.patch \
+        file://0003-Added-mcp25xxfd-driver-support-for-LEC-PX30-A2.patch \
+        file://0004-Added-LT9611-driver-support-for-LEC-PX30-A2.patch \
+        file://0005-Modified-compatible-property-as-per-target-kernel-dt.patch \
+        file://0006-Added-Sx150x-gpio-expander-suppport-for-LEC-PX30-A2.patch \
+        file://0007-Added-SPI-chip-select-enable-disable-support-for-SPI.patch \
+"
+
+# Comment the below line to mount file system from eMMC
+# SRC_URI += "file://0008-Modified-Boot-Arguments-to-mount-fileystem-from-SD-c.patch")"
+
+
diff --git a/smarc-px30.coffee b/smarc-px30.coffee
new file mode 100644
index 000000000..42c2be215
--- /dev/null
+++ b/smarc-px30.coffee
@@ -0,0 +1,35 @@
+deviceTypesCommon = require '@resin.io/device-types/common'
+{ networkOptions, commonImg, instructions } = deviceTypesCommon
+
+module.exports =
+	version: 1
+	slug: 'smarc-px30'
+	name: 'I-Pi SMARC PX30 SD-CARD'
+	arch: 'aarch64'
+	state: 'new'
+	community: true
+
+	instructions: commonImg.instructions
+
+	gettingStartedLink:
+		windows: 'https://www.balena.io/docs/learn/getting-started/smarc-px30/nodejs/'
+		osx: 'https://www.balena.io/docs/learn/getting-started/smarc-px30/nodejs/'
+		linux: 'https://www.balena.io/docs/learn/getting-started/smarc-px30/nodejs/'
+
+	yocto:
+		machine: 'smarc-px30'
+		image: 'resin-image'
+		fstype: 'resinos-img'
+		version: 'yocto-thud'
+		deployArtifact: 'resin-image-smarc-px30.resinos-img'
+		compressed: true
+
+	options: [ networkOptions.group ]
+
+	configuration:
+		config:
+			partition:
+				primary: 1
+			path: '/config.json'
+
+	initialization: commonImg.initialization
diff --git a/smarc-px30.svg b/smarc-px30.svg
new file mode 100644
index 000000000..1e46babee
--- /dev/null
+++ b/smarc-px30.svg
@@ -0,0 +1 @@
+<svg id="Layer_1" data-name="Layer 1" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 40 40"><defs><style>.cls-1{fill:#0091bd;}</style></defs><path class="cls-1" d="M9.3,10.14h2.62V21.37H9.3V20.2a4.3,4.3,0,0,1-3.36,1.51c-3.46,0-5.44-2.88-5.44-6C.5,12.09,3,9.85,6,9.85a4.05,4.05,0,0,1,3.33,1.6ZM3.19,15.81c0,1.93,1.22,3.58,3.11,3.58a3.21,3.21,0,0,0,3.18-3.54c0-2.46-1.51-3.63-3.18-3.63C4.41,12.2,3.19,13.82,3.19,15.81ZM15,10.14h2.62v1a4.58,4.58,0,0,1,1.09-.94,2.94,2.94,0,0,1,1.6-.38,3.88,3.88,0,0,1,2.06.53l-1.07,2.37A2.33,2.33,0,0,0,20,12.34a2.05,2.05,0,0,0-1.63.61,3.57,3.57,0,0,0-.73,2.58v5.84H15Zm9.05,0h2.62v1a3.42,3.42,0,0,1,2.77-1.33,3.29,3.29,0,0,1,2.9,1.64,4,4,0,0,1,3.33-1.64,3.59,3.59,0,0,1,3.2,1.76,5.6,5.6,0,0,1,.59,2.84v6.93H36.88V15.22a4.75,4.75,0,0,0-.25-2,1.48,1.48,0,0,0-1.5-1,1.94,1.94,0,0,0-1.55.82,4.5,4.5,0,0,0-.51,2.56V21.4H30.45V15.22a4.75,4.75,0,0,0-.25-2,1.48,1.48,0,0,0-1.5-1,1.94,1.94,0,0,0-1.55.82,4.5,4.5,0,0,0-.51,2.56V21.4H24.09Z"/><path class="cls-1" d="M14.88,32.17,12.5,24.85h1.7l1,3.47c.12.42.22.82.33,1.18s.21.77.33,1.19h.06c.13-.42.24-.82.33-1.19s.2-.76.31-1.18l1-3.47h1.62L16.8,32.17Z"/><path class="cls-1" d="M23.73,32.34a4.08,4.08,0,0,1-1.24-.18,3,3,0,0,1-1-.49,2.46,2.46,0,0,1-.64-.77,2.08,2.08,0,0,1-.23-1,2,2,0,0,1,.44-1.33,3.59,3.59,0,0,1,1.07-.85v-.06a3.62,3.62,0,0,1-.86-.89A2.12,2.12,0,0,1,21,25.56a2.37,2.37,0,0,1,.21-1,2.07,2.07,0,0,1,.59-.78,2.6,2.6,0,0,1,.9-.49,3.78,3.78,0,0,1,1.14-.17,3.31,3.31,0,0,1,1.11.18,2.37,2.37,0,0,1,.85.49,2.17,2.17,0,0,1,.55.77,2.48,2.48,0,0,1,.19,1,1.88,1.88,0,0,1-.35,1.14,2.93,2.93,0,0,1-.81.8v.06a3.53,3.53,0,0,1,1.09.9,2.16,2.16,0,0,1,.45,1.42,2.11,2.11,0,0,1-.22,1,2.39,2.39,0,0,1-.64.78,3.32,3.32,0,0,1-1,.52A4.08,4.08,0,0,1,23.73,32.34Zm0-1.43a1.34,1.34,0,0,0,.86-.27A1,1,0,0,0,25,29.8a.91.91,0,0,0-.13-.5,1.37,1.37,0,0,0-.38-.38,3.37,3.37,0,0,0-.6-.33l-.76-.34a2.54,2.54,0,0,0-.49.64,1.64,1.64,0,0,0-.2.77,1.12,1.12,0,0,0,.41.92A1.47,1.47,0,0,0,23.77,30.91ZM24.29,27a1.94,1.94,0,0,0,.55-1.3,1.18,1.18,0,0,0-.29-.83,1.12,1.12,0,0,0-1.49-.07,1,1,0,0,0-.3.77,1,1,0,0,0,.42.86A5.17,5.17,0,0,0,24.29,27Z"/></svg>
\ No newline at end of file